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.
- package/LICENSE +21 -0
- package/README.md +633 -0
- package/lib/components/Draggable.d.ts +5 -0
- package/lib/components/Draggable.js +265 -0
- package/lib/components/Droppable.d.ts +264 -0
- package/lib/components/Droppable.js +284 -0
- package/lib/components/Sortable.d.ts +184 -0
- package/lib/components/Sortable.js +225 -0
- package/lib/components/SortableItem.d.ts +158 -0
- package/lib/components/SortableItem.js +251 -0
- package/lib/components/sortableUtils.d.ts +21 -0
- package/lib/components/sortableUtils.js +50 -0
- package/lib/context/DropContext.d.ts +118 -0
- package/lib/context/DropContext.js +233 -0
- package/lib/hooks/index.d.ts +4 -0
- package/lib/hooks/index.js +5 -0
- package/lib/hooks/useDraggable.d.ts +101 -0
- package/lib/hooks/useDraggable.js +567 -0
- package/lib/hooks/useDroppable.d.ts +129 -0
- package/lib/hooks/useDroppable.js +261 -0
- package/lib/hooks/useSortable.d.ts +174 -0
- package/lib/hooks/useSortable.js +361 -0
- package/lib/hooks/useSortableList.d.ts +182 -0
- package/lib/hooks/useSortableList.js +211 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +16 -0
- package/lib/types/context.d.ts +166 -0
- package/lib/types/context.js +80 -0
- package/lib/types/draggable.d.ts +313 -0
- package/lib/types/draggable.js +31 -0
- package/lib/types/droppable.d.ts +197 -0
- package/lib/types/droppable.js +1 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/index.js +8 -0
- package/lib/types/sortable.d.ts +432 -0
- package/lib/types/sortable.js +6 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Vishesh Raheja
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
# React Native Reanimated DnD 🎯
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="documentation/images/reanimated-dnd.gif" alt="React Native Reanimated DnD Demo" style="max-width: 100%; width: 100%;" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<div align="center">
|
|
8
|
+
|
|
9
|
+
**A drag-and-drop library that _finally_ works on React Native** ✨
|
|
10
|
+
|
|
11
|
+
_Powerful, performant, and built for the modern React Native developer_
|
|
12
|
+
|
|
13
|
+
[](https://badge.fury.io/js/react-native-reanimated-dnd)
|
|
14
|
+
[](https://opensource.org/licenses/MIT)
|
|
15
|
+
[](https://www.typescriptlang.org/)
|
|
16
|
+
[](https://reactnative.dev/)
|
|
17
|
+
|
|
18
|
+
<br />
|
|
19
|
+
|
|
20
|
+
<a href="https://react-native-reanimated-dnd.netlify.app/" target="_blank">
|
|
21
|
+
<img src="https://img.shields.io/badge/📖%20Read%20the%20Docs-4f46e5?style=for-the-badge&logo=gitbook&logoColor=white&labelColor=1e293b&color=6366f1" alt="Documentation" />
|
|
22
|
+
</a>
|
|
23
|
+
<a href="#-interactive-examples" target="_blank">
|
|
24
|
+
<img src="https://img.shields.io/badge/📱%20Try%20Live%20Demo-ff3b30?style=for-the-badge&logo=expo&logoColor=white&labelColor=1e293b" alt="Live Demo" />
|
|
25
|
+
</a>
|
|
26
|
+
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🚀 Why This Library?
|
|
32
|
+
|
|
33
|
+
After countless attempts with drag-and-drop solutions that don't work or are simply outdated, this is something that _finally_ works. And it is not just another DnD library, but a **complete ecosystem** built from the ground up for React Native, offering a **best-in-class developer experience** and **production-ready performance**.
|
|
34
|
+
|
|
35
|
+
**Highly feature-packed** with every interaction pattern you'll ever need, yet **simple enough** to get started in minutes. Built for developers who demand both power and simplicity.
|
|
36
|
+
|
|
37
|
+
## ✨ Features
|
|
38
|
+
|
|
39
|
+
- 🚀 **High Performance** - Built with Reanimated 3 for buttery-smooth 60fps animations
|
|
40
|
+
- 🎯 **Flexible API** - From simple drag-and-drop to complex sortable lists
|
|
41
|
+
- 📱 **React Native First** - Designed specifically for mobile, not ported from web
|
|
42
|
+
- 🔧 **TypeScript Ready** - Full type safety with comprehensive definitions
|
|
43
|
+
- 🎨 **Infinitely Customizable** - Every animation, behavior, and style is configurable
|
|
44
|
+
- 📦 **Complete Component Suite** - Draggable, Droppable, Sortable, and more
|
|
45
|
+
- 🎪 **Smart Collision Detection** - Multiple algorithms (center, intersect, contain)
|
|
46
|
+
- 📜 **Sortable Lists** - Drag and drop to sort a Vertical List, also
|
|
47
|
+
supports Automatic scrolling for out of screen dragging
|
|
48
|
+
- 🎭 **Drag Handles** - Precise control with dedicated drag areas
|
|
49
|
+
- 🎬 **Custom Animations** - Spring, timing, or bring your own animation functions
|
|
50
|
+
- 📐 **Pixel-Perfect Positioning** - 9-point alignment system with custom offsets
|
|
51
|
+
- 📦 **Boundary Constraints** - Keep draggables within specific areas
|
|
52
|
+
- ⚡ **State Management** - Complete lifecycle tracking and callbacks
|
|
53
|
+
- 🎯 **Developer Experience** - Intuitive APIs, helpful warnings, and extensive examples
|
|
54
|
+
|
|
55
|
+
## 📱 Interactive Examples
|
|
56
|
+
|
|
57
|
+
**See it in action!** A comprehensive example app with **15 interactive demos** showcasing every feature and use case.
|
|
58
|
+
|
|
59
|
+
<div align="center">
|
|
60
|
+
|
|
61
|
+
### 🎮 Try the Example App
|
|
62
|
+
|
|
63
|
+
<table>
|
|
64
|
+
<tr>
|
|
65
|
+
<td align="center" width="50%">
|
|
66
|
+
|
|
67
|
+
**📱 Scan & Play**
|
|
68
|
+
|
|
69
|
+
<img src="documentation/web-docs/static/img/example-app.svg" alt="Expo QR Code" width="200" height="200" />
|
|
70
|
+
|
|
71
|
+
*Scan with your camera or Expo Go app*
|
|
72
|
+
|
|
73
|
+
</td>
|
|
74
|
+
<td align="center" width="50%">
|
|
75
|
+
|
|
76
|
+
**🚀 Quick Start**
|
|
77
|
+
|
|
78
|
+
1. Install [Expo Go](https://expo.dev/client) on your phone
|
|
79
|
+
2. Scan the QR code with your camera
|
|
80
|
+
3. Open the link in Expo Go
|
|
81
|
+
4. Explore 15 interactive examples!
|
|
82
|
+
|
|
83
|
+
**Or browse the code:**
|
|
84
|
+
[**📂 View Example App →**](./example-app/README.md)
|
|
85
|
+
|
|
86
|
+
</td>
|
|
87
|
+
</tr>
|
|
88
|
+
</table>
|
|
89
|
+
|
|
90
|
+
### 📚 Complete Documentation
|
|
91
|
+
|
|
92
|
+
<a href="https://react-native-reanimated-dnd.netlify.app/" target="_blank">
|
|
93
|
+
<img src="https://img.shields.io/badge/📖%20Documentation-Visit%20Docs-4f46e5?style=for-the-badge&logo=gitbook&logoColor=white&labelColor=1e293b" alt="Documentation" />
|
|
94
|
+
</a>
|
|
95
|
+
|
|
96
|
+
*Comprehensive guides, API reference, and interactive examples*
|
|
97
|
+
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
The example app includes:
|
|
101
|
+
|
|
102
|
+
- 🎵 **Sortable Music Queue** - Complete list reordering with handles
|
|
103
|
+
- 🎯 **Collision Detection** - Different algorithms in action
|
|
104
|
+
- 🎬 **Custom Animations** - Spring, timing, and easing variations
|
|
105
|
+
- 📦 **Boundary Constraints** - Axis-locked and bounded dragging
|
|
106
|
+
- ✨ **Visual Feedback** - Active styles and state management
|
|
107
|
+
- ⚙️ **Advanced Patterns** - Custom implementations and hooks
|
|
108
|
+
|
|
109
|
+
## 🎬 Video Showcase
|
|
110
|
+
|
|
111
|
+
**See the library in action** with these interactive demonstrations showcasing key features and use cases.
|
|
112
|
+
|
|
113
|
+
<div align="center">
|
|
114
|
+
|
|
115
|
+
<table>
|
|
116
|
+
<tr>
|
|
117
|
+
<td align="center" width="50%">
|
|
118
|
+
|
|
119
|
+
### 📋 Sortable Lists
|
|
120
|
+
*Drag and drop to reorder items with smooth animations*
|
|
121
|
+
|
|
122
|
+
https://github.com/entropyconquers/react-native-reanimated-dnd/raw/main/documentation/videos/sortable-lists.mp4
|
|
123
|
+
|
|
124
|
+
**Features:** Auto-scrolling • Drag handles • Smooth transitions
|
|
125
|
+
|
|
126
|
+
</td>
|
|
127
|
+
<td align="center" width="50%">
|
|
128
|
+
|
|
129
|
+
### 🎯 Collision Detection
|
|
130
|
+
*Multiple algorithms for precise drop targeting*
|
|
131
|
+
|
|
132
|
+
https://github.com/entropyconquers/react-native-reanimated-dnd/raw/main/documentation/videos/collision-detection.mp4
|
|
133
|
+
|
|
134
|
+
**Algorithms:** Center • Intersect • Contain
|
|
135
|
+
|
|
136
|
+
</td>
|
|
137
|
+
</tr>
|
|
138
|
+
<tr>
|
|
139
|
+
<td align="center" width="50%">
|
|
140
|
+
|
|
141
|
+
### 🎪 Drag Handles
|
|
142
|
+
*Precise control with dedicated drag areas*
|
|
143
|
+
|
|
144
|
+
https://github.com/entropyconquers/react-native-reanimated-dnd/raw/main/documentation/videos/drag-handles.mp4
|
|
145
|
+
|
|
146
|
+
**Features:** Touch-friendly • Visual feedback • Accessibility
|
|
147
|
+
|
|
148
|
+
</td>
|
|
149
|
+
<td align="center" width="50%">
|
|
150
|
+
|
|
151
|
+
### 📦 Bounded Dragging
|
|
152
|
+
*Constrain movement within specific boundaries*
|
|
153
|
+
|
|
154
|
+
https://github.com/entropyconquers/react-native-reanimated-dnd/raw/main/documentation/videos/bounded-dragging.mp4
|
|
155
|
+
|
|
156
|
+
**Constraints:** Axis-locked • Container bounds • Custom limits
|
|
157
|
+
|
|
158
|
+
</td>
|
|
159
|
+
</tr>
|
|
160
|
+
<tr>
|
|
161
|
+
<td align="center" width="50%">
|
|
162
|
+
|
|
163
|
+
### ✨ Active Drop Styles
|
|
164
|
+
*Visual feedback during drag operations*
|
|
165
|
+
|
|
166
|
+
https://github.com/entropyconquers/react-native-reanimated-dnd/raw/main/documentation/videos/active-drop-styles.mp4
|
|
167
|
+
|
|
168
|
+
**Feedback:** Hover states • Drop zones • Visual cues
|
|
169
|
+
|
|
170
|
+
</td>
|
|
171
|
+
<td align="center" width="50%">
|
|
172
|
+
|
|
173
|
+
### 🔄 State Management
|
|
174
|
+
*Complete lifecycle tracking and callbacks*
|
|
175
|
+
|
|
176
|
+
https://github.com/entropyconquers/react-native-reanimated-dnd/raw/main/documentation/videos/drag-state-management.mp4
|
|
177
|
+
|
|
178
|
+
**States:** Idle • Dragging • Animating • Dropped
|
|
179
|
+
|
|
180
|
+
</td>
|
|
181
|
+
</tr>
|
|
182
|
+
</table>
|
|
183
|
+
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
## 🚀 Installation
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
npm install react-native-reanimated-dnd
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Peer Dependencies
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
npm install react-native-reanimated react-native-gesture-handler
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Follow the setup guides:
|
|
199
|
+
|
|
200
|
+
- [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation)
|
|
201
|
+
- [React Native Gesture Handler](https://docs.swmansion.com/react-native-gesture-handler/docs/installation)
|
|
202
|
+
|
|
203
|
+
## 🏃♂️ Quick Start
|
|
204
|
+
|
|
205
|
+
### Basic Draggable
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import React from "react";
|
|
209
|
+
import { View, Text } from "react-native";
|
|
210
|
+
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
211
|
+
import { Draggable, DropProvider } from "react-native-reanimated-dnd";
|
|
212
|
+
|
|
213
|
+
export default function App() {
|
|
214
|
+
return (
|
|
215
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
216
|
+
<DropProvider>
|
|
217
|
+
<View style={{ flex: 1, padding: 20 }}>
|
|
218
|
+
<Draggable data={{ id: "1", title: "Drag me!" }}>
|
|
219
|
+
<View
|
|
220
|
+
style={{
|
|
221
|
+
padding: 20,
|
|
222
|
+
backgroundColor: "#007AFF",
|
|
223
|
+
borderRadius: 8,
|
|
224
|
+
}}
|
|
225
|
+
>
|
|
226
|
+
<Text style={{ color: "white" }}>Drag me around!</Text>
|
|
227
|
+
</View>
|
|
228
|
+
</Draggable>
|
|
229
|
+
</View>
|
|
230
|
+
</DropProvider>
|
|
231
|
+
</GestureHandlerRootView>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Drag & Drop with Multiple Zones
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
import React from "react";
|
|
240
|
+
import { View, Text } from "react-native";
|
|
241
|
+
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
242
|
+
import {
|
|
243
|
+
Draggable,
|
|
244
|
+
Droppable,
|
|
245
|
+
DropProvider,
|
|
246
|
+
} from "react-native-reanimated-dnd";
|
|
247
|
+
|
|
248
|
+
export default function DragDropExample() {
|
|
249
|
+
const handleDrop = (data: any) => {
|
|
250
|
+
console.log("Item dropped:", data);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
return (
|
|
254
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
255
|
+
<DropProvider>
|
|
256
|
+
<View style={{ flex: 1, padding: 20 }}>
|
|
257
|
+
{/* Draggable Item */}
|
|
258
|
+
<Draggable data={{ id: "1", title: "Drag me!" }}>
|
|
259
|
+
<View style={styles.draggableItem}>
|
|
260
|
+
<Text>📦 Drag me to a zone</Text>
|
|
261
|
+
</View>
|
|
262
|
+
</Draggable>
|
|
263
|
+
|
|
264
|
+
{/* Drop Zones */}
|
|
265
|
+
<Droppable onDrop={handleDrop}>
|
|
266
|
+
<View style={styles.dropZone}>
|
|
267
|
+
<Text>🎯 Drop Zone 1</Text>
|
|
268
|
+
</View>
|
|
269
|
+
</Droppable>
|
|
270
|
+
|
|
271
|
+
<Droppable onDrop={handleDrop}>
|
|
272
|
+
<View style={styles.dropZone}>
|
|
273
|
+
<Text>🎯 Drop Zone 2</Text>
|
|
274
|
+
</View>
|
|
275
|
+
</Droppable>
|
|
276
|
+
</View>
|
|
277
|
+
</DropProvider>
|
|
278
|
+
</GestureHandlerRootView>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Sortable List
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
import React, { useState } from "react";
|
|
287
|
+
import { View, Text } from "react-native";
|
|
288
|
+
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
289
|
+
import { Sortable, SortableItem } from "react-native-reanimated-dnd";
|
|
290
|
+
|
|
291
|
+
interface Task {
|
|
292
|
+
id: string;
|
|
293
|
+
title: string;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export default function SortableExample() {
|
|
297
|
+
const [tasks, setTasks] = useState<Task[]>([
|
|
298
|
+
{ id: "1", title: "Learn React Native" },
|
|
299
|
+
{ id: "2", title: "Build an app" },
|
|
300
|
+
{ id: "3", title: "Deploy to store" },
|
|
301
|
+
]);
|
|
302
|
+
|
|
303
|
+
const renderTask = ({ item, id, positions, ...props }) => (
|
|
304
|
+
<SortableItem
|
|
305
|
+
key={id}
|
|
306
|
+
id={id}
|
|
307
|
+
positions={positions}
|
|
308
|
+
{...props}
|
|
309
|
+
onMove={(itemId, from, to) => {
|
|
310
|
+
const newTasks = [...tasks];
|
|
311
|
+
const [movedTask] = newTasks.splice(from, 1);
|
|
312
|
+
newTasks.splice(to, 0, movedTask);
|
|
313
|
+
setTasks(newTasks);
|
|
314
|
+
}}
|
|
315
|
+
>
|
|
316
|
+
<View style={styles.taskItem}>
|
|
317
|
+
<Text>{item.title}</Text>
|
|
318
|
+
|
|
319
|
+
{/* Drag Handle */}
|
|
320
|
+
<SortableItem.Handle style={styles.dragHandle}>
|
|
321
|
+
<Text>⋮⋮</Text>
|
|
322
|
+
</SortableItem.Handle>
|
|
323
|
+
</View>
|
|
324
|
+
</SortableItem>
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
329
|
+
<Sortable
|
|
330
|
+
data={tasks}
|
|
331
|
+
renderItem={renderTask}
|
|
332
|
+
itemHeight={60}
|
|
333
|
+
style={{ flex: 1, padding: 16 }}
|
|
334
|
+
/>
|
|
335
|
+
</GestureHandlerRootView>
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## 📚 API Reference
|
|
341
|
+
|
|
342
|
+
### Components
|
|
343
|
+
|
|
344
|
+
#### `<Draggable>`
|
|
345
|
+
|
|
346
|
+
Makes any component draggable with extensive customization options.
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
<Draggable
|
|
350
|
+
data={any} // Data associated with the item
|
|
351
|
+
onDragStart={(data) => void} // Called when dragging starts
|
|
352
|
+
onDragEnd={(data) => void} // Called when dragging ends
|
|
353
|
+
onDragging={(position) => void} // Called during dragging
|
|
354
|
+
onStateChange={(state) => void} // Called on state changes
|
|
355
|
+
dragDisabled={boolean} // Disable dragging
|
|
356
|
+
collisionAlgorithm="center|intersect|contain" // Collision detection method
|
|
357
|
+
dragAxis="x|y|both" // Constrain movement axis
|
|
358
|
+
dragBoundsRef={RefObject} // Boundary container reference
|
|
359
|
+
animationFunction={(toValue) => Animation} // Custom animation function
|
|
360
|
+
style={StyleProp<ViewStyle>} // Component styling
|
|
361
|
+
>
|
|
362
|
+
{children}
|
|
363
|
+
</Draggable>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
#### `<Droppable>`
|
|
367
|
+
|
|
368
|
+
Creates drop zones with visual feedback and capacity management.
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
<Droppable
|
|
372
|
+
onDrop={(data) => void} // Called when item is dropped
|
|
373
|
+
onActiveChange={(isActive) => void} // Called on hover state change
|
|
374
|
+
dropDisabled={boolean} // Disable drop functionality
|
|
375
|
+
dropAlignment="top-left|center|bottom-right|..." // Drop positioning
|
|
376
|
+
dropOffset={{ x: number, y: number }} // Position offset
|
|
377
|
+
activeStyle={StyleProp<ViewStyle>} // Style when active
|
|
378
|
+
capacity={number} // Maximum items allowed
|
|
379
|
+
droppableId={string} // Unique identifier
|
|
380
|
+
>
|
|
381
|
+
{children}
|
|
382
|
+
</Droppable>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### `<Sortable>`
|
|
386
|
+
|
|
387
|
+
High-level component for sortable lists with auto-scrolling.
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
<Sortable
|
|
391
|
+
data={Array<{ id: string }>} // Array of items to render
|
|
392
|
+
renderItem={(props) => ReactNode} // Render function for items
|
|
393
|
+
itemHeight={number} // Height of each item
|
|
394
|
+
itemKeyExtractor={(item) => string} // Custom key extractor
|
|
395
|
+
style={StyleProp<ViewStyle>} // List container style
|
|
396
|
+
contentContainerStyle={StyleProp<ViewStyle>} // Content container style
|
|
397
|
+
/>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
#### `<SortableItem>`
|
|
401
|
+
|
|
402
|
+
Individual item within a sortable list with gesture handling.
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
<SortableItem
|
|
406
|
+
id={string} // Unique identifier
|
|
407
|
+
data={any} // Item data
|
|
408
|
+
positions={SharedValue} // Position tracking
|
|
409
|
+
onMove={(id, from, to) => void} // Called when item moves
|
|
410
|
+
onDragStart={(id, position) => void} // Called when dragging starts
|
|
411
|
+
onDrop={(id, position) => void} // Called when item is dropped
|
|
412
|
+
onDragging={(id, overItemId, y) => void} // Called during dragging
|
|
413
|
+
style={StyleProp<ViewStyle>} // Item styling
|
|
414
|
+
animatedStyle={StyleProp<AnimatedStyle>} // Animated styling
|
|
415
|
+
>
|
|
416
|
+
{children}
|
|
417
|
+
</SortableItem>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Hooks
|
|
421
|
+
|
|
422
|
+
#### `useDraggable(options)`
|
|
423
|
+
|
|
424
|
+
Core hook for implementing draggable functionality.
|
|
425
|
+
|
|
426
|
+
#### `useDroppable(options)`
|
|
427
|
+
|
|
428
|
+
Core hook for implementing droppable functionality.
|
|
429
|
+
|
|
430
|
+
#### `useSortable(options)`
|
|
431
|
+
|
|
432
|
+
Hook for individual sortable items with position management.
|
|
433
|
+
|
|
434
|
+
#### `useSortableList(options)`
|
|
435
|
+
|
|
436
|
+
Hook for managing entire sortable lists with auto-scrolling.
|
|
437
|
+
|
|
438
|
+
### Context
|
|
439
|
+
|
|
440
|
+
#### `<DropProvider>`
|
|
441
|
+
|
|
442
|
+
Required context provider that manages global drag-and-drop state.
|
|
443
|
+
|
|
444
|
+
```tsx
|
|
445
|
+
<DropProvider>{/* All draggable and droppable components */}</DropProvider>
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Types & Enums
|
|
449
|
+
|
|
450
|
+
#### `DraggableState`
|
|
451
|
+
|
|
452
|
+
```tsx
|
|
453
|
+
enum DraggableState {
|
|
454
|
+
IDLE = "idle",
|
|
455
|
+
DRAGGING = "dragging",
|
|
456
|
+
ANIMATING = "animating",
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### `CollisionAlgorithm`
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
type CollisionAlgorithm = "center" | "intersect" | "contain";
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
#### `DropAlignment`
|
|
467
|
+
|
|
468
|
+
```tsx
|
|
469
|
+
type DropAlignment =
|
|
470
|
+
| "top-left"
|
|
471
|
+
| "top-center"
|
|
472
|
+
| "top-right"
|
|
473
|
+
| "center-left"
|
|
474
|
+
| "center"
|
|
475
|
+
| "center-right"
|
|
476
|
+
| "bottom-left"
|
|
477
|
+
| "bottom-center"
|
|
478
|
+
| "bottom-right";
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## 🎨 Advanced Usage
|
|
482
|
+
|
|
483
|
+
### Custom Animations
|
|
484
|
+
|
|
485
|
+
```tsx
|
|
486
|
+
import { withTiming, withSpring, Easing } from "react-native-reanimated";
|
|
487
|
+
|
|
488
|
+
// Smooth timing animation
|
|
489
|
+
const smoothAnimation = (toValue) => {
|
|
490
|
+
"worklet";
|
|
491
|
+
return withTiming(toValue, {
|
|
492
|
+
duration: 300,
|
|
493
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
494
|
+
});
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// Spring animation
|
|
498
|
+
const springAnimation = (toValue) => {
|
|
499
|
+
"worklet";
|
|
500
|
+
return withSpring(toValue, {
|
|
501
|
+
damping: 15,
|
|
502
|
+
stiffness: 150,
|
|
503
|
+
});
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
<Draggable animationFunction={springAnimation}>{/* content */}</Draggable>;
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Collision Detection Strategies
|
|
510
|
+
|
|
511
|
+
```tsx
|
|
512
|
+
// Precise center-point collision
|
|
513
|
+
<Draggable collisionAlgorithm="center">
|
|
514
|
+
{/* Requires center point to be over drop zone */}
|
|
515
|
+
</Draggable>
|
|
516
|
+
|
|
517
|
+
// Forgiving intersection collision (default)
|
|
518
|
+
<Draggable collisionAlgorithm="intersect">
|
|
519
|
+
{/* Any overlap triggers collision */}
|
|
520
|
+
</Draggable>
|
|
521
|
+
|
|
522
|
+
// Strict containment collision
|
|
523
|
+
<Draggable collisionAlgorithm="contain">
|
|
524
|
+
{/* Entire draggable must be within drop zone */}
|
|
525
|
+
</Draggable>
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Drag Handles
|
|
529
|
+
|
|
530
|
+
```tsx
|
|
531
|
+
<SortableItem id={item.id} {...props}>
|
|
532
|
+
<View style={styles.itemContainer}>
|
|
533
|
+
<Text>{item.title}</Text>
|
|
534
|
+
|
|
535
|
+
{/* Only this handle area can initiate dragging */}
|
|
536
|
+
<SortableItem.Handle style={styles.dragHandle}>
|
|
537
|
+
<View style={styles.handleIcon}>
|
|
538
|
+
<View style={styles.dot} />
|
|
539
|
+
<View style={styles.dot} />
|
|
540
|
+
<View style={styles.dot} />
|
|
541
|
+
</View>
|
|
542
|
+
</SortableItem.Handle>
|
|
543
|
+
</View>
|
|
544
|
+
</SortableItem>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Bounded Dragging
|
|
548
|
+
|
|
549
|
+
```tsx
|
|
550
|
+
const containerRef = useRef<View>(null);
|
|
551
|
+
|
|
552
|
+
<View ref={containerRef} style={styles.container}>
|
|
553
|
+
<Draggable
|
|
554
|
+
data={data}
|
|
555
|
+
dragBoundsRef={containerRef}
|
|
556
|
+
dragAxis="x" // Constrain to horizontal movement
|
|
557
|
+
>
|
|
558
|
+
{/* content */}
|
|
559
|
+
</Draggable>
|
|
560
|
+
</View>;
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Drop Zone Capacity
|
|
564
|
+
|
|
565
|
+
```tsx
|
|
566
|
+
<Droppable
|
|
567
|
+
capacity={3}
|
|
568
|
+
onDrop={(data) => {
|
|
569
|
+
if (currentItems.length < 3) {
|
|
570
|
+
addItem(data);
|
|
571
|
+
}
|
|
572
|
+
}}
|
|
573
|
+
activeStyle={{
|
|
574
|
+
backgroundColor: currentItems.length < 3 ? "#e8f5e8" : "#ffe8e8",
|
|
575
|
+
}}
|
|
576
|
+
>
|
|
577
|
+
<Text>Drop Zone ({currentItems.length}/3)</Text>
|
|
578
|
+
</Droppable>
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
## 🏃♂️ Running the Example App
|
|
582
|
+
|
|
583
|
+
1. Clone the repository:
|
|
584
|
+
|
|
585
|
+
```bash
|
|
586
|
+
git clone https://github.com/entropyconquers/react-native-reanimated-dnd.git
|
|
587
|
+
cd react-native-reanimated-dnd
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
2. Install dependencies:
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
npm install
|
|
594
|
+
cd example-app
|
|
595
|
+
npm install
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
3. Run the example app:
|
|
599
|
+
|
|
600
|
+
```bash
|
|
601
|
+
# iOS
|
|
602
|
+
npx expo run:ios
|
|
603
|
+
|
|
604
|
+
# Android
|
|
605
|
+
npx expo run:android
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
The example app includes all 15 interactive examples showcasing every feature of the library.
|
|
609
|
+
|
|
610
|
+
## 🤝 Contributing
|
|
611
|
+
|
|
612
|
+
Contributions are always welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
613
|
+
|
|
614
|
+
## 📄 License
|
|
615
|
+
|
|
616
|
+
MIT © [Vishesh Raheja](https://github.com/entropyconquers)
|
|
617
|
+
|
|
618
|
+
## 🙏 Acknowledgments
|
|
619
|
+
|
|
620
|
+
- Built with [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/) for smooth 60fps animations
|
|
621
|
+
- Gesture handling powered by [React Native Gesture Handler](https://docs.swmansion.com/react-native-gesture-handler/)
|
|
622
|
+
- Inspired by the React ecosystem's drag-and-drop libraries
|
|
623
|
+
- Special thanks to the React Native community for feedback and contributions
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
<div align="center">
|
|
628
|
+
|
|
629
|
+
**Made with ❤️ for the React Native community**
|
|
630
|
+
|
|
631
|
+
[⭐ Star on GitHub](https://github.com/entropyconquers/react-native-reanimated-dnd) • [📱 Try the Demo](https://github.com/entropyconquers/react-native-reanimated-dnd/tree/main/example-app) • [📖 Documentation](https://github.com/entropyconquers/react-native-reanimated-dnd#readme)
|
|
632
|
+
|
|
633
|
+
</div>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DraggableHandleProps, DraggableProps } from "../types/draggable";
|
|
3
|
+
export declare const Draggable: (<TData = unknown>({ style: componentStyle, children, ...useDraggableHookOptions }: DraggableProps<TData>) => React.JSX.Element) & {
|
|
4
|
+
Handle: ({ children, style }: DraggableHandleProps) => React.JSX.Element;
|
|
5
|
+
};
|