1- import { Transaction } from "prosemirror-state" ;
1+ import { reactKeys } from "@handlewithcare/react-prosemirror" ;
2+ import { EditorState , Transaction } from "prosemirror-state" ;
23import { EditorView } from "prosemirror-view" ;
34
45import { setShuffleColumns } from "../commands.ts" ;
6+ import { shufflePluginKey } from "../plugin.ts" ;
57
68export function reposition ( view : EditorView , before : number , rect : DOMRect ) : Transaction | null {
79 const gridWrapper = view . dom . closest ( "[data-shuffle-wrapper]" ) ;
@@ -25,6 +27,7 @@ export function reposition(view: EditorView, before: number, rect: DOMRect): Tra
2527 closestDistance = distance ;
2628 }
2729 }
30+
2831 if ( closestBar === null ) return null ;
2932
3033 const $before = view . state . doc . resolve ( before ) ;
@@ -52,5 +55,100 @@ export function reposition(view: EditorView, before: number, rect: DOMRect): Tra
5255 transaction = tr ;
5356 } ) ;
5457
58+ const parentStart = $before . start ( ) ;
59+ const beforeParent = parentStart - 1 ;
60+
61+ const parent = $before . parent ;
62+
63+ if ( parent . type . spec . pitterPatter ?. shuffle ?. role !== "row" ) {
64+ return transaction ;
65+ }
66+
67+ // setShuffleColumns doesn't change any positions in the doc
68+ // so we can safely use a position from before the transaction
69+ const starts = transaction . doc
70+ . nodeAt ( beforeParent ) !
71+ . children ! . map ( ( child ) => child . attrs [ "shuffleStart" ] ) ;
72+ const order = transaction . doc
73+ . nodeAt ( beforeParent ) !
74+ . children ! . map ( ( _ , index ) => index )
75+ . toSorted ( ( a , b ) => starts [ a ] ! - starts [ b ] ! ) ;
76+
77+ reorderSiblingsOnTransaction (
78+ parentStart ,
79+ order ,
80+ transaction ,
81+ view . state . apply ( transaction ) ,
82+ ( tr ) => {
83+ transaction = tr ;
84+ } ,
85+ ) ;
86+
87+ const newPos = transaction . getMeta ( reactKeys ( ) . spec . key ! ) ! . overrides [ before ] ;
88+
89+ transaction . setMeta ( shufflePluginKey , {
90+ type : "map" ,
91+ payload : { newPos } ,
92+ } ) ;
93+
5594 return transaction ;
5695}
96+
97+ // This is copied from React ProseMirror. I don't
98+ // really feel like we should export this, as it's
99+ // not really a command, but in this case we do need
100+ // this version of it, not the command
101+ function reorderSiblingsOnTransaction (
102+ pos : number ,
103+ order : number [ ] ,
104+ tr : Transaction ,
105+ state : EditorState ,
106+ dispatch : ( tr : Transaction ) => void ,
107+ ) {
108+ const orderLookup = order . reduce < number [ ] > ( ( acc , oldIndex , newIndex ) => {
109+ acc [ oldIndex ] = newIndex ;
110+ return acc ;
111+ } , [ ] ) ;
112+ const $pos = state . doc . resolve ( pos ) ;
113+ if ( $pos . start ( ) !== pos ) {
114+ return false ;
115+ }
116+ if ( ! dispatch ) return true ;
117+ const nodes = $pos . parent . children ;
118+ const reordered = nodes
119+ . map ( ( node , i ) => [ node , i ] as const )
120+ . sort ( ( param , param1 ) => {
121+ let [ , a ] = param ,
122+ [ , b ] = param1 ;
123+ return orderLookup [ a ] ! - orderLookup [ b ] ! ;
124+ } )
125+ . map ( ( param ) => {
126+ let [ node ] = param ;
127+ return node ;
128+ } ) ;
129+ tr . replaceWith ( pos , $pos . parent . content . size + pos , reordered ) ;
130+ const meta : { overrides : Record < number , number > } = {
131+ overrides : { } ,
132+ } ;
133+ const oldPositions = [ ] ;
134+ let start = pos ;
135+ for ( const node of nodes ) {
136+ oldPositions . push ( start ) ;
137+ start += node . nodeSize ;
138+ }
139+ start = pos ;
140+ const newPositions : number [ ] = [ ] ;
141+ for ( let i = 0 ; i < reordered . length ; i ++ ) {
142+ const node = reordered [ i ] ;
143+ newPositions [ order [ i ] ! ] = start ;
144+ start += node ! . nodeSize ;
145+ }
146+ for ( let i = 0 ; i < oldPositions . length ; i ++ ) {
147+ const oldPosition = oldPositions [ i ] ! ;
148+ const newPosition = newPositions [ i ] ! ;
149+ meta . overrides [ oldPosition ] = newPosition ;
150+ }
151+ tr . setMeta ( reactKeys ( ) . spec . key ! , meta ) ;
152+ dispatch ( tr ) ;
153+ return true ;
154+ }
0 commit comments