-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lexical-list] Bullet item color matches text color #7024
base: main
Are you sure you want to change the base?
Changes from 5 commits
7080a79
af615a0
6b7f32c
5869d83
5622672
f9f3cc2
e8c3774
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,13 +8,17 @@ | |
|
||
import type {SerializedListItemNode} from './LexicalListItemNode'; | ||
import type {ListType, SerializedListNode} from './LexicalListNode'; | ||
import type {LexicalCommand, LexicalEditor} from 'lexical'; | ||
import type {LexicalCommand, LexicalEditor, LexicalNode} from 'lexical'; | ||
|
||
import {mergeRegister} from '@lexical/utils'; | ||
import { | ||
$getNodeByKey, | ||
$getSelection, | ||
$isRangeSelection, | ||
COMMAND_PRIORITY_LOW, | ||
createCommand, | ||
INSERT_PARAGRAPH_COMMAND, | ||
TextNode, | ||
} from 'lexical'; | ||
|
||
import { | ||
|
@@ -97,6 +101,49 @@ export function registerList(editor: LexicalEditor): () => void { | |
}, | ||
COMMAND_PRIORITY_LOW, | ||
), | ||
editor.registerMutationListener( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using an editor.update in a mutation listener causes an update cascade, if this were directly updating the DOM style and not the node's state it wouldn't be a problem but this will cause a second reconciliation as implemented. Is there a reason why this can't work as a transform? I think it should be fine so long as you check to make sure that the style actually changed before setting it (and thus marking the node dirty again, causing a second iteration of the transform) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I did remove it, but it was throwing me the error that it couldn't find an activeEditor, I'll try again, in case it was an HMR thing, but I tried a few times. OK, will look into making this a transform vs mutationListener. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well if you are reading or updating the editor from a mutation listener then you do need a read or update call, it doesn't put you in a specific editor state because there are two to choose from. Updating is something that shouldn't happen in a mutation listener for the same reason that it shouldn't happen in an update listener (an update listener is basically a mutation listener for the whole editor state) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, revisiting this again. Your suggestion is to have 1 node transform on TextNode-level and have the whole logic in there or just convert the current mutationlistener to a nodetransform. I did the convert of this method, but it doesn't reflect correctly if I already have the style applied and then create a bullet, it only updates after the first character is typed. I've pushed, despite not working to get a bit better clarity There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation is not what I meant, a node transform shouldn't do anything with the DOM, it can just modify the lexical nodes which will reflect to the DOM with updateDOM and/or createDOM. It's possible I misread the previous commit, I'll take a look at it locally in the next day or so. |
||
ListItemNode, | ||
(mutations) => { | ||
editor.update(() => { | ||
for (const [key, type] of mutations) { | ||
if (type !== 'destroyed') { | ||
const node = $getNodeByKey<ListItemNode>(key); | ||
const listItemElement = editor.getElementByKey(key); | ||
if (node && listItemElement) { | ||
const firstChild = node.getFirstChild<LexicalNode>(); | ||
if (firstChild) { | ||
const textElement = editor.getElementByKey( | ||
firstChild.getKey(), | ||
); | ||
if (textElement && textElement.style.cssText) { | ||
listItemElement.setAttribute( | ||
'style', | ||
textElement.style.cssText, | ||
); | ||
} | ||
} else { | ||
const selection = $getSelection(); | ||
if ( | ||
$isRangeSelection(selection) && | ||
selection.isCollapsed() && | ||
selection.style | ||
) { | ||
listItemElement.setAttribute('style', selection.style); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
}, | ||
{skipInitialization: false}, | ||
), | ||
editor.registerNodeTransform(TextNode, (node) => { | ||
const listItemParentNode = node.getParent(); | ||
if ($isListItemNode(listItemParentNode)) { | ||
listItemParentNode.markDirty(); | ||
} | ||
}), | ||
); | ||
return removeListener; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, could you explain to me the general rule here. Why are we avoiding returning 'true' in updateDOM with something like (this.style != prevNode.style), but we are always ok on doing the comparison and changing this in here and returning false. Does updateDOM returning true, trigger a waterfall of updates that is unnecessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check here is for performance and to avoid having style=“” show up in the DOM, it could be unconditionally set.
returning true should be avoided whenever possible, it creates a lot more work on the browser and can lose state if there’s anything ephemeral in the DOM. Same reason why react does DOM diffing instead of rendering everything from scratch, just more manual here.