facebook / lexical

Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.
https://lexical.dev
MIT License
19.09k stars 1.61k forks source link

Bug: Node selection inserts additional line break node #4985

Open Demianeen opened 12 months ago

Demianeen commented 12 months ago

When I make a selection of the paragraph on top of the editor, editor adds additional node.

Lexical version: 0.12.2

https://github.com/facebook/lexical/assets/51330172/efbac5aa-2efe-482c-9cd9-2182179eaf0c

Steps To Reproduce

const paragraphNode = $createParagraphNode()
node.insertBefore(paragraphNode)
paragraphNode.select()
  1. Insert paragraph before the first node
  2. Select it with either select, selectEnd or selectStart as first node

Link to code example: https://codesandbox.io/s/happy-glade-sry4z5?file=/src/plugins/imageBlock/plugins/ImageBlockPlugin/ImageBlockPlugin.tsx

The current behavior

Inserts node if I add node.select() or node.selectStart() or node.selectEnd() when I select paragraph on top of the editor

The expected behavior

It does not insert additional node with line break

acywatson commented 12 months ago

I think this is because we try to add a paragraph node before the node selection if there isn't one so you don't get "stuck" on the decorator node. Does seems like a bug, though.

Demianeen commented 12 months ago

But I do add a paragraph node before selecting it, so there already is one. Or what do you mean?

acywatson commented 12 months ago

But I do add a paragraph node before selecting it, so there already is one. Or what do you mean?

I mean I think the problem is that somewhere in Lexical we try to do something like add a paragraph node before a decorator node if there isn't one. Since you're also adding a paragraph node, there ends up being two. This is just a hypothesis about what is causing the issue.

Demianeen commented 11 months ago

I tried just to select like this:

editor.registerCommand(
        KEY_ENTER_COMMAND,
        (event) => {
          if (event?.shiftKey) {
            parentArticleEditor?.update(() => {
              const imageNode = $getNodeByKey(nodeKey)
              // const paragraphNode = $createParagraphNode()
              // imageNode?.getLatest().insertBefore(paragraphNode)
              // paragraphNode.select()
              imageNode?.selectPrevious()
            })
            return true
          }
          return false
        },
        COMMAND_PRIORITY_NORMAL
      )

Now I can't select at all, so I am not sure if it creates additional node.

Maybe this is because selecting and inserting are happening in the same editor update?

mikelnorth commented 5 months ago

Had a similar issue while setting initial values, worked around it by clearing the root before appending/inserting my own changes.

Does not seem to be a fix for your issue though

For example:

export function SetInitialValueFromJson({
  value,
  disabled,
}: {
  value: SerializedLexicalNode;
  disabled?: boolean;
}) {
  const [editor] = useLexicalComposerContext();

  useEffect(() => {
    editor.update(() => {
      if (!value) return;
      const node = $parseSerializedNode(value);
      // Select the root
      const root = $getRoot();
      root.clear();
      root.append(node);
    });
  }, []);
  return null;
}
1yasa commented 4 months ago

I 'resolved' this problem by a trick way:

    onEnter() {
        console.log('Enter')

        if (!this.selected) return false

        const target = this.node.insertAfter($createParagraphNode()) as ParagraphNode

        window.requestAnimationFrame(() => this.editor.update(() => target.selectStart()))

        return true
    }
Pedshi commented 1 month ago

Had a similar issue where I was trying to add a paragraph node and lexical added ran an extra INSERT_PARAGRAPH_COMMAND which caused two paragraphs to be added. Solved by adding event.preventDefault(); in the KEY_ENTER_COMMAND listener.

This is also how it's handled in ImageComponent.tsx.