react-grid-layout 2.2.4 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +5 -0
  2. package/dist/{ResponsiveGridLayout-BjVraYMQ.d.mts → ResponsiveGridLayout-BSYEMZ9d.d.ts} +4 -4
  3. package/dist/{ResponsiveGridLayout-BrhkSyZk.d.ts → ResponsiveGridLayout-RNuyRTPe.d.mts} +4 -4
  4. package/dist/{calculate-DH4EVtn1.d.mts → calculate-BXoe3Mfz.d.mts} +1 -1
  5. package/dist/{calculate-rP3DHexe.d.ts → calculate-Tc1WkIxl.d.ts} +1 -1
  6. package/dist/{chunk-QAWP6PEK.js → chunk-CUP5Y2ZG.js} +495 -154
  7. package/dist/{chunk-55DQUWLA.js → chunk-QAIA5KAO.js} +33 -22
  8. package/dist/{chunk-BMN6M2VL.js → chunk-SL4EZ2NU.js} +49 -34
  9. package/dist/{chunk-LY5GT7Q2.mjs → chunk-TW4BCTKD.mjs} +19 -4
  10. package/dist/{chunk-KDANGDDL.mjs → chunk-VBU6B7II.mjs} +13 -2
  11. package/dist/{chunk-A5WIFECI.js → chunk-VJJIA3HC.js} +7 -3
  12. package/dist/{chunk-7ZM5LVH2.mjs → chunk-Z6CWRR74.mjs} +426 -85
  13. package/dist/{chunk-76RTO6EO.mjs → chunk-ZYNFVPDS.mjs} +7 -3
  14. package/dist/core.d.mts +5 -5
  15. package/dist/core.d.ts +5 -5
  16. package/dist/core.js +67 -67
  17. package/dist/core.mjs +2 -2
  18. package/dist/extras.d.mts +2 -2
  19. package/dist/extras.d.ts +2 -2
  20. package/dist/extras.js +8 -8
  21. package/dist/extras.mjs +1 -1
  22. package/dist/index.d.mts +5 -5
  23. package/dist/index.d.ts +5 -5
  24. package/dist/index.js +39 -39
  25. package/dist/index.mjs +4 -4
  26. package/dist/legacy.d.mts +18 -9
  27. package/dist/legacy.d.ts +18 -9
  28. package/dist/legacy.js +33 -23
  29. package/dist/legacy.mjs +16 -7
  30. package/dist/{position-CSgQSjwQ.d.ts → position-VdYnMJql.d.ts} +1 -1
  31. package/dist/{position-BV-g3Ezg.d.mts → position-iPly-ecb.d.mts} +1 -1
  32. package/dist/react.d.mts +24 -6
  33. package/dist/react.d.ts +24 -6
  34. package/dist/react.js +25 -25
  35. package/dist/react.mjs +4 -4
  36. package/dist/{responsive-BrTV_0tK.d.mts → responsive-BVtXrrTF.d.mts} +1 -1
  37. package/dist/{responsive-C_YtBQYq.d.ts → responsive-C6s9JAJU.d.ts} +1 -1
  38. package/dist/{types-jd8MiKM1.d.mts → types-DlzNckle.d.mts} +22 -0
  39. package/dist/{types-jd8MiKM1.d.ts → types-DlzNckle.d.ts} +22 -0
  40. package/package.json +3 -2
@@ -1,13 +1,77 @@
1
- import { defaultConstraints, setTransform, setTopLeft, perc, applyPositionConstraints, resizeItemInDirection, applySizeConstraints, defaultPositionStrategy, defaultGridConfig, defaultDragConfig, defaultResizeConfig, defaultDropConfig, getCompactor, getBreakpointFromWidth, getColsFromBreakpoint, findOrGenerateResponsiveLayout, getIndentationValue } from './chunk-KDANGDDL.mjs';
2
- import { calcXYRaw, calcGridItemWHPx, clamp, calcGridColWidth, calcWHRaw, calcGridItemPosition, bottom, getLayoutItem, cloneLayoutItem, moveElement, withLayoutItem, getAllCollisions, calcXY, cloneLayout, correctBounds } from './chunk-76RTO6EO.mjs';
3
- import React2, { useState, useRef, useMemo, useCallback, useEffect } from 'react';
1
+ import { defaultConstraints, setTransform, setTopLeft, perc, applyPositionConstraints, resizeItemInDirection, applySizeConstraints, getCompactor, getBreakpointFromWidth, getColsFromBreakpoint, findOrGenerateResponsiveLayout, getIndentationValue, defaultPositionStrategy, defaultGridConfig, defaultDragConfig, defaultResizeConfig, defaultDropConfig } from './chunk-VBU6B7II.mjs';
2
+ import { calcXYRaw, calcGridItemWHPx, clamp, calcGridColWidth, calcWHRaw, calcGridItemPosition, cloneLayout, bottom, correctBounds, getLayoutItem, cloneLayoutItem, moveElement, withLayoutItem, getAllCollisions, calcXY } from './chunk-ZYNFVPDS.mjs';
3
+ import React2, { useState, useRef, useMemo, useCallback, useEffect, useLayoutEffect } from 'react';
4
4
  import { DraggableCore } from 'react-draggable';
5
5
  import { Resizable } from 'react-resizable';
6
6
  import clsx from 'clsx';
7
7
  import { jsx, jsxs } from 'react/jsx-runtime';
8
8
  import { deepEqual } from 'fast-equals';
9
9
 
10
- function GridItem(props) {
10
+ // src/react/components/edgeScroll.ts
11
+ var EDGE_THRESHOLD = 50;
12
+ var SCROLL_STEP = 12;
13
+ function getNearestScrollable(node) {
14
+ let el = node;
15
+ while (el) {
16
+ const style = window.getComputedStyle(el);
17
+ const overflowY = style.overflowY;
18
+ const scrollable = (overflowY === "auto" || overflowY === "scroll") && el.scrollHeight > el.clientHeight;
19
+ if (scrollable) return el;
20
+ el = el.parentElement;
21
+ }
22
+ return null;
23
+ }
24
+ function createEdgeScrollController(node) {
25
+ const scrollContainer = getNearestScrollable(node);
26
+ let rafId = null;
27
+ let lastX = 0;
28
+ let lastY = 0;
29
+ let running = false;
30
+ function step() {
31
+ const container = scrollContainer;
32
+ if (!container) return;
33
+ const rect = container.getBoundingClientRect();
34
+ const { clientHeight, scrollTop, scrollHeight } = container;
35
+ const { scrollLeft, scrollWidth, clientWidth } = container;
36
+ let dy = 0;
37
+ let dx = 0;
38
+ if (lastY < rect.top + EDGE_THRESHOLD && scrollTop > 0) {
39
+ dy = -SCROLL_STEP;
40
+ } else if (lastY > rect.bottom - EDGE_THRESHOLD && scrollTop + clientHeight < scrollHeight) {
41
+ dy = SCROLL_STEP;
42
+ }
43
+ if (lastX < rect.left + EDGE_THRESHOLD && scrollLeft > 0) {
44
+ dx = -SCROLL_STEP;
45
+ } else if (lastX > rect.right - EDGE_THRESHOLD && scrollLeft + clientWidth < scrollWidth) {
46
+ dx = SCROLL_STEP;
47
+ }
48
+ if (dy !== 0 || dx !== 0) {
49
+ container.scrollTop += dy;
50
+ container.scrollLeft += dx;
51
+ }
52
+ if (running) {
53
+ rafId = requestAnimationFrame(step);
54
+ }
55
+ }
56
+ return {
57
+ feed(clientX, clientY) {
58
+ lastX = clientX;
59
+ lastY = clientY;
60
+ if (!running) {
61
+ running = true;
62
+ rafId = requestAnimationFrame(step);
63
+ }
64
+ },
65
+ stop() {
66
+ running = false;
67
+ if (rafId !== null) {
68
+ cancelAnimationFrame(rafId);
69
+ rafId = null;
70
+ }
71
+ }
72
+ };
73
+ }
74
+ function GridItemInner(props) {
11
75
  const {
12
76
  children,
13
77
  cols,
@@ -19,6 +83,7 @@ function GridItem(props) {
19
83
  isDraggable,
20
84
  isResizable,
21
85
  isBounded,
86
+ allowMobileScroll,
22
87
  static: isStatic,
23
88
  useCSSTransforms = true,
24
89
  usePercentages = false,
@@ -71,6 +136,7 @@ function GridItem(props) {
71
136
  const dragPendingRef = useRef(false);
72
137
  const initialDragClientRef = useRef({ x: 0, y: 0 });
73
138
  const thresholdExceededRef = useRef(false);
139
+ const edgeScrollRef = useRef(null);
74
140
  const positionParams = useMemo(
75
141
  () => ({
76
142
  cols,
@@ -88,7 +154,7 @@ function GridItem(props) {
88
154
  maxRows,
89
155
  containerWidth,
90
156
  containerHeight: 0,
91
- // Auto-height grids don't have a fixed container height
157
+ // Overridden per-interaction with the measured container height
92
158
  rowHeight,
93
159
  margin,
94
160
  // Use empty layout here - the actual layout will be accessed via layoutRef when needed
@@ -98,8 +164,9 @@ function GridItem(props) {
98
164
  [cols, maxRows, containerWidth, rowHeight, margin]
99
165
  );
100
166
  const getConstraintContext = useCallback(
101
- () => ({
167
+ (containerHeight) => ({
102
168
  ...constraintContext,
169
+ containerHeight: containerHeight ?? constraintContext.containerHeight,
103
170
  layout: layoutRef.current
104
171
  }),
105
172
  [constraintContext]
@@ -165,6 +232,11 @@ function GridItem(props) {
165
232
  };
166
233
  }
167
234
  dragPositionRef.current = newPosition;
235
+ if (!edgeScrollRef.current) {
236
+ edgeScrollRef.current = createEdgeScrollController(
237
+ node instanceof HTMLElement ? node : null
238
+ );
239
+ }
168
240
  if (dragThreshold > 0) {
169
241
  const mouseEvent = e;
170
242
  initialDragClientRef.current = {
@@ -240,6 +312,7 @@ function GridItem(props) {
240
312
  });
241
313
  }
242
314
  }
315
+ edgeScrollRef.current?.feed(mouseEvent.clientX, mouseEvent.clientY);
243
316
  let top = dragPositionRef.current.top + deltaY;
244
317
  let left = dragPositionRef.current.left + deltaX;
245
318
  if (isBounded) {
@@ -289,6 +362,8 @@ function GridItem(props) {
289
362
  const onDragStop = useCallback(
290
363
  (e, { node }) => {
291
364
  if (!onDragStopProp || !dragging) return;
365
+ edgeScrollRef.current?.stop();
366
+ edgeScrollRef.current = null;
292
367
  const wasPending = dragPendingRef.current;
293
368
  dragPendingRef.current = false;
294
369
  thresholdExceededRef.current = false;
@@ -348,6 +423,7 @@ function GridItem(props) {
348
423
  };
349
424
  }
350
425
  resizePositionRef.current = updatedSize;
426
+ const containerHeight = node?.offsetParent?.clientHeight ?? 0;
351
427
  const rawSize = calcWHRaw(
352
428
  positionParams,
353
429
  updatedSize.width,
@@ -359,7 +435,7 @@ function GridItem(props) {
359
435
  rawSize.w,
360
436
  rawSize.h,
361
437
  resizeHandle2,
362
- getConstraintContext()
438
+ getConstraintContext(containerHeight)
363
439
  );
364
440
  handler(i, newW, newH, {
365
441
  // react-resizable forwards react-draggable's callback event, which is
@@ -529,12 +605,104 @@ function GridItem(props) {
529
605
  handle,
530
606
  cancel: ".react-resizable-handle" + (cancel ? "," + cancel : ""),
531
607
  scale: transformScale,
608
+ allowMobileScroll,
532
609
  nodeRef: elementRef,
533
610
  children: newChild
534
611
  }
535
612
  );
536
613
  return newChild;
537
614
  }
615
+ var GridItem = React2.memo(GridItemInner, (prev, next) => {
616
+ if (prev.x !== next.x || prev.y !== next.y) return false;
617
+ if (prev.w !== next.w || prev.h !== next.h) return false;
618
+ if (prev.minW !== next.minW || prev.maxW !== next.maxW) return false;
619
+ if (prev.minH !== next.minH || prev.maxH !== next.maxH) return false;
620
+ if (prev.cols !== next.cols) return false;
621
+ if (prev.containerWidth !== next.containerWidth) return false;
622
+ if (prev.rowHeight !== next.rowHeight) return false;
623
+ if (prev.maxRows !== next.maxRows) return false;
624
+ if (prev.margin !== next.margin) return false;
625
+ if (prev.containerPadding !== next.containerPadding) return false;
626
+ if (prev.transformScale !== next.transformScale) return false;
627
+ if (prev.isDraggable !== next.isDraggable) return false;
628
+ if (prev.isResizable !== next.isResizable) return false;
629
+ if (prev.isBounded !== next.isBounded) return false;
630
+ if (prev.allowMobileScroll !== next.allowMobileScroll) return false;
631
+ if (prev.useCSSTransforms !== next.useCSSTransforms) return false;
632
+ if (prev.usePercentages !== next.usePercentages) return false;
633
+ if (prev.children !== next.children) return false;
634
+ if (prev.onDrag !== next.onDrag) return false;
635
+ if (prev.onDragStop !== next.onDragStop) return false;
636
+ if (prev.onResize !== next.onResize) return false;
637
+ if (prev.onResizeStop !== next.onResizeStop) return false;
638
+ if (prev.droppingPosition !== next.droppingPosition) return false;
639
+ return true;
640
+ });
641
+ GridItem.displayName = "GridItem";
642
+
643
+ // src/react/components/dropMath.ts
644
+ function computeDropPosition(input) {
645
+ const {
646
+ clientX,
647
+ clientY,
648
+ gridElement,
649
+ droppingItem,
650
+ event,
651
+ dragOffsetX = 0,
652
+ dragOffsetY = 0,
653
+ transformScale,
654
+ cols,
655
+ margin,
656
+ maxRows,
657
+ rowHeight,
658
+ width,
659
+ containerPadding
660
+ } = input;
661
+ const gridRect = gridElement.getBoundingClientRect();
662
+ const positionParams = {
663
+ cols,
664
+ margin,
665
+ maxRows,
666
+ rowHeight,
667
+ containerWidth: width,
668
+ containerPadding
669
+ };
670
+ const actualColWidth = calcGridColWidth(positionParams);
671
+ const itemPixelWidth = calcGridItemWHPx(
672
+ droppingItem.w,
673
+ actualColWidth,
674
+ margin[0]
675
+ );
676
+ const itemPixelHeight = calcGridItemWHPx(
677
+ droppingItem.h,
678
+ rowHeight,
679
+ margin[1]
680
+ );
681
+ const itemCenterOffsetX = itemPixelWidth / 2;
682
+ const itemCenterOffsetY = itemPixelHeight / 2;
683
+ const scrollLeft = gridElement.scrollLeft ?? 0;
684
+ const scrollTop = gridElement.scrollTop ?? 0;
685
+ const rawGridX = clientX - gridRect.left + scrollLeft + dragOffsetX - itemCenterOffsetX;
686
+ const rawGridY = clientY - gridRect.top + scrollTop + dragOffsetY - itemCenterOffsetY;
687
+ const clampedGridX = Math.max(0, rawGridX);
688
+ const clampedGridY = Math.max(0, rawGridY);
689
+ const newDroppingPosition = {
690
+ left: clampedGridX / transformScale,
691
+ top: clampedGridY / transformScale,
692
+ e: event
693
+ };
694
+ const calculatedXY = calcXY(
695
+ positionParams,
696
+ clampedGridY,
697
+ clampedGridX,
698
+ droppingItem.w,
699
+ droppingItem.h
700
+ );
701
+ return {
702
+ newDroppingPosition,
703
+ calculatedXY
704
+ };
705
+ }
538
706
  var noop = () => {
539
707
  };
540
708
  var layoutClassName = "react-grid-layout";
@@ -652,7 +820,8 @@ function GridLayout(props) {
652
820
  bounded: isBounded,
653
821
  handle: draggableHandle,
654
822
  cancel: draggableCancel,
655
- threshold: dragThreshold
823
+ threshold: dragThreshold,
824
+ allowMobileScroll: dragAllowMobileScroll
656
825
  } = dragConfig;
657
826
  const {
658
827
  enabled: isResizable,
@@ -662,7 +831,9 @@ function GridLayout(props) {
662
831
  const {
663
832
  enabled: isDroppable,
664
833
  defaultItem: defaultDropItem,
665
- onDragOver: dropConfigOnDragOver
834
+ onDragOver: dropConfigOnDragOver,
835
+ touchEnabled = true,
836
+ touchDragSource = "[data-rgl-draggable]"
666
837
  } = dropConfig;
667
838
  const compactor = compactorProp ?? getCompactor("vertical");
668
839
  const compactType = compactor.type;
@@ -688,6 +859,8 @@ function GridLayout(props) {
688
859
  null
689
860
  );
690
861
  const [droppingPosition, setDroppingPosition] = useState();
862
+ const droppingPositionRef = useRef(void 0);
863
+ droppingPositionRef.current = droppingPosition;
691
864
  const oldDragItemRef = useRef(null);
692
865
  const oldResizeItemRef = useRef(null);
693
866
  const oldLayoutRef = useRef(null);
@@ -696,6 +869,15 @@ function GridLayout(props) {
696
869
  const prevPropsLayoutRef = useRef(propsLayout);
697
870
  const prevChildrenRef = useRef(children);
698
871
  const prevCompactTypeRef = useRef(compactType);
872
+ const gridContainerRef = useRef(null);
873
+ const touchDragActiveRef = useRef(false);
874
+ const activeTouchIdRef = useRef(null);
875
+ const droppingDOMNodeRef = useRef(null);
876
+ droppingDOMNodeRef.current = droppingDOMNode;
877
+ const onDropPropRef = useRef(onDropProp);
878
+ useLayoutEffect(() => {
879
+ onDropPropRef.current = onDropProp;
880
+ });
699
881
  const layoutRef = useRef(layout);
700
882
  layoutRef.current = layout;
701
883
  useEffect(() => {
@@ -736,12 +918,12 @@ function GridLayout(props) {
736
918
  layout
737
919
  ]);
738
920
  useEffect(() => {
739
- if (!activeDrag && !deepEqual(layout, prevLayoutRef.current)) {
921
+ if (!activeDrag && !droppingDOMNode && !deepEqual(layout, prevLayoutRef.current)) {
740
922
  prevLayoutRef.current = layout;
741
923
  const publicLayout = layout.filter((l) => l.i !== droppingItem.i);
742
924
  onLayoutChange(publicLayout);
743
925
  }
744
- }, [layout, activeDrag, onLayoutChange, droppingItem.i]);
926
+ }, [layout, activeDrag, droppingDOMNode, onLayoutChange, droppingItem.i]);
745
927
  const containerHeight = useMemo(() => {
746
928
  if (!autoSize) return void 0;
747
929
  const nbRow = bottom(layout);
@@ -799,7 +981,7 @@ function GridLayout(props) {
799
981
  );
800
982
  const onDragStop = useCallback(
801
983
  (i, x, y, data) => {
802
- if (!activeDrag) return;
984
+ if (!oldDragItemRef.current) return;
803
985
  const currentLayout = layoutRef.current;
804
986
  const oldDragItem = oldDragItemRef.current;
805
987
  const l = getLayoutItem(currentLayout, i);
@@ -827,7 +1009,6 @@ function GridLayout(props) {
827
1009
  }
828
1010
  },
829
1011
  [
830
- activeDrag,
831
1012
  preventCollision,
832
1013
  compactType,
833
1014
  cols,
@@ -891,6 +1072,9 @@ function GridLayout(props) {
891
1072
  }
892
1073
  item.w = w;
893
1074
  item.h = h;
1075
+ if (handle === "n" || handle === "nw" || handle === "ne") {
1076
+ item.y = newY ?? item.y;
1077
+ }
894
1078
  return item;
895
1079
  });
896
1080
  if (!l) return;
@@ -924,7 +1108,14 @@ function GridLayout(props) {
924
1108
  data.e,
925
1109
  data.node
926
1110
  );
927
- setLayout(compactor.compact(finalLayout, cols));
1111
+ const compactedLayout = compactor.compact(finalLayout, cols);
1112
+ if (handle === "n" || handle === "nw" || handle === "ne") {
1113
+ const resized = compactedLayout.find((item) => item.i === i);
1114
+ if (resized) {
1115
+ resized.y = l.y;
1116
+ }
1117
+ }
1118
+ setLayout(compactedLayout);
928
1119
  setActiveDrag(placeholder);
929
1120
  },
930
1121
  [preventCollision, compactType, cols, allowOverlap, compactor, onResizeProp]
@@ -955,6 +1146,73 @@ function GridLayout(props) {
955
1146
  },
956
1147
  [cols, compactor, onResizeStopProp, onLayoutChange]
957
1148
  );
1149
+ const placeDroppingItem = useCallback(
1150
+ (itemToPlace, newDroppingPosition, calculatedXY, hasPlaceholder) => {
1151
+ if (!hasPlaceholder) {
1152
+ setDroppingDOMNode(/* @__PURE__ */ jsx("div", {}, itemToPlace.i));
1153
+ setDroppingPosition(newDroppingPosition);
1154
+ const baseLayout = layoutRef.current.filter((l) => l.i !== itemToPlace.i);
1155
+ setLayout([
1156
+ ...baseLayout,
1157
+ {
1158
+ ...itemToPlace,
1159
+ x: calculatedXY.x,
1160
+ y: calculatedXY.y,
1161
+ static: false,
1162
+ isDraggable: true
1163
+ }
1164
+ ]);
1165
+ } else if (droppingPositionRef.current) {
1166
+ const shouldUpdate = droppingPositionRef.current.left !== newDroppingPosition.left || droppingPositionRef.current.top !== newDroppingPosition.top;
1167
+ if (shouldUpdate) {
1168
+ setDroppingPosition(newDroppingPosition);
1169
+ setLayout(
1170
+ (currentLayout) => currentLayout.map(
1171
+ (item) => item.i === itemToPlace.i && (item.x !== calculatedXY.x || item.y !== calculatedXY.y) ? { ...item, x: calculatedXY.x, y: calculatedXY.y } : item
1172
+ )
1173
+ );
1174
+ }
1175
+ }
1176
+ },
1177
+ []
1178
+ );
1179
+ const applyTouchDropPosition = useCallback(
1180
+ (clientX, clientY, nativeEvent) => {
1181
+ const gridEl = gridContainerRef.current;
1182
+ if (!gridEl) return;
1183
+ const { newDroppingPosition, calculatedXY } = computeDropPosition({
1184
+ clientX,
1185
+ clientY,
1186
+ gridElement: gridEl,
1187
+ droppingItem,
1188
+ event: nativeEvent,
1189
+ transformScale,
1190
+ cols,
1191
+ margin,
1192
+ maxRows,
1193
+ rowHeight,
1194
+ width,
1195
+ containerPadding: effectiveContainerPadding
1196
+ });
1197
+ placeDroppingItem(
1198
+ droppingItem,
1199
+ newDroppingPosition,
1200
+ calculatedXY,
1201
+ !!droppingDOMNodeRef.current
1202
+ );
1203
+ },
1204
+ [
1205
+ droppingItem,
1206
+ transformScale,
1207
+ cols,
1208
+ margin,
1209
+ maxRows,
1210
+ rowHeight,
1211
+ width,
1212
+ effectiveContainerPadding,
1213
+ placeDroppingItem
1214
+ ]
1215
+ );
958
1216
  const removeDroppingPlaceholder = useCallback(() => {
959
1217
  const currentLayout = layoutRef.current;
960
1218
  const hasDroppingItem = currentLayout.some((l) => l.i === droppingItem.i);
@@ -995,74 +1253,36 @@ function GridLayout(props) {
995
1253
  ...onDragOverResult
996
1254
  } = rawResult ?? {};
997
1255
  const finalDroppingItem = { ...droppingItem, ...onDragOverResult };
998
- const gridRect = e.currentTarget.getBoundingClientRect();
999
- const positionParams = {
1256
+ const { newDroppingPosition, calculatedXY } = computeDropPosition({
1257
+ clientX: e.clientX,
1258
+ clientY: e.clientY,
1259
+ gridElement: e.currentTarget,
1260
+ droppingItem: finalDroppingItem,
1261
+ event: e.nativeEvent,
1262
+ dragOffsetX,
1263
+ dragOffsetY,
1264
+ transformScale,
1000
1265
  cols,
1001
1266
  margin,
1002
1267
  maxRows,
1003
1268
  rowHeight,
1004
- containerWidth: width,
1269
+ width,
1005
1270
  containerPadding: effectiveContainerPadding
1006
- };
1007
- const actualColWidth = calcGridColWidth(positionParams);
1008
- const itemPixelWidth = calcGridItemWHPx(
1009
- finalDroppingItem.w,
1010
- actualColWidth,
1011
- margin[0]
1012
- );
1013
- const itemPixelHeight = calcGridItemWHPx(
1014
- finalDroppingItem.h,
1015
- rowHeight,
1016
- margin[1]
1271
+ });
1272
+ placeDroppingItem(
1273
+ finalDroppingItem,
1274
+ newDroppingPosition,
1275
+ calculatedXY,
1276
+ !!droppingDOMNode
1017
1277
  );
1018
- const itemCenterOffsetX = itemPixelWidth / 2;
1019
- const itemCenterOffsetY = itemPixelHeight / 2;
1020
- const rawGridX = e.clientX - gridRect.left + dragOffsetX - itemCenterOffsetX;
1021
- const rawGridY = e.clientY - gridRect.top + dragOffsetY - itemCenterOffsetY;
1022
- const clampedGridX = Math.max(0, rawGridX);
1023
- const clampedGridY = Math.max(0, rawGridY);
1024
- const newDroppingPosition = {
1025
- left: clampedGridX / transformScale,
1026
- top: clampedGridY / transformScale,
1027
- e: e.nativeEvent
1028
- };
1029
- if (!droppingDOMNode) {
1030
- const calculatedPosition = calcXY(
1031
- positionParams,
1032
- clampedGridY,
1033
- clampedGridX,
1034
- finalDroppingItem.w,
1035
- finalDroppingItem.h
1036
- );
1037
- setDroppingDOMNode(/* @__PURE__ */ jsx("div", {}, finalDroppingItem.i));
1038
- setDroppingPosition(newDroppingPosition);
1039
- const baseLayout = layoutRef.current.filter(
1040
- (l) => l.i !== finalDroppingItem.i
1041
- );
1042
- setLayout([
1043
- ...baseLayout,
1044
- {
1045
- ...finalDroppingItem,
1046
- x: calculatedPosition.x,
1047
- y: calculatedPosition.y,
1048
- static: false,
1049
- isDraggable: true
1050
- }
1051
- ]);
1052
- } else if (droppingPosition) {
1053
- const shouldUpdate = droppingPosition.left !== newDroppingPosition.left || droppingPosition.top !== newDroppingPosition.top;
1054
- if (shouldUpdate) {
1055
- setDroppingPosition(newDroppingPosition);
1056
- }
1057
- }
1058
1278
  },
1059
1279
  [
1060
1280
  droppingDOMNode,
1061
- droppingPosition,
1062
1281
  droppingItem,
1063
1282
  dropConfigOnDragOver,
1064
1283
  onDropDragOverProp,
1065
1284
  removeDroppingPlaceholder,
1285
+ placeDroppingItem,
1066
1286
  transformScale,
1067
1287
  cols,
1068
1288
  margin,
@@ -1091,18 +1311,106 @@ function GridLayout(props) {
1091
1311
  e.stopPropagation();
1092
1312
  dragEnterCounterRef.current++;
1093
1313
  }, []);
1314
+ const commitDrop = useCallback(
1315
+ (nativeEvent) => {
1316
+ const currentLayout = layoutRef.current;
1317
+ const item = currentLayout.find((l) => l.i === droppingItem.i);
1318
+ removeDroppingPlaceholder();
1319
+ onDropPropRef.current(currentLayout, item, nativeEvent);
1320
+ },
1321
+ [droppingItem.i, removeDroppingPlaceholder]
1322
+ );
1094
1323
  const handleDrop = useCallback(
1095
1324
  (e) => {
1096
1325
  e.preventDefault();
1097
1326
  e.stopPropagation();
1098
- const currentLayout = layoutRef.current;
1099
- const item = currentLayout.find((l) => l.i === droppingItem.i);
1100
1327
  dragEnterCounterRef.current = 0;
1101
- removeDroppingPlaceholder();
1102
- onDropProp(currentLayout, item, e.nativeEvent);
1328
+ commitDrop(e.nativeEvent);
1103
1329
  },
1104
- [droppingItem.i, removeDroppingPlaceholder, onDropProp]
1330
+ [commitDrop]
1105
1331
  );
1332
+ useEffect(() => {
1333
+ if (!isDroppable || !touchEnabled) return;
1334
+ const gridEl = gridContainerRef.current;
1335
+ if (!gridEl) return;
1336
+ const isOverGrid = (clientX, clientY) => {
1337
+ const el = document.elementFromPoint(clientX, clientY);
1338
+ return el ? gridEl.contains(el) : false;
1339
+ };
1340
+ const isSourceElement = (target) => {
1341
+ if (!(target instanceof HTMLElement)) return false;
1342
+ return target.closest(touchDragSource) !== null;
1343
+ };
1344
+ const getTouch = (e) => {
1345
+ const touches = e.changedTouches;
1346
+ if (!touches || touches.length === 0) return void 0;
1347
+ const id = activeTouchIdRef.current;
1348
+ if (id === null) return touches[0];
1349
+ for (let i = 0; i < touches.length; i++) {
1350
+ const touch = touches[i];
1351
+ if (touch && touch.identifier === id) return touch;
1352
+ }
1353
+ return void 0;
1354
+ };
1355
+ const handleTouchStart = (e) => {
1356
+ if (!isSourceElement(e.target)) return;
1357
+ if (activeTouchIdRef.current !== null) return;
1358
+ e.preventDefault();
1359
+ const touch = e.changedTouches?.[0];
1360
+ if (!touch) return;
1361
+ activeTouchIdRef.current = touch.identifier;
1362
+ touchDragActiveRef.current = true;
1363
+ };
1364
+ const handleTouchMove = (e) => {
1365
+ if (!touchDragActiveRef.current) return;
1366
+ e.preventDefault();
1367
+ const touch = getTouch(e);
1368
+ if (!touch) return;
1369
+ if (!isOverGrid(touch.clientX, touch.clientY)) {
1370
+ if (droppingDOMNodeRef.current) removeDroppingPlaceholder();
1371
+ return;
1372
+ }
1373
+ applyTouchDropPosition(touch.clientX, touch.clientY, e);
1374
+ };
1375
+ const handleTouchEnd = (e) => {
1376
+ if (!touchDragActiveRef.current) return;
1377
+ e.preventDefault();
1378
+ const touch = getTouch(e);
1379
+ touchDragActiveRef.current = false;
1380
+ activeTouchIdRef.current = null;
1381
+ if (!touch) return;
1382
+ if (!isOverGrid(touch.clientX, touch.clientY)) {
1383
+ removeDroppingPlaceholder();
1384
+ return;
1385
+ }
1386
+ commitDrop(e);
1387
+ };
1388
+ const handleTouchCancel = () => {
1389
+ if (!touchDragActiveRef.current) return;
1390
+ touchDragActiveRef.current = false;
1391
+ activeTouchIdRef.current = null;
1392
+ removeDroppingPlaceholder();
1393
+ };
1394
+ const opts = { passive: false };
1395
+ document.addEventListener("touchstart", handleTouchStart, opts);
1396
+ document.addEventListener("touchmove", handleTouchMove, opts);
1397
+ document.addEventListener("touchend", handleTouchEnd, opts);
1398
+ document.addEventListener("touchcancel", handleTouchCancel, opts);
1399
+ return () => {
1400
+ document.removeEventListener("touchstart", handleTouchStart, opts);
1401
+ document.removeEventListener("touchmove", handleTouchMove, opts);
1402
+ document.removeEventListener("touchend", handleTouchEnd, opts);
1403
+ document.removeEventListener("touchcancel", handleTouchCancel, opts);
1404
+ };
1405
+ }, [
1406
+ isDroppable,
1407
+ touchEnabled,
1408
+ touchDragSource,
1409
+ applyTouchDropPosition,
1410
+ removeDroppingPlaceholder,
1411
+ commitDrop,
1412
+ droppingItem.i
1413
+ ]);
1106
1414
  const processGridItem = useCallback(
1107
1415
  (child, isDroppingItem) => {
1108
1416
  if (!child || !child.key) return null;
@@ -1133,6 +1441,7 @@ function GridLayout(props) {
1133
1441
  isDraggable: draggable,
1134
1442
  isResizable: resizable,
1135
1443
  isBounded: bounded,
1444
+ allowMobileScroll: dragAllowMobileScroll,
1136
1445
  useCSSTransforms: useCSSTransforms && mounted,
1137
1446
  usePercentages: !mounted,
1138
1447
  transformScale,
@@ -1217,6 +1526,17 @@ function GridLayout(props) {
1217
1526
  }
1218
1527
  );
1219
1528
  };
1529
+ const setGridRef = useCallback(
1530
+ (node) => {
1531
+ gridContainerRef.current = node;
1532
+ if (typeof innerRef === "function") {
1533
+ innerRef(node);
1534
+ } else if (innerRef && "current" in innerRef) {
1535
+ innerRef.current = node;
1536
+ }
1537
+ },
1538
+ [innerRef]
1539
+ );
1220
1540
  const mergedClassName = clsx(layoutClassName, className);
1221
1541
  const mergedStyle = {
1222
1542
  height: containerHeight,
@@ -1225,7 +1545,7 @@ function GridLayout(props) {
1225
1545
  return /* @__PURE__ */ jsxs(
1226
1546
  "div",
1227
1547
  {
1228
- ref: innerRef,
1548
+ ref: setGridRef,
1229
1549
  className: mergedClassName,
1230
1550
  style: mergedStyle,
1231
1551
  onDrop: isDroppable ? handleDrop : void 0,
@@ -1259,20 +1579,33 @@ var DEFAULT_COLS = {
1259
1579
  };
1260
1580
  var noop2 = () => {
1261
1581
  };
1262
- function synchronizeLayoutWithChildren2(initialLayout, children, cols, compactor) {
1582
+ function synchronizeLayoutWithChildren2(initialLayout, children, cols, compactor, reSeedFromDataGrid = false) {
1263
1583
  const layout = [];
1264
1584
  React2.Children.forEach(children, (child) => {
1265
1585
  if (!React2.isValidElement(child) || child.key === null) return;
1266
1586
  const key = String(child.key);
1587
+ const childProps = child.props;
1588
+ const dataGrid = childProps["data-grid"];
1267
1589
  const existingItem = initialLayout.find((l) => l.i === key);
1268
1590
  if (existingItem) {
1269
- layout.push({
1270
- ...existingItem,
1271
- i: key
1272
- });
1591
+ if (reSeedFromDataGrid && dataGrid) {
1592
+ layout.push({
1593
+ ...existingItem,
1594
+ i: key,
1595
+ w: dataGrid.w ?? existingItem.w,
1596
+ h: dataGrid.h ?? existingItem.h,
1597
+ minW: dataGrid.minW ?? existingItem.minW,
1598
+ maxW: dataGrid.maxW ?? existingItem.maxW,
1599
+ minH: dataGrid.minH ?? existingItem.minH,
1600
+ maxH: dataGrid.maxH ?? existingItem.maxH
1601
+ });
1602
+ } else {
1603
+ layout.push({
1604
+ ...existingItem,
1605
+ i: key
1606
+ });
1607
+ }
1273
1608
  } else {
1274
- const childProps = child.props;
1275
- const dataGrid = childProps["data-grid"];
1276
1609
  if (dataGrid) {
1277
1610
  layout.push({
1278
1611
  i: key,
@@ -1304,7 +1637,7 @@ function synchronizeLayoutWithChildren2(initialLayout, children, cols, compactor
1304
1637
  const corrected = correctBounds(layout, { cols });
1305
1638
  return compactor.compact(corrected, cols);
1306
1639
  }
1307
- function ResponsiveGridLayout(props) {
1640
+ function ResponsiveGridLayoutInner(props) {
1308
1641
  const {
1309
1642
  children,
1310
1643
  width,
@@ -1424,11 +1757,13 @@ function ResponsiveGridLayout(props) {
1424
1757
  newCols,
1425
1758
  compactor
1426
1759
  );
1760
+ const layoutWasGenerated = !newLayouts[newBreakpoint];
1427
1761
  newLayout = synchronizeLayoutWithChildren2(
1428
1762
  newLayout,
1429
1763
  children,
1430
1764
  newCols,
1431
- compactor
1765
+ compactor,
1766
+ layoutWasGenerated
1432
1767
  );
1433
1768
  newLayouts[newBreakpoint] = newLayout;
1434
1769
  setBreakpoint(newBreakpoint);
@@ -1521,5 +1856,11 @@ function ResponsiveGridLayout(props) {
1521
1856
  }
1522
1857
  );
1523
1858
  }
1859
+ var ResponsiveGridLayoutWithRef = React2.forwardRef(function ResponsiveGridLayoutForwardRef(props, ref) {
1860
+ const { innerRef, ...rest } = props;
1861
+ const effectiveInnerRef = innerRef ?? ref;
1862
+ return /* @__PURE__ */ jsx(ResponsiveGridLayoutInner, { ...rest, innerRef: effectiveInnerRef });
1863
+ });
1864
+ ResponsiveGridLayoutWithRef.displayName = "ResponsiveGridLayout";
1524
1865
 
1525
- export { GridItem, GridLayout, ResponsiveGridLayout };
1866
+ export { GridItem, GridLayout, ResponsiveGridLayoutWithRef };