1- import { Fragment , type NodeRange , type NodeType , Slice } from 'prosemirror-model' ;
1+ import { Fragment , type Node , type NodeRange , type NodeType , Slice } from 'prosemirror-model' ;
22import { wrapInList } from 'prosemirror-schema-list' ;
33import type { Command , Transaction } from 'prosemirror-state' ;
44import { ReplaceAroundStep , liftTarget } from 'prosemirror-transform' ;
@@ -30,11 +30,17 @@ export const joinPrevList = joinPreviousBlock({
3030 sinks list items deeper.
3131 */
3232const sink = ( tr : Transaction , range : NodeRange , itemType : NodeType ) => {
33- const before = tr . mapping . map ( range . start ) ;
34- const after = tr . mapping . map ( range . end ) ;
35- const startIndex = tr . mapping . map ( range . startIndex ) ;
36-
33+ console . warn ( 'sink' , '=========>>>' ) ;
34+ const before = range . start ;
35+ const after = range . end ;
36+ const startIndex = range . startIndex ;
3737 const parent = range . parent ;
38+
39+ console . log ( 'before' , before ) ;
40+ console . log ( 'after' , after ) ;
41+ console . log ( 'startIndex' , startIndex ) ;
42+ console . log ( 'parent' , parent ) ;
43+
3844 const nodeBefore = parent . child ( startIndex - 1 ) ;
3945
4046 const nestedBefore = nodeBefore . lastChild && nodeBefore . lastChild . type === parent . type ;
@@ -56,65 +62,135 @@ const sink = (tr: Transaction, range: NodeRange, itemType: NodeType) => {
5662 true ,
5763 ) ,
5864 ) ;
65+
66+ // After sinking, lift any nested <li> children back out
67+ const from = range . start ;
68+ const $movedPos = tr . doc . resolve ( from ) ;
69+ const movedItem = $movedPos . nodeAfter ;
70+
71+ if ( movedItem ) {
72+ movedItem . forEach ( ( child , offset ) => {
73+ if ( child . type === parent . type ) {
74+ const nestedStart = from + offset + 1 ;
75+ const nestedEnd = nestedStart + child . nodeSize ;
76+ const $liStart = tr . doc . resolve ( nestedStart + 1 ) ;
77+ const $liEnd = tr . doc . resolve ( nestedEnd - 1 ) ;
78+ const liftRange = $liStart . blockRange ( $liEnd , ( node ) => node . type === itemType ) ;
79+
80+ if ( liftRange ) {
81+ const targetDepth = liftTarget ( liftRange ) ;
82+ if ( targetDepth !== null ) {
83+ tr . lift ( liftRange , targetDepth ) ;
84+ }
85+ }
86+ }
87+ } ) ;
88+ }
89+
5990 return true ;
6091} ;
6192
93+ const isListItemNode = ( node : Node , itemType : NodeType ) =>
94+ node . childCount > 0 && node . firstChild ! . type === itemType ;
95+
96+ /**
97+ * Returns a map of list item positions that should be transformed (e.g., sink or lift).
98+ */
99+ function getListItemsToTransform (
100+ tr : Transaction ,
101+ itemType : NodeType ,
102+ {
103+ start,
104+ end,
105+ from,
106+ to,
107+ } : {
108+ start : number ;
109+ end : number ;
110+ from : number ;
111+ to : number ;
112+ } ,
113+ ) : Map < number , number > {
114+ // console.warn('getListItemsToTransform', start, end, from, to);
115+ const listItemsPoses = new Map < number , number > ( ) ;
116+ let pos = start ;
117+
118+ while ( pos <= end ) {
119+ const node = tr . doc . nodeAt ( pos ) ;
120+
121+ // console.log('pos', pos);
122+ // console.log('node', node?.type.name);
123+
124+ if ( node ?. type === itemType ) {
125+ // console.log('list pos ----->: ', pos, pos + node.nodeSize);
126+ const isBeetwwen =
127+ ( pos <= from && pos + node . nodeSize >= from ) ||
128+ ( pos <= to && pos + node . nodeSize >= to ) ;
129+ if ( isBeetwwen ) {
130+ // console.warn(isBeetwwen);
131+ listItemsPoses . set ( pos , pos + node . nodeSize ) ;
132+ } else {
133+ // console.log(isBeetwwen, pos, pos + node.nodeSize, 'from:to', from, to);
134+ }
135+ }
136+
137+ pos ++ ;
138+ }
139+
140+ return listItemsPoses ;
141+ }
142+
62143export function sinkOnlySelectedListItem ( itemType : NodeType ) : Command {
63144 return ( { tr, selection} , dispatch ) => {
64- const { $from, $to} = selection ;
65- const selectionRange = $from . blockRange (
66- $to ,
67- ( node ) => node . childCount > 0 && node . firstChild ! . type === itemType ,
145+ const { $from, $to, from, to} = selection ;
146+ const listItemSelectionRange = $from . blockRange ( $to , ( node ) =>
147+ isListItemNode ( node , itemType ) ,
68148 ) ;
69- if ( ! selectionRange ) {
70- return false ;
71- }
72-
73- const { startIndex, parent, start, end} = selectionRange ;
74- if ( startIndex === 0 ) {
75- return false ;
76- }
77149
78- const nodeBefore = parent . child ( startIndex - 1 ) ;
79- if ( nodeBefore . type !== itemType ) {
150+ if ( ! listItemSelectionRange ) {
80151 return false ;
81152 }
82153
83154 if ( dispatch ) {
84- // lifts following list items sequentially to prepare correct nesting structure
85- let currentEnd = end - 1 ;
86- while ( currentEnd > start ) {
87- const selectionEnd = tr . mapping . map ( $to . pos ) ;
88-
89- const $candidateBlockEnd = tr . doc . resolve ( currentEnd ) ;
90- const candidateBlockStartPos = $candidateBlockEnd . before ( $candidateBlockEnd . depth ) ;
91- const $candidateBlockStart = tr . doc . resolve ( candidateBlockStartPos ) ;
92- const candidateBlockRange = $candidateBlockStart . blockRange ( $candidateBlockEnd ) ;
93-
94- if ( candidateBlockRange ?. start ) {
95- const $rangeStart = tr . doc . resolve ( candidateBlockRange . start ) ;
96- const shouldLift =
97- candidateBlockRange . start > selectionEnd && isListNode ( $rangeStart . parent ) ;
98-
99- if ( shouldLift ) {
100- currentEnd = candidateBlockRange . start ;
101-
102- const targetDepth = liftTarget ( candidateBlockRange ) ;
103- if ( targetDepth !== null ) {
104- tr . lift ( candidateBlockRange , targetDepth ) ;
105- }
106- }
107- }
155+ const { start, end} = listItemSelectionRange ;
156+ const listItemsPoses = getListItemsToTransform ( tr , itemType , {
157+ start,
158+ end,
159+ from,
160+ to,
161+ } ) ;
108162
109- currentEnd -- ;
110- }
163+ console . warn ( listItemsPoses , 'start: end' , start , end ) ;
164+
165+ for ( const [ startPos , endPos ] of listItemsPoses ) {
166+ const mappedStart = tr . mapping . map ( startPos ) ;
167+ const nodeStart = tr . doc . nodeAt ( mappedStart ) ;
111168
112- // sinks the selected list item deeper into the list hierarchy
113- sink ( tr , selectionRange , itemType ) ;
169+ const mappedEnd = tr . mapping . map ( endPos ) ;
170+ // const nodeEnd = tr.doc.nodeAt(mappedEnd );
114171
172+ console . log ( 'startPos ---->' , startPos ) ;
173+ console . log ( 'endPos ---->' , endPos ) ;
174+
175+ console . log ( 'mapped startPos ---->' , mappedStart ) ;
176+ console . log ( 'mapped endPos ---->' , mappedEnd ) ;
177+
178+ console . log ( 'nodeStart ---->' , nodeStart ?. type . name ) ;
179+
180+ const $mappedStart = tr . doc . resolve ( mappedStart ) ;
181+ const $mappedEnd = tr . doc . resolve ( mappedEnd ) ;
182+ const range = $mappedStart . blockRange ( $mappedEnd ) ;
183+
184+ if ( range ) {
185+ console . log ( 'sink ---->' , range . start , range . end , range ) ;
186+ sink ( tr , range , itemType ) ;
187+ }
188+ }
115189 dispatch ( tr . scrollIntoView ( ) ) ;
190+
116191 return true ;
117192 }
193+
118194 return true ;
119195 } ;
120196}
0 commit comments