diff --git a/packages/lexical-list/src/__tests__/unit/LexicalListItemNode.test.ts b/packages/lexical-list/src/__tests__/unit/LexicalListItemNode.test.ts index 058ef1c1bc3..f6382166886 100644 --- a/packages/lexical-list/src/__tests__/unit/LexicalListItemNode.test.ts +++ b/packages/lexical-list/src/__tests__/unit/LexicalListItemNode.test.ts @@ -1503,6 +1503,53 @@ describe('LexicalListItemNode tests', () => { ); }); + test('Option Enabled: Preserves numbering when a nested sublist precedes the split', async () => { + const {editor} = testEnv; + await editor.update(() => { + const root = $getRoot(); + const list = $createListNode('number'); + const item1 = $createListItemNode(); + item1.append($createTextNode('A')); + + // A nested sublist lives inside its own wrapper
  • , which renders no + // marker of its own and so does not consume a number. + const nestedHolder = $createListItemNode(); + const nested = $createListNode('bullet'); + const nestedItem = $createListItemNode(); + nestedItem.append($createTextNode('A.1')); + nested.append(nestedItem); + nestedHolder.append(nested); + + const item2 = $createListItemNode(); + item2.append($createTextNode('B')); + const emptyItem = $createListItemNode(); + const item3 = $createListItemNode(); + item3.append($createTextNode('C')); + + list.append(item1, nestedHolder, item2, emptyItem, item3); + root.append(list); + + emptyItem.select(); + }); + + await editor.update(() => { + $handleListInsertParagraph(true); + }); + + editor.read('latest', () => { + // A is 1 and B is 2, so the removed empty item was 3 and the split-off + // list has to continue from 3 -- the same rule the flat case follows. + const [firstList, paragraph, secondList] = $getRoot().getChildren(); + expect($isListNode(firstList)).toBe(true); + expect($isParagraphNode(paragraph)).toBe(true); + expect($isListNode(secondList)).toBe(true); + expect((secondList as ListNode).getStart()).toBe(3); + const firstItem = (secondList as ListNode).getFirstChild(); + expect($isListItemNode(firstItem)).toBe(true); + expect((firstItem as ListItemNode).getValue()).toBe(3); + }); + }); + describe('ListItemNode $transform wraps orphan ListItemNodes', () => { test('wraps a single orphan ListItemNode under root in a ListNode', () => { const {editor} = testEnv; diff --git a/packages/lexical-list/src/utils.ts b/packages/lexical-list/src/utils.ts index b01befcba59..59e5a9979ae 100644 --- a/packages/lexical-list/src/utils.ts +++ b/packages/lexical-list/src/utils.ts @@ -201,5 +201,9 @@ export function $getNewListStart( list: ListNode, listItem: ListItemNode, ): number { - return list.getStart() + listItem.getIndexWithinParent(); + // The split-off list continues from the number the split point was rendered + // with. That is the item's value, not its index: `updateChildrenListItemValue` + // deliberately does not advance the counter for items that only wrap a nested + // list, so index and value diverge as soon as the list has a sublist. + return listItem.getValue(); }