@@ -184,14 +184,32 @@ export default class SortableGroupModifier extends Modifier {
184
184
const dimension = direction === 'y' ? 'height' : 'width' ;
185
185
// DOWN or RIGHT
186
186
if ( toIndex > fromIndex ) {
187
- value = item [ direction ] ;
188
- set ( item , direction , nextItem [ direction ] + ( nextItem [ dimension ] - item [ dimension ] ) ) ;
189
- set ( nextItem , direction , value ) ;
187
+ if ( direction === 'grid' ) {
188
+ const valueX = item . x ;
189
+ const valueY = item . y ;
190
+ item . x = nextItem . x + ( nextItem . width - item . width ) ;
191
+ item . y = nextItem . y + ( nextItem . height - item . height ) ;
192
+ nextItem . x = valueX ;
193
+ nextItem . y = valueY ;
194
+ } else {
195
+ value = item [ direction ] ;
196
+ set ( item , direction , nextItem [ direction ] + ( nextItem [ dimension ] - item [ dimension ] ) ) ;
197
+ set ( nextItem , direction , value ) ;
198
+ }
190
199
// UP or LEFT
191
200
} else {
192
- value = nextItem [ direction ] ;
193
- set ( nextItem , direction , item [ direction ] + ( item [ dimension ] - nextItem [ dimension ] ) ) ;
194
- set ( item , direction , value ) ;
201
+ if ( direction === 'grid' ) {
202
+ const valueX = nextItem . x ;
203
+ const valueY = nextItem . y ;
204
+ nextItem . x = item . x + ( item . width - nextItem . width ) ;
205
+ nextItem . y = item . y + ( item . height - nextItem . height ) ;
206
+ item . x = valueX ;
207
+ item . y = valueY ;
208
+ } else {
209
+ value = nextItem [ direction ] ;
210
+ set ( nextItem , direction , item [ direction ] + ( item [ dimension ] - nextItem [ dimension ] ) ) ;
211
+ set ( item , direction , value ) ;
212
+ }
195
213
}
196
214
}
197
215
@@ -212,9 +230,9 @@ export default class SortableGroupModifier extends Modifier {
212
230
this . moveItem ( selectedItem , 1 ) ;
213
231
} else if ( direction === 'y' && isUpArrowKey ( event ) ) {
214
232
this . moveItem ( selectedItem , - 1 ) ;
215
- } else if ( direction === 'x' && isLeftArrowKey ( event ) ) {
233
+ } else if ( ( direction === 'x' || direction === 'grid' ) && isLeftArrowKey ( event ) ) {
216
234
this . moveItem ( selectedItem , - 1 ) ;
217
- } else if ( direction === 'x' && isRightArrowKey ( event ) ) {
235
+ } else if ( ( direction === 'x' || direction === 'grid' ) && isRightArrowKey ( event ) ) {
218
236
this . moveItem ( selectedItem , 1 ) ;
219
237
} else if ( isEnterKey ( event ) || isSpaceKey ( event ) ) {
220
238
// confirm will reset the selectedItem, so caching it here before we remove it.
@@ -531,10 +549,14 @@ export default class SortableGroupModifier extends Modifier {
531
549
*/
532
550
@computed ( 'direction' , 'sortedItems' )
533
551
get firstItemPosition ( ) {
534
- const direction = this . direction ;
535
552
const sortedItems = this . sortedItems ;
536
553
537
- return sortedItems [ 0 ] [ `${ direction } ` ] - sortedItems [ 0 ] . spacing ;
554
+ const item = sortedItems [ 0 ] ;
555
+
556
+ return {
557
+ x : item . x - item . spacing ,
558
+ y : item . y - item . spacing ,
559
+ } ;
538
560
}
539
561
540
562
/**
@@ -544,7 +566,18 @@ export default class SortableGroupModifier extends Modifier {
544
566
*/
545
567
get sortedItems ( ) {
546
568
const direction = this . direction ;
547
- return this . items . sort ( ( a , b ) => a [ direction ] - b [ direction ] ) ;
569
+
570
+ const groupStyles = getComputedStyle ( this . element ) ;
571
+ const groupWidth = parseFloat ( groupStyles . width ) ;
572
+
573
+ return this . items . sort ( ( a , b ) => {
574
+ if ( direction === 'grid' ) {
575
+ let { ax, ay, bx, by } = this . _calculateGridPosition ( a , b , groupWidth ) ;
576
+ if ( ay == by ) return ax - bx ;
577
+ return ay - by ;
578
+ }
579
+ return a [ direction ] - b [ direction ] ;
580
+ } ) ;
548
581
}
549
582
550
583
/**
@@ -603,31 +636,68 @@ export default class SortableGroupModifier extends Modifier {
603
636
/**
604
637
Update item positions (relatively to the first element position).
605
638
@method update
639
+ @param {SortableItemModifier[] } sortedItems
606
640
*/
607
641
@action
608
- update ( ) {
609
- let sortedItems = this . sortedItems ;
642
+ update ( sortedItems ) {
643
+ if ( ! sortedItems ) {
644
+ sortedItems = this . sortedItems ;
645
+ }
646
+
610
647
// Position of the first element
611
- let position = this . _firstItemPosition ;
648
+ let axis = this . _firstItemPosition ;
612
649
613
650
// Just in case we haven’t called prepare first.
614
- if ( position === undefined ) {
615
- position = this . firstItemPosition ;
651
+ if ( axis === undefined ) {
652
+ axis = this . firstItemPosition ;
653
+ }
654
+
655
+ let direction = this . direction ;
656
+
657
+ let position = 0 ;
658
+ let groupPositionRight = 0 ;
659
+ let lastTopOffset = 0 ;
660
+ let maxPrevHeight = 0 ;
661
+
662
+ if ( direction === 'grid' ) {
663
+ position = axis . x ;
664
+ lastTopOffset = axis . y ;
665
+ const groupStyles = getComputedStyle ( this . element ) ;
666
+ groupPositionRight = position + parseFloat ( groupStyles . width ) ;
667
+ } else {
668
+ position = axis [ direction ] ;
616
669
}
617
670
618
671
sortedItems . forEach ( ( item ) => {
619
- let dimension ;
620
- let direction = this . direction ;
672
+ if ( direction === 'grid' && position + item . width > groupPositionRight ) {
673
+ lastTopOffset = lastTopOffset + maxPrevHeight ;
674
+ position = axis . x ;
675
+ maxPrevHeight = 0 ;
676
+ }
621
677
622
678
if ( ! isDestroyed ( item ) && ! item . isDragging ) {
623
- set ( item , direction , position ) ;
679
+ if ( direction === 'grid' ) {
680
+ item . x = position ;
681
+ item . y = lastTopOffset ;
682
+ } else {
683
+ set ( item , direction , position ) ;
684
+ }
624
685
}
625
686
626
687
// add additional spacing around active element
627
688
if ( item . isBusy ) {
628
689
position += item . spacing * 2 ;
629
690
}
630
691
692
+ let dimension ;
693
+
694
+ if ( direction === 'grid' ) {
695
+ dimension = 'width' ;
696
+
697
+ if ( item . height > maxPrevHeight ) {
698
+ maxPrevHeight = item . height ;
699
+ }
700
+ }
631
701
if ( direction === 'x' ) {
632
702
dimension = 'width' ;
633
703
}
@@ -697,6 +767,111 @@ export default class SortableGroupModifier extends Modifier {
697
767
return announcer ;
698
768
}
699
769
770
+ _calculateGridPosition ( a , b , groupWidth ) {
771
+ const groupTopPos = a . element . parentNode ?. offsetTop ?? 0 ;
772
+ const groupLeftPos = a . element . parentNode ?. offsetLeft ?? 0 ;
773
+
774
+ const position = {
775
+ ax : a . x ,
776
+ ay : a . y ,
777
+ bx : b . x ,
778
+ by : b . y ,
779
+ } ;
780
+
781
+ if ( a . isDragging ) {
782
+ const dragItemPos = this . _calculateGridDragItemPos (
783
+ position . ax ,
784
+ position . ay ,
785
+ position . bx ,
786
+ position . by ,
787
+ b . width ,
788
+ b . height ,
789
+ a . moveDirection ,
790
+ groupTopPos ,
791
+ groupLeftPos ,
792
+ groupWidth
793
+ ) ;
794
+ position . ax = dragItemPos . x ;
795
+ position . ay = dragItemPos . y ;
796
+ } else if ( b . isDragging ) {
797
+ const dragItemPos = this . _calculateGridDragItemPos (
798
+ position . bx ,
799
+ position . by ,
800
+ position . ax ,
801
+ position . ay ,
802
+ a . width ,
803
+ a . height ,
804
+ b . moveDirection ,
805
+ groupTopPos ,
806
+ groupLeftPos ,
807
+ groupWidth
808
+ ) ;
809
+ position . bx = dragItemPos . x ;
810
+ position . by = dragItemPos . y ;
811
+ }
812
+
813
+ // Math.hypot needs always a positive number (-5 = 5 in hypot).
814
+ // As a negative number will be positive, we need to fake position from non dragged element
815
+ if ( a . isDragging && position . ax <= 0 ) {
816
+ position . ax = 0 ;
817
+ position . bx += 1 ;
818
+ }
819
+
820
+ if ( b . isDragging && position . bx <= 0 ) {
821
+ position . bx = 0 ;
822
+ position . ax += 1 ;
823
+ }
824
+
825
+ return position ;
826
+ }
827
+
828
+ _calculateGridDragItemPos ( x , y , otherX , otherY , width , height , moveDirection , groupTopPos , groupLeftPos , groupWidth ) {
829
+ const toleranceWidth = width / 4 ;
830
+ const initialX = x ;
831
+
832
+ if ( moveDirection . left ) {
833
+ x = x - toleranceWidth ;
834
+ }
835
+
836
+ if ( moveDirection . right ) {
837
+ x = x + toleranceWidth ;
838
+ // Calculate the maximum of items in row & the maximal x-position of last item
839
+ const itemsPerRow = Math . floor ( groupWidth / width ) ;
840
+ const possibleLastItemPos = ( itemsPerRow - 1 ) * width + groupLeftPos ;
841
+ if ( otherX > initialX && x + width > possibleLastItemPos - 1 ) {
842
+ // Removing one pixel is necessary to move drag item before other element
843
+ x = possibleLastItemPos - 1 ;
844
+ }
845
+ }
846
+
847
+ if ( y < groupTopPos ) {
848
+ y = groupTopPos ;
849
+ }
850
+
851
+ const toleranceHeight = height / 4 ;
852
+
853
+ // When item is moved a quarter of height to top, user wants to move up
854
+ if ( moveDirection . top && y - height + toleranceHeight <= otherY && y >= otherY ) {
855
+ y = otherY ;
856
+ // tolerance that it doesn't jump directly in previews line
857
+ } else if ( moveDirection . top && y >= otherY - toleranceHeight && y <= otherY ) {
858
+ y = otherY ;
859
+ }
860
+
861
+ // When item is moved a quarter of height to bottom, user wants to move down
862
+ if ( moveDirection . bottom && y <= otherY + height - toleranceHeight && y >= otherY ) {
863
+ y = otherY ;
864
+ // tolerance that it doesn't jump directly in next line
865
+ } else if ( moveDirection . bottom && y > otherY - toleranceHeight && y <= otherY ) {
866
+ y = otherY ;
867
+ }
868
+
869
+ return {
870
+ x : x ,
871
+ y : y ,
872
+ } ;
873
+ }
874
+
700
875
// end of API
701
876
702
877
addEventListener ( ) {
0 commit comments