diff --git a/packages/lexical-html/src/index.ts b/packages/lexical-html/src/index.ts index 2ef1ebbdad5..858c5fdf0c2 100644 --- a/packages/lexical-html/src/index.ts +++ b/packages/lexical-html/src/index.ts @@ -31,6 +31,7 @@ import { $isTextNode, ArtificialNode__DO_NOT_USE, ElementNode, + isInlineDomNode, } from 'lexical'; /** @@ -294,9 +295,16 @@ function $createNodesFromDOM( } if (currentLexicalNode == null) { - // If it hasn't been converted to a LexicalNode, we hoist its children - // up to the same level as it. - lexicalNodes = lexicalNodes.concat(childLexicalNodes); + if (childLexicalNodes.length > 0) { + // If it hasn't been converted to a LexicalNode, we hoist its children + // up to the same level as it. + lexicalNodes = lexicalNodes.concat(childLexicalNodes); + } else { + if (isBlockDomNode(node) && isDomNodeBetweenTwoInlineNodes(node)) { + // Empty block dom node that hasnt been converted, we replace it with a linebreak if its between inline nodes + lexicalNodes = lexicalNodes.concat($createLineBreakNode()); + } + } } else { if ($isElementNode(currentLexicalNode)) { // If the current node is a ElementNode after conversion, @@ -359,3 +367,12 @@ function $unwrapArtificalNodes( node.remove(); } } + +function isDomNodeBetweenTwoInlineNodes(node: Node): boolean { + if (node.nextSibling == null || node.previousSibling == null) { + return false; + } + return ( + isInlineDomNode(node.nextSibling) && isInlineDomNode(node.previousSibling) + ); +} diff --git a/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx b/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx index 4847d838d5b..4ab0ea03d91 100644 --- a/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx +++ b/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx @@ -678,6 +678,42 @@ describe('LexicalEventHelpers', () => { ], name: 'two lines and br in spans', }, + { + expectedHTML: + '
  1. 1
    2

  2. 3
', + inputs: [ + pasteHTML('
  1. 1
    2
  2. 3
'), + ], + name: 'empty block node in li behaves like a line break', + }, + { + expectedHTML: + '

1
2

', + inputs: [pasteHTML('
1
2
')], + name: 'empty block node in div behaves like a line break', + }, + { + expectedHTML: + '

12

', + inputs: [pasteHTML('
12
')], + name: 'empty inline node does not behave like a line break', + }, + { + expectedHTML: + '

1

2

', + inputs: [pasteHTML('
1
2
')], + name: 'empty block node between non inline siblings does not behave like a line break', + }, + { + expectedHTML: + '

a

b b

c

z

d e

fg

', + inputs: [ + pasteHTML( + `
a
b b
c
z
d e
fg
`, + ), + ], + name: 'nested divs', + }, ]; suite.forEach((testUnit, i) => { diff --git a/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts b/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts index 014681abf43..b146548383c 100644 --- a/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts +++ b/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts @@ -51,25 +51,6 @@ describe('HTMLCopyAndPaste tests', () => { 456 `, }, - { - expectedHTML: `

a

b b

c

z

d e

fg

`, - name: 'nested divs', - pastedHTML: `
- a -
- b b -
- c -
-
- z -
-
- d e -
- fg -
`, - }, { expectedHTML: `

a b c d e

f g h

`, name: 'multiple nested spans and divs',