Skip to content

[Lexical-list] Bug Fix : Exit list on delete for empty non-first list items#8314

Closed
Jynx2004 wants to merge 50 commits into
facebook:mainfrom
Jynx2004:link_merge
Closed

[Lexical-list] Bug Fix : Exit list on delete for empty non-first list items#8314
Jynx2004 wants to merge 50 commits into
facebook:mainfrom
Jynx2004:link_merge

Conversation

@Jynx2004

@Jynx2004 Jynx2004 commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the standard word processor behavior (Microsoft Word, Google Docs) where pressing Delete on an empty non-first list item exits the list and creates a new paragraph block.

Changes

  • Added DELETE_CHARACTER_COMMAND handler in registerList() that:
    • Detects when cursor is at the start of an empty list item
    • Only triggers for non-first list items (preserves existing behavior for first items)
    • Removes the empty list item and creates a paragraph below the list
    • Moves cursor to the newly created paragraph
    • Uses COMMAND_PRIORITY_LOW to not interfere with other delete handlers

Behavior

Before: Empty list item would remain in the list
After: Pressing Delete on an empty non-first list item exits the list and creates a paragraph

Closes #7577

Test plan

  • Added comprehensive unit tests covering:
    • Main behavior: exits list and creates paragraph
    • Edge case: first empty list item doesn't exit
    • Edge case: list item with content doesn't exit
    • Edge case: removes list if it becomes empty

Comment thread packages/lexical-list/src/index.ts Outdated
Comment thread packages/lexical-list/src/index.ts
Comment on lines +262 to +286
function listNodeHasOverflow(
editor: LexicalEditor,
listNode: ListNode,
): boolean {
const overflowConfig = editor._nodes.get('overflow');
if (!overflowConfig) {
return false;
}
const overflowKlass = overflowConfig.klass;
const stack: Array<LexicalNode> = [listNode];
while (stack.length > 0) {
const node = stack.pop()!;
if (node instanceof overflowKlass) {
return true;
}
if ($isElementNode(node)) {
let child = (node as ElementNode).getLastChild();
while (child !== null) {
stack.push(child);
child = child.getPreviousSibling();
}
}
}
return false;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not acceptable for list to depend on overflow implementation details

@etrepum etrepum marked this pull request as draft April 22, 2026 04:19
@etrepum etrepum added the stale-pr PRs that are closed due to staleness. Please reopen the PR if there are new updates label May 11, 2026
@etrepum

etrepum commented May 11, 2026

Copy link
Copy Markdown
Collaborator

Closing due to inactivity, re-open or create a new PR when/if you intend to continue working on this

@etrepum etrepum closed this May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. extended-tests Run extended e2e tests on a PR stale-pr PRs that are closed due to staleness. Please reopen the PR if there are new updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Backspace on Empty ListItem Does Not Convert to Paragraph (Word-like Behavior Broken)

2 participants