1- import { getClosestAncestorBlockGroupIndex } from 'roosterjs-content-model-dom' ;
2- import type { DeleteSelectionStep , ContentModelListItem } from 'roosterjs-content-model-types' ;
1+ import {
2+ createListItem ,
3+ getClosestAncestorBlockGroupIndex ,
4+ mutateBlock ,
5+ } from 'roosterjs-content-model-dom' ;
6+ import type {
7+ DeleteSelectionStep ,
8+ ContentModelListItem ,
9+ ContentModelBlock ,
10+ } from 'roosterjs-content-model-types' ;
311
412/**
513 * @internal
@@ -10,21 +18,65 @@ export const deleteList: DeleteSelectionStep = context => {
1018 }
1119
1220 const { paragraph, marker, path } = context . insertPoint ;
21+ const index = getClosestAncestorBlockGroupIndex < ContentModelListItem > (
22+ path ,
23+ [ 'ListItem' ] ,
24+ [ 'TableCell' , 'FormatContainer' ]
25+ ) ;
26+ const item = path [ index ] ;
27+ const parent = path [ index + 1 ] ;
1328
14- if ( paragraph . segments [ 0 ] == marker ) {
15- const index = getClosestAncestorBlockGroupIndex < ContentModelListItem > (
16- path ,
17- [ 'ListItem' ] ,
18- [ 'TableCell' , 'FormatContainer' ]
19- ) ;
20- const item = path [ index ] as ContentModelListItem | undefined ;
21- const lastLevel = item ?. levels [ item . levels . length - 1 ] ;
22-
23- if ( lastLevel && item ?. blocks [ 0 ] == paragraph ) {
24- if ( lastLevel . format . displayForDummyItem == 'block' ) {
25- item . levels . pop ( ) ;
29+ if (
30+ item ?. blockGroupType == 'ListItem' &&
31+ item . levels . length > 0 &&
32+ paragraph . segments [ 0 ] == marker &&
33+ parent
34+ ) {
35+ const mutableList = mutateBlock ( item ) ;
36+ const lastLevel = mutableList . levels [ mutableList . levels . length - 1 ] ;
37+ const listItemIndex = parent . blocks . indexOf ( item ) ;
38+ const previousItem = parent . blocks [ listItemIndex - 1 ] ;
39+
40+ // 1. If the last level is dummy, just remove it (legacy behavior)
41+ // 2. If focus is at the beginning of list item and previous block is a list item with the same level count,
42+ // merge current list item into previous one
43+ // 3. Otherwise, split the list item. Keep the blocks before the paragraph in the current list item,
44+ // move the rest to a new list item (if there are multiple levels) or directly to parent (if only one level)
45+ if ( lastLevel . format . displayForDummyItem == 'block' ) {
46+ mutableList . levels . pop ( ) ;
47+
48+ context . deleteResult = 'range' ;
49+ } else if (
50+ item . blocks [ 0 ] == paragraph &&
51+ previousItem ?. blockType == 'BlockGroup' &&
52+ previousItem . blockGroupType == 'ListItem' &&
53+ previousItem . levels . length == mutableList . levels . length
54+ ) {
55+ const mutablePreviousItem = mutateBlock ( previousItem ) ;
56+
57+ mutablePreviousItem . blocks . push ( ...mutableList . blocks ) ;
58+ mutateBlock ( parent ) . blocks . splice ( listItemIndex , 1 ) ;
59+
60+ context . deleteResult = 'range' ;
61+ } else {
62+ const removedBlocks = mutableList . blocks . splice (
63+ mutableList . blocks . indexOf ( paragraph ) ,
64+ mutableList . blocks . length
65+ ) ;
66+
67+ if ( mutableList . levels . length > 1 ) {
68+ const newListItem = createListItem (
69+ mutableList . levels . slice ( 0 , - 1 ) ,
70+ mutableList . format
71+ ) ;
72+
73+ newListItem . blocks = removedBlocks . map (
74+ block => mutateBlock ( block ) as ContentModelBlock
75+ ) ;
76+
77+ mutateBlock ( parent ) . blocks . splice ( listItemIndex + 1 , 0 , newListItem ) ;
2678 } else {
27- lastLevel . format . displayForDummyItem = 'block' ;
79+ mutateBlock ( parent ) . blocks . splice ( listItemIndex + 1 , 0 , ... removedBlocks ) ;
2880 }
2981
3082 context . deleteResult = 'range' ;
0 commit comments