react-native-swappable-grid 1.0.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.
- package/README.md +284 -0
- package/lib/commonjs/ChildWrapper.js +320 -0
- package/lib/commonjs/ChildWrapper.js.map +1 -0
- package/lib/commonjs/SwappableGrid.js +378 -0
- package/lib/commonjs/SwappableGrid.js.map +1 -0
- package/lib/commonjs/index.js +14 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/utils/helpers/computerMinHeight.js +11 -0
- package/lib/commonjs/utils/helpers/computerMinHeight.js.map +1 -0
- package/lib/commonjs/utils/helpers/gestures/PanWithLongPress.js +249 -0
- package/lib/commonjs/utils/helpers/gestures/PanWithLongPress.js.map +1 -0
- package/lib/commonjs/utils/helpers/indexCalculations.js +73 -0
- package/lib/commonjs/utils/helpers/indexCalculations.js.map +1 -0
- package/lib/commonjs/utils/useGridLayout.js +205 -0
- package/lib/commonjs/utils/useGridLayout.js.map +1 -0
- package/lib/module/ChildWrapper.js +313 -0
- package/lib/module/ChildWrapper.js.map +1 -0
- package/lib/module/SwappableGrid.js +370 -0
- package/lib/module/SwappableGrid.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/utils/helpers/computerMinHeight.js +5 -0
- package/lib/module/utils/helpers/computerMinHeight.js.map +1 -0
- package/lib/module/utils/helpers/gestures/PanWithLongPress.js +242 -0
- package/lib/module/utils/helpers/gestures/PanWithLongPress.js.map +1 -0
- package/lib/module/utils/helpers/indexCalculations.js +64 -0
- package/lib/module/utils/helpers/indexCalculations.js.map +1 -0
- package/lib/module/utils/useGridLayout.js +199 -0
- package/lib/module/utils/useGridLayout.js.map +1 -0
- package/lib/typescript/ChildWrapper.d.ts +23 -0
- package/lib/typescript/SwappableGrid.d.ts +85 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/utils/helpers/computerMinHeight.d.ts +1 -0
- package/lib/typescript/utils/helpers/gestures/PanWithLongPress.d.ts +40 -0
- package/lib/typescript/utils/helpers/indexCalculations.d.ts +28 -0
- package/lib/typescript/utils/useGridLayout.d.ts +46 -0
- package/package.json +68 -0
- package/src/ChildWrapper.tsx +376 -0
- package/src/SwappableGrid.tsx +492 -0
- package/src/index.ts +2 -0
- package/src/utils/helpers/computerMinHeight.ts +9 -0
- package/src/utils/helpers/gestures/PanWithLongPress.ts +304 -0
- package/src/utils/helpers/indexCalculations.ts +91 -0
- package/src/utils/useGridLayout.ts +236 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.PanWithLongPress = void 0;
|
|
7
|
+
var _reactNativeGestureHandler = require("react-native-gesture-handler");
|
|
8
|
+
var _reactNativeReanimated = require("react-native-reanimated");
|
|
9
|
+
var _indexCalculations = require("../indexCalculations");
|
|
10
|
+
const PanWithLongPress = props => {
|
|
11
|
+
const {
|
|
12
|
+
order,
|
|
13
|
+
dynamicNumColumns,
|
|
14
|
+
activeKey,
|
|
15
|
+
offsetX,
|
|
16
|
+
offsetY,
|
|
17
|
+
startX,
|
|
18
|
+
startY,
|
|
19
|
+
dragMode,
|
|
20
|
+
positions,
|
|
21
|
+
itemsByKey,
|
|
22
|
+
itemWidth,
|
|
23
|
+
itemHeight,
|
|
24
|
+
containerPadding,
|
|
25
|
+
gap,
|
|
26
|
+
setOrderState,
|
|
27
|
+
onDragEnd,
|
|
28
|
+
onOrderChange,
|
|
29
|
+
scrollSpeed,
|
|
30
|
+
scrollThreshold,
|
|
31
|
+
scrollViewRef,
|
|
32
|
+
scrollOffset,
|
|
33
|
+
viewportH,
|
|
34
|
+
longPressMs,
|
|
35
|
+
contentH,
|
|
36
|
+
reverse = false,
|
|
37
|
+
deleteComponentPosition,
|
|
38
|
+
deleteItem,
|
|
39
|
+
contentPaddingBottom = 0
|
|
40
|
+
} = props;
|
|
41
|
+
const scrollDir = (0, _reactNativeReanimated.useSharedValue)(0); // -1 = up, 1 = down, 0 = none
|
|
42
|
+
const initialScrollOffset = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
43
|
+
(0, _reactNativeReanimated.useDerivedValue)(() => {
|
|
44
|
+
if (!dragMode.value || !activeKey.value) return;
|
|
45
|
+
if (viewportH.value <= 0 || contentH.value <= 0) return;
|
|
46
|
+
const key = activeKey.value;
|
|
47
|
+
const p = positions[key];
|
|
48
|
+
if (!p) return;
|
|
49
|
+
|
|
50
|
+
// 1. Clamp scroll offset
|
|
51
|
+
const maxScroll = contentH.value - viewportH.value;
|
|
52
|
+
const newScroll = Math.max(0, Math.min(scrollOffset.value + scrollDir.value * scrollSpeed, maxScroll));
|
|
53
|
+
(0, _reactNativeReanimated.scrollTo)(scrollViewRef, 0, newScroll, false);
|
|
54
|
+
const scrollDelta = newScroll - initialScrollOffset.value;
|
|
55
|
+
scrollOffset.value = newScroll;
|
|
56
|
+
|
|
57
|
+
// 2. Clamp item position
|
|
58
|
+
// Allow dragging into padding area (paddingBottom from style prop)
|
|
59
|
+
const minY = 0;
|
|
60
|
+
// Add paddingBottom to maxY to allow dragging into the padding area
|
|
61
|
+
const maxY = contentH.value - itemHeight + contentPaddingBottom;
|
|
62
|
+
const proposedY = startY.value + offsetY.value + scrollDelta;
|
|
63
|
+
p.y.value = Math.max(minY, Math.min(proposedY, maxY));
|
|
64
|
+
|
|
65
|
+
// X stays normal
|
|
66
|
+
p.x.value = startX.value + offsetX.value;
|
|
67
|
+
|
|
68
|
+
// Keep loop alive
|
|
69
|
+
requestAnimationFrame(() => {
|
|
70
|
+
scrollDir.value = scrollDir.value;
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
const getIndexOfKey = key => {
|
|
74
|
+
"worklet";
|
|
75
|
+
|
|
76
|
+
return order.value.findIndex(x => x === key);
|
|
77
|
+
};
|
|
78
|
+
return _reactNativeGestureHandler.Gesture.Pan().minDistance(10).activateAfterLongPress(longPressMs).onStart(({
|
|
79
|
+
x,
|
|
80
|
+
y
|
|
81
|
+
}) => {
|
|
82
|
+
initialScrollOffset.value = scrollOffset.value;
|
|
83
|
+
dragMode.value = true;
|
|
84
|
+
let bestKey = null;
|
|
85
|
+
let bestDist = Number.MAX_VALUE;
|
|
86
|
+
order.value.forEach(key => {
|
|
87
|
+
const p = positions[key];
|
|
88
|
+
if (!p) return;
|
|
89
|
+
const cx = p.x.value + itemWidth / 2;
|
|
90
|
+
const cy = p.y.value + itemHeight / 2;
|
|
91
|
+
const dx = cx - x;
|
|
92
|
+
const dy = cy - y;
|
|
93
|
+
const dist2 = dx * dx + dy * dy;
|
|
94
|
+
if (dist2 < bestDist) {
|
|
95
|
+
bestDist = dist2;
|
|
96
|
+
bestKey = key;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
if (!bestKey) return;
|
|
100
|
+
activeKey.value = bestKey;
|
|
101
|
+
const p = positions[bestKey];
|
|
102
|
+
p.active.value = (0, _reactNativeReanimated.withTiming)(1, {
|
|
103
|
+
duration: 120
|
|
104
|
+
});
|
|
105
|
+
startX.value = p.x.value;
|
|
106
|
+
startY.value = p.y.value;
|
|
107
|
+
offsetX.value = 0;
|
|
108
|
+
offsetY.value = 0;
|
|
109
|
+
}).onUpdate(({
|
|
110
|
+
translationX,
|
|
111
|
+
translationY
|
|
112
|
+
}) => {
|
|
113
|
+
if (!dragMode.value) return;
|
|
114
|
+
const key = activeKey.value;
|
|
115
|
+
if (!key) return;
|
|
116
|
+
const p = positions[key];
|
|
117
|
+
const scrollDelta = scrollOffset.value - initialScrollOffset.value;
|
|
118
|
+
|
|
119
|
+
// Update active (top-left)
|
|
120
|
+
offsetX.value = translationX;
|
|
121
|
+
offsetY.value = translationY;
|
|
122
|
+
p.x.value = startX.value + offsetX.value;
|
|
123
|
+
p.y.value = startY.value + offsetY.value + scrollDelta;
|
|
124
|
+
|
|
125
|
+
// Auto-scroll (unchanged)
|
|
126
|
+
const pointerYInViewport = p.y.value - scrollOffset.value;
|
|
127
|
+
if (pointerYInViewport > viewportH.value - scrollThreshold) {
|
|
128
|
+
scrollDir.value = 1;
|
|
129
|
+
} else if (pointerYInViewport < scrollThreshold) {
|
|
130
|
+
scrollDir.value = -1;
|
|
131
|
+
} else {
|
|
132
|
+
scrollDir.value = 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Compute target index from the active tile's **center**
|
|
136
|
+
const centerY = p.y.value + itemHeight / 2;
|
|
137
|
+
const fromIndex = getIndexOfKey(key);
|
|
138
|
+
let toIndex;
|
|
139
|
+
if (dynamicNumColumns.value === 1) {
|
|
140
|
+
toIndex = (0, _indexCalculations.toIndex1ColFromLiveMidlines)(order, positions, activeKey, itemHeight, centerY, reverse // ← pass your prop
|
|
141
|
+
);
|
|
142
|
+
} else {
|
|
143
|
+
// unchanged multi-column path
|
|
144
|
+
const centerX = p.x.value + itemWidth / 2;
|
|
145
|
+
toIndex = (0, _indexCalculations.xyToIndex)({
|
|
146
|
+
order,
|
|
147
|
+
x: centerX,
|
|
148
|
+
y: centerY,
|
|
149
|
+
itemWidth,
|
|
150
|
+
itemHeight,
|
|
151
|
+
dynamicNumColumns,
|
|
152
|
+
containerPadding,
|
|
153
|
+
gap
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (toIndex !== fromIndex && toIndex >= 0 && toIndex <= order.value.length - 1) {
|
|
157
|
+
const next = [...order.value];
|
|
158
|
+
next.splice(fromIndex, 1);
|
|
159
|
+
next.splice(toIndex, 0, key);
|
|
160
|
+
order.value = next;
|
|
161
|
+
}
|
|
162
|
+
}).onEnd(() => {
|
|
163
|
+
scrollDir.value = 0; // stop auto-scroll
|
|
164
|
+
if (!dragMode.value) return;
|
|
165
|
+
const key = activeKey.value;
|
|
166
|
+
if (!key) {
|
|
167
|
+
dragMode.value = false;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const p = positions[key];
|
|
171
|
+
|
|
172
|
+
// Check if item was dropped into delete component
|
|
173
|
+
if (deleteComponentPosition !== null && deleteComponentPosition !== void 0 && deleteComponentPosition.value && deleteItem) {
|
|
174
|
+
const deletePos = deleteComponentPosition.value;
|
|
175
|
+
|
|
176
|
+
// Add tolerance/padding to make it easier to hit (20% of item size)
|
|
177
|
+
const tolerance = Math.min(itemWidth, itemHeight) * 0.2;
|
|
178
|
+
const expandedDeleteX = deletePos.x - tolerance;
|
|
179
|
+
const expandedDeleteY = deletePos.y - tolerance;
|
|
180
|
+
const expandedDeleteWidth = deletePos.width + tolerance * 2;
|
|
181
|
+
const expandedDeleteHeight = deletePos.height + tolerance * 2;
|
|
182
|
+
|
|
183
|
+
// Check if item bounding box overlaps with expanded delete component bounds
|
|
184
|
+
// This is more forgiving than checking just the center point
|
|
185
|
+
const itemLeft = p.x.value;
|
|
186
|
+
const itemRight = p.x.value + itemWidth;
|
|
187
|
+
const itemTop = p.y.value;
|
|
188
|
+
const itemBottom = p.y.value + itemHeight;
|
|
189
|
+
|
|
190
|
+
// Bounding box intersection check
|
|
191
|
+
const overlaps = itemLeft < expandedDeleteX + expandedDeleteWidth && itemRight > expandedDeleteX && itemTop < expandedDeleteY + expandedDeleteHeight && itemBottom > expandedDeleteY;
|
|
192
|
+
if (overlaps) {
|
|
193
|
+
// Item was dropped into delete component - delete it
|
|
194
|
+
(0, _reactNativeReanimated.runOnJS)(deleteItem)(key);
|
|
195
|
+
// Note: deleteItem will handle calling onDelete callback if provided
|
|
196
|
+
p.active.value = (0, _reactNativeReanimated.withTiming)(0, {
|
|
197
|
+
duration: 120
|
|
198
|
+
});
|
|
199
|
+
activeKey.value = null;
|
|
200
|
+
dragMode.value = false;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Normal drop - return to grid position
|
|
206
|
+
const idx = getIndexOfKey(key);
|
|
207
|
+
const {
|
|
208
|
+
x,
|
|
209
|
+
y
|
|
210
|
+
} = (0, _indexCalculations.indexToXY)({
|
|
211
|
+
index: idx,
|
|
212
|
+
itemWidth,
|
|
213
|
+
itemHeight,
|
|
214
|
+
dynamicNumColumns,
|
|
215
|
+
containerPadding,
|
|
216
|
+
gap
|
|
217
|
+
});
|
|
218
|
+
const scale = Math.min(itemWidth, itemHeight) / 200; // 100px baseline
|
|
219
|
+
|
|
220
|
+
const damping = 18 * scale;
|
|
221
|
+
const stiffness = 240 * scale;
|
|
222
|
+
const mass = Math.max(0.05, scale); // helps stability for tiny items
|
|
223
|
+
|
|
224
|
+
p.x.value = (0, _reactNativeReanimated.withSpring)(x, {
|
|
225
|
+
damping,
|
|
226
|
+
stiffness,
|
|
227
|
+
mass
|
|
228
|
+
});
|
|
229
|
+
p.y.value = (0, _reactNativeReanimated.withSpring)(y, {
|
|
230
|
+
damping,
|
|
231
|
+
stiffness,
|
|
232
|
+
mass
|
|
233
|
+
});
|
|
234
|
+
p.active.value = (0, _reactNativeReanimated.withTiming)(0, {
|
|
235
|
+
duration: 120
|
|
236
|
+
});
|
|
237
|
+
(0, _reactNativeReanimated.runOnJS)(setOrderState)(order.value);
|
|
238
|
+
if (onDragEnd) {
|
|
239
|
+
(0, _reactNativeReanimated.runOnJS)(onDragEnd)(order.value.map(key => itemsByKey[key]));
|
|
240
|
+
}
|
|
241
|
+
if (onOrderChange) {
|
|
242
|
+
(0, _reactNativeReanimated.runOnJS)(onOrderChange)([...order.value]);
|
|
243
|
+
}
|
|
244
|
+
activeKey.value = null;
|
|
245
|
+
dragMode.value = false;
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
exports.PanWithLongPress = PanWithLongPress;
|
|
249
|
+
//# sourceMappingURL=PanWithLongPress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNativeGestureHandler","require","_reactNativeReanimated","_indexCalculations","PanWithLongPress","props","order","dynamicNumColumns","activeKey","offsetX","offsetY","startX","startY","dragMode","positions","itemsByKey","itemWidth","itemHeight","containerPadding","gap","setOrderState","onDragEnd","onOrderChange","scrollSpeed","scrollThreshold","scrollViewRef","scrollOffset","viewportH","longPressMs","contentH","reverse","deleteComponentPosition","deleteItem","contentPaddingBottom","scrollDir","useSharedValue","initialScrollOffset","useDerivedValue","value","key","p","maxScroll","newScroll","Math","max","min","scrollTo","scrollDelta","minY","maxY","proposedY","y","x","requestAnimationFrame","getIndexOfKey","findIndex","Gesture","Pan","minDistance","activateAfterLongPress","onStart","bestKey","bestDist","Number","MAX_VALUE","forEach","cx","cy","dx","dy","dist2","active","withTiming","duration","onUpdate","translationX","translationY","pointerYInViewport","centerY","fromIndex","toIndex","toIndex1ColFromLiveMidlines","centerX","xyToIndex","length","next","splice","onEnd","deletePos","tolerance","expandedDeleteX","expandedDeleteY","expandedDeleteWidth","width","expandedDeleteHeight","height","itemLeft","itemRight","itemTop","itemBottom","overlaps","runOnJS","idx","indexToXY","index","scale","damping","stiffness","mass","withSpring","map","exports"],"sources":["PanWithLongPress.ts"],"sourcesContent":["import { Gesture } from \"react-native-gesture-handler\";\nimport {\n runOnJS,\n SharedValue,\n withSpring,\n withTiming,\n scrollTo,\n AnimatedRef,\n useSharedValue,\n useDerivedValue,\n} from \"react-native-reanimated\";\nimport {\n indexToXY,\n toIndex1ColFromLiveMidlines,\n xyToIndex,\n} from \"../indexCalculations\";\n\ninterface PanProps {\n order: SharedValue<string[]>;\n dynamicNumColumns: SharedValue<number>;\n activeKey: SharedValue<string | null>;\n offsetX: SharedValue<number>;\n offsetY: SharedValue<number>;\n startX: SharedValue<number>;\n startY: SharedValue<number>;\n dragMode: SharedValue<boolean>;\n positions: any;\n itemsByKey: any;\n itemWidth: number;\n itemHeight: number;\n containerPadding: number;\n gap: number;\n setOrderState: React.Dispatch<React.SetStateAction<string[]>>;\n onDragEnd?: (ordered: ChildNode[]) => void;\n onOrderChange?: (keys: string[]) => void;\n\n // scrolling\n scrollSpeed: number;\n scrollThreshold: number;\n scrollViewRef: AnimatedRef<any>;\n scrollOffset: SharedValue<number>;\n viewportH: SharedValue<number>;\n longPressMs: number;\n contentH: SharedValue<number>;\n reverse?: boolean;\n deleteComponentPosition?: SharedValue<{\n x: number;\n y: number;\n width: number;\n height: number;\n } | null>;\n deleteItem?: (key: string) => void;\n contentPaddingBottom?: number; // Padding bottom from style prop to allow dragging into padding area\n}\n\nexport const PanWithLongPress = (props: PanProps & { longPressMs: number }) => {\n const {\n order,\n dynamicNumColumns,\n activeKey,\n offsetX,\n offsetY,\n startX,\n startY,\n dragMode,\n positions,\n itemsByKey,\n itemWidth,\n itemHeight,\n containerPadding,\n gap,\n setOrderState,\n onDragEnd,\n onOrderChange,\n scrollSpeed,\n scrollThreshold,\n scrollViewRef,\n scrollOffset,\n viewportH,\n longPressMs,\n contentH,\n reverse = false,\n deleteComponentPosition,\n deleteItem,\n contentPaddingBottom = 0,\n } = props;\n\n const scrollDir = useSharedValue(0); // -1 = up, 1 = down, 0 = none\n const initialScrollOffset = useSharedValue(0);\n\n useDerivedValue(() => {\n if (!dragMode.value || !activeKey.value) return;\n\n if (viewportH.value <= 0 || contentH.value <= 0) return;\n\n const key = activeKey.value;\n const p = positions[key];\n if (!p) return;\n\n // 1. Clamp scroll offset\n const maxScroll = contentH.value - viewportH.value;\n const newScroll = Math.max(\n 0,\n Math.min(scrollOffset.value + scrollDir.value * scrollSpeed, maxScroll)\n );\n\n scrollTo(scrollViewRef, 0, newScroll, false);\n const scrollDelta = newScroll - initialScrollOffset.value;\n scrollOffset.value = newScroll;\n\n // 2. Clamp item position\n // Allow dragging into padding area (paddingBottom from style prop)\n const minY = 0;\n // Add paddingBottom to maxY to allow dragging into the padding area\n const maxY = contentH.value - itemHeight + contentPaddingBottom;\n const proposedY = startY.value + offsetY.value + scrollDelta;\n p.y.value = Math.max(minY, Math.min(proposedY, maxY));\n\n // X stays normal\n p.x.value = startX.value + offsetX.value;\n\n // Keep loop alive\n requestAnimationFrame(() => {\n scrollDir.value = scrollDir.value;\n });\n });\n\n const getIndexOfKey = (key: string) => {\n \"worklet\";\n return order.value.findIndex((x) => x === key);\n };\n\n return Gesture.Pan()\n .minDistance(10)\n .activateAfterLongPress(longPressMs)\n .onStart(({ x, y }) => {\n initialScrollOffset.value = scrollOffset.value;\n dragMode.value = true;\n let bestKey: string | null = null;\n let bestDist = Number.MAX_VALUE;\n order.value.forEach((key) => {\n const p = positions[key];\n if (!p) return;\n const cx = p.x.value + itemWidth / 2;\n const cy = p.y.value + itemHeight / 2;\n const dx = cx - x;\n const dy = cy - y;\n const dist2 = dx * dx + dy * dy;\n if (dist2 < bestDist) {\n bestDist = dist2;\n bestKey = key;\n }\n });\n if (!bestKey) return;\n activeKey.value = bestKey;\n const p = positions[bestKey]!;\n p.active.value = withTiming(1, { duration: 120 });\n startX.value = p.x.value;\n startY.value = p.y.value;\n offsetX.value = 0;\n offsetY.value = 0;\n })\n .onUpdate(({ translationX, translationY }) => {\n if (!dragMode.value) return;\n const key = activeKey.value;\n if (!key) return;\n\n const p = positions[key]!;\n const scrollDelta = scrollOffset.value - initialScrollOffset.value;\n\n // Update active (top-left)\n offsetX.value = translationX;\n offsetY.value = translationY;\n p.x.value = startX.value + offsetX.value;\n p.y.value = startY.value + offsetY.value + scrollDelta;\n\n // Auto-scroll (unchanged)\n const pointerYInViewport = p.y.value - scrollOffset.value;\n if (pointerYInViewport > viewportH.value - scrollThreshold) {\n scrollDir.value = 1;\n } else if (pointerYInViewport < scrollThreshold) {\n scrollDir.value = -1;\n } else {\n scrollDir.value = 0;\n }\n\n // Compute target index from the active tile's **center**\n const centerY = p.y.value + itemHeight / 2;\n const fromIndex = getIndexOfKey(key);\n\n let toIndex: number;\n if (dynamicNumColumns.value === 1) {\n toIndex = toIndex1ColFromLiveMidlines(\n order,\n positions,\n activeKey,\n itemHeight,\n centerY,\n reverse // ← pass your prop\n );\n } else {\n // unchanged multi-column path\n const centerX = p.x.value + itemWidth / 2;\n toIndex = xyToIndex({\n order,\n x: centerX,\n y: centerY,\n itemWidth,\n itemHeight,\n dynamicNumColumns,\n containerPadding,\n gap,\n });\n }\n\n if (\n toIndex !== fromIndex &&\n toIndex >= 0 &&\n toIndex <= order.value.length - 1\n ) {\n const next = [...order.value];\n next.splice(fromIndex, 1);\n next.splice(toIndex, 0, key);\n order.value = next;\n }\n })\n .onEnd(() => {\n scrollDir.value = 0; // stop auto-scroll\n if (!dragMode.value) return;\n const key = activeKey.value;\n if (!key) {\n dragMode.value = false;\n return;\n }\n const p = positions[key]!;\n\n // Check if item was dropped into delete component\n if (deleteComponentPosition?.value && deleteItem) {\n const deletePos = deleteComponentPosition.value;\n\n // Add tolerance/padding to make it easier to hit (20% of item size)\n const tolerance = Math.min(itemWidth, itemHeight) * 0.2;\n const expandedDeleteX = deletePos.x - tolerance;\n const expandedDeleteY = deletePos.y - tolerance;\n const expandedDeleteWidth = deletePos.width + tolerance * 2;\n const expandedDeleteHeight = deletePos.height + tolerance * 2;\n\n // Check if item bounding box overlaps with expanded delete component bounds\n // This is more forgiving than checking just the center point\n const itemLeft = p.x.value;\n const itemRight = p.x.value + itemWidth;\n const itemTop = p.y.value;\n const itemBottom = p.y.value + itemHeight;\n\n // Bounding box intersection check\n const overlaps =\n itemLeft < expandedDeleteX + expandedDeleteWidth &&\n itemRight > expandedDeleteX &&\n itemTop < expandedDeleteY + expandedDeleteHeight &&\n itemBottom > expandedDeleteY;\n\n if (overlaps) {\n // Item was dropped into delete component - delete it\n runOnJS(deleteItem)(key);\n // Note: deleteItem will handle calling onDelete callback if provided\n p.active.value = withTiming(0, { duration: 120 });\n activeKey.value = null;\n dragMode.value = false;\n return;\n }\n }\n\n // Normal drop - return to grid position\n const idx = getIndexOfKey(key);\n const { x, y } = indexToXY({\n index: idx,\n itemWidth,\n itemHeight,\n dynamicNumColumns,\n containerPadding,\n gap,\n });\n const scale = Math.min(itemWidth, itemHeight) / 200; // 100px baseline\n\n const damping = 18 * scale;\n const stiffness = 240 * scale;\n const mass = Math.max(0.05, scale); // helps stability for tiny items\n\n p.x.value = withSpring(x, { damping, stiffness, mass });\n p.y.value = withSpring(y, { damping, stiffness, mass });\n\n p.active.value = withTiming(0, { duration: 120 });\n\n runOnJS(setOrderState)(order.value);\n if (onDragEnd) {\n runOnJS(onDragEnd)(order.value.map((key) => itemsByKey[key]));\n }\n if (onOrderChange) {\n runOnJS(onOrderChange)([...order.value]);\n }\n activeKey.value = null;\n dragMode.value = false;\n });\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.xyToIndex = exports.toIndex1ColFromLiveMidlines = exports.indexToXY = void 0;
|
|
7
|
+
const indexToXY = ({
|
|
8
|
+
index,
|
|
9
|
+
itemHeight,
|
|
10
|
+
itemWidth,
|
|
11
|
+
dynamicNumColumns,
|
|
12
|
+
containerPadding,
|
|
13
|
+
gap
|
|
14
|
+
}) => {
|
|
15
|
+
"worklet";
|
|
16
|
+
|
|
17
|
+
const cols = dynamicNumColumns.value;
|
|
18
|
+
const col = index % cols;
|
|
19
|
+
const row = Math.floor(index / cols);
|
|
20
|
+
const x = containerPadding + col * (itemWidth + gap);
|
|
21
|
+
const y = containerPadding + row * (itemHeight + gap);
|
|
22
|
+
return {
|
|
23
|
+
x,
|
|
24
|
+
y
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
exports.indexToXY = indexToXY;
|
|
28
|
+
const xyToIndex = ({
|
|
29
|
+
order,
|
|
30
|
+
x,
|
|
31
|
+
y,
|
|
32
|
+
itemHeight,
|
|
33
|
+
itemWidth,
|
|
34
|
+
dynamicNumColumns,
|
|
35
|
+
gap,
|
|
36
|
+
containerPadding
|
|
37
|
+
}) => {
|
|
38
|
+
"worklet";
|
|
39
|
+
|
|
40
|
+
const cols = dynamicNumColumns.value;
|
|
41
|
+
|
|
42
|
+
// Work with CENTER coordinates relative to the content box
|
|
43
|
+
const relX = x - containerPadding;
|
|
44
|
+
const relY = y - containerPadding;
|
|
45
|
+
const col = Math.floor(relX / (itemWidth + gap));
|
|
46
|
+
const row = Math.floor(relY / (itemHeight + gap));
|
|
47
|
+
const clampedCol = Math.max(0, Math.min(cols - 1, col));
|
|
48
|
+
const maxRows = Math.max(1, Math.ceil(order.value.length / cols));
|
|
49
|
+
const clampedRow = Math.max(0, Math.min(maxRows - 1, row));
|
|
50
|
+
return clampedRow * cols + clampedCol;
|
|
51
|
+
};
|
|
52
|
+
exports.xyToIndex = xyToIndex;
|
|
53
|
+
const toIndex1ColFromLiveMidlines = (order, positions, activeKey, itemHeight, centerY, reverse) => {
|
|
54
|
+
"worklet";
|
|
55
|
+
|
|
56
|
+
const list = order.value.filter(k => k !== activeKey.value);
|
|
57
|
+
|
|
58
|
+
// Sort by actual on-screen Y (top → bottom)
|
|
59
|
+
list.sort((a, b) => positions[a].y.value - positions[b].y.value);
|
|
60
|
+
|
|
61
|
+
// Find visual slot v (0..list.length)
|
|
62
|
+
let v = 0;
|
|
63
|
+
for (; v < list.length; v++) {
|
|
64
|
+
const mid = positions[list[v]].y.value + itemHeight / 2;
|
|
65
|
+
if (centerY < mid) break;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Map visual slot → array index AFTER removal (reverse aware)
|
|
69
|
+
const afterRemovalLen = list.length;
|
|
70
|
+
return reverse ? afterRemovalLen - v : v;
|
|
71
|
+
};
|
|
72
|
+
exports.toIndex1ColFromLiveMidlines = toIndex1ColFromLiveMidlines;
|
|
73
|
+
//# sourceMappingURL=indexCalculations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["indexToXY","index","itemHeight","itemWidth","dynamicNumColumns","containerPadding","gap","cols","value","col","row","Math","floor","x","y","exports","xyToIndex","order","relX","relY","clampedCol","max","min","maxRows","ceil","length","clampedRow","toIndex1ColFromLiveMidlines","positions","activeKey","centerY","reverse","list","filter","k","sort","a","b","v","mid","afterRemovalLen"],"sources":["indexCalculations.ts"],"sourcesContent":["import { SharedValue } from \"react-native-reanimated\";\n\ninterface IndexToXYProps {\n index: number;\n itemHeight: number;\n itemWidth: number;\n dynamicNumColumns: SharedValue<number>;\n containerPadding: number;\n gap: number;\n}\n\nexport const indexToXY = ({\n index,\n itemHeight,\n itemWidth,\n dynamicNumColumns,\n containerPadding,\n gap,\n}: IndexToXYProps) => {\n \"worklet\";\n const cols = dynamicNumColumns.value;\n const col = index % cols;\n const row = Math.floor(index / cols);\n const x = containerPadding + col * (itemWidth + gap);\n const y = containerPadding + row * (itemHeight + gap);\n return { x, y };\n};\n\ninterface XYToIndexProps {\n order: SharedValue<string[]>;\n x: number;\n y: number;\n itemHeight: number;\n itemWidth: number;\n dynamicNumColumns: SharedValue<number>;\n containerPadding: number;\n gap: number;\n}\n\nexport const xyToIndex = ({\n order,\n x,\n y,\n itemHeight,\n itemWidth,\n dynamicNumColumns,\n gap,\n containerPadding,\n}: XYToIndexProps) => {\n \"worklet\";\n const cols = dynamicNumColumns.value;\n\n // Work with CENTER coordinates relative to the content box\n const relX = x - containerPadding;\n const relY = y - containerPadding;\n\n const col = Math.floor(relX / (itemWidth + gap));\n const row = Math.floor(relY / (itemHeight + gap));\n\n const clampedCol = Math.max(0, Math.min(cols - 1, col));\n const maxRows = Math.max(1, Math.ceil(order.value.length / cols));\n const clampedRow = Math.max(0, Math.min(maxRows - 1, row));\n\n return clampedRow * cols + clampedCol;\n};\n\nexport const toIndex1ColFromLiveMidlines = (\n order: SharedValue<string[]>,\n positions: Record<string, { y: SharedValue<number> }>,\n activeKey: SharedValue<string | null>,\n itemHeight: number,\n centerY: number,\n reverse: boolean\n) => {\n \"worklet\";\n const list = order.value.filter((k) => k !== activeKey.value);\n\n // Sort by actual on-screen Y (top → bottom)\n list.sort((a, b) => positions[a].y.value - positions[b].y.value);\n\n // Find visual slot v (0..list.length)\n let v = 0;\n for (; v < list.length; v++) {\n const mid = positions[list[v]].y.value + itemHeight / 2;\n if (centerY < mid) break;\n }\n\n // Map visual slot → array index AFTER removal (reverse aware)\n const afterRemovalLen = list.length;\n return reverse ? afterRemovalLen - v : v;\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useGridLayout = useGridLayout;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _reactNativeGestureHandler = require("react-native-gesture-handler");
|
|
9
|
+
var _reactNativeReanimated = require("react-native-reanimated");
|
|
10
|
+
var _indexCalculations = require("./helpers/indexCalculations");
|
|
11
|
+
var _PanWithLongPress = require("./helpers/gestures/PanWithLongPress");
|
|
12
|
+
function useGridLayout({
|
|
13
|
+
reverse,
|
|
14
|
+
children,
|
|
15
|
+
itemWidth,
|
|
16
|
+
itemHeight,
|
|
17
|
+
gap,
|
|
18
|
+
containerPadding,
|
|
19
|
+
longPressMs,
|
|
20
|
+
numColumns,
|
|
21
|
+
onDragEnd,
|
|
22
|
+
onOrderChange,
|
|
23
|
+
onDelete,
|
|
24
|
+
scrollViewRef,
|
|
25
|
+
scrollSpeed,
|
|
26
|
+
scrollThreshold,
|
|
27
|
+
contentPaddingBottom = 0
|
|
28
|
+
}) {
|
|
29
|
+
const childArray = _react.Children.toArray(children).filter(_react.isValidElement);
|
|
30
|
+
const keys = childArray.map(child => {
|
|
31
|
+
if (!("key" in child) || child.key == null) {
|
|
32
|
+
throw new Error("All children must have a unique 'key' prop.");
|
|
33
|
+
}
|
|
34
|
+
return String(child.key);
|
|
35
|
+
});
|
|
36
|
+
const [orderState, setOrderState] = (0, _react.useState)(keys);
|
|
37
|
+
const itemsByKey = (0, _react.useMemo)(() => {
|
|
38
|
+
const map = {};
|
|
39
|
+
childArray.forEach(child => {
|
|
40
|
+
map[String(child.key)] = child;
|
|
41
|
+
});
|
|
42
|
+
return map;
|
|
43
|
+
}, [children]);
|
|
44
|
+
const dynamicNumColumns = (0, _reactNativeReanimated.useSharedValue)(numColumns ? numColumns : 1);
|
|
45
|
+
const order = (0, _reactNativeReanimated.useSharedValue)(orderState);
|
|
46
|
+
const contentW = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
47
|
+
const viewportH = (0, _reactNativeReanimated.useSharedValue)(0); // **visible height of ScrollView**
|
|
48
|
+
const activeKey = (0, _reactNativeReanimated.useSharedValue)(null);
|
|
49
|
+
const offsetX = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
50
|
+
const offsetY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
51
|
+
const startX = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
52
|
+
const startY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
53
|
+
const dragMode = (0, _reactNativeReanimated.useSharedValue)(false);
|
|
54
|
+
const anyItemInDeleteMode = (0, _reactNativeReanimated.useSharedValue)(false); // Global delete mode state
|
|
55
|
+
const contentH = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
56
|
+
const scrollOffset = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
57
|
+
const onScroll = (0, _reactNativeReanimated.useAnimatedScrollHandler)({
|
|
58
|
+
onScroll: e => {
|
|
59
|
+
scrollOffset.value = e.contentOffset.y;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// initial positions (create shared values consistently by data length)
|
|
64
|
+
const positionsArray = childArray.map((d, i) => {
|
|
65
|
+
const {
|
|
66
|
+
x,
|
|
67
|
+
y
|
|
68
|
+
} = (0, _indexCalculations.indexToXY)({
|
|
69
|
+
index: i,
|
|
70
|
+
itemWidth,
|
|
71
|
+
itemHeight,
|
|
72
|
+
dynamicNumColumns,
|
|
73
|
+
containerPadding,
|
|
74
|
+
gap
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
key: d.key,
|
|
78
|
+
pos: {
|
|
79
|
+
x: (0, _reactNativeReanimated.useSharedValue)(x),
|
|
80
|
+
y: (0, _reactNativeReanimated.useSharedValue)(y),
|
|
81
|
+
active: (0, _reactNativeReanimated.useSharedValue)(0)
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
const positions = (0, _react.useMemo)(() => {
|
|
86
|
+
const obj = {};
|
|
87
|
+
positionsArray.forEach(({
|
|
88
|
+
key,
|
|
89
|
+
pos
|
|
90
|
+
}) => {
|
|
91
|
+
obj[key ?? `key-${Math.random().toString(36).slice(2)}`] = pos;
|
|
92
|
+
});
|
|
93
|
+
return obj;
|
|
94
|
+
}, [positionsArray]);
|
|
95
|
+
const deleteItem = key => {
|
|
96
|
+
setOrderState(prev => prev.filter(k => k !== key));
|
|
97
|
+
order.value = order.value.filter(k => k !== key);
|
|
98
|
+
onOrderChange === null || onOrderChange === void 0 || onOrderChange([...order.value]);
|
|
99
|
+
// Call onDelete callback if provided (for both delete button and drop-to-delete)
|
|
100
|
+
if (onDelete) {
|
|
101
|
+
onDelete(key);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
(0, _reactNativeReanimated.useDerivedValue)(() => {
|
|
105
|
+
order.value.forEach((key, i) => {
|
|
106
|
+
if (activeKey.value === key) return; // ⬅️ do not layout the active tile
|
|
107
|
+
|
|
108
|
+
const p = positions[key];
|
|
109
|
+
if (!p) return;
|
|
110
|
+
const displayIndex = reverse ? order.value.length - 1 - i : i;
|
|
111
|
+
const {
|
|
112
|
+
x,
|
|
113
|
+
y
|
|
114
|
+
} = (0, _indexCalculations.indexToXY)({
|
|
115
|
+
index: displayIndex,
|
|
116
|
+
itemWidth,
|
|
117
|
+
itemHeight,
|
|
118
|
+
dynamicNumColumns,
|
|
119
|
+
containerPadding,
|
|
120
|
+
gap
|
|
121
|
+
});
|
|
122
|
+
const scale = Math.min(itemWidth, itemHeight) / 100; // 100px baseline
|
|
123
|
+
|
|
124
|
+
const damping = 18 * scale;
|
|
125
|
+
const stiffness = 240 * scale;
|
|
126
|
+
const mass = Math.max(0.1, scale); // helps stability for tiny items
|
|
127
|
+
|
|
128
|
+
p.x.value = (0, _reactNativeReanimated.withSpring)(x, {
|
|
129
|
+
damping,
|
|
130
|
+
stiffness,
|
|
131
|
+
mass
|
|
132
|
+
});
|
|
133
|
+
p.y.value = (0, _reactNativeReanimated.withSpring)(y, {
|
|
134
|
+
damping,
|
|
135
|
+
stiffness,
|
|
136
|
+
mass
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Layout of the ScrollView (viewport) — height we compare against for edge-scrolling
|
|
142
|
+
const onLayoutScrollView = e => {
|
|
143
|
+
viewportH.value = e.nativeEvent.layout.height;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Layout of the content view — width used to compute columns
|
|
147
|
+
const onLayoutContent = e => {
|
|
148
|
+
contentW.value = e.nativeEvent.layout.width;
|
|
149
|
+
contentH.value = e.nativeEvent.layout.height;
|
|
150
|
+
if (numColumns) {
|
|
151
|
+
dynamicNumColumns.value = numColumns;
|
|
152
|
+
} else {
|
|
153
|
+
const possibleCols = Math.floor((e.nativeEvent.layout.width - containerPadding * 2 + gap) / (itemWidth + gap));
|
|
154
|
+
dynamicNumColumns.value = Math.max(1, possibleCols);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const deleteComponentPosition = (0, _reactNativeReanimated.useSharedValue)(null);
|
|
158
|
+
const composed = _reactNativeGestureHandler.Gesture.Simultaneous((0, _PanWithLongPress.PanWithLongPress)({
|
|
159
|
+
contentH,
|
|
160
|
+
order,
|
|
161
|
+
dynamicNumColumns,
|
|
162
|
+
activeKey,
|
|
163
|
+
offsetX,
|
|
164
|
+
offsetY,
|
|
165
|
+
startX,
|
|
166
|
+
startY,
|
|
167
|
+
dragMode,
|
|
168
|
+
positions,
|
|
169
|
+
itemsByKey,
|
|
170
|
+
itemWidth,
|
|
171
|
+
itemHeight,
|
|
172
|
+
containerPadding,
|
|
173
|
+
gap,
|
|
174
|
+
setOrderState,
|
|
175
|
+
onDragEnd,
|
|
176
|
+
onOrderChange,
|
|
177
|
+
scrollViewRef,
|
|
178
|
+
scrollOffset,
|
|
179
|
+
viewportH,
|
|
180
|
+
longPressMs,
|
|
181
|
+
scrollSpeed,
|
|
182
|
+
scrollThreshold,
|
|
183
|
+
reverse,
|
|
184
|
+
deleteComponentPosition,
|
|
185
|
+
deleteItem,
|
|
186
|
+
contentPaddingBottom
|
|
187
|
+
}));
|
|
188
|
+
return {
|
|
189
|
+
itemsByKey,
|
|
190
|
+
orderState,
|
|
191
|
+
dragMode,
|
|
192
|
+
anyItemInDeleteMode,
|
|
193
|
+
composed,
|
|
194
|
+
dynamicNumColumns,
|
|
195
|
+
onLayoutContent,
|
|
196
|
+
onLayoutScrollView,
|
|
197
|
+
positions,
|
|
198
|
+
onScroll,
|
|
199
|
+
childArray,
|
|
200
|
+
order,
|
|
201
|
+
deleteItem,
|
|
202
|
+
deleteComponentPosition
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=useGridLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","require","_reactNativeGestureHandler","_reactNativeReanimated","_indexCalculations","_PanWithLongPress","useGridLayout","reverse","children","itemWidth","itemHeight","gap","containerPadding","longPressMs","numColumns","onDragEnd","onOrderChange","onDelete","scrollViewRef","scrollSpeed","scrollThreshold","contentPaddingBottom","childArray","Children","toArray","filter","isValidElement","keys","map","child","key","Error","String","orderState","setOrderState","useState","itemsByKey","useMemo","forEach","dynamicNumColumns","useSharedValue","order","contentW","viewportH","activeKey","offsetX","offsetY","startX","startY","dragMode","anyItemInDeleteMode","contentH","scrollOffset","onScroll","useAnimatedScrollHandler","e","value","contentOffset","y","positionsArray","d","i","x","indexToXY","index","pos","active","positions","obj","Math","random","toString","slice","deleteItem","prev","k","useDerivedValue","p","displayIndex","length","scale","min","damping","stiffness","mass","max","withSpring","onLayoutScrollView","nativeEvent","layout","height","onLayoutContent","width","possibleCols","floor","deleteComponentPosition","composed","Gesture","Simultaneous","PanWithLongPress"],"sources":["useGridLayout.ts"],"sourcesContent":["import { Children, isValidElement, ReactNode, useMemo, useState } from \"react\";\nimport { LayoutChangeEvent } from \"react-native\";\nimport { Gesture } from \"react-native-gesture-handler\";\nimport {\n AnimatedRef,\n SharedValue,\n useAnimatedScrollHandler,\n useDerivedValue,\n useSharedValue,\n withSpring,\n} from \"react-native-reanimated\";\nimport { indexToXY } from \"./helpers/indexCalculations\";\nimport { PanWithLongPress } from \"./helpers/gestures/PanWithLongPress\";\n\ninterface useGridLayoutProps {\n reverse?: boolean;\n children: ReactNode;\n itemWidth: number;\n itemHeight: number;\n gap: number;\n containerPadding: number;\n longPressMs: number;\n numColumns?: number;\n onDragEnd?: (ordered: ChildNode[]) => void;\n onOrderChange?: (keys: string[]) => void;\n onDelete?: (key: string) => void;\n scrollViewRef: AnimatedRef<any>;\n scrollSpeed: number;\n scrollThreshold: number;\n contentPaddingBottom?: number;\n}\n\nexport function useGridLayout({\n reverse,\n children,\n itemWidth,\n itemHeight,\n gap,\n containerPadding,\n longPressMs,\n numColumns,\n onDragEnd,\n onOrderChange,\n onDelete,\n scrollViewRef,\n scrollSpeed,\n scrollThreshold,\n contentPaddingBottom = 0,\n}: useGridLayoutProps) {\n const childArray = Children.toArray(children).filter(isValidElement);\n const keys = childArray.map((child) => {\n if (!(\"key\" in child) || child.key == null) {\n throw new Error(\"All children must have a unique 'key' prop.\");\n }\n return String(child.key);\n });\n\n const [orderState, setOrderState] = useState(keys);\n\n const itemsByKey = useMemo(() => {\n const map: Record<string, ReactNode> = {};\n childArray.forEach((child) => {\n map[String(child.key)] = child;\n });\n return map;\n }, [children]);\n\n const dynamicNumColumns: SharedValue<number> = useSharedValue(\n numColumns ? numColumns : 1\n );\n const order = useSharedValue<string[]>(orderState);\n const contentW = useSharedValue(0);\n const viewportH = useSharedValue(0); // **visible height of ScrollView**\n const activeKey = useSharedValue<string | null>(null);\n const offsetX = useSharedValue(0);\n const offsetY = useSharedValue(0);\n const startX = useSharedValue(0);\n const startY = useSharedValue(0);\n const dragMode = useSharedValue(false);\n const anyItemInDeleteMode = useSharedValue(false); // Global delete mode state\n const contentH = useSharedValue(0);\n const scrollOffset = useSharedValue(0);\n\n const onScroll = useAnimatedScrollHandler({\n onScroll: (e) => {\n scrollOffset.value = e.contentOffset.y;\n },\n });\n\n // initial positions (create shared values consistently by data length)\n const positionsArray = childArray.map((d, i) => {\n const { x, y } = indexToXY({\n index: i,\n itemWidth,\n itemHeight,\n dynamicNumColumns,\n containerPadding,\n gap,\n });\n return {\n key: d.key,\n pos: {\n x: useSharedValue(x),\n y: useSharedValue(y),\n active: useSharedValue(0),\n },\n };\n });\n\n const positions = useMemo(() => {\n const obj: Record<string, (typeof positionsArray)[number][\"pos\"]> = {};\n\n positionsArray.forEach(({ key, pos }) => {\n obj[key ?? `key-${Math.random().toString(36).slice(2)}`] = pos;\n });\n\n return obj;\n }, [positionsArray]);\n\n const deleteItem = (key: string) => {\n setOrderState((prev) => prev.filter((k) => k !== key));\n order.value = order.value.filter((k) => k !== key);\n onOrderChange?.([...order.value]);\n // Call onDelete callback if provided (for both delete button and drop-to-delete)\n if (onDelete) {\n onDelete(key);\n }\n };\n\n useDerivedValue(() => {\n order.value.forEach((key, i) => {\n if (activeKey.value === key) return; // ⬅️ do not layout the active tile\n\n const p = positions[key];\n if (!p) return;\n\n const displayIndex = reverse ? order.value.length - 1 - i : i;\n\n const { x, y } = indexToXY({\n index: displayIndex,\n itemWidth,\n itemHeight,\n dynamicNumColumns,\n containerPadding,\n gap,\n });\n\n const scale = Math.min(itemWidth, itemHeight) / 100; // 100px baseline\n\n const damping = 18 * scale;\n const stiffness = 240 * scale;\n const mass = Math.max(0.1, scale); // helps stability for tiny items\n\n p.x.value = withSpring(x, { damping, stiffness, mass });\n p.y.value = withSpring(y, { damping, stiffness, mass });\n });\n });\n\n // Layout of the ScrollView (viewport) — height we compare against for edge-scrolling\n const onLayoutScrollView = (e: LayoutChangeEvent) => {\n viewportH.value = e.nativeEvent.layout.height;\n };\n\n // Layout of the content view — width used to compute columns\n const onLayoutContent = (e: LayoutChangeEvent) => {\n contentW.value = e.nativeEvent.layout.width;\n contentH.value = e.nativeEvent.layout.height;\n\n if (numColumns) {\n dynamicNumColumns.value = numColumns;\n } else {\n const possibleCols = Math.floor(\n (e.nativeEvent.layout.width - containerPadding * 2 + gap) /\n (itemWidth + gap)\n );\n dynamicNumColumns.value = Math.max(1, possibleCols);\n }\n };\n\n const deleteComponentPosition = useSharedValue<{\n x: number;\n y: number;\n width: number;\n height: number;\n } | null>(null);\n\n const composed = Gesture.Simultaneous(\n PanWithLongPress({\n contentH,\n order,\n dynamicNumColumns,\n activeKey,\n offsetX,\n offsetY,\n startX,\n startY,\n dragMode,\n positions,\n itemsByKey,\n itemWidth,\n itemHeight,\n containerPadding,\n gap,\n setOrderState,\n onDragEnd,\n onOrderChange,\n scrollViewRef,\n scrollOffset,\n viewportH,\n longPressMs,\n scrollSpeed,\n scrollThreshold,\n reverse,\n deleteComponentPosition,\n deleteItem,\n contentPaddingBottom,\n })\n );\n\n return {\n itemsByKey,\n orderState,\n dragMode,\n anyItemInDeleteMode,\n composed,\n dynamicNumColumns,\n onLayoutContent,\n onLayoutScrollView,\n positions,\n onScroll,\n childArray,\n order,\n deleteItem,\n deleteComponentPosition,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|