react-native-reorderable-list 0.16.2 → 0.17.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/README.md +12 -5
- package/lib/commonjs/components/NestedReorderableList.js +6 -6
- package/lib/commonjs/components/NestedReorderableList.js.map +1 -1
- package/lib/commonjs/components/ReorderableList.js +3 -3
- package/lib/commonjs/components/ReorderableList.js.map +1 -1
- package/lib/commonjs/components/ReorderableListCell.js +20 -18
- package/lib/commonjs/components/ReorderableListCell.js.map +1 -1
- package/lib/commonjs/components/ReorderableListCore.js +168 -158
- package/lib/commonjs/components/ReorderableListCore.js.map +1 -1
- package/lib/commonjs/components/ScrollViewContainer.js +13 -12
- package/lib/commonjs/components/ScrollViewContainer.js.map +1 -1
- package/lib/commonjs/contexts/ReorderableListContext.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/components/NestedReorderableList.js +6 -6
- package/lib/module/components/NestedReorderableList.js.map +1 -1
- package/lib/module/components/ReorderableList.js +3 -3
- package/lib/module/components/ReorderableList.js.map +1 -1
- package/lib/module/components/ReorderableListCell.js +20 -18
- package/lib/module/components/ReorderableListCell.js.map +1 -1
- package/lib/module/components/ReorderableListCore.js +168 -158
- package/lib/module/components/ReorderableListCore.js.map +1 -1
- package/lib/module/components/ScrollViewContainer.js +13 -12
- package/lib/module/components/ScrollViewContainer.js.map +1 -1
- package/lib/module/contexts/ReorderableListContext.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/components/ReorderableListCell.d.ts +3 -3
- package/lib/typescript/components/ReorderableListCell.d.ts.map +1 -1
- package/lib/typescript/components/ReorderableListCore.d.ts +3 -3
- package/lib/typescript/components/ReorderableListCore.d.ts.map +1 -1
- package/lib/typescript/components/ScrollViewContainer.d.ts.map +1 -1
- package/lib/typescript/contexts/ReorderableListContext.d.ts +2 -1
- package/lib/typescript/contexts/ReorderableListContext.d.ts.map +1 -1
- package/lib/typescript/contexts/ScrollViewContainerContext.d.ts +3 -3
- package/lib/typescript/contexts/ScrollViewContainerContext.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types/props.d.ts +18 -4
- package/lib/typescript/types/props.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/NestedReorderableList.tsx +6 -6
- package/src/components/ReorderableList.tsx +3 -3
- package/src/components/ReorderableListCell.tsx +27 -19
- package/src/components/ReorderableListCore.tsx +277 -217
- package/src/components/ScrollViewContainer.tsx +27 -14
- package/src/contexts/ReorderableListContext.ts +2 -1
- package/src/contexts/ScrollViewContainerContext.ts +3 -3
- package/src/index.ts +2 -0
- package/src/types/props.ts +24 -5
|
@@ -31,9 +31,9 @@ const ReorderableListCore = ({
|
|
|
31
31
|
onDragEnd,
|
|
32
32
|
onIndexChange,
|
|
33
33
|
scrollViewContainerRef,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
scrollViewPageXY,
|
|
35
|
+
scrollViewSize,
|
|
36
|
+
scrollViewScrollOffsetXY,
|
|
37
37
|
scrollViewScrollEnabledProp,
|
|
38
38
|
setScrollViewForceDisableScroll,
|
|
39
39
|
scrollable,
|
|
@@ -58,35 +58,35 @@ const ReorderableListCore = ({
|
|
|
58
58
|
const scrollEnabledProp = (0, _hooks.usePropAsSharedValue)(scrollEnabled);
|
|
59
59
|
const currentScrollEnabled = (0, _reactNativeReanimated.useSharedValue)(scrollEnabled);
|
|
60
60
|
const gestureState = (0, _reactNativeReanimated.useSharedValue)(_reactNativeGestureHandler.State.UNDETERMINED);
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
// The scroll y translation of the list since drag start
|
|
69
|
-
const
|
|
70
|
-
// The initial scroll offset y of the list on drag start
|
|
71
|
-
const
|
|
72
|
-
// The scroll y translation of the ScrollViewContainer since drag start
|
|
73
|
-
const
|
|
74
|
-
// The initial scroll offset y of the ScrollViewContainer on drag start
|
|
75
|
-
const
|
|
76
|
-
const
|
|
61
|
+
const currentXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
62
|
+
const currentTranslationXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
63
|
+
const currentItemDragCenterXY = (0, _reactNativeReanimated.useSharedValue)(null);
|
|
64
|
+
const startItemDragCenterXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
65
|
+
const flatListScrollOffsetXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
66
|
+
const flatListSize = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
67
|
+
const flatListPageXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
68
|
+
// The scroll x or y translation of the list since drag start
|
|
69
|
+
const dragScrollTranslationXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
70
|
+
// The initial scroll offset x or y of the list on drag start
|
|
71
|
+
const dragInitialScrollOffsetXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
72
|
+
// The scroll x or y translation of the ScrollViewContainer since drag start
|
|
73
|
+
const scrollViewDragScrollTranslationXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
74
|
+
// The initial scroll offset x or y of the ScrollViewContainer on drag start
|
|
75
|
+
const scrollViewDragInitialScrollOffsetXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
76
|
+
const draggedSize = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
77
77
|
const itemOffset = (0, _reactNativeReanimated.useSharedValue)([]);
|
|
78
|
-
const
|
|
79
|
-
// We need to track data length since itemOffset and
|
|
78
|
+
const itemSize = (0, _reactNativeReanimated.useSharedValue)([]);
|
|
79
|
+
// We need to track data length since itemOffset and itemSize might contain more data than we need.
|
|
80
80
|
// e.g. items are removed from the list, in which case layout data for those items is set to 0.
|
|
81
81
|
const itemCount = (0, _reactNativeReanimated.useSharedValue)(data.length);
|
|
82
82
|
const autoscrollTrigger = (0, _reactNativeReanimated.useSharedValue)(-1);
|
|
83
83
|
const lastAutoscrollTrigger = (0, _reactNativeReanimated.useSharedValue)(-1);
|
|
84
|
-
const
|
|
84
|
+
const dragXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
85
85
|
const currentIndex = (0, _reactNativeReanimated.useSharedValue)(-1);
|
|
86
86
|
const draggedIndex = (0, _reactNativeReanimated.useSharedValue)(-1);
|
|
87
87
|
const state = (0, _reactNativeReanimated.useSharedValue)(_types.ReorderableListState.IDLE);
|
|
88
88
|
const dragEndHandlers = (0, _reactNativeReanimated.useSharedValue)([]);
|
|
89
|
-
const
|
|
89
|
+
const startXY = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
90
90
|
const scaleDefault = (0, _reactNativeReanimated.useSharedValue)(1);
|
|
91
91
|
const opacityDefault = (0, _reactNativeReanimated.useSharedValue)(1);
|
|
92
92
|
const dragDirection = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
@@ -98,9 +98,10 @@ const ReorderableListCore = ({
|
|
|
98
98
|
const animationDurationProp = (0, _hooks.usePropAsSharedValue)(animationDuration);
|
|
99
99
|
const autoscrollActivationDeltaProp = (0, _hooks.usePropAsSharedValue)(autoscrollActivationDelta);
|
|
100
100
|
const dragEnabledProp = (0, _hooks.usePropAsSharedValue)(dragEnabled ?? true);
|
|
101
|
+
const horizontalProp = (0, _hooks.usePropAsSharedValue)(!!rest.horizontal);
|
|
101
102
|
|
|
102
103
|
// Position of the list relative to the scroll container
|
|
103
|
-
const
|
|
104
|
+
const nestedFlatListPositionXY = (0, _reactNativeReanimated.useDerivedValue)(() => flatListPageXY.value - ((scrollViewPageXY === null || scrollViewPageXY === void 0 ? void 0 : scrollViewPageXY.value) || 0));
|
|
104
105
|
(0, _react.useEffect)(() => {
|
|
105
106
|
itemCount.value = data.length;
|
|
106
107
|
|
|
@@ -110,13 +111,13 @@ const ReorderableListCore = ({
|
|
|
110
111
|
if (data.length < prevItemCount.current) {
|
|
111
112
|
for (let i = data.length; i < prevItemCount.current; i++) {
|
|
112
113
|
(0, _reactNativeReanimated.runOnUI)(() => {
|
|
113
|
-
|
|
114
|
+
itemSize.value[i] = 0;
|
|
114
115
|
itemOffset.value[i] = 0;
|
|
115
116
|
})();
|
|
116
117
|
}
|
|
117
118
|
}
|
|
118
119
|
prevItemCount.current = data.length;
|
|
119
|
-
}, [data.length,
|
|
120
|
+
}, [data.length, itemSize, itemOffset, itemCount]);
|
|
120
121
|
(0, _react.useEffect)(() => {
|
|
121
122
|
if (!markedCellsRef.current ||
|
|
122
123
|
// Clean keys once they surpass by 10% the size of the list itself.
|
|
@@ -149,12 +150,13 @@ const ReorderableListCore = ({
|
|
|
149
150
|
return `${cellKey}#${mark}`;
|
|
150
151
|
}, []);
|
|
151
152
|
const listContextValue = (0, _react.useMemo)(() => ({
|
|
152
|
-
|
|
153
|
+
draggedSize,
|
|
153
154
|
currentIndex,
|
|
154
155
|
draggedIndex,
|
|
155
156
|
dragEndHandlers,
|
|
156
157
|
activeIndex,
|
|
157
158
|
itemLayoutAnimation: itemLayoutAnimationPropRef,
|
|
159
|
+
horizontal: horizontalProp,
|
|
158
160
|
cellAnimations: {
|
|
159
161
|
...cellAnimations,
|
|
160
162
|
transform: cellAnimations && 'transform' in cellAnimations ? cellAnimations.transform : [{
|
|
@@ -162,7 +164,7 @@ const ReorderableListCore = ({
|
|
|
162
164
|
}],
|
|
163
165
|
opacity: cellAnimations && 'opacity' in cellAnimations ? cellAnimations.opacity : opacityDefault
|
|
164
166
|
}
|
|
165
|
-
}), [
|
|
167
|
+
}), [draggedSize, currentIndex, draggedIndex, dragEndHandlers, activeIndex, cellAnimations, itemLayoutAnimationPropRef, scaleDefault, opacityDefault, horizontalProp]);
|
|
166
168
|
|
|
167
169
|
/**
|
|
168
170
|
* Decides the intended drag direction of the user.
|
|
@@ -174,41 +176,46 @@ const ReorderableListCore = ({
|
|
|
174
176
|
const setDragDirection = (0, _react.useCallback)(e => {
|
|
175
177
|
'worklet';
|
|
176
178
|
|
|
177
|
-
const
|
|
179
|
+
const absoluteXY = horizontalProp.value ? e.absoluteX : e.absoluteY;
|
|
180
|
+
const velocityXY = horizontalProp.value ? e.velocityX : e.velocityY;
|
|
181
|
+
const direction = velocityXY > 0 ? 1 : -1;
|
|
178
182
|
if (direction !== dragDirection.value) {
|
|
179
183
|
if (lastDragDirectionPivot.value === null) {
|
|
180
|
-
lastDragDirectionPivot.value =
|
|
181
|
-
} else if (Math.abs(
|
|
184
|
+
lastDragDirectionPivot.value = absoluteXY;
|
|
185
|
+
} else if (Math.abs(absoluteXY - lastDragDirectionPivot.value) >= autoscrollActivationDeltaProp.value) {
|
|
182
186
|
dragDirection.value = direction;
|
|
183
|
-
lastDragDirectionPivot.value =
|
|
187
|
+
lastDragDirectionPivot.value = absoluteXY;
|
|
184
188
|
}
|
|
185
189
|
}
|
|
186
|
-
}, [dragDirection, lastDragDirectionPivot, autoscrollActivationDeltaProp]);
|
|
187
|
-
const
|
|
190
|
+
}, [dragDirection, lastDragDirectionPivot, autoscrollActivationDeltaProp, horizontalProp]);
|
|
191
|
+
const setCurrentItemDragCenterXY = (0, _react.useCallback)(e => {
|
|
188
192
|
'worklet';
|
|
189
193
|
|
|
190
|
-
|
|
194
|
+
const translationXY = horizontalProp.value ? e.translationX : e.translationY;
|
|
195
|
+
if (currentItemDragCenterXY.value === null) {
|
|
191
196
|
if (currentIndex.value >= 0) {
|
|
192
|
-
const itemCenter =
|
|
193
|
-
// the y coordinate of the item relative to the list
|
|
194
|
-
const
|
|
195
|
-
const value =
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
const itemCenter = itemSize.value[currentIndex.value] * 0.5;
|
|
198
|
+
// the x or y coordinate of the item relative to the list
|
|
199
|
+
const itemXY = itemOffset.value[currentIndex.value] - (flatListScrollOffsetXY.value + scrollViewDragScrollTranslationXY.value);
|
|
200
|
+
const value = itemXY + itemCenter + translationXY;
|
|
201
|
+
startItemDragCenterXY.value = value;
|
|
202
|
+
currentItemDragCenterXY.value = value;
|
|
198
203
|
}
|
|
199
204
|
} else {
|
|
200
|
-
|
|
205
|
+
currentItemDragCenterXY.value = startItemDragCenterXY.value + translationXY;
|
|
201
206
|
}
|
|
202
|
-
}, [
|
|
207
|
+
}, [horizontalProp, currentItemDragCenterXY, currentIndex, startItemDragCenterXY, itemOffset, itemSize, flatListScrollOffsetXY, scrollViewDragScrollTranslationXY]);
|
|
203
208
|
const panGestureHandler = (0, _react.useMemo)(() => (panGesture || _reactNativeGestureHandler.Gesture.Pan()).onBegin(e => {
|
|
204
209
|
'worklet';
|
|
205
210
|
|
|
206
211
|
// prevent new dragging until item is completely released
|
|
207
212
|
if (state.value === _types.ReorderableListState.IDLE) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
const xy = horizontalProp.value ? e.x : e.y;
|
|
214
|
+
const translationXY = horizontalProp.value ? e.translationX : e.translationY;
|
|
215
|
+
startXY.value = xy;
|
|
216
|
+
currentXY.value = xy;
|
|
217
|
+
currentTranslationXY.value = translationXY;
|
|
218
|
+
dragXY.value = translationXY;
|
|
212
219
|
gestureState.value = e.state;
|
|
213
220
|
}
|
|
214
221
|
}).onUpdate(e => {
|
|
@@ -218,10 +225,11 @@ const ReorderableListCore = ({
|
|
|
218
225
|
setDragDirection(e);
|
|
219
226
|
}
|
|
220
227
|
if (state.value !== _types.ReorderableListState.RELEASED) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
setCurrentItemDragCenterXY(e);
|
|
229
|
+
const translationXY = horizontalProp.value ? e.translationX : e.translationY;
|
|
230
|
+
currentXY.value = startXY.value + translationXY;
|
|
231
|
+
currentTranslationXY.value = translationXY;
|
|
232
|
+
dragXY.value = translationXY + dragScrollTranslationXY.value + scrollViewDragScrollTranslationXY.value;
|
|
225
233
|
gestureState.value = e.state;
|
|
226
234
|
}
|
|
227
235
|
}).onEnd(e => {
|
|
@@ -232,7 +240,7 @@ const ReorderableListCore = ({
|
|
|
232
240
|
'worklet';
|
|
233
241
|
|
|
234
242
|
gestureState.value = e.state;
|
|
235
|
-
}), [panGesture, state,
|
|
243
|
+
}), [panGesture, state, startXY, currentXY, currentTranslationXY, dragXY, gestureState, dragScrollTranslationXY, scrollViewDragScrollTranslationXY, setDragDirection, setCurrentItemDragCenterXY, horizontalProp]);
|
|
236
244
|
const panGestureHandlerWithPropOptions = (0, _react.useMemo)(() => {
|
|
237
245
|
if (typeof panActivateAfterLongPress === 'number') {
|
|
238
246
|
panGestureHandler.activateAfterLongPress(panActivateAfterLongPress);
|
|
@@ -276,13 +284,13 @@ const ReorderableListCore = ({
|
|
|
276
284
|
|
|
277
285
|
state.value = _types.ReorderableListState.IDLE;
|
|
278
286
|
draggedIndex.value = -1;
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
287
|
+
dragXY.value = 0;
|
|
288
|
+
dragScrollTranslationXY.value = 0;
|
|
289
|
+
scrollViewDragScrollTranslationXY.value = 0;
|
|
282
290
|
dragDirection.value = 0;
|
|
283
291
|
lastDragDirectionPivot.value = null;
|
|
284
|
-
|
|
285
|
-
}, [state, draggedIndex,
|
|
292
|
+
currentItemDragCenterXY.value = null;
|
|
293
|
+
}, [state, draggedIndex, dragXY, dragScrollTranslationXY, scrollViewDragScrollTranslationXY, dragDirection, lastDragDirectionPivot, currentItemDragCenterXY]);
|
|
286
294
|
const resetSharedValuesAfterAnimations = (0, _react.useCallback)(() => {
|
|
287
295
|
setTimeout((0, _reactNativeReanimated.runOnUI)(resetSharedValues), animationDurationProp.value);
|
|
288
296
|
}, [resetSharedValues, animationDurationProp]);
|
|
@@ -319,14 +327,14 @@ const ReorderableListCore = ({
|
|
|
319
327
|
const index1 = itemDirection ? from : to;
|
|
320
328
|
const index2 = itemDirection ? to : from;
|
|
321
329
|
const newOffset1 = itemOffset.value[index1];
|
|
322
|
-
const
|
|
323
|
-
const newOffset2 = itemOffset.value[index2] +
|
|
324
|
-
const
|
|
330
|
+
const newSize1 = itemSize.value[index2];
|
|
331
|
+
const newOffset2 = itemOffset.value[index2] + itemSize.value[index2] - itemSize.value[index1];
|
|
332
|
+
const newSize2 = itemSize.value[index1];
|
|
325
333
|
itemOffset.value[index1] = newOffset1;
|
|
326
|
-
|
|
334
|
+
itemSize.value[index1] = newSize1;
|
|
327
335
|
itemOffset.value[index2] = newOffset2;
|
|
328
|
-
|
|
329
|
-
}, [itemOffset,
|
|
336
|
+
itemSize.value[index2] = newSize2;
|
|
337
|
+
}, [itemOffset, itemSize]);
|
|
330
338
|
|
|
331
339
|
/**
|
|
332
340
|
* Computes a potential new drop container for the current dragged item and evaluates
|
|
@@ -338,29 +346,29 @@ const ReorderableListCore = ({
|
|
|
338
346
|
const computeCurrentIndex = (0, _react.useCallback)(() => {
|
|
339
347
|
'worklet';
|
|
340
348
|
|
|
341
|
-
if (
|
|
349
|
+
if (currentItemDragCenterXY.value === null) {
|
|
342
350
|
return currentIndex.value;
|
|
343
351
|
}
|
|
344
352
|
|
|
345
|
-
//
|
|
346
|
-
const
|
|
353
|
+
// Apply scroll offset and scroll container translation.
|
|
354
|
+
const relativeDragCenterXY = flatListScrollOffsetXY.value + scrollViewDragScrollTranslationXY.value + currentItemDragCenterXY.value;
|
|
347
355
|
const currentOffset = itemOffset.value[currentIndex.value];
|
|
348
|
-
const
|
|
349
|
-
const currentCenter = currentOffset +
|
|
356
|
+
const currentSize = itemSize.value[currentIndex.value];
|
|
357
|
+
const currentCenter = currentOffset + currentSize * 0.5;
|
|
350
358
|
const max = itemCount.value;
|
|
351
|
-
const possibleIndex =
|
|
359
|
+
const possibleIndex = relativeDragCenterXY < currentCenter ? Math.max(0, currentIndex.value - 1) : Math.min(max - 1, currentIndex.value + 1);
|
|
352
360
|
if (currentIndex.value !== possibleIndex) {
|
|
353
361
|
let possibleOffset = itemOffset.value[possibleIndex];
|
|
354
362
|
if (possibleIndex > currentIndex.value) {
|
|
355
|
-
possibleOffset +=
|
|
363
|
+
possibleOffset += itemSize.value[possibleIndex] - currentSize;
|
|
356
364
|
}
|
|
357
|
-
const possibleCenter = possibleOffset +
|
|
358
|
-
const distanceFromCurrent = Math.abs(
|
|
359
|
-
const distanceFromPossible = Math.abs(
|
|
365
|
+
const possibleCenter = possibleOffset + currentSize * 0.5;
|
|
366
|
+
const distanceFromCurrent = Math.abs(relativeDragCenterXY - currentCenter);
|
|
367
|
+
const distanceFromPossible = Math.abs(relativeDragCenterXY - possibleCenter);
|
|
360
368
|
return distanceFromCurrent <= distanceFromPossible ? currentIndex.value : possibleIndex;
|
|
361
369
|
}
|
|
362
370
|
return currentIndex.value;
|
|
363
|
-
}, [currentIndex,
|
|
371
|
+
}, [currentIndex, currentItemDragCenterXY, itemCount, itemOffset, itemSize, flatListScrollOffsetXY, scrollViewDragScrollTranslationXY]);
|
|
364
372
|
const setCurrentIndex = (0, _react.useCallback)(() => {
|
|
365
373
|
'worklet';
|
|
366
374
|
|
|
@@ -382,7 +390,7 @@ const ReorderableListCore = ({
|
|
|
382
390
|
scaleDefault.value = (0, _reactNativeReanimated.withTiming)(scaleConfig.toValue, scaleConfig);
|
|
383
391
|
}
|
|
384
392
|
|
|
385
|
-
//
|
|
393
|
+
// If no custom opacity run the default.
|
|
386
394
|
if (!(cellAnimations && 'opacity' in cellAnimations)) {
|
|
387
395
|
const opacityConfig = _constants.OPACITY_ANIMATION_CONFIG_DEFAULT[type];
|
|
388
396
|
opacityDefault.value = (0, _reactNativeReanimated.withTiming)(opacityConfig.toValue, opacityConfig);
|
|
@@ -398,7 +406,7 @@ const ReorderableListCore = ({
|
|
|
398
406
|
(0, _reactNativeReanimated.runOnJS)(setActiveIndex)(-1);
|
|
399
407
|
}
|
|
400
408
|
|
|
401
|
-
//
|
|
409
|
+
// Trigger onDragEnd event.
|
|
402
410
|
let e = {
|
|
403
411
|
from: draggedIndex.value,
|
|
404
412
|
to: currentIndex.value
|
|
@@ -411,23 +419,23 @@ const ReorderableListCore = ({
|
|
|
411
419
|
|
|
412
420
|
// they are actually swapped on drag translation
|
|
413
421
|
const currentItemOffset = itemOffset.value[draggedIndex.value];
|
|
414
|
-
const
|
|
422
|
+
const currentItemSize = itemSize.value[draggedIndex.value];
|
|
415
423
|
const draggedItemOffset = itemOffset.value[currentIndex.value];
|
|
416
|
-
const
|
|
417
|
-
const
|
|
424
|
+
const draggedItemSize = itemSize.value[currentIndex.value];
|
|
425
|
+
const newPositionXY = currentIndex.value > draggedIndex.value ? draggedItemOffset - currentItemOffset : draggedItemOffset - currentItemOffset + (draggedItemSize - currentItemSize);
|
|
418
426
|
runDefaultDragAnimations('end');
|
|
419
|
-
if (
|
|
420
|
-
//
|
|
421
|
-
|
|
427
|
+
if (dragXY.value !== newPositionXY) {
|
|
428
|
+
// Animate dragged item to its new position on release.
|
|
429
|
+
dragXY.value = (0, _reactNativeReanimated.withTiming)(newPositionXY, {
|
|
422
430
|
duration: animationDurationProp.value,
|
|
423
431
|
easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.ease)
|
|
424
432
|
}, () => {
|
|
425
433
|
(0, _reactNativeReanimated.runOnJS)(reorder)(draggedIndex.value, currentIndex.value);
|
|
426
434
|
});
|
|
427
435
|
} else {
|
|
428
|
-
//
|
|
436
|
+
// User might drag and release the item without moving it so,
|
|
429
437
|
// since the animation end callback is not executed in that case
|
|
430
|
-
// we need to reset values as the reorder function would do
|
|
438
|
+
// we need to reset values as the reorder function would do.
|
|
431
439
|
(0, _reactNativeReanimated.runOnJS)(resetSharedValuesAfterAnimations)();
|
|
432
440
|
}
|
|
433
441
|
}
|
|
@@ -435,58 +443,58 @@ const ReorderableListCore = ({
|
|
|
435
443
|
const computeHiddenArea = (0, _react.useCallback)(() => {
|
|
436
444
|
'worklet';
|
|
437
445
|
|
|
438
|
-
if (!
|
|
446
|
+
if (!scrollViewScrollOffsetXY || !scrollViewSize) {
|
|
439
447
|
return {
|
|
440
|
-
|
|
441
|
-
|
|
448
|
+
start: 0,
|
|
449
|
+
end: 0
|
|
442
450
|
};
|
|
443
451
|
}
|
|
444
452
|
|
|
445
453
|
// hidden area cannot be negative
|
|
446
|
-
const
|
|
447
|
-
const
|
|
454
|
+
const start = Math.max(0, scrollViewScrollOffsetXY.value - nestedFlatListPositionXY.value);
|
|
455
|
+
const end = Math.max(0, nestedFlatListPositionXY.value + flatListSize.value - (scrollViewScrollOffsetXY.value + scrollViewSize.value));
|
|
448
456
|
return {
|
|
449
|
-
|
|
450
|
-
|
|
457
|
+
start,
|
|
458
|
+
end
|
|
451
459
|
};
|
|
452
|
-
}, [
|
|
460
|
+
}, [scrollViewScrollOffsetXY, scrollViewSize, nestedFlatListPositionXY, flatListSize]);
|
|
453
461
|
const computeThresholdArea = (0, _react.useCallback)(() => {
|
|
454
462
|
'worklet';
|
|
455
463
|
|
|
456
464
|
const hiddenArea = computeHiddenArea();
|
|
457
|
-
const
|
|
458
|
-
const
|
|
465
|
+
const offsetStart = Math.max(0, (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.start) || (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.top) || 0);
|
|
466
|
+
const offsetEnd = Math.max(0, (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.end) || (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.bottom) || 0);
|
|
459
467
|
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
460
|
-
const
|
|
461
|
-
const area =
|
|
462
|
-
const
|
|
463
|
-
const
|
|
468
|
+
const visibleSize = flatListSize.value - (hiddenArea.start + hiddenArea.end) - (offsetStart + offsetEnd);
|
|
469
|
+
const area = visibleSize * threshold;
|
|
470
|
+
const start = area + offsetStart;
|
|
471
|
+
const end = flatListSize.value - area - offsetEnd;
|
|
464
472
|
return {
|
|
465
|
-
|
|
466
|
-
|
|
473
|
+
start,
|
|
474
|
+
end
|
|
467
475
|
};
|
|
468
|
-
}, [computeHiddenArea, autoscrollThreshold, autoscrollThresholdOffset,
|
|
476
|
+
}, [computeHiddenArea, autoscrollThreshold, autoscrollThresholdOffset, flatListSize]);
|
|
469
477
|
const computeContainerThresholdArea = (0, _react.useCallback)(() => {
|
|
470
478
|
'worklet';
|
|
471
479
|
|
|
472
|
-
if (!
|
|
480
|
+
if (!scrollViewSize) {
|
|
473
481
|
return {
|
|
474
|
-
|
|
475
|
-
|
|
482
|
+
start: -Infinity,
|
|
483
|
+
end: Infinity
|
|
476
484
|
};
|
|
477
485
|
}
|
|
478
|
-
const
|
|
479
|
-
const
|
|
486
|
+
const offsetStart = Math.max(0, (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.start) || (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.top) || 0);
|
|
487
|
+
const offsetEnd = Math.max(0, (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.end) || (autoscrollThresholdOffset === null || autoscrollThresholdOffset === void 0 ? void 0 : autoscrollThresholdOffset.bottom) || 0);
|
|
480
488
|
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
481
|
-
const
|
|
482
|
-
const area =
|
|
483
|
-
const
|
|
484
|
-
const
|
|
489
|
+
const visibleSize = scrollViewSize.value - (offsetStart + offsetEnd);
|
|
490
|
+
const area = visibleSize * threshold;
|
|
491
|
+
const start = area + offsetStart;
|
|
492
|
+
const end = visibleSize - area - offsetEnd;
|
|
485
493
|
return {
|
|
486
|
-
|
|
487
|
-
|
|
494
|
+
start,
|
|
495
|
+
end
|
|
488
496
|
};
|
|
489
|
-
}, [autoscrollThreshold, autoscrollThresholdOffset,
|
|
497
|
+
}, [autoscrollThreshold, autoscrollThresholdOffset, scrollViewSize]);
|
|
490
498
|
const shouldScrollContainer = (0, _react.useCallback)(y => {
|
|
491
499
|
'worklet';
|
|
492
500
|
|
|
@@ -495,52 +503,53 @@ const ReorderableListCore = ({
|
|
|
495
503
|
|
|
496
504
|
// We should scroll the container if there's a hidden part of the nested list.
|
|
497
505
|
// We might have floating errors like 0.0001 which we should ignore.
|
|
498
|
-
return nestedListHiddenArea.
|
|
506
|
+
return nestedListHiddenArea.start > 0.01 && y <= containerThresholdArea.start || nestedListHiddenArea.end > 0.01 && y >= containerThresholdArea.end;
|
|
499
507
|
}, [computeHiddenArea, computeContainerThresholdArea]);
|
|
500
|
-
const
|
|
508
|
+
const getRelativeContainerXY = (0, _react.useCallback)(() => {
|
|
501
509
|
'worklet';
|
|
502
510
|
|
|
503
|
-
return
|
|
504
|
-
}, [
|
|
505
|
-
const
|
|
511
|
+
return currentXY.value + nestedFlatListPositionXY.value - scrollViewDragInitialScrollOffsetXY.value;
|
|
512
|
+
}, [currentXY, nestedFlatListPositionXY, scrollViewDragInitialScrollOffsetXY]);
|
|
513
|
+
const getRelativeListXY = (0, _react.useCallback)(() => {
|
|
506
514
|
'worklet';
|
|
507
515
|
|
|
508
|
-
return
|
|
509
|
-
}, [
|
|
516
|
+
return currentXY.value + scrollViewDragScrollTranslationXY.value;
|
|
517
|
+
}, [currentXY, scrollViewDragScrollTranslationXY]);
|
|
510
518
|
const scrollDirection = (0, _react.useCallback)(() => {
|
|
511
519
|
'worklet';
|
|
512
520
|
|
|
513
|
-
const
|
|
514
|
-
if (shouldScrollContainer(
|
|
521
|
+
const relativeContainerXY = getRelativeContainerXY();
|
|
522
|
+
if (shouldScrollContainer(relativeContainerXY)) {
|
|
515
523
|
const containerThresholdArea = computeContainerThresholdArea();
|
|
516
|
-
if (
|
|
524
|
+
if (relativeContainerXY <= containerThresholdArea.start) {
|
|
517
525
|
return -1;
|
|
518
526
|
}
|
|
519
|
-
if (
|
|
527
|
+
if (relativeContainerXY >= containerThresholdArea.end) {
|
|
520
528
|
return 1;
|
|
521
529
|
}
|
|
522
530
|
} else if (scrollable) {
|
|
523
|
-
const
|
|
531
|
+
const relativeListXY = getRelativeListXY();
|
|
524
532
|
const thresholdArea = computeThresholdArea();
|
|
525
|
-
if (
|
|
533
|
+
if (relativeListXY <= thresholdArea.start) {
|
|
526
534
|
return -1;
|
|
527
535
|
}
|
|
528
|
-
if (
|
|
536
|
+
if (relativeListXY >= thresholdArea.end) {
|
|
529
537
|
return 1;
|
|
530
538
|
}
|
|
531
539
|
}
|
|
532
540
|
return 0;
|
|
533
|
-
}, [shouldScrollContainer, computeThresholdArea, computeContainerThresholdArea,
|
|
534
|
-
(0, _reactNativeReanimated.useAnimatedReaction)(() =>
|
|
541
|
+
}, [shouldScrollContainer, computeThresholdArea, computeContainerThresholdArea, getRelativeContainerXY, getRelativeListXY, scrollable]);
|
|
542
|
+
(0, _reactNativeReanimated.useAnimatedReaction)(() => currentXY.value, () => {
|
|
535
543
|
if (state.value === _types.ReorderableListState.DRAGGED || state.value === _types.ReorderableListState.AUTOSCROLL) {
|
|
536
544
|
setCurrentIndex();
|
|
537
545
|
|
|
538
546
|
// Trigger autoscroll when:
|
|
539
|
-
// 1. Within the threshold area (
|
|
547
|
+
// 1. Within the threshold area (start or end of list)
|
|
540
548
|
// 2. Have dragged in the same direction as the scroll
|
|
541
549
|
// 3. Not already in autoscroll mode
|
|
542
550
|
if (dragDirection.value === scrollDirection()) {
|
|
543
|
-
// When the first two conditions are met and it's already in autoscroll mode,
|
|
551
|
+
// When the first two conditions are met and it's already in autoscroll mode,
|
|
552
|
+
// we let it continue (no-op).
|
|
544
553
|
if (state.value !== _types.ReorderableListState.AUTOSCROLL) {
|
|
545
554
|
state.value = _types.ReorderableListState.AUTOSCROLL;
|
|
546
555
|
lastAutoscrollTrigger.value = autoscrollTrigger.value;
|
|
@@ -555,17 +564,18 @@ const ReorderableListCore = ({
|
|
|
555
564
|
if (autoscrollTrigger.value !== lastAutoscrollTrigger.value && state.value === _types.ReorderableListState.AUTOSCROLL) {
|
|
556
565
|
const autoscrollIncrement = dragDirection.value * _constants.AUTOSCROLL_CONFIG.increment * autoscrollSpeedScale;
|
|
557
566
|
if (autoscrollIncrement !== 0) {
|
|
558
|
-
let scrollOffset =
|
|
567
|
+
let scrollOffset = flatListScrollOffsetXY.value;
|
|
559
568
|
let listRef = flatListRef;
|
|
560
569
|
|
|
561
570
|
// Checking on every autoscroll whether to scroll the container,
|
|
562
571
|
// this allows to smoothly pass the scroll from the container to the nested list
|
|
563
572
|
// without any gesture input.
|
|
564
|
-
if (
|
|
565
|
-
scrollOffset =
|
|
573
|
+
if (scrollViewScrollOffsetXY && shouldScrollContainer(getRelativeContainerXY())) {
|
|
574
|
+
scrollOffset = scrollViewScrollOffsetXY.value;
|
|
566
575
|
listRef = scrollViewContainerRef;
|
|
567
576
|
}
|
|
568
|
-
|
|
577
|
+
const scrollToValue = scrollOffset + autoscrollIncrement;
|
|
578
|
+
(0, _reactNativeReanimated.scrollTo)(listRef, horizontalProp.value ? scrollToValue : 0, horizontalProp.value ? 0 : scrollToValue, true);
|
|
569
579
|
}
|
|
570
580
|
|
|
571
581
|
// when autoscrolling user may not be moving his finger so we need
|
|
@@ -576,16 +586,16 @@ const ReorderableListCore = ({
|
|
|
576
586
|
|
|
577
587
|
// flatlist scroll handler
|
|
578
588
|
const handleScroll = (0, _reactNativeReanimated.useAnimatedScrollHandler)(e => {
|
|
579
|
-
|
|
589
|
+
flatListScrollOffsetXY.value = horizontalProp.value ? e.contentOffset.x : e.contentOffset.y;
|
|
580
590
|
|
|
581
591
|
// Checking if the list is not scrollable instead of the scrolling state.
|
|
582
592
|
// Fixes a bug on iOS where the item is shifted after autoscrolling and then
|
|
583
593
|
// moving away from the area.
|
|
584
594
|
if (!currentScrollEnabled.value) {
|
|
585
|
-
|
|
595
|
+
dragScrollTranslationXY.value = flatListScrollOffsetXY.value - dragInitialScrollOffsetXY.value;
|
|
586
596
|
}
|
|
587
597
|
if (state.value === _types.ReorderableListState.AUTOSCROLL) {
|
|
588
|
-
|
|
598
|
+
dragXY.value = currentTranslationXY.value + dragScrollTranslationXY.value + scrollViewDragScrollTranslationXY.value;
|
|
589
599
|
lastAutoscrollTrigger.value = autoscrollTrigger.value;
|
|
590
600
|
autoscrollTrigger.value = (0, _reactNativeReanimated.withDelay)(autoscrollDelay, (0, _reactNativeReanimated.withTiming)(autoscrollTrigger.value * -1, {
|
|
591
601
|
duration: 0
|
|
@@ -594,16 +604,16 @@ const ReorderableListCore = ({
|
|
|
594
604
|
});
|
|
595
605
|
|
|
596
606
|
// container scroll handler
|
|
597
|
-
(0, _reactNativeReanimated.useAnimatedReaction)(() =>
|
|
607
|
+
(0, _reactNativeReanimated.useAnimatedReaction)(() => scrollViewScrollOffsetXY === null || scrollViewScrollOffsetXY === void 0 ? void 0 : scrollViewScrollOffsetXY.value, value => {
|
|
598
608
|
if (value) {
|
|
599
609
|
// Checking if the list is not scrollable instead of the scrolling state.
|
|
600
|
-
// Fixes a bug on iOS where the item is shifted after autoscrolling and then
|
|
610
|
+
// Fixes a bug on iOS where the item is shifted, after autoscrolling and then
|
|
601
611
|
// moving away from the area.
|
|
602
612
|
if (!currentScrollEnabled.value) {
|
|
603
|
-
|
|
613
|
+
scrollViewDragScrollTranslationXY.value = value - scrollViewDragInitialScrollOffsetXY.value;
|
|
604
614
|
}
|
|
605
615
|
if (state.value === _types.ReorderableListState.AUTOSCROLL) {
|
|
606
|
-
|
|
616
|
+
dragXY.value = currentTranslationXY.value + scrollViewDragScrollTranslationXY.value;
|
|
607
617
|
lastAutoscrollTrigger.value = autoscrollTrigger.value;
|
|
608
618
|
autoscrollTrigger.value = (0, _reactNativeReanimated.withDelay)(autoscrollDelay, (0, _reactNativeReanimated.withTiming)(autoscrollTrigger.value * -1, {
|
|
609
619
|
duration: 0
|
|
@@ -618,17 +628,17 @@ const ReorderableListCore = ({
|
|
|
618
628
|
return;
|
|
619
629
|
}
|
|
620
630
|
|
|
621
|
-
//
|
|
631
|
+
// Allow new drag when item is completely released.
|
|
622
632
|
if (state.value === _types.ReorderableListState.IDLE) {
|
|
623
|
-
//
|
|
624
|
-
// after scrolling the parent list it would offset the new dragged item in another nested list
|
|
633
|
+
// Resetting shared values again fixes a flickeing bug in nested lists where
|
|
634
|
+
// after scrolling the parent list it would offset the new dragged item in another nested list.
|
|
625
635
|
resetSharedValues();
|
|
626
636
|
if (shouldUpdateActiveItem) {
|
|
627
637
|
(0, _reactNativeReanimated.runOnJS)(setActiveIndex)(index);
|
|
628
638
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
639
|
+
dragInitialScrollOffsetXY.value = flatListScrollOffsetXY.value;
|
|
640
|
+
scrollViewDragInitialScrollOffsetXY.value = (scrollViewScrollOffsetXY === null || scrollViewScrollOffsetXY === void 0 ? void 0 : scrollViewScrollOffsetXY.value) || 0;
|
|
641
|
+
draggedSize.value = itemSize.value[index];
|
|
632
642
|
draggedIndex.value = index;
|
|
633
643
|
currentIndex.value = index;
|
|
634
644
|
state.value = _types.ReorderableListState.DRAGGED;
|
|
@@ -640,29 +650,30 @@ const ReorderableListCore = ({
|
|
|
640
650
|
index
|
|
641
651
|
});
|
|
642
652
|
}
|
|
643
|
-
}, [dragEnabledProp, resetSharedValues, shouldUpdateActiveItem,
|
|
653
|
+
}, [dragEnabledProp, resetSharedValues, shouldUpdateActiveItem, dragInitialScrollOffsetXY, scrollViewScrollOffsetXY, scrollViewDragInitialScrollOffsetXY, setScrollEnabled, currentIndex, draggedSize, draggedIndex, state, flatListScrollOffsetXY, itemSize, onDragStart, runDefaultDragAnimations]);
|
|
644
654
|
const handleFlatListLayout = (0, _react.useCallback)(e => {
|
|
645
|
-
|
|
655
|
+
flatListSize.value = horizontalProp.value ? e.nativeEvent.layout.width : e.nativeEvent.layout.height;
|
|
646
656
|
|
|
647
657
|
// If nested in a scroll container.
|
|
648
|
-
if (
|
|
649
|
-
// Timeout fixes a bug where measure returns height 0.
|
|
658
|
+
if (scrollViewScrollOffsetXY) {
|
|
659
|
+
// Timeout fixes a bug where measure returns width or height 0.
|
|
650
660
|
setTimeout(() => {
|
|
651
661
|
(0, _reactNativeReanimated.runOnUI)(() => {
|
|
652
662
|
const measurement = (0, _reactNativeReanimated.measure)(flatListRef);
|
|
653
663
|
if (!measurement) {
|
|
654
664
|
return;
|
|
655
665
|
}
|
|
666
|
+
const pageXY = horizontalProp.value ? measurement.pageX : measurement.pageY;
|
|
656
667
|
|
|
657
668
|
// We need to use pageY because the list might be nested into other views,
|
|
658
669
|
// It's important that we take the measurement of the list without any scroll offset
|
|
659
670
|
// from the scroll container.
|
|
660
|
-
|
|
671
|
+
flatListPageXY.value = pageXY + ((scrollViewScrollOffsetXY === null || scrollViewScrollOffsetXY === void 0 ? void 0 : scrollViewScrollOffsetXY.value) || 0);
|
|
661
672
|
})();
|
|
662
673
|
}, 100);
|
|
663
674
|
}
|
|
664
675
|
onLayout === null || onLayout === void 0 || onLayout(e);
|
|
665
|
-
}, [flatListRef,
|
|
676
|
+
}, [flatListRef, flatListPageXY, flatListSize, horizontalProp, scrollViewScrollOffsetXY, onLayout]);
|
|
666
677
|
const handleRef = (0, _react.useCallback)(value => {
|
|
667
678
|
flatListRef(value);
|
|
668
679
|
if (typeof ref === 'function') {
|
|
@@ -672,7 +683,7 @@ const ReorderableListCore = ({
|
|
|
672
683
|
}
|
|
673
684
|
}, [flatListRef, ref]);
|
|
674
685
|
const combinedGesture = (0, _react.useMemo)(() => {
|
|
675
|
-
//
|
|
686
|
+
// Android is able to handle nested scroll view, but not the full size ones like iOS.
|
|
676
687
|
if (outerScrollGesture && !(_reactNative.Platform.OS === 'android' && scrollable)) {
|
|
677
688
|
return _reactNativeGestureHandler.Gesture.Simultaneous(outerScrollGesture, gestureHandler);
|
|
678
689
|
}
|
|
@@ -686,8 +697,8 @@ const ReorderableListCore = ({
|
|
|
686
697
|
// forces remount with key change on reorder
|
|
687
698
|
key: createCellKey(cellKey),
|
|
688
699
|
itemOffset: itemOffset,
|
|
689
|
-
|
|
690
|
-
|
|
700
|
+
itemSize: itemSize,
|
|
701
|
+
dragXY: dragXY,
|
|
691
702
|
draggedIndex: draggedIndex,
|
|
692
703
|
animationDuration: animationDurationProp,
|
|
693
704
|
startDrag: startDrag
|
|
@@ -704,7 +715,6 @@ const ReorderableListCore = ({
|
|
|
704
715
|
onLayout: handleFlatListLayout,
|
|
705
716
|
onScroll: composedScrollHandler,
|
|
706
717
|
scrollEventThrottle: 1,
|
|
707
|
-
horizontal: false,
|
|
708
718
|
removeClippedSubviews: false,
|
|
709
719
|
numColumns: 1
|
|
710
720
|
// We force disable scroll or let the component prop control it.
|