react-native-gtkx 0.3.0-alpha.1 → 0.4.0-alpha.2

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 (151) hide show
  1. package/README.md +1 -1
  2. package/dist/adw/index.d.ts +3 -2
  3. package/dist/adw/index.js +21 -4
  4. package/dist/adw/index.js.map +1 -1
  5. package/dist/adw/widgets.generated.d.ts +1 -1
  6. package/dist/adw/widgets.generated.js +2 -2
  7. package/dist/adw/widgets.generated.js.map +1 -1
  8. package/dist/animated/create-animated.d.ts +2 -0
  9. package/dist/animated/create-animated.js +2 -0
  10. package/dist/animated/create-animated.js.map +1 -1
  11. package/dist/animated/event.d.ts +15 -0
  12. package/dist/animated/event.js +80 -0
  13. package/dist/animated/event.js.map +1 -0
  14. package/dist/animated/index.d.ts +4 -0
  15. package/dist/animated/index.js +8 -0
  16. package/dist/animated/index.js.map +1 -1
  17. package/dist/animated/spring.d.ts +10 -0
  18. package/dist/animated/spring.js +20 -6
  19. package/dist/animated/spring.js.map +1 -1
  20. package/dist/animated/timing.d.ts +10 -0
  21. package/dist/animated/timing.js +21 -13
  22. package/dist/animated/timing.js.map +1 -1
  23. package/dist/apis/host.gtkx.js +70 -11
  24. package/dist/apis/host.gtkx.js.map +1 -1
  25. package/dist/common/navigation-stack.d.ts +6 -3
  26. package/dist/common/navigation-stack.js +8 -1
  27. package/dist/common/navigation-stack.js.map +1 -1
  28. package/dist/common/widget.js +2 -11
  29. package/dist/common/widget.js.map +1 -1
  30. package/dist/components/animated.d.ts +1 -0
  31. package/dist/components/animated.js +28 -4
  32. package/dist/components/animated.js.map +1 -1
  33. package/dist/components/app-registry.js +32 -8
  34. package/dist/components/app-registry.js.map +1 -1
  35. package/dist/components/request-animation-frame.d.ts +33 -0
  36. package/dist/components/request-animation-frame.js +83 -0
  37. package/dist/components/request-animation-frame.js.map +1 -0
  38. package/dist/components/scroll-view.js +60 -2
  39. package/dist/components/scroll-view.js.map +1 -1
  40. package/dist/components/virtualized-list.js +1 -4
  41. package/dist/components/virtualized-list.js.map +1 -1
  42. package/dist/dnd/autoscroll.d.ts +44 -0
  43. package/dist/dnd/autoscroll.js +176 -0
  44. package/dist/dnd/autoscroll.js.map +1 -0
  45. package/dist/dnd/grid-order.d.ts +45 -0
  46. package/dist/dnd/grid-order.js +151 -0
  47. package/dist/dnd/grid-order.js.map +1 -0
  48. package/dist/dnd/grid.d.ts +44 -0
  49. package/dist/dnd/grid.js +397 -0
  50. package/dist/dnd/grid.js.map +1 -0
  51. package/dist/dnd/gtk-controllers.d.ts +16 -2
  52. package/dist/dnd/gtk-controllers.js +23 -3
  53. package/dist/dnd/gtk-controllers.js.map +1 -1
  54. package/dist/dnd/index.d.ts +4 -2
  55. package/dist/dnd/index.js +9 -2
  56. package/dist/dnd/index.js.map +1 -1
  57. package/dist/dnd/order-state.d.ts +14 -0
  58. package/dist/dnd/order-state.js +55 -0
  59. package/dist/dnd/order-state.js.map +1 -0
  60. package/dist/dnd/order.d.ts +19 -0
  61. package/dist/dnd/order.js +19 -0
  62. package/dist/dnd/order.js.map +1 -1
  63. package/dist/dnd/sortable.d.ts +29 -4
  64. package/dist/dnd/sortable.js +308 -115
  65. package/dist/dnd/sortable.js.map +1 -1
  66. package/dist/dnd/types.d.ts +236 -14
  67. package/dist/dnd/types.js +30 -0
  68. package/dist/dnd/types.js.map +1 -1
  69. package/dist/gesture-handler-compat/attach-context.d.ts +29 -0
  70. package/dist/gesture-handler-compat/attach-context.js +90 -0
  71. package/dist/gesture-handler-compat/attach-context.js.map +1 -0
  72. package/dist/gesture-handler-compat/detector-runtime.d.ts +14 -3
  73. package/dist/gesture-handler-compat/detector-runtime.js +15 -5
  74. package/dist/gesture-handler-compat/detector-runtime.js.map +1 -1
  75. package/dist/gesture-handler-compat/detector.js +57 -2
  76. package/dist/gesture-handler-compat/detector.js.map +1 -1
  77. package/dist/gesture-handler-compat/gesture-state-manager.d.ts +5 -0
  78. package/dist/gesture-handler-compat/gesture-state-manager.js +77 -0
  79. package/dist/gesture-handler-compat/gesture-state-manager.js.map +1 -0
  80. package/dist/gesture-handler-compat/index.d.ts +2 -2
  81. package/dist/gesture-handler-compat/index.js +38 -33
  82. package/dist/gesture-handler-compat/index.js.map +1 -1
  83. package/dist/gesture-handler-compat/recognizer.d.ts +12 -1
  84. package/dist/gesture-handler-compat/recognizer.js +23 -9
  85. package/dist/gesture-handler-compat/recognizer.js.map +1 -1
  86. package/dist/gesture-handler-compat/tag-registry.d.ts +14 -0
  87. package/dist/gesture-handler-compat/tag-registry.js +19 -0
  88. package/dist/gesture-handler-compat/tag-registry.js.map +1 -0
  89. package/dist/globals/index.d.ts +47 -0
  90. package/dist/globals/index.js +181 -0
  91. package/dist/globals/index.js.map +1 -0
  92. package/dist/globals/install.d.ts +1 -0
  93. package/dist/globals/install.js +14 -0
  94. package/dist/globals/install.js.map +1 -0
  95. package/dist/gtkx/bridge/adw-namespace.d.ts +2 -0
  96. package/dist/gtkx/bridge/adw-namespace.js +26 -0
  97. package/dist/gtkx/bridge/adw-namespace.js.map +1 -0
  98. package/dist/gtkx/bridge/adw.d.ts +23 -0
  99. package/dist/gtkx/bridge/adw.js +93 -0
  100. package/dist/gtkx/bridge/adw.js.map +1 -0
  101. package/dist/gtkx/bridge/color-scheme-parse.d.ts +11 -0
  102. package/dist/gtkx/bridge/color-scheme-parse.js +42 -0
  103. package/dist/gtkx/bridge/color-scheme-parse.js.map +1 -0
  104. package/dist/gtkx/bridge/color-scheme-portal.d.ts +24 -0
  105. package/dist/gtkx/bridge/color-scheme-portal.js +172 -0
  106. package/dist/gtkx/bridge/color-scheme-portal.js.map +1 -0
  107. package/dist/gtkx/bridge/core.d.ts +25 -0
  108. package/dist/gtkx/bridge/core.js +69 -0
  109. package/dist/gtkx/bridge/core.js.map +1 -0
  110. package/dist/gtkx/bridge/drag-layer.d.ts +27 -0
  111. package/dist/gtkx/bridge/drag-layer.js +177 -0
  112. package/dist/gtkx/bridge/drag-layer.js.map +1 -0
  113. package/dist/gtkx/bridge/index.d.ts +1 -27
  114. package/dist/gtkx/bridge/index.js +12 -71
  115. package/dist/gtkx/bridge/index.js.map +1 -1
  116. package/dist/gtkx/bridge/widgets.generated.adw.d.ts +1 -0
  117. package/dist/gtkx/bridge/widgets.generated.adw.js +16 -0
  118. package/dist/gtkx/bridge/widgets.generated.adw.js.map +1 -0
  119. package/dist/gtkx/bridge/widgets.generated.d.ts +0 -1
  120. package/dist/gtkx/bridge/widgets.generated.js +3 -3
  121. package/dist/gtkx/bridge/widgets.generated.js.map +1 -1
  122. package/dist/index.js +20 -0
  123. package/dist/index.js.map +1 -1
  124. package/dist/mcp/data/generated.d.ts +41 -20
  125. package/dist/mcp/data/generated.js +46 -20
  126. package/dist/mcp/data/generated.js.map +1 -1
  127. package/dist/metro/index.d.ts +1 -0
  128. package/dist/metro/index.js +12 -0
  129. package/dist/metro/index.js.map +1 -1
  130. package/dist/navigation/sidebar.js +2 -45
  131. package/dist/navigation/sidebar.js.map +1 -1
  132. package/dist/reanimated-compat/animatable-value.d.ts +158 -0
  133. package/dist/reanimated-compat/animatable-value.js +316 -0
  134. package/dist/reanimated-compat/animatable-value.js.map +1 -0
  135. package/dist/reanimated-compat/animation.d.ts +34 -13
  136. package/dist/reanimated-compat/animation.js +97 -25
  137. package/dist/reanimated-compat/animation.js.map +1 -1
  138. package/dist/reanimated-compat/mutable.js +6 -6
  139. package/dist/reanimated-compat/mutable.js.map +1 -1
  140. package/dist/reanimated-compat/updater-animations.js +32 -12
  141. package/dist/reanimated-compat/updater-animations.js.map +1 -1
  142. package/dist/runner/host-dev.js +5 -1
  143. package/dist/runner/host-dev.js.map +1 -1
  144. package/dist/runner/host.js +9 -1
  145. package/dist/runner/host.js.map +1 -1
  146. package/dist/vite/index.js +130 -0
  147. package/dist/vite/index.js.map +1 -1
  148. package/package.json +1 -1
  149. package/dist/gtkx/bridge/theme.d.ts +0 -4
  150. package/dist/gtkx/bridge/theme.js +0 -5
  151. package/dist/gtkx/bridge/theme.js.map +0 -1
@@ -0,0 +1,397 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // `SortableGrid`, `SortableGridItem`, `useGridSortable` and
3
+ // `useGridSortableList` — the 2-D sibling of `Sortable`, same reorder-by-
4
+ // crossing mechanism, one more axis.
5
+ //
6
+ // Upstream lays every cell out `position: absolute`, at a `top`/`left` a
7
+ // `useAnimatedStyle` computes from `positions.value[id]`, and sizes the
8
+ // container to `calculateGridContentDimensions` for exactly that reason —
9
+ // nothing else would give the absolutely-positioned cells a scroll range.
10
+ // This mirror has no equivalent of that computed style (`docs/research/
11
+ // drag-and-drop.md`'s `Sortable` section explains why: no per-frame
12
+ // transform outside a real gesture), so the grid is a real Yoga FLEX-WRAP
13
+ // layout instead: the content container is a fixed-size cross axis (`columns`
14
+ // × `itemWidth` for a vertical grid, `rows` × `itemHeight` for a horizontal
15
+ // one) with `flexWrap: "wrap"`, and cells of a fixed `itemWidth`/`itemHeight`
16
+ // wrap themselves into rows or columns exactly the way the absolute
17
+ // positions upstream computes would place them — because both are the same
18
+ // arithmetic (`grid-order.ts`'s `calculateGridPosition`), just applied by two
19
+ // different engines. The one thing this could not reproduce either way is in
20
+ // docs/api.md: the grid's overall size is whatever Yoga measures, not
21
+ // `calculateGridContentDimensions`; `useGridSortableList` still reports that
22
+ // number for an app that wants upstream's own formula.
23
+ //
24
+ // WHAT DECIDES A CROSSING, and why it changed: see `sortable.tsx`'s own
25
+ // module comment for the full reasoning — the same change applies here, one
26
+ // more axis. This used to be GDK hit-testing the raw pointer against a
27
+ // neighbour cell's full rect (a cell's own `onEnter`) — grab-point
28
+ // DEPENDENT. It is now the dragged cell's own TRACKED position:
29
+ // `useEdgeAutoscroll`'s `onDragMotion` (this grid's shared motion
30
+ // controller) feeds `handleDragMotion` below, which tracks
31
+ // `calculateGridPosition(fromIndex, ...)` plus the pointer's delta on both
32
+ // axes since the drag began, and resolves the cell it lands on by ROUNDING
33
+ // both axes rather than `getGridCellFromCoordinates`'s own floor — the
34
+ // dragged cell's CENTRE against a slot's centre (`grid-order.ts`'s
35
+ // `resolveTrackedGridIndex`), not its top-left corner against the slot's
36
+ // origin. The origin is `DragSourceControllers`'s `onGrab`, converted to
37
+ // this grid's own container coordinates, never the first motion sample.
38
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
39
+ import { widgetForHandle } from "../components/measure";
40
+ import { ScrollView } from "../components/scroll-view";
41
+ import { View } from "../components/view";
42
+ import { computePointIn } from "../gtkx/bridge/index";
43
+ import { useEdgeAutoscroll } from "./autoscroll";
44
+ import { DraggableContext, DraggableHandle } from "./draggable";
45
+ import { calculateGridContentDimensions, calculateGridPosition, gridPositionsToOrder, listToGridObject, reorderGridInsert, reorderGridSwap, resolveTrackedGridIndex, } from "./grid-order";
46
+ import { DragSourceControllers, DropTargetControllers } from "./gtk-controllers";
47
+ import { keyOf, useOrder } from "./order-state";
48
+ import { GridOrientation, GridScrollDirection, GridStrategy, } from "./types";
49
+ export { calculateGridContentDimensions, calculateGridPosition, calculateIndexFromRowColumn, findItemIdAtIndex, getGridCellFromCoordinates, listToGridObject, reorderGridInsert, reorderGridSwap, } from "./grid-order";
50
+ const SortableGridContext = createContext(null);
51
+ const useGridSharedBoxes = (order, dimensions, orientation, strategy, autoScrollDirection) => {
52
+ const positions = useMemo(() => ({
53
+ value: listToGridObject(order, dimensions, orientation),
54
+ }), [order, dimensions, orientation]);
55
+ const idle = useMemo(() => ({
56
+ scrollY: { value: 0 },
57
+ scrollX: { value: 0 },
58
+ }), []);
59
+ const itemsCount = order.length;
60
+ return useMemo(() => ({
61
+ positions,
62
+ ...idle,
63
+ plumbing: () => ({
64
+ positions,
65
+ scrollY: idle.scrollY,
66
+ scrollX: idle.scrollX,
67
+ autoScrollDirection,
68
+ itemsCount,
69
+ dimensions,
70
+ orientation,
71
+ strategy,
72
+ }),
73
+ }), [
74
+ positions,
75
+ idle,
76
+ itemsCount,
77
+ dimensions,
78
+ orientation,
79
+ strategy,
80
+ autoScrollDirection,
81
+ ]);
82
+ };
83
+ const gridDirectionFor = (dx, dy) => {
84
+ if (dy < 0 && dx < 0) {
85
+ return GridScrollDirection.UpLeft;
86
+ }
87
+ if (dy < 0 && dx > 0) {
88
+ return GridScrollDirection.UpRight;
89
+ }
90
+ if (dy > 0 && dx < 0) {
91
+ return GridScrollDirection.DownLeft;
92
+ }
93
+ if (dy > 0 && dx > 0) {
94
+ return GridScrollDirection.DownRight;
95
+ }
96
+ if (dy < 0) {
97
+ return GridScrollDirection.Up;
98
+ }
99
+ if (dy > 0) {
100
+ return GridScrollDirection.Down;
101
+ }
102
+ if (dx < 0) {
103
+ return GridScrollDirection.Left;
104
+ }
105
+ if (dx > 0) {
106
+ return GridScrollDirection.Right;
107
+ }
108
+ return GridScrollDirection.None;
109
+ };
110
+ /**
111
+ * Owns the order of a sortable grid, for an app rendering its own container —
112
+ * the grid's counterpart of `useSortableList`. **The order half only**, same
113
+ * contract: rows still need to sit inside a `SortableGrid` for the drag
114
+ * wiring, which travels through context. No autoscroll wiring either, for
115
+ * the same reason `useSortableList` has none — this hook builds no
116
+ * `ScrollView` of its own.
117
+ */
118
+ export const useGridSortableList = (options) => {
119
+ const { dimensions, orientation = GridOrientation.Vertical, strategy = GridStrategy.Insert, } = options;
120
+ const { order, items } = useOrder(options.data, options.itemKeyExtractor);
121
+ const idleAutoScroll = useMemo(() => ({
122
+ value: GridScrollDirection.None,
123
+ }), []);
124
+ const boxes = useGridSharedBoxes(order, dimensions, orientation, strategy, idleAutoScroll);
125
+ const dropProviderRef = useRef(null);
126
+ const noop = useCallback(() => { }, []);
127
+ const { width: contentWidth, height: contentHeight } = calculateGridContentDimensions(order.length, dimensions, orientation);
128
+ return {
129
+ positions: boxes.positions,
130
+ scrollY: boxes.scrollY,
131
+ scrollX: boxes.scrollX,
132
+ autoScrollDirection: idleAutoScroll,
133
+ dropProviderRef,
134
+ handleScroll: noop,
135
+ handleScrollEnd: noop,
136
+ contentWidth,
137
+ contentHeight,
138
+ items,
139
+ getItemProps: () => boxes.plumbing(),
140
+ };
141
+ };
142
+ /**
143
+ * A grid whose cells reorder by dragging.
144
+ *
145
+ * ```tsx
146
+ * <SortableGrid
147
+ * data={photos}
148
+ * dimensions={{ columns: 3, itemWidth: 100, itemHeight: 100, columnGap: 8, rowGap: 8 }}
149
+ * renderItem={({ item, id, ...rest }) => (
150
+ * <SortableGridItem key={id} id={id} data={item} {...rest}>
151
+ * <Image source={{ uri: item.uri }} style={{ flex: 1 }} />
152
+ * </SortableGridItem>
153
+ * )}
154
+ * />
155
+ * ```
156
+ *
157
+ * No list-level `onMove`/`onDragStart`/`onDrop`/`onDragging` — same as
158
+ * upstream's own `SortableGridProps`, which carries none either; wire them on
159
+ * each `SortableGridItem` instead.
160
+ */
161
+ export const SortableGrid = ({ data, renderItem, dimensions, orientation = GridOrientation.Vertical, strategy = GridStrategy.Insert, style, contentContainerStyle, itemKeyExtractor,
162
+ // `scrollEnabled` is accepted and ignored: this platform's `ScrollView` has
163
+ // no prop to disable input the way upstream's does (`docs/api.md`), so
164
+ // there is nothing here to forward it to — not destructured at all, rather
165
+ // than bound and unused.
166
+ testID, }) => {
167
+ if (!dimensions.itemWidth || !dimensions.itemHeight) {
168
+ throw new Error("react-native-gtkx/dnd: SortableGrid requires itemWidth and itemHeight in dimensions");
169
+ }
170
+ if (orientation === GridOrientation.Vertical && !dimensions.columns) {
171
+ throw new Error("react-native-gtkx/dnd: SortableGrid requires columns in dimensions when orientation is vertical");
172
+ }
173
+ if (orientation === GridOrientation.Horizontal && !dimensions.rows) {
174
+ throw new Error("react-native-gtkx/dnd: SortableGrid requires rows in dimensions when orientation is horizontal");
175
+ }
176
+ const { scope, order, setOrder, items } = useOrder(data, itemKeyExtractor);
177
+ const isHorizontal = orientation === GridOrientation.Horizontal;
178
+ const containerRef = useRef(null);
179
+ const scrollViewRef = useRef(null);
180
+ const beforeDrag = useRef(null);
181
+ const orderRef = useRef(order);
182
+ useEffect(() => {
183
+ orderRef.current = order;
184
+ }, [order]);
185
+ const callbacks = useRef(new Map());
186
+ const registerCallbacks = useCallback((id, cbs) => {
187
+ if (cbs) {
188
+ callbacks.current.set(id, cbs);
189
+ }
190
+ else {
191
+ callbacks.current.delete(id);
192
+ }
193
+ }, []);
194
+ const moveOnto = useCallback((draggedId, targetId) => {
195
+ setOrder((current) => {
196
+ const positions = listToGridObject(current, dimensions, orientation);
197
+ const activePosition = positions[draggedId];
198
+ const targetPosition = positions[targetId];
199
+ if (!activePosition || !targetPosition) {
200
+ return current;
201
+ }
202
+ const nextPositions = strategy === GridStrategy.Swap
203
+ ? reorderGridSwap(positions, draggedId, targetId, dimensions, orientation)
204
+ : reorderGridInsert(positions, draggedId, targetPosition.index, dimensions, orientation);
205
+ const next = gridPositionsToOrder(nextPositions);
206
+ if (next.length === current.length &&
207
+ next.every((id, index) => id === current[index])) {
208
+ return current;
209
+ }
210
+ callbacks.current
211
+ .get(draggedId)
212
+ ?.onMove?.(draggedId, activePosition.index, nextPositions[draggedId].index);
213
+ return next;
214
+ });
215
+ }, [setOrder, dimensions, orientation, strategy]);
216
+ // The dragged cell's own tracked position — see `sortable.tsx`'s twin for
217
+ // why this is a ref, and its `base` field's derivation.
218
+ const tracking = useRef(null);
219
+ const handleDragMotion = useCallback((x, y) => {
220
+ const state = tracking.current;
221
+ if (!state) {
222
+ return;
223
+ }
224
+ const trackedX = x + state.baseX;
225
+ const trackedY = y + state.baseY;
226
+ const resolvedIndex = resolveTrackedGridIndex(trackedX, trackedY, dimensions, orientation, orderRef.current.length);
227
+ if (resolvedIndex === state.lastResolvedIndex) {
228
+ return;
229
+ }
230
+ state.lastResolvedIndex = resolvedIndex;
231
+ const targetId = orderRef.current[resolvedIndex];
232
+ if (targetId !== undefined && targetId !== state.draggedId) {
233
+ moveOnto(state.draggedId, targetId);
234
+ }
235
+ }, [dimensions, orientation, moveOnto]);
236
+ const autoscroll = useEdgeAutoscroll({
237
+ containerRef,
238
+ scrollViewRef,
239
+ axes: "both",
240
+ none: GridScrollDirection.None,
241
+ directionFor: gridDirectionFor,
242
+ onDragMotion: handleDragMotion,
243
+ });
244
+ const boxes = useGridSharedBoxes(order, dimensions, orientation, strategy, autoscroll.direction);
245
+ const beginDrag = useCallback((draggedId, grabWidget, grabX, grabY) => {
246
+ beforeDrag.current = orderRef.current;
247
+ autoscroll.setActive(true);
248
+ const fromIndex = orderRef.current.indexOf(draggedId);
249
+ tracking.current = null;
250
+ const container = widgetForHandle(containerRef.current);
251
+ if (grabWidget && container && fromIndex !== -1) {
252
+ const origin = computePointIn(grabWidget, container, grabX, grabY);
253
+ if (origin) {
254
+ // Unlike the plain list, a grid cell's size is not measured: it is
255
+ // already a real, enforced Yoga size — `SortableGridItem` styles
256
+ // every cell to exactly `dimensions.itemWidth`/`itemHeight`
257
+ // (grid.tsx below), so the same numbers this component was
258
+ // already handed are what the tracked position's slots use too.
259
+ const rest = calculateGridPosition(fromIndex, dimensions, orientation);
260
+ tracking.current = {
261
+ draggedId,
262
+ baseX: rest.x - origin.x,
263
+ baseY: rest.y - origin.y,
264
+ lastResolvedIndex: fromIndex,
265
+ };
266
+ }
267
+ }
268
+ return fromIndex;
269
+ }, [autoscroll, dimensions, orientation]);
270
+ const endDrag = useCallback((draggedId, dropped) => {
271
+ autoscroll.setActive(false);
272
+ tracking.current = null;
273
+ const restore = beforeDrag.current;
274
+ beforeDrag.current = null;
275
+ if (!dropped) {
276
+ if (restore) {
277
+ setOrder(() => restore);
278
+ }
279
+ return null;
280
+ }
281
+ const settled = orderRef.current;
282
+ const positions = listToGridObject(settled, dimensions, orientation);
283
+ return { index: positions[draggedId]?.index ?? -1, positions };
284
+ }, [setOrder, dimensions, orientation, autoscroll]);
285
+ const contextValue = useMemo(() => ({ scope, registerCallbacks, moveOnto, beginDrag, endDrag }), [scope, registerCallbacks, moveOnto, beginDrag, endDrag]);
286
+ const { width: crossAxisWidth } = calculateGridContentDimensions(order.length, dimensions, GridOrientation.Vertical);
287
+ const { height: crossAxisHeight } = calculateGridContentDimensions(order.length, dimensions, GridOrientation.Horizontal);
288
+ return (_jsx(SortableGridContext.Provider, { value: contextValue, children: _jsxs(View, { ref: containerRef, style: { flex: 1 }, children: [autoscroll.controllers, _jsx(ScrollView, { ref: scrollViewRef, horizontal: isHorizontal, style: style, contentContainerStyle: [
289
+ isHorizontal
290
+ ? {
291
+ flexDirection: "column",
292
+ flexWrap: "wrap",
293
+ height: crossAxisHeight,
294
+ columnGap: dimensions.columnGap,
295
+ rowGap: dimensions.rowGap,
296
+ }
297
+ : {
298
+ flexDirection: "row",
299
+ flexWrap: "wrap",
300
+ width: crossAxisWidth,
301
+ columnGap: dimensions.columnGap,
302
+ rowGap: dimensions.rowGap,
303
+ },
304
+ contentContainerStyle,
305
+ ], testID: testID, children: items.map((item, index) => renderItem({
306
+ item,
307
+ index,
308
+ id: keyOf(item, index, itemKeyExtractor),
309
+ ...boxes.plumbing(),
310
+ })) })] }) }));
311
+ };
312
+ /**
313
+ * The reorder half of the module, as a hook, for a cell that owns its own
314
+ * view.
315
+ */
316
+ export const useGridSortable = (options) => {
317
+ const { id, onMove, onDragStart, onDrop, onDragging } = options;
318
+ const grid = useContext(SortableGridContext);
319
+ if (grid === null) {
320
+ throw new Error("react-native-gtkx/dnd: SortableGridItem/useGridSortable must be inside a SortableGrid");
321
+ }
322
+ const [isMoving, setIsMoving] = useState(false);
323
+ const [hasHandle, setHasHandle] = useState(false);
324
+ const registerHandle = useCallback((registered) => {
325
+ setHasHandle(registered);
326
+ }, []);
327
+ useEffect(() => {
328
+ grid.registerCallbacks(id, { onMove, onDragStart, onDrop });
329
+ return () => grid.registerCallbacks(id, null);
330
+ }, [grid, id, onMove, onDragStart, onDrop]);
331
+ const [mounted, setMounted] = useState(false);
332
+ // eslint-disable-next-line react-hooks/set-state-in-effect
333
+ useEffect(() => setMounted(true), []);
334
+ // Same list only, including this cell itself — see sortable.tsx's
335
+ // `useSortable` for why refusing a self-drop is wrong on this platform.
336
+ const accepts = useCallback((payload) => payload.scope === grid.scope, [grid]);
337
+ // `DragSourceControllers`'s own grab point — see sortable.tsx's
338
+ // `useSortable` for the same field and why it is captured here rather than
339
+ // read from the first motion sample.
340
+ const grab = useRef({
341
+ widget: null,
342
+ x: 0,
343
+ y: 0,
344
+ });
345
+ const dragControllers = (_jsx(DragSourceControllers, { payload: { scope: grid.scope, id }, onGrab: (x, y, widget) => {
346
+ grab.current = { widget, x, y };
347
+ }, onDragBegin: () => {
348
+ setIsMoving(true);
349
+ const position = grid.beginDrag(id, grab.current.widget, grab.current.x, grab.current.y);
350
+ onDragStart?.(id, position);
351
+ }, onDragEnd: (dropped) => {
352
+ setIsMoving(false);
353
+ const result = grid.endDrag(id, dropped);
354
+ if (result) {
355
+ onDrop?.(id, result.index, result.positions);
356
+ }
357
+ } }));
358
+ const dropControllers = (_jsx(DropTargetControllers, { accepts: accepts,
359
+ // No `onEnter` any more — the reorder decision is the grid's own
360
+ // tracking (`handleDragMotion`), not this cell's drop target. This
361
+ // target still has to exist and accept, or GDK would refuse the drop;
362
+ // `onMotion` still reports the public `onDragging` callback.
363
+ onMotion: (payload, x, y) => {
364
+ onDragging?.(payload.id, id, x, y);
365
+ }, onDrop: () => { } }));
366
+ return {
367
+ animatedStyle: undefined,
368
+ isMoving,
369
+ hasHandle,
370
+ registerHandle,
371
+ dragControllers,
372
+ children: (_jsxs(_Fragment, { children: [mounted && !hasHandle ? dragControllers : null, dropControllers] })),
373
+ };
374
+ };
375
+ /** One cell of a {@link SortableGrid}. Both a drag source and a drop target:
376
+ * the cell you drag onto is the position the dragged cell takes (or trades
377
+ * with, under `GridStrategy.Swap`). */
378
+ export const SortableGridItem = ({ id, data, dimensions, children, style, animatedStyle, testID, onMove, onDragStart, onDrop, onDragging, }) => {
379
+ const sortable = useGridSortable({
380
+ id,
381
+ data,
382
+ onMove,
383
+ onDragStart,
384
+ onDrop,
385
+ onDragging,
386
+ });
387
+ const handleContext = useMemo(() => ({
388
+ source: sortable.dragControllers,
389
+ registerHandle: sortable.registerHandle,
390
+ }), [sortable.dragControllers, sortable.registerHandle]);
391
+ const cellSize = dimensions
392
+ ? { width: dimensions.itemWidth, height: dimensions.itemHeight }
393
+ : undefined;
394
+ return (_jsx(View, { style: animatedStyle ? [cellSize, style, animatedStyle] : [cellSize, style], testID: testID, children: _jsxs(DraggableContext.Provider, { value: handleContext, children: [sortable.children, children] }) }));
395
+ };
396
+ SortableGridItem.Handle = DraggableHandle;
397
+ //# sourceMappingURL=grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.js","sourceRoot":"","sources":["../../src/dnd/grid.tsx"],"names":[],"mappings":"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","sourcesContent":["// `SortableGrid`, `SortableGridItem`, `useGridSortable` and\n// `useGridSortableList` — the 2-D sibling of `Sortable`, same reorder-by-\n// crossing mechanism, one more axis.\n//\n// Upstream lays every cell out `position: absolute`, at a `top`/`left` a\n// `useAnimatedStyle` computes from `positions.value[id]`, and sizes the\n// container to `calculateGridContentDimensions` for exactly that reason —\n// nothing else would give the absolutely-positioned cells a scroll range.\n// This mirror has no equivalent of that computed style (`docs/research/\n// drag-and-drop.md`'s `Sortable` section explains why: no per-frame\n// transform outside a real gesture), so the grid is a real Yoga FLEX-WRAP\n// layout instead: the content container is a fixed-size cross axis (`columns`\n// × `itemWidth` for a vertical grid, `rows` × `itemHeight` for a horizontal\n// one) with `flexWrap: \"wrap\"`, and cells of a fixed `itemWidth`/`itemHeight`\n// wrap themselves into rows or columns exactly the way the absolute\n// positions upstream computes would place them — because both are the same\n// arithmetic (`grid-order.ts`'s `calculateGridPosition`), just applied by two\n// different engines. The one thing this could not reproduce either way is in\n// docs/api.md: the grid's overall size is whatever Yoga measures, not\n// `calculateGridContentDimensions`; `useGridSortableList` still reports that\n// number for an app that wants upstream's own formula.\n//\n// WHAT DECIDES A CROSSING, and why it changed: see `sortable.tsx`'s own\n// module comment for the full reasoning — the same change applies here, one\n// more axis. This used to be GDK hit-testing the raw pointer against a\n// neighbour cell's full rect (a cell's own `onEnter`) — grab-point\n// DEPENDENT. It is now the dragged cell's own TRACKED position:\n// `useEdgeAutoscroll`'s `onDragMotion` (this grid's shared motion\n// controller) feeds `handleDragMotion` below, which tracks\n// `calculateGridPosition(fromIndex, ...)` plus the pointer's delta on both\n// axes since the drag began, and resolves the cell it lands on by ROUNDING\n// both axes rather than `getGridCellFromCoordinates`'s own floor — the\n// dragged cell's CENTRE against a slot's centre (`grid-order.ts`'s\n// `resolveTrackedGridIndex`), not its top-left corner against the slot's\n// origin. The origin is `DragSourceControllers`'s `onGrab`, converted to\n// this grid's own container coordinates, never the first motion sample.\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport type { MeasureHandle } from \"../components/measure\"\nimport { widgetForHandle } from \"../components/measure\"\nimport { ScrollView, type ScrollViewHandle } from \"../components/scroll-view\"\nimport { View } from \"../components/view\"\nimport { computePointIn, type Gtk } from \"../gtkx/bridge/index\"\nimport { useEdgeAutoscroll } from \"./autoscroll\"\nimport { DraggableContext, DraggableHandle } from \"./draggable\"\nimport {\n calculateGridContentDimensions,\n calculateGridPosition,\n gridPositionsToOrder,\n listToGridObject,\n reorderGridInsert,\n reorderGridSwap,\n resolveTrackedGridIndex,\n} from \"./grid-order\"\nimport { DragSourceControllers, DropTargetControllers } from \"./gtk-controllers\"\nimport { keyOf, useOrder } from \"./order-state\"\nimport type { DragPayload } from \"./payload\"\nimport {\n GridOrientation,\n GridScrollDirection,\n GridStrategy,\n type GridItemPlumbing,\n type GridPositions,\n type SharedValueLike,\n type SortableData,\n type SortableGridItemProps,\n type SortableGridProps,\n type UseGridSortableListOptions,\n type UseGridSortableListReturn,\n type UseGridSortableOptions,\n type UseGridSortableReturn,\n} from \"./types\"\n\nexport {\n calculateGridContentDimensions,\n calculateGridPosition,\n calculateIndexFromRowColumn,\n findItemIdAtIndex,\n getGridCellFromCoordinates,\n listToGridObject,\n reorderGridInsert,\n reorderGridSwap,\n} from \"./grid-order\"\n\n// --- the list ---------------------------------------------------------------\n\ntype GridItemCallbacks = {\n onMove?: (id: string, from: number, to: number) => void\n onDragStart?: (id: string, position: number) => void\n onDrop?: (id: string, position: number, allPositions?: GridPositions) => void\n}\n\ntype SortableGridContextValue = {\n scope: string\n /** The dragged item's own callbacks live on ITS OWN `SortableGridItem`, not\n * on `SortableGrid` (upstream has no list-level callbacks for the grid —\n * `SortableGridProps` carries none). A reorder is decided by the grid's\n * own reorder tracking (`handleDragMotion`), not by any one cell's\n * component instance, so the dragged cell's own `onMove` is reached\n * through this small registry rather than a closure `moveOnto` could\n * capture directly. */\n registerCallbacks: (id: string, callbacks: GridItemCallbacks | null) => void\n /** Called from the grid's own reorder tracking when the dragged cell's\n * tracked position resolves to a new slot — no longer from a cell's own\n * `onEnter`, see the module comment. */\n moveOnto: (draggedId: string, targetId: string) => void\n /** `grabWidget`/`grabX`/`grabY` are `DragSourceControllers`'s `onGrab`,\n * forwarded as-is — see `sortable.tsx`'s `SortableContextValue.beginDrag`\n * for what this converts them into. Still returns the dragged cell's\n * `fromIndex`, unchanged, for `onDragStart`. */\n beginDrag: (\n draggedId: string,\n grabWidget: Gtk.Widget | null,\n grabX: number,\n grabY: number,\n ) => number\n endDrag: (\n draggedId: string,\n dropped: boolean,\n ) => { index: number; positions: GridPositions } | null\n}\n\nconst SortableGridContext = createContext<SortableGridContextValue | null>(null)\n\nconst useGridSharedBoxes = (\n order: string[],\n dimensions: GridItemPlumbing[\"dimensions\"],\n orientation: GridOrientation,\n strategy: GridStrategy,\n autoScrollDirection: SharedValueLike<GridScrollDirection>,\n) => {\n const positions = useMemo(\n (): SharedValueLike<GridPositions> => ({\n value: listToGridObject(order, dimensions, orientation),\n }),\n [order, dimensions, orientation],\n )\n const idle = useMemo(\n () => ({\n scrollY: { value: 0 },\n scrollX: { value: 0 },\n }),\n [],\n )\n const itemsCount = order.length\n\n return useMemo(\n () => ({\n positions,\n ...idle,\n plumbing: (): GridItemPlumbing => ({\n positions,\n scrollY: idle.scrollY,\n scrollX: idle.scrollX,\n autoScrollDirection,\n itemsCount,\n dimensions,\n orientation,\n strategy,\n }),\n }),\n [\n positions,\n idle,\n itemsCount,\n dimensions,\n orientation,\n strategy,\n autoScrollDirection,\n ],\n )\n}\n\nconst gridDirectionFor = (\n dx: -1 | 0 | 1,\n dy: -1 | 0 | 1,\n): GridScrollDirection => {\n if (dy < 0 && dx < 0) {\n return GridScrollDirection.UpLeft\n }\n if (dy < 0 && dx > 0) {\n return GridScrollDirection.UpRight\n }\n if (dy > 0 && dx < 0) {\n return GridScrollDirection.DownLeft\n }\n if (dy > 0 && dx > 0) {\n return GridScrollDirection.DownRight\n }\n if (dy < 0) {\n return GridScrollDirection.Up\n }\n if (dy > 0) {\n return GridScrollDirection.Down\n }\n if (dx < 0) {\n return GridScrollDirection.Left\n }\n if (dx > 0) {\n return GridScrollDirection.Right\n }\n return GridScrollDirection.None\n}\n\n/**\n * Owns the order of a sortable grid, for an app rendering its own container —\n * the grid's counterpart of `useSortableList`. **The order half only**, same\n * contract: rows still need to sit inside a `SortableGrid` for the drag\n * wiring, which travels through context. No autoscroll wiring either, for\n * the same reason `useSortableList` has none — this hook builds no\n * `ScrollView` of its own.\n */\nexport const useGridSortableList = <TData extends SortableData>(\n options: UseGridSortableListOptions<TData>,\n): UseGridSortableListReturn<TData> => {\n const {\n dimensions,\n orientation = GridOrientation.Vertical,\n strategy = GridStrategy.Insert,\n } = options\n const { order, items } = useOrder(options.data, options.itemKeyExtractor)\n const idleAutoScroll = useMemo(\n (): SharedValueLike<GridScrollDirection> => ({\n value: GridScrollDirection.None,\n }),\n [],\n )\n const boxes = useGridSharedBoxes(\n order,\n dimensions,\n orientation,\n strategy,\n idleAutoScroll,\n )\n const dropProviderRef = useRef(null)\n const noop = useCallback(() => {}, [])\n const { width: contentWidth, height: contentHeight } =\n calculateGridContentDimensions(order.length, dimensions, orientation)\n\n return {\n positions: boxes.positions,\n scrollY: boxes.scrollY,\n scrollX: boxes.scrollX,\n autoScrollDirection: idleAutoScroll,\n dropProviderRef,\n handleScroll: noop,\n handleScrollEnd: noop,\n contentWidth,\n contentHeight,\n items,\n getItemProps: () => boxes.plumbing(),\n }\n}\n\n/**\n * A grid whose cells reorder by dragging.\n *\n * ```tsx\n * <SortableGrid\n * data={photos}\n * dimensions={{ columns: 3, itemWidth: 100, itemHeight: 100, columnGap: 8, rowGap: 8 }}\n * renderItem={({ item, id, ...rest }) => (\n * <SortableGridItem key={id} id={id} data={item} {...rest}>\n * <Image source={{ uri: item.uri }} style={{ flex: 1 }} />\n * </SortableGridItem>\n * )}\n * />\n * ```\n *\n * No list-level `onMove`/`onDragStart`/`onDrop`/`onDragging` — same as\n * upstream's own `SortableGridProps`, which carries none either; wire them on\n * each `SortableGridItem` instead.\n */\nexport const SortableGrid = <TData extends SortableData>({\n data,\n renderItem,\n dimensions,\n orientation = GridOrientation.Vertical,\n strategy = GridStrategy.Insert,\n style,\n contentContainerStyle,\n itemKeyExtractor,\n // `scrollEnabled` is accepted and ignored: this platform's `ScrollView` has\n // no prop to disable input the way upstream's does (`docs/api.md`), so\n // there is nothing here to forward it to — not destructured at all, rather\n // than bound and unused.\n testID,\n}: SortableGridProps<TData>): ReactNode => {\n if (!dimensions.itemWidth || !dimensions.itemHeight) {\n throw new Error(\n \"react-native-gtkx/dnd: SortableGrid requires itemWidth and itemHeight in dimensions\",\n )\n }\n if (orientation === GridOrientation.Vertical && !dimensions.columns) {\n throw new Error(\n \"react-native-gtkx/dnd: SortableGrid requires columns in dimensions when orientation is vertical\",\n )\n }\n if (orientation === GridOrientation.Horizontal && !dimensions.rows) {\n throw new Error(\n \"react-native-gtkx/dnd: SortableGrid requires rows in dimensions when orientation is horizontal\",\n )\n }\n\n const { scope, order, setOrder, items } = useOrder(data, itemKeyExtractor)\n const isHorizontal = orientation === GridOrientation.Horizontal\n\n const containerRef = useRef<MeasureHandle | null>(null)\n const scrollViewRef = useRef<ScrollViewHandle | null>(null)\n\n const beforeDrag = useRef<string[] | null>(null)\n const orderRef = useRef(order)\n useEffect(() => {\n orderRef.current = order\n }, [order])\n\n const callbacks = useRef(new Map<string, GridItemCallbacks>())\n const registerCallbacks = useCallback(\n (id: string, cbs: GridItemCallbacks | null) => {\n if (cbs) {\n callbacks.current.set(id, cbs)\n } else {\n callbacks.current.delete(id)\n }\n },\n [],\n )\n\n const moveOnto = useCallback(\n (draggedId: string, targetId: string) => {\n setOrder((current) => {\n const positions = listToGridObject(current, dimensions, orientation)\n const activePosition = positions[draggedId]\n const targetPosition = positions[targetId]\n if (!activePosition || !targetPosition) {\n return current\n }\n const nextPositions =\n strategy === GridStrategy.Swap\n ? reorderGridSwap(\n positions,\n draggedId,\n targetId,\n dimensions,\n orientation,\n )\n : reorderGridInsert(\n positions,\n draggedId,\n targetPosition.index,\n dimensions,\n orientation,\n )\n const next = gridPositionsToOrder(nextPositions)\n if (\n next.length === current.length &&\n next.every((id, index) => id === current[index])\n ) {\n return current\n }\n callbacks.current\n .get(draggedId)\n ?.onMove?.(\n draggedId,\n activePosition.index,\n nextPositions[draggedId]!.index,\n )\n return next\n })\n },\n [setOrder, dimensions, orientation, strategy],\n )\n\n // The dragged cell's own tracked position — see `sortable.tsx`'s twin for\n // why this is a ref, and its `base` field's derivation.\n const tracking = useRef<{\n draggedId: string\n baseX: number\n baseY: number\n lastResolvedIndex: number\n } | null>(null)\n\n const handleDragMotion = useCallback(\n (x: number, y: number) => {\n const state = tracking.current\n if (!state) {\n return\n }\n const trackedX = x + state.baseX\n const trackedY = y + state.baseY\n const resolvedIndex = resolveTrackedGridIndex(\n trackedX,\n trackedY,\n dimensions,\n orientation,\n orderRef.current.length,\n )\n if (resolvedIndex === state.lastResolvedIndex) {\n return\n }\n state.lastResolvedIndex = resolvedIndex\n const targetId = orderRef.current[resolvedIndex]\n if (targetId !== undefined && targetId !== state.draggedId) {\n moveOnto(state.draggedId, targetId)\n }\n },\n [dimensions, orientation, moveOnto],\n )\n\n const autoscroll = useEdgeAutoscroll<GridScrollDirection>({\n containerRef,\n scrollViewRef,\n axes: \"both\",\n none: GridScrollDirection.None,\n directionFor: gridDirectionFor,\n onDragMotion: handleDragMotion,\n })\n\n const boxes = useGridSharedBoxes(\n order,\n dimensions,\n orientation,\n strategy,\n autoscroll.direction,\n )\n\n const beginDrag = useCallback(\n (\n draggedId: string,\n grabWidget: Gtk.Widget | null,\n grabX: number,\n grabY: number,\n ): number => {\n beforeDrag.current = orderRef.current\n autoscroll.setActive(true)\n const fromIndex = orderRef.current.indexOf(draggedId)\n\n tracking.current = null\n const container = widgetForHandle(containerRef.current)\n if (grabWidget && container && fromIndex !== -1) {\n const origin = computePointIn(grabWidget, container, grabX, grabY)\n if (origin) {\n // Unlike the plain list, a grid cell's size is not measured: it is\n // already a real, enforced Yoga size — `SortableGridItem` styles\n // every cell to exactly `dimensions.itemWidth`/`itemHeight`\n // (grid.tsx below), so the same numbers this component was\n // already handed are what the tracked position's slots use too.\n const rest = calculateGridPosition(fromIndex, dimensions, orientation)\n tracking.current = {\n draggedId,\n baseX: rest.x - origin.x,\n baseY: rest.y - origin.y,\n lastResolvedIndex: fromIndex,\n }\n }\n }\n return fromIndex\n },\n [autoscroll, dimensions, orientation],\n )\n\n const endDrag = useCallback(\n (\n draggedId: string,\n dropped: boolean,\n ): { index: number; positions: GridPositions } | null => {\n autoscroll.setActive(false)\n tracking.current = null\n const restore = beforeDrag.current\n beforeDrag.current = null\n if (!dropped) {\n if (restore) {\n setOrder(() => restore)\n }\n return null\n }\n const settled = orderRef.current\n const positions = listToGridObject(settled, dimensions, orientation)\n return { index: positions[draggedId]?.index ?? -1, positions }\n },\n [setOrder, dimensions, orientation, autoscroll],\n )\n\n const contextValue = useMemo<SortableGridContextValue>(\n () => ({ scope, registerCallbacks, moveOnto, beginDrag, endDrag }),\n [scope, registerCallbacks, moveOnto, beginDrag, endDrag],\n )\n\n const { width: crossAxisWidth } = calculateGridContentDimensions(\n order.length,\n dimensions,\n GridOrientation.Vertical,\n )\n const { height: crossAxisHeight } = calculateGridContentDimensions(\n order.length,\n dimensions,\n GridOrientation.Horizontal,\n )\n\n return (\n <SortableGridContext.Provider value={contextValue}>\n <View\n ref={containerRef}\n style={{ flex: 1 }}\n >\n {autoscroll.controllers}\n <ScrollView\n ref={scrollViewRef}\n horizontal={isHorizontal}\n style={style}\n contentContainerStyle={[\n isHorizontal\n ? {\n flexDirection: \"column\",\n flexWrap: \"wrap\",\n height: crossAxisHeight,\n columnGap: dimensions.columnGap,\n rowGap: dimensions.rowGap,\n }\n : {\n flexDirection: \"row\",\n flexWrap: \"wrap\",\n width: crossAxisWidth,\n columnGap: dimensions.columnGap,\n rowGap: dimensions.rowGap,\n },\n contentContainerStyle,\n ]}\n testID={testID}\n >\n {items.map((item, index) =>\n renderItem({\n item,\n index,\n id: keyOf(item, index, itemKeyExtractor),\n ...boxes.plumbing(),\n }),\n )}\n </ScrollView>\n </View>\n </SortableGridContext.Provider>\n )\n}\n\n/**\n * The reorder half of the module, as a hook, for a cell that owns its own\n * view.\n */\nexport const useGridSortable = <TData,>(\n options: UseGridSortableOptions<TData>,\n): UseGridSortableReturn => {\n const { id, onMove, onDragStart, onDrop, onDragging } = options\n const grid = useContext(SortableGridContext)\n if (grid === null) {\n throw new Error(\n \"react-native-gtkx/dnd: SortableGridItem/useGridSortable must be inside a SortableGrid\",\n )\n }\n const [isMoving, setIsMoving] = useState(false)\n const [hasHandle, setHasHandle] = useState(false)\n\n const registerHandle = useCallback((registered: boolean) => {\n setHasHandle(registered)\n }, [])\n\n useEffect(() => {\n grid.registerCallbacks(id, { onMove, onDragStart, onDrop })\n return () => grid.registerCallbacks(id, null)\n }, [grid, id, onMove, onDragStart, onDrop])\n\n const [mounted, setMounted] = useState(false)\n // eslint-disable-next-line react-hooks/set-state-in-effect\n useEffect(() => setMounted(true), [])\n\n // Same list only, including this cell itself — see sortable.tsx's\n // `useSortable` for why refusing a self-drop is wrong on this platform.\n const accepts = useCallback(\n (payload: DragPayload) => payload.scope === grid.scope,\n [grid],\n )\n\n // `DragSourceControllers`'s own grab point — see sortable.tsx's\n // `useSortable` for the same field and why it is captured here rather than\n // read from the first motion sample.\n const grab = useRef<{ widget: Gtk.Widget | null; x: number; y: number }>({\n widget: null,\n x: 0,\n y: 0,\n })\n\n const dragControllers = (\n <DragSourceControllers\n payload={{ scope: grid.scope, id }}\n onGrab={(x, y, widget) => {\n grab.current = { widget, x, y }\n }}\n onDragBegin={() => {\n setIsMoving(true)\n const position = grid.beginDrag(\n id,\n grab.current.widget,\n grab.current.x,\n grab.current.y,\n )\n onDragStart?.(id, position)\n }}\n onDragEnd={(dropped) => {\n setIsMoving(false)\n const result = grid.endDrag(id, dropped)\n if (result) {\n onDrop?.(id, result.index, result.positions)\n }\n }}\n />\n )\n\n const dropControllers = (\n <DropTargetControllers\n accepts={accepts}\n // No `onEnter` any more — the reorder decision is the grid's own\n // tracking (`handleDragMotion`), not this cell's drop target. This\n // target still has to exist and accept, or GDK would refuse the drop;\n // `onMotion` still reports the public `onDragging` callback.\n onMotion={(payload, x, y) => {\n onDragging?.(payload.id, id, x, y)\n }}\n onDrop={() => {}}\n />\n )\n\n return {\n animatedStyle: undefined,\n isMoving,\n hasHandle,\n registerHandle,\n dragControllers,\n children: (\n <>\n {mounted && !hasHandle ? dragControllers : null}\n {dropControllers}\n </>\n ),\n }\n}\n\n/** One cell of a {@link SortableGrid}. Both a drag source and a drop target:\n * the cell you drag onto is the position the dragged cell takes (or trades\n * with, under `GridStrategy.Swap`). */\nexport const SortableGridItem = <TData,>({\n id,\n data,\n dimensions,\n children,\n style,\n animatedStyle,\n testID,\n onMove,\n onDragStart,\n onDrop,\n onDragging,\n}: SortableGridItemProps<TData>): ReactNode => {\n const sortable = useGridSortable<TData>({\n id,\n data,\n onMove,\n onDragStart,\n onDrop,\n onDragging,\n } as UseGridSortableOptions<TData>)\n\n const handleContext = useMemo(\n () => ({\n source: sortable.dragControllers,\n registerHandle: sortable.registerHandle,\n }),\n [sortable.dragControllers, sortable.registerHandle],\n )\n\n const cellSize = dimensions\n ? { width: dimensions.itemWidth, height: dimensions.itemHeight }\n : undefined\n\n return (\n <View\n style={\n animatedStyle ? [cellSize, style, animatedStyle] : [cellSize, style]\n }\n testID={testID}\n >\n <DraggableContext.Provider value={handleContext}>\n {sortable.children}\n {children}\n </DraggableContext.Provider>\n </View>\n )\n}\n\nSortableGridItem.Handle = DraggableHandle\n"]}
@@ -1,10 +1,17 @@
1
1
  import { type ReactNode } from "react";
2
+ import { Gtk } from "../gtkx/bridge/index";
2
3
  import { type DragPayload } from "./payload";
3
4
  export type DragSourceControllersProps = {
4
5
  payload: DragPayload;
5
6
  /** Reports the grab point in the source widget's own coordinates, which is
6
- * where the drag icon's hotspot goes and where `tx`/`ty` start from. */
7
- onGrab?: (x: number, y: number) => void;
7
+ * where the drag icon's hotspot goes and where `tx`/`ty` start from. The
8
+ * widget itself rides along too `Sortable`/`SortableGrid` use it to
9
+ * convert this point into their own container's coordinates with
10
+ * `computePointIn` (see sortable.tsx/grid.tsx), the origin their reorder
11
+ * tracking measures every subsequent motion event against. `null` only
12
+ * when GDK could not resolve a widget for the drag source itself, which
13
+ * should not happen in practice. */
14
+ onGrab?: (x: number, y: number, widget: Gtk.Widget | null) => void;
8
15
  onDragBegin?: () => void;
9
16
  /** `dropped` is what GDK's own `drag-end` reports: whether a target took
10
17
  * it. `drag-cancel` reports the negative case separately, so both are
@@ -18,6 +25,13 @@ export type DragSourceControllersProps = {
18
25
  * inside it the drag began — so the thing appears to lift off under the
19
26
  * cursor rather than jump to it. That is the visual no JS drag can produce,
20
27
  * and the reason this module is built on GDK at all.
28
+ *
29
+ * A second, window-level copy of the same picture rides alongside it for as
30
+ * long as the drag stays over this window — `gtkx/bridge/drag-layer.ts` has
31
+ * the reason: `setIcon`'s own icon is a compositor surface, unclipped by any
32
+ * `overflow: hidden` ancestor but also outside this process's own widget
33
+ * tree, so nothing in it can prove that escape happened. The window-level
34
+ * copy is the same escape, provable.
21
35
  */
22
36
  export declare const DragSourceControllers: ({ payload, onGrab, onDragBegin, onDragEnd, }: DragSourceControllersProps) => ReactNode;
23
37
  export type DropTargetControllersProps = {
@@ -9,7 +9,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
9
9
  // (docs/platform-layer.md).
10
10
  import { useRef } from "react";
11
11
  import { Controllers } from "../gtk/controllers";
12
- import { Gdk, GObject, Gtk, GtkDragSource, GtkDropTarget, } from "../gtkx/bridge/index";
12
+ import { beginDragLayer, Gdk, GObject, Gtk, GtkDragSource, GtkDropTarget, } from "../gtkx/bridge/index";
13
13
  import { decodePayload, encodePayload } from "./payload";
14
14
  /**
15
15
  * A `GtkDragSource` on the enclosing React Native component's widget.
@@ -18,28 +18,48 @@ import { decodePayload, encodePayload } from "./payload";
18
18
  * inside it the drag began — so the thing appears to lift off under the
19
19
  * cursor rather than jump to it. That is the visual no JS drag can produce,
20
20
  * and the reason this module is built on GDK at all.
21
+ *
22
+ * A second, window-level copy of the same picture rides alongside it for as
23
+ * long as the drag stays over this window — `gtkx/bridge/drag-layer.ts` has
24
+ * the reason: `setIcon`'s own icon is a compositor surface, unclipped by any
25
+ * `overflow: hidden` ancestor but also outside this process's own widget
26
+ * tree, so nothing in it can prove that escape happened. The window-level
27
+ * copy is the same escape, provable.
21
28
  */
22
29
  export const DragSourceControllers = ({ payload, onGrab, onDragBegin, onDragEnd, }) => {
23
30
  // GDK emits `drag-cancel` AND then `drag-end` for a refused drop, so the
24
31
  // cancel is recorded and read by the end handler rather than reported
25
32
  // twice.
26
33
  const cancelled = useRef(false);
34
+ // Set in `onPrepare`, consumed in `onDragBegin` — the window-level layer
35
+ // only starts once GDK confirms the drag is really happening, but the
36
+ // widget and grab point it needs are only ever handed to `onPrepare`.
37
+ const grab = useRef(null);
38
+ const dragLayer = useRef(null);
27
39
  return (_jsx(Controllers, { children: _jsx(GtkDragSource, { actions: Gdk.DragAction.MOVE, onPrepare: (x, y, self) => {
28
40
  const widget = self.getWidget();
29
41
  if (widget) {
30
42
  self.setIcon(Gtk.WidgetPaintable.new(widget), Math.round(x), Math.round(y));
43
+ grab.current = { widget, x, y };
31
44
  }
32
- onGrab?.(x, y);
45
+ onGrab?.(x, y, widget);
33
46
  return Gdk.ContentProvider.newForValue(GObject.buildValue(GObject.TYPE_STRING, (value) => value.setString(encodePayload(payload))));
34
47
  }, onDragBegin: () => {
35
48
  cancelled.current = false;
49
+ if (grab.current) {
50
+ dragLayer.current = beginDragLayer(grab.current.widget, grab.current.x, grab.current.y);
51
+ }
36
52
  onDragBegin?.();
37
53
  }, onDragCancel: () => {
38
54
  cancelled.current = true;
39
55
  // false: let GTK play its own "snap back" animation, which is the
40
56
  // platform's way of saying the drop was refused.
41
57
  return false;
42
- }, onDragEnd: () => onDragEnd?.(!cancelled.current) }) }));
58
+ }, onDragEnd: () => {
59
+ dragLayer.current?.end();
60
+ dragLayer.current = null;
61
+ onDragEnd?.(!cancelled.current);
62
+ } }) }));
43
63
  };
44
64
  /**
45
65
  * A `GtkDropTarget` on the enclosing React Native component's widget,
@@ -1 +1 @@
1
- {"version":3,"file":"gtk-controllers.js","sourceRoot":"","sources":["../../src/dnd/gtk-controllers.tsx"],"names":[],"mappings":"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","sourcesContent":["// The two GTK controllers everything in this module is built from, wrapped\n// once so `Draggable`, `Droppable` and `SortableItem` do not each re-derive\n// the drag-icon and payload details.\n//\n// Both go through `Controllers` from react-native-gtkx/gtk — the same public\n// door an app would use. Nothing here is reachable only from inside the\n// platform, which is the property `List`/`ListRow` already established\n// (docs/platform-layer.md).\nimport { useRef, type ReactNode } from \"react\"\nimport { Controllers } from \"../gtk/controllers\"\nimport {\n Gdk,\n GObject,\n Gtk,\n GtkDragSource,\n GtkDropTarget,\n} from \"../gtkx/bridge/index\"\nimport { decodePayload, encodePayload, type DragPayload } from \"./payload\"\n\nexport type DragSourceControllersProps = {\n payload: DragPayload\n /** Reports the grab point in the source widget's own coordinates, which is\n * where the drag icon's hotspot goes and where `tx`/`ty` start from. */\n onGrab?: (x: number, y: number) => void\n onDragBegin?: () => void\n /** `dropped` is what GDK's own `drag-end` reports: whether a target took\n * it. `drag-cancel` reports the negative case separately, so both are\n * folded into one callback here. */\n onDragEnd?: (dropped: boolean) => void\n}\n\n/**\n * A `GtkDragSource` on the enclosing React Native component's widget.\n *\n * The drag icon is a `Gtk.WidgetPaintable` of that widget, offset by where\n * inside it the drag began — so the thing appears to lift off under the\n * cursor rather than jump to it. That is the visual no JS drag can produce,\n * and the reason this module is built on GDK at all.\n */\nexport const DragSourceControllers = ({\n payload,\n onGrab,\n onDragBegin,\n onDragEnd,\n}: DragSourceControllersProps): ReactNode => {\n // GDK emits `drag-cancel` AND then `drag-end` for a refused drop, so the\n // cancel is recorded and read by the end handler rather than reported\n // twice.\n const cancelled = useRef(false)\n\n return (\n <Controllers>\n <GtkDragSource\n actions={Gdk.DragAction.MOVE}\n onPrepare={(x, y, self) => {\n const widget = self.getWidget()\n if (widget) {\n self.setIcon(\n Gtk.WidgetPaintable.new(widget),\n Math.round(x),\n Math.round(y),\n )\n }\n onGrab?.(x, y)\n return Gdk.ContentProvider.newForValue(\n GObject.buildValue(GObject.TYPE_STRING, (value) =>\n value.setString(encodePayload(payload)),\n ),\n )\n }}\n onDragBegin={() => {\n cancelled.current = false\n onDragBegin?.()\n }}\n onDragCancel={() => {\n cancelled.current = true\n // false: let GTK play its own \"snap back\" animation, which is the\n // platform's way of saying the drop was refused.\n return false\n }}\n onDragEnd={() => onDragEnd?.(!cancelled.current)}\n />\n </Controllers>\n )\n}\n\nexport type DropTargetControllersProps = {\n /** Return false to refuse — GDK then shows the no-drop cursor, which is\n * better feedback than upstream's silent skip. */\n accepts: (payload: DragPayload) => boolean\n onDrop: (payload: DragPayload, x: number, y: number) => void\n onEnter?: (payload: DragPayload) => void\n onMotion?: (payload: DragPayload, x: number, y: number) => void\n onLeave?: () => void\n}\n\n/**\n * A `GtkDropTarget` on the enclosing React Native component's widget,\n * accepting the string payload this module encodes.\n *\n * The payload is decoded before `accepts` is consulted, so a string dragged\n * in from a text editor is refused rather than mistaken for a draggable.\n */\nexport const DropTargetControllers = ({\n accepts,\n onDrop,\n onEnter,\n onMotion,\n onLeave,\n}: DropTargetControllersProps): ReactNode => {\n // The payload of the drag currently overhead, sampled on `::enter` and kept\n // for `::motion` (which is not handed the target).\n const hovering = useRef<DragPayload | null>(null)\n\n return (\n <Controllers>\n <GtkDropTarget\n actions={Gdk.DragAction.MOVE}\n types={[GObject.TYPE_STRING]}\n // Without this `gtk_drop_target_get_value()` returns NULL until the\n // drop itself, so `::enter` could not tell one drag from another and\n // every zone would light up for every payload. Preloading is exactly\n // the property GTK provides for reading the data during the drag; the\n // cost it warns about (fetching data from another process on hover)\n // does not apply, because the payload is a short string this process\n // wrote.\n preload\n onEnter={(_x, _y, self) => {\n const payload = payloadOf(self)\n hovering.current = payload\n // A payload that is not readable yet is NOT refused: refusing in\n // `::enter` ends the drag for this target permanently, while\n // accepting and re-checking at drop time is recoverable. Only a\n // payload we can read AND reject is turned away.\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onEnter?.(payload)\n }\n return Gdk.DragAction.MOVE\n }}\n onMotion={(x, y) => {\n const payload = hovering.current\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onMotion?.(payload, x, y)\n }\n return Gdk.DragAction.MOVE\n }}\n onLeave={() => {\n hovering.current = null\n onLeave?.()\n }}\n onDrop={(value, x, y) => {\n hovering.current = null\n const payload = decodePayload(value.getString())\n if (!payload || !accepts(payload)) {\n return false\n }\n onDrop(payload, x, y)\n return true\n }}\n />\n </Controllers>\n )\n}\n\n/**\n * The payload of the drag currently over a drop target, readable during the\n * drag because the target above sets `preload`.\n */\nconst payloadOf = (target: Gtk.DropTarget): DragPayload | null => {\n const value = target.getValue()\n if (!value) {\n return null\n }\n return decodePayload(value.getString())\n}\n"]}
1
+ {"version":3,"file":"gtk-controllers.js","sourceRoot":"","sources":["../../src/dnd/gtk-controllers.tsx"],"names":[],"mappings":"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","sourcesContent":["// The two GTK controllers everything in this module is built from, wrapped\n// once so `Draggable`, `Droppable` and `SortableItem` do not each re-derive\n// the drag-icon and payload details.\n//\n// Both go through `Controllers` from react-native-gtkx/gtk — the same public\n// door an app would use. Nothing here is reachable only from inside the\n// platform, which is the property `List`/`ListRow` already established\n// (docs/platform-layer.md).\nimport { useRef, type ReactNode } from \"react\"\nimport { Controllers } from \"../gtk/controllers\"\nimport {\n beginDragLayer,\n Gdk,\n GObject,\n Gtk,\n GtkDragSource,\n GtkDropTarget,\n type DragLayerHandle,\n} from \"../gtkx/bridge/index\"\nimport { decodePayload, encodePayload, type DragPayload } from \"./payload\"\n\nexport type DragSourceControllersProps = {\n payload: DragPayload\n /** Reports the grab point in the source widget's own coordinates, which is\n * where the drag icon's hotspot goes and where `tx`/`ty` start from. The\n * widget itself rides along too — `Sortable`/`SortableGrid` use it to\n * convert this point into their own container's coordinates with\n * `computePointIn` (see sortable.tsx/grid.tsx), the origin their reorder\n * tracking measures every subsequent motion event against. `null` only\n * when GDK could not resolve a widget for the drag source itself, which\n * should not happen in practice. */\n onGrab?: (x: number, y: number, widget: Gtk.Widget | null) => void\n onDragBegin?: () => void\n /** `dropped` is what GDK's own `drag-end` reports: whether a target took\n * it. `drag-cancel` reports the negative case separately, so both are\n * folded into one callback here. */\n onDragEnd?: (dropped: boolean) => void\n}\n\n/**\n * A `GtkDragSource` on the enclosing React Native component's widget.\n *\n * The drag icon is a `Gtk.WidgetPaintable` of that widget, offset by where\n * inside it the drag began — so the thing appears to lift off under the\n * cursor rather than jump to it. That is the visual no JS drag can produce,\n * and the reason this module is built on GDK at all.\n *\n * A second, window-level copy of the same picture rides alongside it for as\n * long as the drag stays over this window — `gtkx/bridge/drag-layer.ts` has\n * the reason: `setIcon`'s own icon is a compositor surface, unclipped by any\n * `overflow: hidden` ancestor but also outside this process's own widget\n * tree, so nothing in it can prove that escape happened. The window-level\n * copy is the same escape, provable.\n */\nexport const DragSourceControllers = ({\n payload,\n onGrab,\n onDragBegin,\n onDragEnd,\n}: DragSourceControllersProps): ReactNode => {\n // GDK emits `drag-cancel` AND then `drag-end` for a refused drop, so the\n // cancel is recorded and read by the end handler rather than reported\n // twice.\n const cancelled = useRef(false)\n // Set in `onPrepare`, consumed in `onDragBegin` — the window-level layer\n // only starts once GDK confirms the drag is really happening, but the\n // widget and grab point it needs are only ever handed to `onPrepare`.\n const grab = useRef<{ widget: Gtk.Widget; x: number; y: number } | null>(null)\n const dragLayer = useRef<DragLayerHandle | null>(null)\n\n return (\n <Controllers>\n <GtkDragSource\n actions={Gdk.DragAction.MOVE}\n onPrepare={(x, y, self) => {\n const widget = self.getWidget()\n if (widget) {\n self.setIcon(\n Gtk.WidgetPaintable.new(widget),\n Math.round(x),\n Math.round(y),\n )\n grab.current = { widget, x, y }\n }\n onGrab?.(x, y, widget)\n return Gdk.ContentProvider.newForValue(\n GObject.buildValue(GObject.TYPE_STRING, (value) =>\n value.setString(encodePayload(payload)),\n ),\n )\n }}\n onDragBegin={() => {\n cancelled.current = false\n if (grab.current) {\n dragLayer.current = beginDragLayer(\n grab.current.widget,\n grab.current.x,\n grab.current.y,\n )\n }\n onDragBegin?.()\n }}\n onDragCancel={() => {\n cancelled.current = true\n // false: let GTK play its own \"snap back\" animation, which is the\n // platform's way of saying the drop was refused.\n return false\n }}\n onDragEnd={() => {\n dragLayer.current?.end()\n dragLayer.current = null\n onDragEnd?.(!cancelled.current)\n }}\n />\n </Controllers>\n )\n}\n\nexport type DropTargetControllersProps = {\n /** Return false to refuse — GDK then shows the no-drop cursor, which is\n * better feedback than upstream's silent skip. */\n accepts: (payload: DragPayload) => boolean\n onDrop: (payload: DragPayload, x: number, y: number) => void\n onEnter?: (payload: DragPayload) => void\n onMotion?: (payload: DragPayload, x: number, y: number) => void\n onLeave?: () => void\n}\n\n/**\n * A `GtkDropTarget` on the enclosing React Native component's widget,\n * accepting the string payload this module encodes.\n *\n * The payload is decoded before `accepts` is consulted, so a string dragged\n * in from a text editor is refused rather than mistaken for a draggable.\n */\nexport const DropTargetControllers = ({\n accepts,\n onDrop,\n onEnter,\n onMotion,\n onLeave,\n}: DropTargetControllersProps): ReactNode => {\n // The payload of the drag currently overhead, sampled on `::enter` and kept\n // for `::motion` (which is not handed the target).\n const hovering = useRef<DragPayload | null>(null)\n\n return (\n <Controllers>\n <GtkDropTarget\n actions={Gdk.DragAction.MOVE}\n types={[GObject.TYPE_STRING]}\n // Without this `gtk_drop_target_get_value()` returns NULL until the\n // drop itself, so `::enter` could not tell one drag from another and\n // every zone would light up for every payload. Preloading is exactly\n // the property GTK provides for reading the data during the drag; the\n // cost it warns about (fetching data from another process on hover)\n // does not apply, because the payload is a short string this process\n // wrote.\n preload\n onEnter={(_x, _y, self) => {\n const payload = payloadOf(self)\n hovering.current = payload\n // A payload that is not readable yet is NOT refused: refusing in\n // `::enter` ends the drag for this target permanently, while\n // accepting and re-checking at drop time is recoverable. Only a\n // payload we can read AND reject is turned away.\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onEnter?.(payload)\n }\n return Gdk.DragAction.MOVE\n }}\n onMotion={(x, y) => {\n const payload = hovering.current\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onMotion?.(payload, x, y)\n }\n return Gdk.DragAction.MOVE\n }}\n onLeave={() => {\n hovering.current = null\n onLeave?.()\n }}\n onDrop={(value, x, y) => {\n hovering.current = null\n const payload = decodePayload(value.getString())\n if (!payload || !accepts(payload)) {\n return false\n }\n onDrop(payload, x, y)\n return true\n }}\n />\n </Controllers>\n )\n}\n\n/**\n * The payload of the drag currently over a drop target, readable during the\n * drag because the target above sets `preload`.\n */\nconst payloadOf = (target: Gtk.DropTarget): DragPayload | null => {\n const value = target.getValue()\n if (!value) {\n return null\n }\n return decodePayload(value.getString())\n}\n"]}
@@ -2,5 +2,7 @@ export { DropProvider, useDropContext } from "./context";
2
2
  export { Draggable, DraggableHandle, useDraggable, type UseDraggableResult, } from "./draggable";
3
3
  export { Droppable, useDroppable } from "./droppable";
4
4
  export { clamp, listToObject, objectMove } from "./order";
5
- export { Sortable, SortableItem, useSortable, useSortableList, } from "./sortable";
6
- export { DraggableState, HorizontalScrollDirection, ScrollDirection, SortableDirection, type AnimationFunction, type CollisionAlgorithm, type DraggableHandleProps, type DraggableProps, type DropAlignment, type DroppableProps, type DroppedItemsMap, type DropOffset, type DropProviderProps, type DropProviderRef, type SharedValueLike, type SortableData, type SortableHandleProps, type SortableItemProps, type SortableProps, type SortableRenderItemProps, type UseDraggableOptions, type UseDraggableReturn, type UseDroppableOptions, type UseDroppableReturn, type UseSortableListOptions, type UseSortableListReturn, type UseSortableOptions, type UseSortableReturn, } from "./types";
5
+ export { Sortable, SortableItem, useHorizontalSortable, useHorizontalSortableList, useSortable, useSortableList, } from "./sortable";
6
+ export { SortableGrid, SortableGridItem, useGridSortable, useGridSortableList, } from "./grid";
7
+ export { calculateGridContentDimensions, calculateGridPosition, calculateIndexFromRowColumn, findItemIdAtIndex, getGridCellFromCoordinates, listToGridObject, reorderGridInsert, reorderGridSwap, } from "./grid-order";
8
+ export { DraggableState, GridOrientation, GridScrollDirection, GridStrategy, HorizontalScrollDirection, ScrollDirection, SortableDirection, type AnimationFunction, type CollisionAlgorithm, type DraggableHandleProps, type DraggableProps, type DropAlignment, type DroppableProps, type DroppedItemsMap, type DropOffset, type DropProviderProps, type DropProviderRef, type GridCallbacks, type GridDimensions, type GridItemPlumbing, type GridPosition, type GridPositions, type SharedValueLike, type SortableData, type SortableGridItemProps, type SortableGridProps, type SortableGridRenderItemProps, type SortableHandleProps, type SortableItemProps, type SortableProps, type SortableRenderItemProps, type UseDraggableOptions, type UseDraggableReturn, type UseDroppableOptions, type UseDroppableReturn, type UseGridSortableListOptions, type UseGridSortableListReturn, type UseGridSortableOptions, type UseGridSortableReturn, type UseHorizontalSortableListOptions, type UseHorizontalSortableListReturn, type UseHorizontalSortableOptions, type UseHorizontalSortableReturn, type UseSortableListOptions, type UseSortableListReturn, type UseSortableOptions, type UseSortableReturn, } from "./types";