react-native-drax 0.11.0-alpha.2 → 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/LICENSE.md +1 -1
- package/README.md +385 -227
- package/lib/module/DebugOverlay.js +121 -0
- package/lib/module/DebugOverlay.js.map +1 -0
- package/lib/module/Drax.js +36 -0
- package/lib/module/Drax.js.map +1 -0
- package/lib/module/DraxContext.js +6 -0
- package/lib/module/DraxContext.js.map +1 -0
- package/lib/module/DraxHandle.js +47 -0
- package/lib/module/DraxHandle.js.map +1 -0
- package/lib/module/DraxHandleContext.js +11 -0
- package/lib/module/DraxHandleContext.js.map +1 -0
- package/lib/module/DraxList.js +108 -0
- package/lib/module/DraxList.js.map +1 -0
- package/lib/module/DraxProvider.js +203 -0
- package/lib/module/DraxProvider.js.map +1 -0
- package/lib/module/DraxScrollView.js +167 -0
- package/lib/module/DraxScrollView.js.map +1 -0
- package/lib/module/DraxSubprovider.js +21 -0
- package/lib/module/DraxSubprovider.js.map +1 -0
- package/lib/module/DraxView.js +348 -0
- package/lib/module/DraxView.js.map +1 -0
- package/lib/module/HoverLayer.js +152 -0
- package/lib/module/HoverLayer.js.map +1 -0
- package/lib/module/SortableBoardContainer.js +386 -0
- package/lib/module/SortableBoardContainer.js.map +1 -0
- package/lib/module/SortableBoardContext.js +6 -0
- package/lib/module/SortableBoardContext.js.map +1 -0
- package/lib/module/SortableContainer.js +561 -0
- package/lib/module/SortableContainer.js.map +1 -0
- package/lib/module/SortableItem.js +226 -0
- package/lib/module/SortableItem.js.map +1 -0
- package/lib/module/SortableItemContext.js +38 -0
- package/lib/module/SortableItemContext.js.map +1 -0
- package/lib/module/compat/detectVersion.js +19 -0
- package/lib/module/compat/detectVersion.js.map +1 -0
- package/lib/module/compat/index.js +5 -0
- package/lib/module/compat/index.js.map +1 -0
- package/lib/module/compat/types.js +4 -0
- package/lib/module/compat/types.js.map +1 -0
- package/lib/module/compat/useDraxPanGesture.js +94 -0
- package/lib/module/compat/useDraxPanGesture.js.map +1 -0
- package/lib/module/hooks/index.js +5 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/useCallbackDispatch.js +681 -0
- package/lib/module/hooks/useCallbackDispatch.js.map +1 -0
- package/lib/module/hooks/useDragGesture.js +240 -0
- package/lib/module/hooks/useDragGesture.js.map +1 -0
- package/lib/module/hooks/useDraxContext.js +12 -0
- package/lib/module/hooks/useDraxContext.js.map +1 -0
- package/lib/module/hooks/useDraxId.js +13 -0
- package/lib/module/hooks/useDraxId.js.map +1 -0
- package/lib/module/hooks/useDraxMethods.js +73 -0
- package/lib/module/hooks/useDraxMethods.js.map +1 -0
- package/lib/module/hooks/useDraxScrollHandler.js +97 -0
- package/lib/module/hooks/useDraxScrollHandler.js.map +1 -0
- package/lib/module/hooks/useSortableBoard.js +37 -0
- package/lib/module/hooks/useSortableBoard.js.map +1 -0
- package/lib/module/hooks/useSortableList.js +824 -0
- package/lib/module/hooks/useSortableList.js.map +1 -0
- package/lib/module/hooks/useSpatialIndex.js +283 -0
- package/lib/module/hooks/useSpatialIndex.js.map +1 -0
- package/lib/module/hooks/useViewStyles.js +158 -0
- package/lib/module/hooks/useViewStyles.js.map +1 -0
- package/lib/module/hooks/useWebScrollFreeze.js +52 -0
- package/lib/module/hooks/useWebScrollFreeze.js.map +1 -0
- package/lib/module/index.js +37 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/math.js +222 -0
- package/lib/module/math.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/params.js +88 -0
- package/lib/module/params.js.map +1 -0
- package/lib/module/types.js +213 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/DebugOverlay.d.ts +17 -0
- package/lib/typescript/src/DebugOverlay.d.ts.map +1 -0
- package/lib/typescript/src/Drax.d.ts +28 -0
- package/lib/typescript/src/Drax.d.ts.map +1 -0
- package/lib/typescript/src/DraxContext.d.ts +3 -0
- package/lib/typescript/src/DraxContext.d.ts.map +1 -0
- package/lib/typescript/src/DraxHandle.d.ts +25 -0
- package/lib/typescript/src/DraxHandle.d.ts.map +1 -0
- package/lib/typescript/src/DraxHandleContext.d.ts +12 -0
- package/lib/typescript/src/DraxHandleContext.d.ts.map +1 -0
- package/lib/typescript/src/DraxList.d.ts +66 -0
- package/lib/typescript/src/DraxList.d.ts.map +1 -0
- package/lib/typescript/src/DraxProvider.d.ts +4 -0
- package/lib/typescript/src/DraxProvider.d.ts.map +1 -0
- package/lib/typescript/src/DraxScrollView.d.ts +7 -0
- package/lib/typescript/src/DraxScrollView.d.ts.map +1 -0
- package/lib/typescript/src/DraxSubprovider.d.ts +4 -0
- package/lib/typescript/src/DraxSubprovider.d.ts.map +1 -0
- package/lib/typescript/src/DraxView.d.ts +4 -0
- package/lib/typescript/src/DraxView.d.ts.map +1 -0
- package/lib/typescript/src/HoverLayer.d.ts +38 -0
- package/lib/typescript/src/HoverLayer.d.ts.map +1 -0
- package/lib/typescript/src/SortableBoardContainer.d.ts +11 -0
- package/lib/typescript/src/SortableBoardContainer.d.ts.map +1 -0
- package/lib/typescript/src/SortableBoardContext.d.ts +4 -0
- package/lib/typescript/src/SortableBoardContext.d.ts.map +1 -0
- package/lib/typescript/src/SortableContainer.d.ts +13 -0
- package/lib/typescript/src/SortableContainer.d.ts.map +1 -0
- package/lib/typescript/src/SortableItem.d.ts +14 -0
- package/lib/typescript/src/SortableItem.d.ts.map +1 -0
- package/lib/typescript/src/SortableItemContext.d.ts +37 -0
- package/lib/typescript/src/SortableItemContext.d.ts.map +1 -0
- package/lib/typescript/src/compat/detectVersion.d.ts +2 -0
- package/lib/typescript/src/compat/detectVersion.d.ts.map +1 -0
- package/lib/typescript/src/compat/index.d.ts +4 -0
- package/lib/typescript/src/compat/index.d.ts.map +1 -0
- package/lib/typescript/src/compat/types.d.ts +33 -0
- package/lib/typescript/src/compat/types.d.ts.map +1 -0
- package/lib/typescript/src/compat/useDraxPanGesture.d.ts +8 -0
- package/lib/typescript/src/compat/useDraxPanGesture.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +3 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useCallbackDispatch.d.ts +40 -0
- package/lib/typescript/src/hooks/useCallbackDispatch.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useDragGesture.d.ts +17 -0
- package/lib/typescript/src/hooks/useDragGesture.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useDraxContext.d.ts +2 -0
- package/lib/typescript/src/hooks/useDraxContext.d.ts.map +1 -0
- package/{build → lib/typescript/src}/hooks/useDraxId.d.ts +1 -0
- package/lib/typescript/src/hooks/useDraxId.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useDraxMethods.d.ts +13 -0
- package/lib/typescript/src/hooks/useDraxMethods.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useDraxScrollHandler.d.ts +27 -0
- package/lib/typescript/src/hooks/useDraxScrollHandler.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useSortableBoard.d.ts +10 -0
- package/lib/typescript/src/hooks/useSortableBoard.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useSortableList.d.ts +11 -0
- package/lib/typescript/src/hooks/useSortableList.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useSpatialIndex.d.ts +22 -0
- package/lib/typescript/src/hooks/useSpatialIndex.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useViewStyles.d.ts +183 -0
- package/lib/typescript/src/hooks/useViewStyles.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useWebScrollFreeze.d.ts +14 -0
- package/lib/typescript/src/hooks/useWebScrollFreeze.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +25 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/math.d.ts +52 -0
- package/lib/typescript/src/math.d.ts.map +1 -0
- package/{build → lib/typescript/src}/params.d.ts +13 -9
- package/lib/typescript/src/params.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +743 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +164 -34
- package/src/DebugOverlay.tsx +140 -0
- package/src/Drax.ts +33 -0
- package/src/DraxContext.ts +8 -0
- package/src/DraxHandle.tsx +52 -0
- package/src/DraxHandleContext.ts +15 -0
- package/src/DraxList.tsx +181 -0
- package/src/DraxProvider.tsx +224 -0
- package/src/DraxScrollView.tsx +180 -0
- package/src/DraxSubprovider.tsx +22 -0
- package/src/DraxView.tsx +430 -0
- package/src/HoverLayer.tsx +167 -0
- package/src/SortableBoardContainer.tsx +439 -0
- package/src/SortableBoardContext.ts +6 -0
- package/src/SortableContainer.tsx +642 -0
- package/src/SortableItem.tsx +264 -0
- package/src/SortableItemContext.ts +46 -0
- package/src/compat/detectVersion.ts +17 -0
- package/src/compat/index.ts +7 -0
- package/src/compat/types.ts +35 -0
- package/src/compat/useDraxPanGesture.ts +112 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useCallbackDispatch.tsx +823 -0
- package/src/hooks/useDragGesture.ts +273 -0
- package/src/hooks/useDraxContext.ts +11 -0
- package/src/hooks/useDraxId.ts +11 -0
- package/src/hooks/useDraxMethods.ts +71 -0
- package/src/hooks/useDraxScrollHandler.ts +121 -0
- package/src/hooks/useSortableBoard.ts +44 -0
- package/src/hooks/useSortableList.ts +868 -0
- package/src/hooks/useSpatialIndex.ts +336 -0
- package/src/hooks/useViewStyles.ts +180 -0
- package/src/hooks/useWebScrollFreeze.ts +60 -0
- package/src/index.ts +110 -0
- package/src/math.ts +251 -0
- package/src/params.ts +74 -0
- package/src/types.ts +919 -0
- package/.editorconfig +0 -15
- package/.eslintrc.js +0 -4
- package/.prettierrc +0 -16
- package/CHANGELOG.md +0 -270
- package/CODE-OF-CONDUCT.md +0 -85
- package/CONTRIBUTING.md +0 -15
- package/FUNDING.yml +0 -4
- package/build/AllHoverViews.d.ts +0 -0
- package/build/AllHoverViews.js +0 -30
- package/build/DraxContext.d.ts +0 -2
- package/build/DraxContext.js +0 -6
- package/build/DraxList.d.ts +0 -8
- package/build/DraxList.js +0 -512
- package/build/DraxListItem.d.ts +0 -7
- package/build/DraxListItem.js +0 -121
- package/build/DraxProvider.d.ts +0 -2
- package/build/DraxProvider.js +0 -704
- package/build/DraxScrollView.d.ts +0 -6
- package/build/DraxScrollView.js +0 -136
- package/build/DraxSubprovider.d.ts +0 -3
- package/build/DraxSubprovider.js +0 -18
- package/build/DraxView.d.ts +0 -8
- package/build/DraxView.js +0 -93
- package/build/HoverView.d.ts +0 -8
- package/build/HoverView.js +0 -40
- package/build/PanGestureDetector.d.ts +0 -3
- package/build/PanGestureDetector.js +0 -49
- package/build/hooks/index.d.ts +0 -4
- package/build/hooks/index.js +0 -11
- package/build/hooks/useContent.d.ts +0 -23
- package/build/hooks/useContent.js +0 -212
- package/build/hooks/useDraxContext.d.ts +0 -1
- package/build/hooks/useDraxContext.js +0 -13
- package/build/hooks/useDraxId.js +0 -13
- package/build/hooks/useDraxProtocol.d.ts +0 -5
- package/build/hooks/useDraxProtocol.js +0 -32
- package/build/hooks/useDraxRegistry.d.ts +0 -78
- package/build/hooks/useDraxRegistry.js +0 -714
- package/build/hooks/useDraxScrollHandler.d.ts +0 -25
- package/build/hooks/useDraxScrollHandler.js +0 -89
- package/build/hooks/useDraxState.d.ts +0 -10
- package/build/hooks/useDraxState.js +0 -132
- package/build/hooks/useMeasurements.d.ts +0 -9
- package/build/hooks/useMeasurements.js +0 -119
- package/build/hooks/useStatus.d.ts +0 -11
- package/build/hooks/useStatus.js +0 -96
- package/build/index.d.ts +0 -9
- package/build/index.js +0 -33
- package/build/math.d.ts +0 -22
- package/build/math.js +0 -68
- package/build/params.js +0 -27
- package/build/transform.d.ts +0 -11
- package/build/transform.js +0 -59
- package/build/types.d.ts +0 -807
- package/build/types.js +0 -46
- package/docs/concept.md +0 -79
- package/docs/images/color-drag-drop.gif +0 -0
- package/docs/images/deck-cards.gif +0 -0
- package/docs/images/drag-drop-events.jpg +0 -0
- package/docs/images/knight-moves.gif +0 -0
- package/docs/images/reorderable-list.gif +0 -0
package/src/math.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DraxViewMeasurements,
|
|
3
|
+
HitTestResult,
|
|
4
|
+
Position,
|
|
5
|
+
SpatialEntry,
|
|
6
|
+
ViewDimensions,
|
|
7
|
+
} from './types';
|
|
8
|
+
|
|
9
|
+
export const getRelativePosition = (
|
|
10
|
+
{ x, y }: Position,
|
|
11
|
+
{ width, height, x: x0, y: y0 }: DraxViewMeasurements
|
|
12
|
+
) => {
|
|
13
|
+
'worklet';
|
|
14
|
+
const rx = x - x0;
|
|
15
|
+
const ry = y - y0;
|
|
16
|
+
return {
|
|
17
|
+
relativePosition: { x: rx, y: ry },
|
|
18
|
+
// Guard against division by zero for zero-dimension views
|
|
19
|
+
relativePositionRatio: { x: rx / (width || 1), y: ry / (height || 1) },
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const generateRandomId = () =>
|
|
24
|
+
`${Math.random().toString(36).substring(2)}${Math.random().toString(36).substring(2)}`;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Compute the absolute position of a spatial entry by walking the parent chain.
|
|
28
|
+
* Accounts for scroll offsets at each level.
|
|
29
|
+
*/
|
|
30
|
+
export const computeAbsolutePositionWorklet = (
|
|
31
|
+
entryIndex: number,
|
|
32
|
+
entries: SpatialEntry[],
|
|
33
|
+
scrollOffsets: Position[]
|
|
34
|
+
): Position => {
|
|
35
|
+
'worklet';
|
|
36
|
+
const entry = entries[entryIndex];
|
|
37
|
+
if (!entry) return { x: 0, y: 0 };
|
|
38
|
+
|
|
39
|
+
let absX = entry.x;
|
|
40
|
+
let absY = entry.y;
|
|
41
|
+
let parentIdx = entry.parentIndex;
|
|
42
|
+
|
|
43
|
+
while (parentIdx >= 0) {
|
|
44
|
+
const parent = entries[parentIdx];
|
|
45
|
+
if (!parent) break;
|
|
46
|
+
const parentScroll = scrollOffsets[parentIdx] || { x: 0, y: 0 };
|
|
47
|
+
absX += parent.x - parentScroll.x;
|
|
48
|
+
absY += parent.y - parentScroll.y;
|
|
49
|
+
parentIdx = parent.parentIndex;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { x: absX, y: absY };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Extra padding (in points) applied to monitoring views during hit-testing.
|
|
57
|
+
* During auto-scroll the hover center can drift outside the container's visible
|
|
58
|
+
* bounds. This padding prevents false monitor exits that would prematurely end
|
|
59
|
+
* the drag. Receptive views keep exact bounds for precise drop targeting.
|
|
60
|
+
*/
|
|
61
|
+
const MONITOR_HIT_TEST_PADDING = 100;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Hit-test all views in the spatial index against a given absolute position.
|
|
65
|
+
* Runs entirely on the UI thread as a worklet.
|
|
66
|
+
* Returns the deepest receptive view and all monitoring views that contain the point.
|
|
67
|
+
*
|
|
68
|
+
* @param position - Center of the hover view (absolute)
|
|
69
|
+
* @param entries - Spatial index entries
|
|
70
|
+
* @param scrollOffsets - Scroll offsets per entry
|
|
71
|
+
* @param excludeId - ID of the dragged view (excluded from hit-testing)
|
|
72
|
+
* @param draggedDimensions - Optional dimensions of the dragged view (needed for intersect/contain)
|
|
73
|
+
*/
|
|
74
|
+
export const hitTestWorklet = (
|
|
75
|
+
position: Position,
|
|
76
|
+
entries: SpatialEntry[],
|
|
77
|
+
scrollOffsets: Position[],
|
|
78
|
+
excludeId: string,
|
|
79
|
+
draggedDimensions?: ViewDimensions
|
|
80
|
+
): HitTestResult => {
|
|
81
|
+
'worklet';
|
|
82
|
+
|
|
83
|
+
let receiverId = '';
|
|
84
|
+
const monitorIds: string[] = [];
|
|
85
|
+
|
|
86
|
+
// Find the dragged item's parent index for rejectOwnChildren check
|
|
87
|
+
let draggedParentIndex = -1;
|
|
88
|
+
for (let i = 0; i < entries.length; i++) {
|
|
89
|
+
if (entries[i]?.id === excludeId) {
|
|
90
|
+
draggedParentIndex = entries[i]!.parentIndex;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Dragged view bounds (for intersect/contain algorithms)
|
|
96
|
+
const dw = draggedDimensions?.width ?? 0;
|
|
97
|
+
const dh = draggedDimensions?.height ?? 0;
|
|
98
|
+
// position is the center of the hover view; compute top-left
|
|
99
|
+
const dragLeft = position.x - dw / 2;
|
|
100
|
+
const dragTop = position.y - dh / 2;
|
|
101
|
+
const dragRight = dragLeft + dw;
|
|
102
|
+
const dragBottom = dragTop + dh;
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < entries.length; i++) {
|
|
105
|
+
const entry = entries[i];
|
|
106
|
+
if (!entry) continue;
|
|
107
|
+
if (entry.id === excludeId) continue;
|
|
108
|
+
if (!entry.receptive && !entry.monitoring) continue;
|
|
109
|
+
|
|
110
|
+
// Skip views with zero dimensions (not yet measured)
|
|
111
|
+
if (entry.width === 0 || entry.height === 0) continue;
|
|
112
|
+
|
|
113
|
+
// Compute absolute position by walking parent chain
|
|
114
|
+
const absPos = computeAbsolutePositionWorklet(i, entries, scrollOffsets);
|
|
115
|
+
|
|
116
|
+
const recLeft = absPos.x;
|
|
117
|
+
const recTop = absPos.y;
|
|
118
|
+
const recRight = recLeft + entry.width;
|
|
119
|
+
const recBottom = recTop + entry.height;
|
|
120
|
+
|
|
121
|
+
let isHit: boolean;
|
|
122
|
+
const algo = entry.collisionAlgorithm;
|
|
123
|
+
|
|
124
|
+
if (algo === 'intersect' && dw > 0 && dh > 0) {
|
|
125
|
+
// Any overlap between dragged view and receiver
|
|
126
|
+
isHit =
|
|
127
|
+
dragLeft < recRight &&
|
|
128
|
+
dragRight > recLeft &&
|
|
129
|
+
dragTop < recBottom &&
|
|
130
|
+
dragBottom > recTop;
|
|
131
|
+
} else if (algo === 'contain' && dw > 0 && dh > 0) {
|
|
132
|
+
// Dragged view is fully inside receiver
|
|
133
|
+
isHit =
|
|
134
|
+
dragLeft >= recLeft &&
|
|
135
|
+
dragRight <= recRight &&
|
|
136
|
+
dragTop >= recTop &&
|
|
137
|
+
dragBottom <= recBottom;
|
|
138
|
+
} else {
|
|
139
|
+
// Default 'center': hover center is inside receiver
|
|
140
|
+
isHit =
|
|
141
|
+
position.x >= recLeft &&
|
|
142
|
+
position.y >= recTop &&
|
|
143
|
+
position.x < recRight &&
|
|
144
|
+
position.y < recBottom;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (isHit) {
|
|
148
|
+
if (entry.monitoring) monitorIds.push(entry.id);
|
|
149
|
+
// Take the last (deepest/most recently registered) receptive match
|
|
150
|
+
// Skip if this receiver rejects drags from its own children
|
|
151
|
+
if (entry.receptive) {
|
|
152
|
+
if (entry.rejectOwnChildren && i === draggedParentIndex) {
|
|
153
|
+
// This receiver is the parent of the dragged item — skip
|
|
154
|
+
} else {
|
|
155
|
+
receiverId = entry.id;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
} else if (entry.monitoring) {
|
|
159
|
+
// Padded bounds check for monitoring views only (tolerates hover drift during auto-scroll)
|
|
160
|
+
const isPaddedHit =
|
|
161
|
+
position.x >= recLeft - MONITOR_HIT_TEST_PADDING &&
|
|
162
|
+
position.y >= recTop - MONITOR_HIT_TEST_PADDING &&
|
|
163
|
+
position.x < recRight + MONITOR_HIT_TEST_PADDING &&
|
|
164
|
+
position.y < recBottom + MONITOR_HIT_TEST_PADDING;
|
|
165
|
+
if (isPaddedHit) {
|
|
166
|
+
monitorIds.push(entry.id);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return { receiverId, monitorIds };
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// ─── Snap Alignment Helper ──────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
/** Named alignment positions for snap targets within a receiver */
|
|
177
|
+
export type SnapAlignment =
|
|
178
|
+
| 'center'
|
|
179
|
+
| 'top-left'
|
|
180
|
+
| 'top-center'
|
|
181
|
+
| 'top-right'
|
|
182
|
+
| 'center-left'
|
|
183
|
+
| 'center-right'
|
|
184
|
+
| 'bottom-left'
|
|
185
|
+
| 'bottom-center'
|
|
186
|
+
| 'bottom-right';
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Compute a snap target position that aligns a dragged view within a receiver
|
|
190
|
+
* at the specified alignment point, with an optional pixel offset.
|
|
191
|
+
*
|
|
192
|
+
* Use as the return value from onDragDrop/onReceiveDragDrop/onMonitorDragDrop:
|
|
193
|
+
* ```
|
|
194
|
+
* onReceiveDragDrop={({ dragged, receiver }) =>
|
|
195
|
+
* snapToAlignment(receiver.measurements, dragged.measurements, 'top-left', { x: 8, y: 8 })
|
|
196
|
+
* }
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export const snapToAlignment = (
|
|
200
|
+
receiver: { x: number; y: number; width: number; height: number },
|
|
201
|
+
dragged: { width: number; height: number } | undefined,
|
|
202
|
+
alignment: SnapAlignment = 'center',
|
|
203
|
+
offset: Position = { x: 0, y: 0 }
|
|
204
|
+
): Position => {
|
|
205
|
+
const dw = dragged?.width ?? 0;
|
|
206
|
+
const dh = dragged?.height ?? 0;
|
|
207
|
+
|
|
208
|
+
let x: number;
|
|
209
|
+
let y: number;
|
|
210
|
+
|
|
211
|
+
switch (alignment) {
|
|
212
|
+
case 'top-left':
|
|
213
|
+
x = receiver.x;
|
|
214
|
+
y = receiver.y;
|
|
215
|
+
break;
|
|
216
|
+
case 'top-center':
|
|
217
|
+
x = receiver.x + (receiver.width - dw) / 2;
|
|
218
|
+
y = receiver.y;
|
|
219
|
+
break;
|
|
220
|
+
case 'top-right':
|
|
221
|
+
x = receiver.x + receiver.width - dw;
|
|
222
|
+
y = receiver.y;
|
|
223
|
+
break;
|
|
224
|
+
case 'center-left':
|
|
225
|
+
x = receiver.x;
|
|
226
|
+
y = receiver.y + (receiver.height - dh) / 2;
|
|
227
|
+
break;
|
|
228
|
+
case 'center':
|
|
229
|
+
x = receiver.x + (receiver.width - dw) / 2;
|
|
230
|
+
y = receiver.y + (receiver.height - dh) / 2;
|
|
231
|
+
break;
|
|
232
|
+
case 'center-right':
|
|
233
|
+
x = receiver.x + receiver.width - dw;
|
|
234
|
+
y = receiver.y + (receiver.height - dh) / 2;
|
|
235
|
+
break;
|
|
236
|
+
case 'bottom-left':
|
|
237
|
+
x = receiver.x;
|
|
238
|
+
y = receiver.y + receiver.height - dh;
|
|
239
|
+
break;
|
|
240
|
+
case 'bottom-center':
|
|
241
|
+
x = receiver.x + (receiver.width - dw) / 2;
|
|
242
|
+
y = receiver.y + receiver.height - dh;
|
|
243
|
+
break;
|
|
244
|
+
case 'bottom-right':
|
|
245
|
+
x = receiver.x + receiver.width - dw;
|
|
246
|
+
y = receiver.y + receiver.height - dh;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return { x: x + offset.x, y: y + offset.y };
|
|
251
|
+
};
|
package/src/params.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Default snapback delay in milliseconds */
|
|
2
|
+
export const defaultSnapbackDelay = 100;
|
|
3
|
+
|
|
4
|
+
/** Default snapback duration in milliseconds */
|
|
5
|
+
export const defaultSnapbackDuration = 250;
|
|
6
|
+
|
|
7
|
+
/** Default pre-drag long press delay in milliseconds */
|
|
8
|
+
export const defaultLongPressDelay = 0;
|
|
9
|
+
|
|
10
|
+
/** Default pre-drag long press delay in milliseconds for DraxList items */
|
|
11
|
+
export const defaultListItemLongPressDelay = 250;
|
|
12
|
+
|
|
13
|
+
/** Default scroll event throttle (number of events per second) for DraxScrollView */
|
|
14
|
+
export const defaultScrollEventThrottle = 8;
|
|
15
|
+
|
|
16
|
+
/** Default interval length in milliseconds for auto-scrolling jumps */
|
|
17
|
+
export const defaultAutoScrollIntervalLength = 250;
|
|
18
|
+
|
|
19
|
+
/** Default auto-scroll jump distance, as a fraction relative to content width/length */
|
|
20
|
+
export const defaultAutoScrollJumpRatio = 0.2;
|
|
21
|
+
|
|
22
|
+
/** Default drag-over maximum position threshold for auto-scroll back, as a fraction relative to content width/length */
|
|
23
|
+
export const defaultAutoScrollBackThreshold = 0.1;
|
|
24
|
+
|
|
25
|
+
/** Default drag-over minimum position threshold for auto-scroll forward, as a fraction relative to content width/length */
|
|
26
|
+
export const defaultAutoScrollForwardThreshold = 0.9;
|
|
27
|
+
|
|
28
|
+
/** Duration in milliseconds for list item shift/reorder animations */
|
|
29
|
+
export const ITEM_SHIFT_ANIMATION_DURATION = 200;
|
|
30
|
+
|
|
31
|
+
/** Resolved animation configuration for sortable item shifts */
|
|
32
|
+
export interface ResolvedAnimationConfig {
|
|
33
|
+
useSpring: boolean;
|
|
34
|
+
shiftDuration: number;
|
|
35
|
+
springDamping: number;
|
|
36
|
+
springStiffness: number;
|
|
37
|
+
springMass: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Frozen preset singletons — avoids object allocation on every call.
|
|
41
|
+
const PRESET_DEFAULT: ResolvedAnimationConfig = Object.freeze({
|
|
42
|
+
useSpring: false, shiftDuration: 200, springDamping: 15, springStiffness: 150, springMass: 1,
|
|
43
|
+
});
|
|
44
|
+
const PRESET_SPRING: ResolvedAnimationConfig = Object.freeze({
|
|
45
|
+
useSpring: true, shiftDuration: 200, springDamping: 15, springStiffness: 150, springMass: 1,
|
|
46
|
+
});
|
|
47
|
+
const PRESET_GENTLE: ResolvedAnimationConfig = Object.freeze({
|
|
48
|
+
useSpring: true, shiftDuration: 200, springDamping: 20, springStiffness: 100, springMass: 1.2,
|
|
49
|
+
});
|
|
50
|
+
const PRESET_SNAPPY: ResolvedAnimationConfig = Object.freeze({
|
|
51
|
+
useSpring: true, shiftDuration: 200, springDamping: 20, springStiffness: 300, springMass: 0.8,
|
|
52
|
+
});
|
|
53
|
+
const PRESET_NONE: ResolvedAnimationConfig = Object.freeze({
|
|
54
|
+
useSpring: false, shiftDuration: 0, springDamping: 15, springStiffness: 150, springMass: 1,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/** Resolve a SortableAnimationConfig (preset or custom) to concrete values */
|
|
58
|
+
export function resolveAnimationConfig(
|
|
59
|
+
config: import('./types').SortableAnimationConfig | undefined
|
|
60
|
+
): ResolvedAnimationConfig {
|
|
61
|
+
if (!config || config === 'default') return PRESET_DEFAULT;
|
|
62
|
+
if (config === 'spring') return PRESET_SPRING;
|
|
63
|
+
if (config === 'gentle') return PRESET_GENTLE;
|
|
64
|
+
if (config === 'snappy') return PRESET_SNAPPY;
|
|
65
|
+
if (config === 'none') return PRESET_NONE;
|
|
66
|
+
// Custom config — only case that allocates
|
|
67
|
+
return {
|
|
68
|
+
useSpring: config.useSpring ?? false,
|
|
69
|
+
shiftDuration: config.shiftDuration ?? 200,
|
|
70
|
+
springDamping: config.springDamping ?? 15,
|
|
71
|
+
springStiffness: config.springStiffness ?? 150,
|
|
72
|
+
springMass: config.springMass ?? 1,
|
|
73
|
+
};
|
|
74
|
+
}
|