From 9836d540f3203f5068b206db6263d380161c0bc8 Mon Sep 17 00:00:00 2001 From: GermanJablo <43938777+GermanJablo@users.noreply.github.com> Date: Sat, 2 Dec 2023 14:37:44 -0300 Subject: [PATCH] Fix insertNodes bugs (#5325) Co-authored-by: Gerard Rovira Co-authored-by: EgonBolton <43938777+EgonBolton@users.noreply.github.com> --- .../unit/LexicalSelectionHelpers.test.ts | 30 ++++++++++++++++++- packages/lexical/src/LexicalSelection.ts | 13 ++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts b/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts index 07eaedc842f..9f56e900505 100644 --- a/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts +++ b/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts @@ -7,7 +7,7 @@ */ import {$createLinkNode} from '@lexical/link'; -import {$createHeadingNode} from '@lexical/rich-text'; +import {$createHeadingNode, $isHeadingNode} from '@lexical/rich-text'; import { $getSelectionStyleValueForProperty, $patchStyleText, @@ -21,6 +21,7 @@ import { $getRoot, $getSelection, $insertNodes, + $isParagraphNode, $isRangeSelection, $setSelection, RangeSelection, @@ -2631,6 +2632,33 @@ describe('insertNodes', () => { expect($getRoot().getTextContent()).toBe('footext'); }); }); + + it('last node is LineBreakNode', async () => { + const editor = createTestEditor(); + const element = document.createElement('div'); + editor.setRootElement(element); + + await editor.update(() => { + // Empty text node to test empty text split + const paragraph = $createParagraphNode(); + $getRoot().append(paragraph); + const selection = paragraph.select(); + expect($isRangeSelection(selection)).toBeTruthy(); + + const newHeading = $createHeadingNode('h1').append( + $createTextNode('heading'), + ); + selection.insertNodes([newHeading, $createLineBreakNode()]); + }); + editor.getEditorState().read(() => { + expect(element.innerHTML).toBe( + '

heading


', + ); + const selectedNode = ($getSelection() as RangeSelection).anchor.getNode(); + expect($isParagraphNode(selectedNode)).toBeTruthy(); + expect($isHeadingNode(selectedNode.getPreviousSibling())).toBeTruthy(); + }); + }); }); describe('$patchStyleText', () => { diff --git a/packages/lexical/src/LexicalSelection.ts b/packages/lexical/src/LexicalSelection.ts index df2c793b6d4..5e7df8368ee 100644 --- a/packages/lexical/src/LexicalSelection.ts +++ b/packages/lexical/src/LexicalSelection.ts @@ -1596,18 +1596,17 @@ export class RangeSelection implements BaseSelection { const notInline = (node: LexicalNode) => ($isElementNode(node) || $isDecoratorNode(node)) && !node.isInline(); - const nodeToSelect = $isElementNode(last) - ? last.getLastDescendant() || last - : last; if (!nodes.some(notInline)) { const index = removeTextAndSplitBlock(this); firstBlock.splice(index, 0, nodes); - nodeToSelect.selectEnd(); + last.selectEnd(); return; } // CASE 3: At least 1 element of the array is not inline - const blocks = $wrapInlineNodes(nodes).getChildren(); + const blocksParent = $wrapInlineNodes(nodes); + const nodeToSelect = blocksParent.getLastDescendant()!; + const blocks = blocksParent.getChildren(); const isLI = (node: LexicalNode) => '__value' in node && '__checked' in node; const isMergeable = (node: LexicalNode) => @@ -1632,7 +1631,7 @@ export class RangeSelection implements BaseSelection { if ( insertedParagraph && - $isElementNode(lastToInsert) && + $isElementNode(lastInsertedBlock) && (isLI(insertedParagraph) || INTERNAL_$isBlock(lastToInsert)) ) { lastInsertedBlock.append(...insertedParagraph.getChildren()); @@ -1648,7 +1647,7 @@ export class RangeSelection implements BaseSelection { const lastChild = $isElementNode(firstBlock) ? firstBlock.getLastChild() : null; - if ($isLineBreakNode(lastChild) && lastToInsert !== firstBlock) { + if ($isLineBreakNode(lastChild) && lastInsertedBlock !== firstBlock) { lastChild.remove(); } }