From b3dc8d690b721a0eb8c0ff1b671fdd9b25cac0b2 Mon Sep 17 00:00:00 2001 From: Vitali Kozlov Date: Wed, 22 May 2024 00:49:15 -0700 Subject: [PATCH] Fix delete line for selections ending with elements --- .../__tests__/e2e/Selection.spec.mjs | 46 +++++++++++++++++++ packages/lexical/src/LexicalSelection.ts | 16 ++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs b/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs index 22a15388f5e0..20ebff8f39c6 100644 --- a/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs @@ -217,6 +217,52 @@ test.describe('Selection', () => { ); }); + test('can delete line which ends with element with CMD+delete', async ({ + page, + isPlainText, + }) => { + test.skip(isPlainText || !IS_MAC); + await focusEditor(page); + await page.keyboard.type('One'); + await page.keyboard.press('Enter'); + await page.keyboard.type('Two'); + // sample image + await pasteFromClipboard(page, { + 'text/html': ` + +
+ Yellow flower in tilt shift lens +
+
+ `, + }); + + const deleteLine = async () => { + await keyDownCtrlOrMeta(page); + await page.keyboard.press('Backspace'); + await keyUpCtrlOrMeta(page); + }; + + await deleteLine(); + await assertHTML( + page, + html` +

+ One +

+ `, + ); + await deleteLine(); + await assertHTML( + page, + html` +


+ `, + ); + }); + test('Can insert inline element within text and put selection after it', async ({ page, isPlainText, diff --git a/packages/lexical/src/LexicalSelection.ts b/packages/lexical/src/LexicalSelection.ts index a62cb36e00b2..d6c76af0f201 100644 --- a/packages/lexical/src/LexicalSelection.ts +++ b/packages/lexical/src/LexicalSelection.ts @@ -1696,10 +1696,16 @@ export class RangeSelection implements BaseSelection { */ deleteLine(isBackward: boolean): void { if (this.isCollapsed()) { - if (this.anchor.type === 'text') { - this.modify('extend', isBackward, 'lineboundary'); + // Since `domSelection.modify('extend', ..., 'lineboundary')` works well for text selections + // but doesn't properly handle selections which end on elements, a space character is added + // for such selections transforming their anchor's type to 'text' + const anchorIsElement = this.anchor.type === 'element'; + if (anchorIsElement) { + this.insertText(' '); } + this.modify('extend', isBackward, 'lineboundary'); + // If selection is extended to cover text edge then extend it one character more // to delete its parent element. Otherwise text content will be deleted but empty // parent node will remain @@ -1707,6 +1713,12 @@ export class RangeSelection implements BaseSelection { if (endPoint.offset === 0) { this.modify('extend', isBackward, 'character'); } + + // Adjusts selection to include an extra character added for element anchors to remove it + if (anchorIsElement) { + const startPoint = isBackward ? this.anchor : this.focus; + startPoint.set(startPoint.key, startPoint.offset + 1, startPoint.type); + } } this.removeText(); }