react-native-reanimated-dnd 1.0.1

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 (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +633 -0
  3. package/lib/components/Draggable.d.ts +5 -0
  4. package/lib/components/Draggable.js +265 -0
  5. package/lib/components/Droppable.d.ts +264 -0
  6. package/lib/components/Droppable.js +284 -0
  7. package/lib/components/Sortable.d.ts +184 -0
  8. package/lib/components/Sortable.js +225 -0
  9. package/lib/components/SortableItem.d.ts +158 -0
  10. package/lib/components/SortableItem.js +251 -0
  11. package/lib/components/sortableUtils.d.ts +21 -0
  12. package/lib/components/sortableUtils.js +50 -0
  13. package/lib/context/DropContext.d.ts +118 -0
  14. package/lib/context/DropContext.js +233 -0
  15. package/lib/hooks/index.d.ts +4 -0
  16. package/lib/hooks/index.js +5 -0
  17. package/lib/hooks/useDraggable.d.ts +101 -0
  18. package/lib/hooks/useDraggable.js +567 -0
  19. package/lib/hooks/useDroppable.d.ts +129 -0
  20. package/lib/hooks/useDroppable.js +261 -0
  21. package/lib/hooks/useSortable.d.ts +174 -0
  22. package/lib/hooks/useSortable.js +361 -0
  23. package/lib/hooks/useSortableList.d.ts +182 -0
  24. package/lib/hooks/useSortableList.js +211 -0
  25. package/lib/index.d.ts +11 -0
  26. package/lib/index.js +16 -0
  27. package/lib/types/context.d.ts +166 -0
  28. package/lib/types/context.js +80 -0
  29. package/lib/types/draggable.d.ts +313 -0
  30. package/lib/types/draggable.js +31 -0
  31. package/lib/types/droppable.d.ts +197 -0
  32. package/lib/types/droppable.js +1 -0
  33. package/lib/types/index.d.ts +4 -0
  34. package/lib/types/index.js +8 -0
  35. package/lib/types/sortable.d.ts +432 -0
  36. package/lib/types/sortable.js +6 -0
  37. package/package.json +59 -0
@@ -0,0 +1,313 @@
1
+ import { ViewStyle, View, StyleProp } from "react-native";
2
+ import Animated, { AnimatedStyle, useAnimatedRef } from "react-native-reanimated";
3
+ import { GestureType } from "react-native-gesture-handler";
4
+ import { LayoutChangeEvent } from "react-native";
5
+ /**
6
+ * Enum representing the different states a draggable item can be in.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { DraggableState } from './types/draggable';
11
+ *
12
+ * const handleStateChange = (state: DraggableState) => {
13
+ * switch (state) {
14
+ * case DraggableState.IDLE:
15
+ * console.log('Item is at rest');
16
+ * break;
17
+ * case DraggableState.DRAGGING:
18
+ * console.log('Item is being dragged');
19
+ * break;
20
+ * case DraggableState.DROPPED:
21
+ * console.log('Item was successfully dropped');
22
+ * break;
23
+ * }
24
+ * };
25
+ * ```
26
+ */
27
+ export declare enum DraggableState {
28
+ /** Item is at rest in its original or dropped position */
29
+ IDLE = "IDLE",
30
+ /** Item is currently being dragged by the user */
31
+ DRAGGING = "DRAGGING",
32
+ /** Item has been successfully dropped on a valid drop zone */
33
+ DROPPED = "DROPPED"
34
+ }
35
+ /**
36
+ * Custom animation function type for controlling how draggable items animate.
37
+ *
38
+ * @param toValue - The target value to animate to
39
+ * @returns The animated value (typically from withSpring, withTiming, etc.)
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const customAnimation: AnimationFunction = (toValue) => {
44
+ * 'worklet';
45
+ * return withTiming(toValue, { duration: 500, easing: Easing.bounce });
46
+ * };
47
+ * ```
48
+ */
49
+ export type AnimationFunction = (toValue: number) => number;
50
+ /**
51
+ * Collision detection algorithms for determining when a draggable overlaps with a droppable.
52
+ *
53
+ * - `center`: Collision detected when the center point of the draggable is over the droppable
54
+ * - `intersect`: Collision detected when any part of the draggable overlaps with the droppable (default)
55
+ * - `contain`: Collision detected when the entire draggable is contained within the droppable
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // For precise dropping, use center collision
60
+ * const preciseDraggable = useDraggable({
61
+ * data: myData,
62
+ * collisionAlgorithm: 'center'
63
+ * });
64
+ *
65
+ * // For easy dropping, use intersect (default)
66
+ * const easyDraggable = useDraggable({
67
+ * data: myData,
68
+ * collisionAlgorithm: 'intersect'
69
+ * });
70
+ *
71
+ * // For strict containment, use contain
72
+ * const strictDraggable = useDraggable({
73
+ * data: myData,
74
+ * collisionAlgorithm: 'contain'
75
+ * });
76
+ * ```
77
+ */
78
+ export type CollisionAlgorithm = "center" | "intersect" | "contain";
79
+ /**
80
+ * Configuration options for the useDraggable hook.
81
+ *
82
+ * @template TData - The type of data associated with the draggable item
83
+ */
84
+ export interface UseDraggableOptions<TData = unknown> {
85
+ /**
86
+ * Data payload associated with this draggable item. This data is passed to drop handlers
87
+ * when the item is successfully dropped.
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const data = { id: '1', name: 'Task 1', priority: 'high' };
92
+ * ```
93
+ */
94
+ data: TData;
95
+ /**
96
+ * Unique identifier for this draggable item. If not provided, one will be generated automatically.
97
+ * Used for tracking dropped items and managing state.
98
+ */
99
+ draggableId?: string;
100
+ /**
101
+ * Whether dragging is disabled for this item. When true, the item cannot be dragged.
102
+ * Useful for conditionally enabling/disabling drag functionality.
103
+ *
104
+ * @default false
105
+ */
106
+ dragDisabled?: boolean;
107
+ /**
108
+ * Callback fired when dragging starts.
109
+ *
110
+ * @param data - The data associated with the draggable item
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const handleDragStart = (data) => {
115
+ * console.log('Started dragging:', data.name);
116
+ * setIsDragging(true);
117
+ * };
118
+ * ```
119
+ */
120
+ onDragStart?: (data: TData) => void;
121
+ /**
122
+ * Callback fired when dragging ends (regardless of whether it was dropped successfully).
123
+ *
124
+ * @param data - The data associated with the draggable item
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const handleDragEnd = (data) => {
129
+ * console.log('Finished dragging:', data.name);
130
+ * setIsDragging(false);
131
+ * };
132
+ * ```
133
+ */
134
+ onDragEnd?: (data: TData) => void;
135
+ /**
136
+ * Callback fired continuously while dragging. Useful for real-time feedback.
137
+ *
138
+ * @param payload - Object containing position and translation information
139
+ * @param payload.x - Original X position of the item
140
+ * @param payload.y - Original Y position of the item
141
+ * @param payload.tx - Current X translation from original position
142
+ * @param payload.ty - Current Y translation from original position
143
+ * @param payload.itemData - The data associated with the draggable item
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const handleDragging = ({ x, y, tx, ty, itemData }) => {
148
+ * const currentX = x + tx;
149
+ * const currentY = y + ty;
150
+ * console.log(`${itemData.name} is at (${currentX}, ${currentY})`);
151
+ * };
152
+ * ```
153
+ */
154
+ onDragging?: (payload: {
155
+ x: number;
156
+ y: number;
157
+ tx: number;
158
+ ty: number;
159
+ itemData: TData;
160
+ }) => void;
161
+ /**
162
+ * Callback fired when the draggable state changes.
163
+ *
164
+ * @param state - The new state of the draggable item
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const handleStateChange = (state) => {
169
+ * if (state === DraggableState.DROPPED) {
170
+ * showSuccessMessage();
171
+ * }
172
+ * };
173
+ * ```
174
+ */
175
+ onStateChange?: (state: DraggableState) => void;
176
+ /**
177
+ * Custom animation function for controlling how the item animates when dropped.
178
+ * If not provided, uses default spring animation.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const bounceAnimation = (toValue) => {
183
+ * 'worklet';
184
+ * return withTiming(toValue, {
185
+ * duration: 600,
186
+ * easing: Easing.bounce
187
+ * });
188
+ * };
189
+ * ```
190
+ */
191
+ animationFunction?: AnimationFunction;
192
+ /**
193
+ * Reference to a View that defines the dragging boundaries. The draggable item
194
+ * will be constrained within this view's bounds.
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const boundsRef = useRef<View>(null);
199
+ *
200
+ * return (
201
+ * <View ref={boundsRef} style={styles.container}>
202
+ * <Draggable dragBoundsRef={boundsRef} data={data}>
203
+ * <Text>Bounded draggable</Text>
204
+ * </Draggable>
205
+ * </View>
206
+ * );
207
+ * ```
208
+ */
209
+ dragBoundsRef?: React.RefObject<Animated.View | View>;
210
+ /**
211
+ * Constrains dragging to a specific axis.
212
+ *
213
+ * - `x`: Only horizontal movement allowed
214
+ * - `y`: Only vertical movement allowed
215
+ * - `both`: Movement in both directions (default)
216
+ *
217
+ * @default "both"
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * // Horizontal slider
222
+ * const horizontalDraggable = useDraggable({
223
+ * data: sliderData,
224
+ * dragAxis: 'x'
225
+ * });
226
+ *
227
+ * // Vertical slider
228
+ * const verticalDraggable = useDraggable({
229
+ * data: sliderData,
230
+ * dragAxis: 'y'
231
+ * });
232
+ * ```
233
+ */
234
+ dragAxis?: "x" | "y" | "both";
235
+ /**
236
+ * Algorithm used for collision detection with drop zones.
237
+ *
238
+ * @default "intersect"
239
+ *
240
+ * @see {@link CollisionAlgorithm} for detailed explanation of each algorithm
241
+ */
242
+ collisionAlgorithm?: CollisionAlgorithm;
243
+ /**
244
+ * Children elements - used internally for handle detection.
245
+ * @internal
246
+ */
247
+ children?: React.ReactNode;
248
+ /**
249
+ * Handle component type - used internally for handle detection.
250
+ * @internal
251
+ */
252
+ handleComponent?: React.ComponentType<any>;
253
+ }
254
+ /**
255
+ * Return value from the useDraggable hook.
256
+ */
257
+ export interface UseDraggableReturn {
258
+ /**
259
+ * Props to spread on the animated view that will be draggable.
260
+ * Contains the animated style and layout handler.
261
+ */
262
+ animatedViewProps: {
263
+ /** Animated style containing transform values for dragging */
264
+ style: AnimatedStyle<ViewStyle>;
265
+ /** Layout change handler for position updates */
266
+ onLayout: (event: LayoutChangeEvent) => void;
267
+ };
268
+ /**
269
+ * Gesture object to attach to GestureDetector for handling drag interactions.
270
+ * Only used when no handle is present (entire component is draggable).
271
+ */
272
+ gesture: GestureType;
273
+ /**
274
+ * Current state of the draggable item.
275
+ * @see {@link DraggableState}
276
+ */
277
+ state: DraggableState;
278
+ /**
279
+ * Animated ref for the draggable view. Used internally for measurements.
280
+ */
281
+ animatedViewRef: ReturnType<typeof useAnimatedRef<Animated.View>>;
282
+ /**
283
+ * Whether this draggable has a handle component. When true, only the handle
284
+ * can initiate dragging. When false, the entire component is draggable.
285
+ */
286
+ hasHandle: boolean;
287
+ }
288
+ export interface DraggableContextValue {
289
+ gesture: any;
290
+ state: DraggableState;
291
+ }
292
+ /**
293
+ * Props for the Draggable component.
294
+ *
295
+ * @template TData - The type of data associated with the draggable item
296
+ */
297
+ export interface DraggableProps<TData = unknown> extends UseDraggableOptions<TData> {
298
+ /** Style to apply to the draggable container */
299
+ style?: StyleProp<ViewStyle>;
300
+ /** The content to render inside the draggable */
301
+ children: React.ReactNode;
302
+ /** Callback fired when the draggable state changes */
303
+ onStateChange?: (state: DraggableState) => void;
304
+ }
305
+ /**
306
+ * Props for the Handle component.
307
+ */
308
+ export interface DraggableHandleProps {
309
+ /** The content to render inside the handle */
310
+ children: React.ReactNode;
311
+ /** Optional style to apply to the handle */
312
+ style?: StyleProp<ViewStyle>;
313
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Enum representing the different states a draggable item can be in.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { DraggableState } from './types/draggable';
7
+ *
8
+ * const handleStateChange = (state: DraggableState) => {
9
+ * switch (state) {
10
+ * case DraggableState.IDLE:
11
+ * console.log('Item is at rest');
12
+ * break;
13
+ * case DraggableState.DRAGGING:
14
+ * console.log('Item is being dragged');
15
+ * break;
16
+ * case DraggableState.DROPPED:
17
+ * console.log('Item was successfully dropped');
18
+ * break;
19
+ * }
20
+ * };
21
+ * ```
22
+ */
23
+ export var DraggableState;
24
+ (function (DraggableState) {
25
+ /** Item is at rest in its original or dropped position */
26
+ DraggableState["IDLE"] = "IDLE";
27
+ /** Item is currently being dragged by the user */
28
+ DraggableState["DRAGGING"] = "DRAGGING";
29
+ /** Item has been successfully dropped on a valid drop zone */
30
+ DraggableState["DROPPED"] = "DROPPED";
31
+ })(DraggableState || (DraggableState = {}));
@@ -0,0 +1,197 @@
1
+ import { LayoutChangeEvent, StyleProp, ViewStyle } from "react-native";
2
+ import Animated, { useAnimatedRef } from "react-native-reanimated";
3
+ import { DropAlignment, DropOffset } from "./context";
4
+ /**
5
+ * Configuration options for the useDroppable hook.
6
+ *
7
+ * @template TData - The type of data that can be dropped on this droppable
8
+ */
9
+ export interface UseDroppableOptions<TData = unknown> {
10
+ /**
11
+ * Callback function fired when an item is successfully dropped on this droppable.
12
+ * This is where you handle the drop logic for your application.
13
+ *
14
+ * @param data - The data from the draggable item that was dropped
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const handleDrop = (data: TaskData) => {
19
+ * console.log('Task dropped:', data.name);
20
+ * moveTaskToColumn(data.id, 'completed');
21
+ * showNotification(`${data.name} completed!`);
22
+ * };
23
+ * ```
24
+ */
25
+ onDrop: (data: TData) => void;
26
+ /**
27
+ * Whether this droppable is disabled. When true, items cannot be dropped here.
28
+ * Useful for conditionally enabling/disabling drop functionality.
29
+ *
30
+ * @default false
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const isDisabled = user.role !== 'admin';
35
+ *
36
+ * const { viewProps } = useDroppable({
37
+ * onDrop: handleDrop,
38
+ * dropDisabled: isDisabled
39
+ * });
40
+ * ```
41
+ */
42
+ dropDisabled?: boolean;
43
+ /**
44
+ * Callback fired when the active state of this droppable changes.
45
+ * Active state indicates whether a draggable item is currently hovering over this droppable.
46
+ *
47
+ * @param isActive - Whether a draggable is currently hovering over this droppable
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const handleActiveChange = (isActive: boolean) => {
52
+ * if (isActive) {
53
+ * playHoverSound();
54
+ * setHighlighted(true);
55
+ * } else {
56
+ * setHighlighted(false);
57
+ * }
58
+ * };
59
+ * ```
60
+ */
61
+ onActiveChange?: (isActive: boolean) => void;
62
+ /**
63
+ * How dropped items should be aligned within this droppable area.
64
+ *
65
+ * Available alignments:
66
+ * - `center`: Center the item within the droppable (default)
67
+ * - `top-left`: Align to top-left corner
68
+ * - `top-center`: Align to top edge, centered horizontally
69
+ * - `top-right`: Align to top-right corner
70
+ * - `center-left`: Align to left edge, centered vertically
71
+ * - `center-right`: Align to right edge, centered vertically
72
+ * - `bottom-left`: Align to bottom-left corner
73
+ * - `bottom-center`: Align to bottom edge, centered horizontally
74
+ * - `bottom-right`: Align to bottom-right corner
75
+ *
76
+ * @default "center"
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * // Items dropped here will snap to the top-left corner
81
+ * const { viewProps } = useDroppable({
82
+ * onDrop: handleDrop,
83
+ * dropAlignment: 'top-left'
84
+ * });
85
+ * ```
86
+ */
87
+ dropAlignment?: DropAlignment;
88
+ /**
89
+ * Additional pixel offset to apply after alignment.
90
+ * Useful for fine-tuning the exact position where items are dropped.
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * // Drop items 10px to the right and 5px down from the center
95
+ * const { viewProps } = useDroppable({
96
+ * onDrop: handleDrop,
97
+ * dropAlignment: 'center',
98
+ * dropOffset: { x: 10, y: 5 }
99
+ * });
100
+ * ```
101
+ */
102
+ dropOffset?: DropOffset;
103
+ /**
104
+ * Style to apply when a draggable item is hovering over this droppable.
105
+ * This provides visual feedback to users about valid drop targets.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const activeStyle = {
110
+ * backgroundColor: 'rgba(0, 255, 0, 0.2)',
111
+ * borderColor: '#00ff00',
112
+ * borderWidth: 2,
113
+ * transform: [{ scale: 1.05 }]
114
+ * };
115
+ *
116
+ * const { viewProps } = useDroppable({
117
+ * onDrop: handleDrop,
118
+ * activeStyle
119
+ * });
120
+ * ```
121
+ */
122
+ activeStyle?: StyleProp<ViewStyle>;
123
+ /**
124
+ * Unique identifier for this droppable. If not provided, one will be generated automatically.
125
+ * Used for tracking which droppable items are dropped on.
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * const { viewProps } = useDroppable({
130
+ * droppableId: 'todo-column',
131
+ * onDrop: handleDrop
132
+ * });
133
+ * ```
134
+ */
135
+ droppableId?: string;
136
+ /**
137
+ * Maximum number of items that can be dropped on this droppable.
138
+ * When capacity is reached, additional items cannot be dropped here.
139
+ *
140
+ * @default 1
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * // Allow up to 5 items in this drop zone
145
+ * const { viewProps } = useDroppable({
146
+ * onDrop: handleDrop,
147
+ * capacity: 5
148
+ * });
149
+ *
150
+ * // Unlimited capacity
151
+ * const { viewProps } = useDroppable({
152
+ * onDrop: handleDrop,
153
+ * capacity: Infinity
154
+ * });
155
+ * ```
156
+ */
157
+ capacity?: number;
158
+ }
159
+ /**
160
+ * Return value from the useDroppable hook.
161
+ */
162
+ export interface UseDroppableReturn {
163
+ /**
164
+ * Props to spread on the view that will act as a drop zone.
165
+ * Contains layout handler and conditional active styling.
166
+ */
167
+ viewProps: {
168
+ /** Layout change handler for position tracking */
169
+ onLayout: (event: LayoutChangeEvent) => void;
170
+ /** Style applied when active (draggable hovering) */
171
+ style?: StyleProp<ViewStyle>;
172
+ };
173
+ /**
174
+ * Whether a draggable item is currently hovering over this droppable.
175
+ * Useful for conditional rendering or additional visual feedback.
176
+ */
177
+ isActive: boolean;
178
+ /**
179
+ * The active style that was passed in options. Useful for external styling logic.
180
+ */
181
+ activeStyle?: StyleProp<ViewStyle>;
182
+ /**
183
+ * Animated ref for the droppable view. Used internally for measurements.
184
+ */
185
+ animatedViewRef: ReturnType<typeof useAnimatedRef<Animated.View>>;
186
+ }
187
+ /**
188
+ * Props for the Droppable component.
189
+ *
190
+ * @template TData - The type of data that can be dropped on this droppable
191
+ */
192
+ export interface DroppableProps<TData = unknown> extends UseDroppableOptions<TData> {
193
+ /** Style to apply to the droppable container */
194
+ style?: StyleProp<ViewStyle>;
195
+ /** The content to render inside the droppable */
196
+ children: React.ReactNode;
197
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export * from "./draggable";
2
+ export * from "./droppable";
3
+ export * from "./sortable";
4
+ export * from "./context";
@@ -0,0 +1,8 @@
1
+ // Re-export all draggable types
2
+ export * from "./draggable";
3
+ // Re-export all droppable types
4
+ export * from "./droppable";
5
+ // Re-export all sortable types
6
+ export * from "./sortable";
7
+ // Re-export all context types
8
+ export * from "./context";