react-native-reanimated-dnd 1.0.2 → 1.0.4
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/lib/components/Draggable.js +1 -265
- package/lib/components/Droppable.d.ts +0 -260
- package/lib/components/Droppable.js +1 -284
- package/lib/components/Sortable.d.ts +0 -179
- package/lib/components/Sortable.js +1 -225
- package/lib/components/SortableItem.d.ts +0 -152
- package/lib/components/SortableItem.js +1 -251
- package/lib/components/sortableUtils.js +1 -50
- package/lib/context/DropContext.d.ts +0 -115
- package/lib/context/DropContext.js +1 -233
- package/lib/hooks/index.js +1 -5
- package/lib/hooks/useDraggable.d.ts +0 -99
- package/lib/hooks/useDraggable.js +1 -567
- package/lib/hooks/useDroppable.d.ts +0 -127
- package/lib/hooks/useDroppable.js +1 -261
- package/lib/hooks/useSortable.d.ts +0 -127
- package/lib/hooks/useSortable.js +1 -361
- package/lib/hooks/useSortableList.d.ts +0 -155
- package/lib/hooks/useSortableList.js +1 -211
- package/lib/index.js +1 -16
- package/lib/types/context.d.ts +0 -99
- package/lib/types/context.js +1 -80
- package/lib/types/draggable.d.ts +0 -260
- package/lib/types/draggable.js +1 -31
- package/lib/types/droppable.d.ts +0 -171
- package/lib/types/droppable.js +1 -1
- package/lib/types/index.js +1 -8
- package/lib/types/sortable.d.ts +0 -333
- package/lib/types/sortable.js +1 -6
- package/package.json +9 -4
|
@@ -1,265 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import React, { createContext, useContext } from "react";
|
|
3
|
-
import Animated from "react-native-reanimated";
|
|
4
|
-
import { GestureDetector } from "react-native-gesture-handler";
|
|
5
|
-
import { useDraggable } from "../hooks/useDraggable";
|
|
6
|
-
// Create a context to share gesture and state between Draggable and Handle
|
|
7
|
-
const DraggableContext = createContext(null);
|
|
8
|
-
/**
|
|
9
|
-
* A handle component that can be used within Draggable to create a specific
|
|
10
|
-
* draggable area. When a Handle is present, only the handle area can initiate
|
|
11
|
-
* dragging, while the rest of the draggable remains non-interactive for dragging.
|
|
12
|
-
*
|
|
13
|
-
* @param props - Props for the handle component
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* Basic drag handle:
|
|
17
|
-
* ```typescript
|
|
18
|
-
* <Draggable data={{ id: '1', name: 'Item 1' }}>
|
|
19
|
-
* <View style={styles.itemContent}>
|
|
20
|
-
* <Text>Item content (not draggable)</Text>
|
|
21
|
-
*
|
|
22
|
-
* <Draggable.Handle style={styles.dragHandle}>
|
|
23
|
-
* <Icon name="drag-handle" size={20} />
|
|
24
|
-
* </Draggable.Handle>
|
|
25
|
-
* </View>
|
|
26
|
-
* </Draggable>
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* Custom styled handle:
|
|
31
|
-
* ```typescript
|
|
32
|
-
* <Draggable data={{ id: '2', type: 'card' }}>
|
|
33
|
-
* <View style={styles.card}>
|
|
34
|
-
* <Text style={styles.title}>Card Title</Text>
|
|
35
|
-
* <Text style={styles.content}>Card content...</Text>
|
|
36
|
-
*
|
|
37
|
-
* <Draggable.Handle style={styles.customHandle}>
|
|
38
|
-
* <View style={styles.handleDots}>
|
|
39
|
-
* <View style={styles.dot} />
|
|
40
|
-
* <View style={styles.dot} />
|
|
41
|
-
* <View style={styles.dot} />
|
|
42
|
-
* </View>
|
|
43
|
-
* </Draggable.Handle>
|
|
44
|
-
* </View>
|
|
45
|
-
* </Draggable>
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
const Handle = ({ children, style }) => {
|
|
49
|
-
const draggableContext = useContext(DraggableContext);
|
|
50
|
-
if (!draggableContext) {
|
|
51
|
-
console.warn("Draggable.Handle must be used within a Draggable component");
|
|
52
|
-
return <>{children}</>;
|
|
53
|
-
}
|
|
54
|
-
return (<GestureDetector gesture={draggableContext.gesture}>
|
|
55
|
-
<Animated.View style={style}>{children}</Animated.View>
|
|
56
|
-
</GestureDetector>);
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* A versatile draggable component with advanced features like collision detection,
|
|
60
|
-
* bounded dragging, axis constraints, and custom animations.
|
|
61
|
-
*
|
|
62
|
-
* The Draggable component provides a complete drag-and-drop solution that can be
|
|
63
|
-
* used standalone or within a DropProvider context for drop zone interactions.
|
|
64
|
-
* It supports both full-item dragging and handle-based dragging patterns.
|
|
65
|
-
*
|
|
66
|
-
* @template TData - The type of data associated with the draggable item
|
|
67
|
-
* @param props - Configuration props for the draggable component
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* Basic draggable item:
|
|
71
|
-
* ```typescript
|
|
72
|
-
* import { Draggable } from './components/Draggable';
|
|
73
|
-
*
|
|
74
|
-
* function BasicDraggable() {
|
|
75
|
-
* return (
|
|
76
|
-
* <Draggable
|
|
77
|
-
* data={{ id: '1', name: 'Draggable Item', type: 'task' }}
|
|
78
|
-
* onDragStart={(data) => console.log('Started dragging:', data.name)}
|
|
79
|
-
* onDragEnd={(data) => console.log('Finished dragging:', data.name)}
|
|
80
|
-
* >
|
|
81
|
-
* <View style={styles.item}>
|
|
82
|
-
* <Text>Drag me anywhere!</Text>
|
|
83
|
-
* </View>
|
|
84
|
-
* </Draggable>
|
|
85
|
-
* );
|
|
86
|
-
* }
|
|
87
|
-
* ```
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* Draggable with custom animation and constraints:
|
|
91
|
-
* ```typescript
|
|
92
|
-
* function ConstrainedDraggable() {
|
|
93
|
-
* const boundsRef = useRef<View>(null);
|
|
94
|
-
*
|
|
95
|
-
* return (
|
|
96
|
-
* <View ref={boundsRef} style={styles.container}>
|
|
97
|
-
* <Draggable
|
|
98
|
-
* data={{ id: '2', category: 'bounded' }}
|
|
99
|
-
* dragBoundsRef={boundsRef}
|
|
100
|
-
* dragAxis="x" // Only horizontal movement
|
|
101
|
-
* animationFunction={(toValue) => {
|
|
102
|
-
* 'worklet';
|
|
103
|
-
* return withTiming(toValue, { duration: 300 });
|
|
104
|
-
* }}
|
|
105
|
-
* collisionAlgorithm="center"
|
|
106
|
-
* style={styles.draggableItem}
|
|
107
|
-
* >
|
|
108
|
-
* <View style={styles.slider}>
|
|
109
|
-
* <Text>Horizontal Slider</Text>
|
|
110
|
-
* </View>
|
|
111
|
-
* </Draggable>
|
|
112
|
-
* </View>
|
|
113
|
-
* );
|
|
114
|
-
* }
|
|
115
|
-
* ```
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* Draggable with handle and state tracking:
|
|
119
|
-
* ```typescript
|
|
120
|
-
* function HandleDraggable() {
|
|
121
|
-
* const [dragState, setDragState] = useState(DraggableState.IDLE);
|
|
122
|
-
*
|
|
123
|
-
* return (
|
|
124
|
-
* <Draggable
|
|
125
|
-
* data={{ id: '3', title: 'Card with Handle' }}
|
|
126
|
-
* onStateChange={setDragState}
|
|
127
|
-
* onDragging={({ x, y, tx, ty }) => {
|
|
128
|
-
* console.log(`Position: (${x + tx}, ${y + ty})`);
|
|
129
|
-
* }}
|
|
130
|
-
* style={[
|
|
131
|
-
* styles.card,
|
|
132
|
-
* dragState === DraggableState.DRAGGING && styles.dragging
|
|
133
|
-
* ]}
|
|
134
|
-
* >
|
|
135
|
-
* <View style={styles.cardContent}>
|
|
136
|
-
* <Text style={styles.cardTitle}>Card Title</Text>
|
|
137
|
-
* <Text style={styles.cardBody}>
|
|
138
|
-
* This card can only be dragged by its handle.
|
|
139
|
-
* </Text>
|
|
140
|
-
*
|
|
141
|
-
* <Draggable.Handle style={styles.dragHandle}>
|
|
142
|
-
* <View style={styles.handleIcon}>
|
|
143
|
-
* <Text>⋮⋮</Text>
|
|
144
|
-
* </View>
|
|
145
|
-
* </Draggable.Handle>
|
|
146
|
-
* </View>
|
|
147
|
-
* </Draggable>
|
|
148
|
-
* );
|
|
149
|
-
* }
|
|
150
|
-
* ```
|
|
151
|
-
*
|
|
152
|
-
* @example
|
|
153
|
-
* Draggable with collision detection and drop zones:
|
|
154
|
-
* ```typescript
|
|
155
|
-
* function DragDropExample() {
|
|
156
|
-
* return (
|
|
157
|
-
* <DropProvider>
|
|
158
|
-
* <View style={styles.container}>
|
|
159
|
-
* <Draggable
|
|
160
|
-
* data={{ id: '4', type: 'file', name: 'document.pdf' }}
|
|
161
|
-
* collisionAlgorithm="intersect"
|
|
162
|
-
* onDragStart={(data) => {
|
|
163
|
-
* hapticFeedback();
|
|
164
|
-
* setDraggedItem(data);
|
|
165
|
-
* }}
|
|
166
|
-
* onDragEnd={(data) => {
|
|
167
|
-
* setDraggedItem(null);
|
|
168
|
-
* }}
|
|
169
|
-
* >
|
|
170
|
-
* <View style={styles.fileItem}>
|
|
171
|
-
* <Icon name="file-pdf" size={24} />
|
|
172
|
-
* <Text>{data.name}</Text>
|
|
173
|
-
* </View>
|
|
174
|
-
* </Draggable>
|
|
175
|
-
*
|
|
176
|
-
* <Droppable
|
|
177
|
-
* onDrop={(data) => {
|
|
178
|
-
* console.log('File dropped:', data.name);
|
|
179
|
-
* moveToTrash(data.id);
|
|
180
|
-
* }}
|
|
181
|
-
* >
|
|
182
|
-
* <View style={styles.trashZone}>
|
|
183
|
-
* <Icon name="trash" size={32} />
|
|
184
|
-
* <Text>Drop files here to delete</Text>
|
|
185
|
-
* </View>
|
|
186
|
-
* </Droppable>
|
|
187
|
-
* </View>
|
|
188
|
-
* </DropProvider>
|
|
189
|
-
* );
|
|
190
|
-
* }
|
|
191
|
-
* ```
|
|
192
|
-
*
|
|
193
|
-
* @example
|
|
194
|
-
* Draggable with disabled state and conditional behavior:
|
|
195
|
-
* ```typescript
|
|
196
|
-
* function ConditionalDraggable({ item, canDrag }) {
|
|
197
|
-
* return (
|
|
198
|
-
* <Draggable
|
|
199
|
-
* data={item}
|
|
200
|
-
* dragDisabled={!canDrag}
|
|
201
|
-
* onDragStart={(data) => {
|
|
202
|
-
* if (data.locked) {
|
|
203
|
-
* showError('This item is locked');
|
|
204
|
-
* return;
|
|
205
|
-
* }
|
|
206
|
-
* analytics.track('drag_start', { itemId: data.id });
|
|
207
|
-
* }}
|
|
208
|
-
* style={[
|
|
209
|
-
* styles.item,
|
|
210
|
-
* !canDrag && styles.disabled
|
|
211
|
-
* ]}
|
|
212
|
-
* >
|
|
213
|
-
* <View style={styles.itemContent}>
|
|
214
|
-
* <Text style={styles.itemTitle}>{item.title}</Text>
|
|
215
|
-
* {item.locked && <Icon name="lock" size={16} />}
|
|
216
|
-
* {!canDrag && <Text style={styles.disabledText}>Drag disabled</Text>}
|
|
217
|
-
* </View>
|
|
218
|
-
* </Draggable>
|
|
219
|
-
* );
|
|
220
|
-
* }
|
|
221
|
-
* ```
|
|
222
|
-
*
|
|
223
|
-
* @see {@link Draggable.Handle} for creating drag handles
|
|
224
|
-
* @see {@link useDraggable} for the underlying hook
|
|
225
|
-
* @see {@link Droppable} for drop zone components
|
|
226
|
-
* @see {@link DraggableState} for state management
|
|
227
|
-
* @see {@link CollisionAlgorithm} for collision detection options
|
|
228
|
-
* @see {@link UseDraggableOptions} for configuration options
|
|
229
|
-
* @see {@link UseDraggableReturn} for hook return details
|
|
230
|
-
* @see {@link DropProvider} for drag-and-drop context setup
|
|
231
|
-
*/
|
|
232
|
-
const DraggableComponent = ({
|
|
233
|
-
// Destructure component-specific props first
|
|
234
|
-
style: componentStyle, children,
|
|
235
|
-
// Collect all other props (which are now the modified UseDraggableOptions)
|
|
236
|
-
...useDraggableHookOptions }) => {
|
|
237
|
-
// Pass the collected useDraggableHookOptions object directly to the hook
|
|
238
|
-
// Also pass children and Handle component reference for handle detection
|
|
239
|
-
const { animatedViewProps, gesture, state, hasHandle, animatedViewRef } = useDraggable({
|
|
240
|
-
...useDraggableHookOptions,
|
|
241
|
-
children,
|
|
242
|
-
handleComponent: Handle,
|
|
243
|
-
});
|
|
244
|
-
// Create the context value
|
|
245
|
-
const contextValue = {
|
|
246
|
-
gesture,
|
|
247
|
-
state,
|
|
248
|
-
};
|
|
249
|
-
// Render the component
|
|
250
|
-
const content = (<Animated.View ref={animatedViewRef} {...animatedViewProps} style={[componentStyle, animatedViewProps.style]} collapsable={false}>
|
|
251
|
-
<DraggableContext.Provider value={contextValue}>
|
|
252
|
-
{children}
|
|
253
|
-
</DraggableContext.Provider>
|
|
254
|
-
</Animated.View>);
|
|
255
|
-
// If a handle is found, let the handle control the dragging
|
|
256
|
-
// Otherwise, the entire component is draggable
|
|
257
|
-
if (hasHandle) {
|
|
258
|
-
return content;
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
return <GestureDetector gesture={gesture}>{content}</GestureDetector>;
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
// Attach the Handle as a static property
|
|
265
|
-
export const Draggable = Object.assign(DraggableComponent, { Handle });
|
|
1
|
+
import React,{createContext,useContext}from"react";import Animated from"react-native-reanimated";import{GestureDetector}from"react-native-gesture-handler";import{useDraggable}from"../hooks/useDraggable";const DraggableContext=createContext(null),Handle=({children:e,style:t})=>{const a=useContext(DraggableContext);return a?React.createElement(GestureDetector,{gesture:a.gesture},React.createElement(Animated.View,{style:t},e)):React.createElement(React.Fragment,null,e)},DraggableComponent=({style:e,children:t,...a})=>{const{animatedViewProps:r,gesture:n,state:l,hasHandle:o,animatedViewRef:c}=useDraggable({...a,children:t,handleComponent:Handle}),s={gesture:n,state:l},g=React.createElement(Animated.View,{ref:c,...r,style:[e,r.style],collapsable:!1},React.createElement(DraggableContext.Provider,{value:s},t));return o?g:React.createElement(GestureDetector,{gesture:n},g)};export const Draggable=Object.assign(DraggableComponent,{Handle});
|
|
@@ -1,264 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DroppableProps } from "../types/droppable";
|
|
3
3
|
export declare const _getUniqueDroppableId: () => number;
|
|
4
|
-
/**
|
|
5
|
-
* A component that creates drop zones for receiving draggable items.
|
|
6
|
-
*
|
|
7
|
-
* The Droppable component provides visual feedback when draggable items hover over it
|
|
8
|
-
* and handles the drop logic when items are released. It integrates seamlessly with
|
|
9
|
-
* the drag-and-drop context to provide collision detection and proper positioning
|
|
10
|
-
* of dropped items.
|
|
11
|
-
*
|
|
12
|
-
* @template TData - The type of data that can be dropped on this droppable
|
|
13
|
-
* @param props - Configuration props for the droppable component
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* Basic drop zone:
|
|
17
|
-
* ```typescript
|
|
18
|
-
* import { Droppable } from './components/Droppable';
|
|
19
|
-
*
|
|
20
|
-
* function BasicDropZone() {
|
|
21
|
-
* const handleDrop = (data) => {
|
|
22
|
-
* console.log('Item dropped:', data);
|
|
23
|
-
* // Handle the dropped item
|
|
24
|
-
* addItemToList(data);
|
|
25
|
-
* };
|
|
26
|
-
*
|
|
27
|
-
* return (
|
|
28
|
-
* <Droppable onDrop={handleDrop}>
|
|
29
|
-
* <View style={styles.dropZone}>
|
|
30
|
-
* <Text>Drop items here</Text>
|
|
31
|
-
* </View>
|
|
32
|
-
* </Droppable>
|
|
33
|
-
* );
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* Drop zone with visual feedback:
|
|
39
|
-
* ```typescript
|
|
40
|
-
* function VisualDropZone() {
|
|
41
|
-
* const [isHovered, setIsHovered] = useState(false);
|
|
42
|
-
*
|
|
43
|
-
* return (
|
|
44
|
-
* <Droppable
|
|
45
|
-
* onDrop={(data) => {
|
|
46
|
-
* console.log('Dropped:', data.name);
|
|
47
|
-
* processDroppedItem(data);
|
|
48
|
-
* }}
|
|
49
|
-
* onActiveChange={setIsHovered}
|
|
50
|
-
* activeStyle={{
|
|
51
|
-
* backgroundColor: 'rgba(0, 255, 0, 0.2)',
|
|
52
|
-
* borderColor: '#00ff00',
|
|
53
|
-
* borderWidth: 2,
|
|
54
|
-
* transform: [{ scale: 1.05 }]
|
|
55
|
-
* }}
|
|
56
|
-
* style={styles.dropZone}
|
|
57
|
-
* >
|
|
58
|
-
* <View style={[
|
|
59
|
-
* styles.dropContent,
|
|
60
|
-
* isHovered && styles.hoveredContent
|
|
61
|
-
* ]}>
|
|
62
|
-
* <Icon
|
|
63
|
-
* name="cloud-upload"
|
|
64
|
-
* size={32}
|
|
65
|
-
* color={isHovered ? '#00ff00' : '#666'}
|
|
66
|
-
* />
|
|
67
|
-
* <Text style={styles.dropText}>
|
|
68
|
-
* {isHovered ? 'Release to drop' : 'Drag files here'}
|
|
69
|
-
* </Text>
|
|
70
|
-
* </View>
|
|
71
|
-
* </Droppable>
|
|
72
|
-
* );
|
|
73
|
-
* }
|
|
74
|
-
* ```
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* Drop zone with custom alignment and capacity:
|
|
78
|
-
* ```typescript
|
|
79
|
-
* function TaskColumn() {
|
|
80
|
-
* const [tasks, setTasks] = useState([]);
|
|
81
|
-
* const maxTasks = 5;
|
|
82
|
-
*
|
|
83
|
-
* return (
|
|
84
|
-
* <Droppable
|
|
85
|
-
* droppableId="todo-column"
|
|
86
|
-
* onDrop={(task) => {
|
|
87
|
-
* if (tasks.length < maxTasks) {
|
|
88
|
-
* setTasks(prev => [...prev, task]);
|
|
89
|
-
* updateTaskStatus(task.id, 'todo');
|
|
90
|
-
* }
|
|
91
|
-
* }}
|
|
92
|
-
* dropAlignment="top-center"
|
|
93
|
-
* dropOffset={{ x: 0, y: 10 }}
|
|
94
|
-
* capacity={maxTasks}
|
|
95
|
-
* activeStyle={{
|
|
96
|
-
* backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
|
97
|
-
* borderColor: '#3b82f6',
|
|
98
|
-
* borderWidth: 2,
|
|
99
|
-
* borderStyle: 'dashed'
|
|
100
|
-
* }}
|
|
101
|
-
* style={styles.column}
|
|
102
|
-
* >
|
|
103
|
-
* <Text style={styles.columnTitle}>
|
|
104
|
-
* To Do ({tasks.length}/{maxTasks})
|
|
105
|
-
* </Text>
|
|
106
|
-
*
|
|
107
|
-
* {tasks.map(task => (
|
|
108
|
-
* <TaskCard key={task.id} task={task} />
|
|
109
|
-
* ))}
|
|
110
|
-
*
|
|
111
|
-
* {tasks.length === 0 && (
|
|
112
|
-
* <Text style={styles.emptyText}>
|
|
113
|
-
* Drop tasks here
|
|
114
|
-
* </Text>
|
|
115
|
-
* )}
|
|
116
|
-
* </Droppable>
|
|
117
|
-
* );
|
|
118
|
-
* }
|
|
119
|
-
* ```
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* Conditional drop zone with validation:
|
|
123
|
-
* ```typescript
|
|
124
|
-
* function RestrictedDropZone() {
|
|
125
|
-
* const [canAcceptFiles, setCanAcceptFiles] = useState(true);
|
|
126
|
-
* const [uploadProgress, setUploadProgress] = useState(0);
|
|
127
|
-
*
|
|
128
|
-
* const handleDrop = (fileData) => {
|
|
129
|
-
* // Validate file type and size
|
|
130
|
-
* if (fileData.type !== 'image') {
|
|
131
|
-
* showError('Only image files are allowed');
|
|
132
|
-
* return;
|
|
133
|
-
* }
|
|
134
|
-
*
|
|
135
|
-
* if (fileData.size > 5000000) { // 5MB limit
|
|
136
|
-
* showError('File size must be under 5MB');
|
|
137
|
-
* return;
|
|
138
|
-
* }
|
|
139
|
-
*
|
|
140
|
-
* // Start upload
|
|
141
|
-
* setCanAcceptFiles(false);
|
|
142
|
-
* uploadFile(fileData, setUploadProgress)
|
|
143
|
-
* .then(() => {
|
|
144
|
-
* showSuccess('File uploaded successfully');
|
|
145
|
-
* setCanAcceptFiles(true);
|
|
146
|
-
* setUploadProgress(0);
|
|
147
|
-
* })
|
|
148
|
-
* .catch(() => {
|
|
149
|
-
* showError('Upload failed');
|
|
150
|
-
* setCanAcceptFiles(true);
|
|
151
|
-
* setUploadProgress(0);
|
|
152
|
-
* });
|
|
153
|
-
* };
|
|
154
|
-
*
|
|
155
|
-
* return (
|
|
156
|
-
* <Droppable
|
|
157
|
-
* onDrop={handleDrop}
|
|
158
|
-
* dropDisabled={!canAcceptFiles}
|
|
159
|
-
* onActiveChange={(active) => {
|
|
160
|
-
* if (active && !canAcceptFiles) {
|
|
161
|
-
* showTooltip('Upload in progress...');
|
|
162
|
-
* }
|
|
163
|
-
* }}
|
|
164
|
-
* activeStyle={{
|
|
165
|
-
* backgroundColor: canAcceptFiles
|
|
166
|
-
* ? 'rgba(34, 197, 94, 0.1)'
|
|
167
|
-
* : 'rgba(239, 68, 68, 0.1)',
|
|
168
|
-
* borderColor: canAcceptFiles ? '#22c55e' : '#ef4444'
|
|
169
|
-
* }}
|
|
170
|
-
* style={[
|
|
171
|
-
* styles.uploadZone,
|
|
172
|
-
* !canAcceptFiles && styles.disabled
|
|
173
|
-
* ]}
|
|
174
|
-
* >
|
|
175
|
-
* <View style={styles.uploadContent}>
|
|
176
|
-
* {uploadProgress > 0 ? (
|
|
177
|
-
* <>
|
|
178
|
-
* <ProgressBar progress={uploadProgress} />
|
|
179
|
-
* <Text>Uploading... {Math.round(uploadProgress * 100)}%</Text>
|
|
180
|
-
* </>
|
|
181
|
-
* ) : (
|
|
182
|
-
* <>
|
|
183
|
-
* <Icon
|
|
184
|
-
* name="image"
|
|
185
|
-
* size={48}
|
|
186
|
-
* color={canAcceptFiles ? '#22c55e' : '#ef4444'}
|
|
187
|
-
* />
|
|
188
|
-
* <Text style={styles.uploadText}>
|
|
189
|
-
* {canAcceptFiles
|
|
190
|
-
* ? 'Drop images here (max 5MB)'
|
|
191
|
-
* : 'Upload in progress...'}
|
|
192
|
-
* </Text>
|
|
193
|
-
* </>
|
|
194
|
-
* )}
|
|
195
|
-
* </View>
|
|
196
|
-
* </Droppable>
|
|
197
|
-
* );
|
|
198
|
-
* }
|
|
199
|
-
* ```
|
|
200
|
-
*
|
|
201
|
-
* @example
|
|
202
|
-
* Multiple drop zones with different behaviors:
|
|
203
|
-
* ```typescript
|
|
204
|
-
* function MultiDropZoneExample() {
|
|
205
|
-
* const [items, setItems] = useState([]);
|
|
206
|
-
* const [trash, setTrash] = useState([]);
|
|
207
|
-
*
|
|
208
|
-
* return (
|
|
209
|
-
* <DropProvider>
|
|
210
|
-
* <View style={styles.container}>
|
|
211
|
-
* {/* Source items *\/}
|
|
212
|
-
* {items.map(item => (
|
|
213
|
-
* <Draggable key={item.id} data={item}>
|
|
214
|
-
* <ItemCard item={item} />
|
|
215
|
-
* </Draggable>
|
|
216
|
-
* ))}
|
|
217
|
-
*
|
|
218
|
-
* {/* Archive drop zone *\/}
|
|
219
|
-
* <Droppable
|
|
220
|
-
* droppableId="archive"
|
|
221
|
-
* onDrop={(item) => {
|
|
222
|
-
* archiveItem(item.id);
|
|
223
|
-
* setItems(prev => prev.filter(i => i.id !== item.id));
|
|
224
|
-
* }}
|
|
225
|
-
* dropAlignment="center"
|
|
226
|
-
* activeStyle={styles.archiveActive}
|
|
227
|
-
* >
|
|
228
|
-
* <View style={styles.archiveZone}>
|
|
229
|
-
* <Icon name="archive" size={24} />
|
|
230
|
-
* <Text>Archive</Text>
|
|
231
|
-
* </View>
|
|
232
|
-
* </Droppable>
|
|
233
|
-
*
|
|
234
|
-
* {/* Trash drop zone *\/}
|
|
235
|
-
* <Droppable
|
|
236
|
-
* droppableId="trash"
|
|
237
|
-
* onDrop={(item) => {
|
|
238
|
-
* setTrash(prev => [...prev, item]);
|
|
239
|
-
* setItems(prev => prev.filter(i => i.id !== item.id));
|
|
240
|
-
* }}
|
|
241
|
-
* dropAlignment="center"
|
|
242
|
-
* activeStyle={styles.trashActive}
|
|
243
|
-
* capacity={10} // Max 10 items in trash
|
|
244
|
-
* >
|
|
245
|
-
* <View style={styles.trashZone}>
|
|
246
|
-
* <Icon name="trash" size={24} />
|
|
247
|
-
* <Text>Trash ({trash.length}/10)</Text>
|
|
248
|
-
* </View>
|
|
249
|
-
* </Droppable>
|
|
250
|
-
* </View>
|
|
251
|
-
* </DropProvider>
|
|
252
|
-
* );
|
|
253
|
-
* }
|
|
254
|
-
* ```
|
|
255
|
-
*
|
|
256
|
-
* @see {@link useDroppable} for the underlying hook
|
|
257
|
-
* @see {@link Draggable} for draggable components
|
|
258
|
-
* @see {@link DropAlignment} for alignment options
|
|
259
|
-
* @see {@link DropOffset} for offset configuration
|
|
260
|
-
* @see {@link UseDroppableOptions} for configuration options
|
|
261
|
-
* @see {@link UseDroppableReturn} for hook return details
|
|
262
|
-
* @see {@link DropProvider} for drag-and-drop context setup
|
|
263
|
-
*/
|
|
264
4
|
export declare const Droppable: <TData = unknown>({ onDrop, dropDisabled, onActiveChange, dropAlignment, dropOffset, activeStyle, droppableId, capacity, style, children, }: DroppableProps<TData>) => React.ReactElement;
|