Skip to content

Commit

Permalink
Remove special case for collapsible forward deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
etrepum committed Feb 18, 2025
1 parent 484cd5b commit c1cd850
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 102 deletions.
111 changes: 106 additions & 5 deletions packages/lexical-playground/__tests__/e2e/Selection.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ test.describe.parallel('Selection', () => {
);
});

test('Can delete forward a Collapsible', async ({page, isPlainText}) => {
test(`Can't delete forward a Collapsible`, async ({page, isPlainText}) => {
test.skip(isPlainText);
if (!IS_MAC) {
// Do Windows/Linux have equivalent shortcuts?
Expand All @@ -389,6 +389,7 @@ test.describe.parallel('Selection', () => {
await focusEditor(page);
await page.keyboard.type('abc');
await insertCollapsible(page);
await page.keyboard.type('title');
await moveToEditorBeginning(page);
await moveRight(page, 3);
await deleteForward(page);
Expand All @@ -401,15 +402,68 @@ test.describe.parallel('Selection', () => {
dir="ltr">
<span data-lexical-text="true">abc</span>
</p>
<div class="Collapsible__container" open="">
<summary class="Collapsible__title">
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">title</span>
</p>
</summary>
<div class="Collapsible__content">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</div>
</div>
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
`,
);
});

// TODO I don't think this test is correct but at least this test will prevent it from regressing
// even further
test('Can delete forward a Table', async ({page, isPlainText}) => {
test(`Can't delete backward a Collapsible`, async ({page, isPlainText}) => {
test.skip(isPlainText);
if (!IS_MAC) {
// Do Windows/Linux have equivalent shortcuts?
return;
}
await focusEditor(page);
await page.keyboard.type('abc');
await insertCollapsible(page);
await page.keyboard.type('title');
await moveRight(page, 2);
await page.keyboard.type('after');
await moveLeft(page, 'after'.length);
await deleteBackward(page);

await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">abc</span>
</p>
<div class="Collapsible__container" open="">
<summary class="Collapsible__title">
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">title</span>
</p>
</summary>
<div class="Collapsible__content">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</div>
</div>
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">after</span>
</p>
`,
);
});

test(`Can't delete forward a Table`, async ({page, isPlainText}) => {
test.skip(isPlainText);
if (!IS_MAC) {
// Do Windows/Linux have equivalent shortcuts?
Expand Down Expand Up @@ -451,6 +505,53 @@ test.describe.parallel('Selection', () => {
);
});

test(`Can't delete backward a Table`, async ({page, isPlainText}) => {
test.skip(isPlainText);
if (!IS_MAC) {
// Do Windows/Linux have equivalent shortcuts?
return;
}
await focusEditor(page);
await page.keyboard.type('abc');
await insertTable(page, 1, 2);
await moveToEditorEnd(page);
await page.keyboard.type('after');
await moveLeft(page, 'after'.length);
await deleteBackward(page);

await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">abc</span>
</p>
<table class="PlaygroundEditorTheme__table">
<colgroup>
<col style="width: 92px" />
<col style="width: 92px" />
</colgroup>
<tr>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
<th
class="PlaygroundEditorTheme__tableCell PlaygroundEditorTheme__tableCellHeader">
<p class="PlaygroundEditorTheme__paragraph"><br /></p>
</th>
</tr>
</table>
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">after</span>
</p>
`,
);
});

test('Can delete block elements', async ({page, isPlainText}) => {
test.skip(isPlainText);
await focusEditor(page);
Expand Down
97 changes: 0 additions & 97 deletions packages/lexical-playground/src/plugins/CollapsiblePlugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,12 @@ import {
mergeRegister,
} from '@lexical/utils';
import {
$caretFromPoint,
$createParagraphNode,
$extendCaretToRange,
$getCaretRange,
$getSelection,
$isChildCaret,
$isElementNode,
$isRangeSelection,
$isSiblingCaret,
$setSelectionFromCaretRange,
COMMAND_PRIORITY_LOW,
createCommand,
DELETE_CHARACTER_COMMAND,
ElementNode,
INSERT_PARAGRAPH_COMMAND,
INTERNAL_$isBlock,
KEY_ARROW_DOWN_COMMAND,
KEY_ARROW_LEFT_COMMAND,
KEY_ARROW_RIGHT_COMMAND,
Expand Down Expand Up @@ -170,93 +160,6 @@ export default function CollapsiblePlugin(): null {
}
}),

// This handles the case when container is collapsed and we delete its previous sibling
// into it, it would cause collapsed content deleted (since it's display: none, and selection
// swallows it when deletes single char). Instead we expand container, which is although
// not perfect, but avoids bigger problem
editor.registerCommand(
DELETE_CHARACTER_COMMAND,
(isBackward) => {
const selection = $getSelection();
if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
return false;
}
if (!isBackward) {
// inherit strange forward delete behavior per e2e election test
// 'Can delete forward a Collapsible'
const forwardRange = $extendCaretToRange(
$caretFromPoint(selection.anchor, 'next'),
);
let lastBlock: ElementNode | undefined;
for (const caret of forwardRange.iterNodeCarets('shadowRoot')) {
if ($isSiblingCaret(caret) && $isElementNode(caret.origin)) {
if (INTERNAL_$isBlock(caret.origin)) {
lastBlock = caret.origin;
}
continue;
} else if (
lastBlock &&
$isChildCaret(caret) &&
$isCollapsibleContainerNode(caret.origin)
) {
// Unwrap the collapsible, emulating the previous behavior
// where the forward deletion opened the title's shadow root,
// but skip the step where we let the transforms unwrap the nodes
const children = caret.origin.getChildren().flatMap((child) => {
if ($isCollapsibleTitleNode(child)) {
const nestedChildren = child.getChildren();
const [firstChild] = nestedChildren;
// unnest the first paragraph of the title
if (
$isElementNode(firstChild) &&
INTERNAL_$isBlock(firstChild)
) {
nestedChildren.splice(0, 1, ...firstChild.getChildren());
}
return nestedChildren;
} else if ($isCollapsibleContentNode(child)) {
return child.getChildren();
} else {
return [child];
}
});
const collapsedRange = $getCaretRange(
forwardRange.anchor,
forwardRange.anchor,
);
// insert the children,
$setSelectionFromCaretRange(collapsedRange).insertNodes(
children,
);
caret.origin.remove();
$setSelectionFromCaretRange(collapsedRange);
return true;
}
break;
}
}

if (selection.anchor.offset !== 0) {
return false;
}

const anchorNode = selection.anchor.getNode();
const topLevelElement = anchorNode.getTopLevelElement();
if (topLevelElement === null) {
return false;
}

const container = topLevelElement.getPreviousSibling();
if (!$isCollapsibleContainerNode(container) || container.getOpen()) {
return false;
}

container.setOpen(true);
return true;
},
COMMAND_PRIORITY_LOW,
),

// When collapsible is the last child pressing down/right arrow will insert paragraph
// below it to allow adding more content. It's similar what $insertBlockNode
// (mainly for decorators), except it'll always be possible to continue adding
Expand Down

0 comments on commit c1cd850

Please sign in to comment.