facebook / lexical

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

Bug: Additional break line when initializing or copy/pasting in the editor with break lines #3677

Closed mariofpalb closed 11 months ago

mariofpalb commented 1 year ago

When I initialize the Lexical editor from an DOM like <p><br></p>, passing through generateNodesFromDOM and inserting the generated nodes to the editor, it imports it with an additional break line like <p><br><br></p>. This makes the editor have more break lines than expected. It is also curious that both
count as one character if I delete them and count the characters.

@zeitstein mentioned in a discord chat that when trying to pass a single <p></p> without break lines, it also imports it with an additional break line like <p><br></p>. They also mention that that this PR can be related -> https://github.com/facebook/lexical/pull/3581 (thanks for rising this up in the discord chat, here is the full thread: https://discord.com/channels/953974421008293909/1060331843578249376)

I also managed to reproduce it when copying some text with break lines from the Notes Application from my Mac.

Lexical version: 0.7.6

Steps To Reproduce

  1. Write something like this (with some break lines) in a Note in the Mac Notes Application:
    
    First line

Fifth line


2. Copy the five lines (or the block of text you have written) and paste it in the lexical playground editor
3. You can find that there are more than 5 lines in this particular case.
<img width="1177" alt="image" src="https://user-images.githubusercontent.com/26458400/210821038-a7e4d114-222c-4034-9cb5-5a73be0fb2d1.png">

-----------------

Here is an example of the InitialState plugin to initialize the editor from a preview HTML string (not sure why is duplicating the text in the codesandbox, in my code only runs once): https://codesandbox.io/s/break-line-example-w1ic2x?file=/src/plugins/InitialState.js

## The current behavior
When copying or initializing some text with break lines, it duplicates them, making the text different from the expected one.

## The expected behavior
When copying or initializing some text with break lines, the number of break lines is exactly the same as the one inserted in the editor.
chalecki commented 1 year ago

I'm facing the same issue. I've noticed $generateNodesFromDOM is adding an extra <br /> tag for each "empty" paragraph. If you put any character, eg. period or even empty space - the problem does not exist

rabishah commented 1 year ago

Facing the same issue, exactly as @chalecki .

willwang888 commented 1 year ago

Facing the same issue!

chalecki commented 1 year ago

I think it was introduced in #590 in commit f38d4d52f24abc26d59c73989fc92c36fab19f8d .

Commenting on this line https://github.com/facebook/lexical/blob/main/packages/lexical/src/LexicalReconciler.ts#L324 does the trick I think but I lack knowledge on the overall flow so would be best to hear from @trueadm more on this behavior

almazkaliyev commented 1 year ago

maybe this can helps u

const removeLineBreaks = (inputHtml: string): string => {
  let copy = inputHtml
  copy = copy.replaceAll('<br>', '')
  return copy
}

const onChange = (_: EditorState, editorInstance: LexicalEditor) => {
  editorInstance.update(() => {
    const generatedHtml = $generateHtmlFromNodes(editorInstance, null)
    let resultHtmlString = wrapTables(generatedHtml)
    resultHtmlString = removeLineBreaks(generatedHtml)
    setHtml(resultHtmlString)
  })
}
mariofpalb commented 1 year ago

@almazkaliyev the point is not to remove every <br> from the generated HTML, I want to keep the exact number of break lines from a copy/paste and when initialising the editor with some previous HTML saved from the database.

sagarchoudhary96 commented 1 year ago

@thegreatercurve do we have any updates for the fix for this issue ?

obinmatt commented 1 year ago

@thegreatercurve any updates? 😄

oleksandr-danylchenko commented 1 year ago
Having the same issue. An empty text field has the <p><br></p by default Rich text field $generateHtmlFromNodes result
image image
ferugi commented 1 year ago

I've found that a single empty paragraph converted to HTML with $generateHtmlFromNodes will result in <p><br></p>. However when converting back from HTML to Lexical nodes with $generateNodesFromDOM and then updating the contents of the editor's root node, I end up with the following HTML in the ContentEditable element: <p><br><br></p>.

keithhackbarth commented 1 year ago

@oleksandr-danylchenko and @ferugi - I am experiencing both of your observations reproducibly as well. @thegreatercurve - Let me know if anything we can do to help (ie test cases, repo steps, etc.)

rjullian commented 1 year ago

I'm facing a similar issue and would really appreciate any updates on the progress made toward resolving it. Thanks.

alexz-spotnana commented 1 year ago

This is my function to initialize the editor state from HTML. Since the lexical's renderer adds additional
tags, this function does the opposite – decreases the number of
tags by 1 in the parsed DOM and then parses DOM to nodes and inserts them into the editor.

const parser = new DOMParser();
const dom = parser.parseFromString(initialHtml, 'text/html');

const elementsWithBr = dom.querySelectorAll('*:not(br) > br');
for (let i = 0; i < elementsWithBr.length; i += 1) {
  const brElement = elementsWithBr[i];
  const parentElement = brElement.parentNode;
  const lastBr = parentElement?.querySelectorAll('br:last-child')[0];
  if (lastBr === brElement) {
    parentElement?.removeChild(brElement);
  }
}

const nodes = $generateNodesFromDOM(editor, dom);

$getRoot().select();
$insertNodes(nodes);

Does work for me, but checked on some basic HTML fragments that fit my needs.

gajanan999 commented 3 months ago

HI ,

I am facing this issue still in version 0.12.0

kazimirchuk commented 3 months ago

Facing the same issue version 0.12.4

rtrevisanlectra commented 2 months ago

Hello, same issue in version 0.13.1

mustafamoe commented 2 months ago

Same issue in version 0.13.1

dpr10 commented 1 month ago

Hello, I'm having the same issue but found a workaround, if you clear the editor before the insertion, the line break is removed.

$getRoot().clear();
$getRoot().select();
$insertNodes(nodes);
Michael7141 commented 1 month ago

Hello, I'm having the same issue but found a workaround, if you clear the editor before the insertion, the line break is removed.

$getRoot().clear();
$getRoot().select();
$insertNodes(nodes);

bless your soul; cuz u set mine on fire