react-native-reorderable-list 0.8.0 → 0.10.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 +104 -32
- package/lib/commonjs/components/ReorderableListCell.js +19 -14
- package/lib/commonjs/components/ReorderableListCell.js.map +1 -1
- package/lib/commonjs/components/ReorderableListCore/ReorderableListCore.js +11 -11
- package/lib/commonjs/components/ReorderableListCore/ReorderableListCore.js.map +1 -1
- package/lib/commonjs/components/ReorderableListCore/useReorderableListCore.js +50 -22
- package/lib/commonjs/components/ReorderableListCore/useReorderableListCore.js.map +1 -1
- package/lib/commonjs/components/helpers.js +32 -0
- package/lib/commonjs/components/helpers.js.map +1 -0
- package/lib/commonjs/contexts/ReorderableCellContext.js.map +1 -1
- package/lib/commonjs/contexts/ReorderableListContext.js.map +1 -1
- package/lib/commonjs/hooks/index.js +11 -0
- package/lib/commonjs/hooks/index.js.map +1 -1
- package/lib/commonjs/hooks/useIsActive.js +16 -0
- package/lib/commonjs/hooks/useIsActive.js.map +1 -0
- package/lib/commonjs/index.js +6 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types/misc.js.map +1 -1
- package/lib/module/components/ReorderableListCell.js +19 -14
- package/lib/module/components/ReorderableListCell.js.map +1 -1
- package/lib/module/components/ReorderableListCore/ReorderableListCore.js +11 -11
- package/lib/module/components/ReorderableListCore/ReorderableListCore.js.map +1 -1
- package/lib/module/components/ReorderableListCore/useReorderableListCore.js +51 -23
- package/lib/module/components/ReorderableListCore/useReorderableListCore.js.map +1 -1
- package/lib/module/components/helpers.js +25 -0
- package/lib/module/components/helpers.js.map +1 -0
- package/lib/module/contexts/ReorderableCellContext.js.map +1 -1
- package/lib/module/contexts/ReorderableListContext.js.map +1 -1
- package/lib/module/hooks/index.js +1 -0
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/useIsActive.js +9 -0
- package/lib/module/hooks/useIsActive.js.map +1 -0
- package/lib/module/index.js +2 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/misc.js.map +1 -1
- package/lib/typescript/components/ReorderableListCell.d.ts.map +1 -1
- package/lib/typescript/components/ReorderableListCore/useReorderableListCore.d.ts +138 -3
- package/lib/typescript/components/ReorderableListCore/useReorderableListCore.d.ts.map +1 -1
- package/lib/typescript/components/helpers.d.ts +11 -0
- package/lib/typescript/components/helpers.d.ts.map +1 -0
- package/lib/typescript/contexts/ReorderableCellContext.d.ts +1 -0
- package/lib/typescript/contexts/ReorderableCellContext.d.ts.map +1 -1
- package/lib/typescript/contexts/ReorderableListContext.d.ts +3 -2
- package/lib/typescript/contexts/ReorderableListContext.d.ts.map +1 -1
- package/lib/typescript/hooks/index.d.ts +1 -0
- package/lib/typescript/hooks/index.d.ts.map +1 -1
- package/lib/typescript/hooks/useIsActive.d.ts +2 -0
- package/lib/typescript/hooks/useIsActive.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +2 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types/misc.d.ts +9 -0
- package/lib/typescript/types/misc.d.ts.map +1 -1
- package/lib/typescript/types/props.d.ts +35 -8
- package/lib/typescript/types/props.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/components/ReorderableListCell.tsx +24 -11
- package/src/components/ReorderableListCore/ReorderableListCore.tsx +9 -9
- package/src/components/ReorderableListCore/useReorderableListCore.ts +68 -20
- package/src/components/helpers.ts +36 -0
- package/src/contexts/ReorderableCellContext.ts +1 -0
- package/src/contexts/ReorderableListContext.ts +4 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useIsActive.ts +7 -0
- package/src/index.ts +2 -0
- package/src/types/misc.ts +10 -0
- package/src/types/props.ts +71 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/types/props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/types/props.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-reorderable-list",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Reorderable list for React Native applications, powered by Reanimated",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -146,6 +146,8 @@
|
|
|
146
146
|
"import"
|
|
147
147
|
],
|
|
148
148
|
"rules": {
|
|
149
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
150
|
+
"no-console": "error",
|
|
149
151
|
"prettier/prettier": [
|
|
150
152
|
"error",
|
|
151
153
|
{
|
|
@@ -14,6 +14,7 @@ import Animated, {
|
|
|
14
14
|
|
|
15
15
|
import {ReorderableCellContext, ReorderableListContext} from '../contexts';
|
|
16
16
|
import {useContext} from '../hooks';
|
|
17
|
+
import {applyAnimatedStyles} from './helpers';
|
|
17
18
|
|
|
18
19
|
interface ReorderableListCellProps<T>
|
|
19
20
|
extends Omit<CellRendererProps<T>, 'cellKey'> {
|
|
@@ -37,28 +38,29 @@ export const ReorderableListCell = memo(
|
|
|
37
38
|
draggedIndex,
|
|
38
39
|
animationDuration,
|
|
39
40
|
}: ReorderableListCellProps<T>) => {
|
|
40
|
-
const {currentIndex, draggedHeight,
|
|
41
|
-
ReorderableListContext
|
|
42
|
-
);
|
|
41
|
+
const {currentIndex, draggedHeight, activeIndex, cellAnimations} =
|
|
42
|
+
useContext(ReorderableListContext);
|
|
43
43
|
const dragHandler = useCallback(
|
|
44
44
|
() => runOnUI(startDrag)(index),
|
|
45
45
|
[startDrag, index],
|
|
46
46
|
);
|
|
47
47
|
|
|
48
|
+
const isActive = activeIndex === index;
|
|
48
49
|
const contextValue = useMemo(
|
|
49
50
|
() => ({
|
|
50
51
|
index,
|
|
51
52
|
dragHandler,
|
|
52
53
|
draggedIndex,
|
|
54
|
+
isActive,
|
|
53
55
|
}),
|
|
54
|
-
[index, dragHandler, draggedIndex],
|
|
56
|
+
[index, dragHandler, draggedIndex, isActive],
|
|
55
57
|
);
|
|
56
58
|
|
|
57
59
|
// Keep separate animated reactions that update itemTranslateY
|
|
58
60
|
// otherwise animations might stutter if multiple are triggered
|
|
59
61
|
// (even in other cells, e.g. released item and reordering cells)
|
|
60
62
|
const itemTranslateY = useSharedValue(0);
|
|
61
|
-
const
|
|
63
|
+
const isActiveCell = useDerivedValue(() => draggedIndex.value === index);
|
|
62
64
|
|
|
63
65
|
useAnimatedReaction(
|
|
64
66
|
() => dragY.value,
|
|
@@ -101,12 +103,23 @@ export const ReorderableListCell = memo(
|
|
|
101
103
|
);
|
|
102
104
|
|
|
103
105
|
const animatedStyle = useAnimatedStyle(() => {
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
if (isActiveCell.value) {
|
|
107
|
+
const transform = [{translateY: itemTranslateY.value}];
|
|
108
|
+
if (Array.isArray(cellAnimations.transform)) {
|
|
109
|
+
const customTransform = cellAnimations.transform.map(x =>
|
|
110
|
+
applyAnimatedStyles({}, x),
|
|
111
|
+
) as [];
|
|
112
|
+
transform.push(...customTransform);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return applyAnimatedStyles(
|
|
116
|
+
{
|
|
117
|
+
transform,
|
|
118
|
+
zIndex: 999,
|
|
119
|
+
},
|
|
120
|
+
cellAnimations,
|
|
121
|
+
['transform'],
|
|
122
|
+
);
|
|
110
123
|
}
|
|
111
124
|
|
|
112
125
|
return {
|
|
@@ -43,8 +43,8 @@ interface ReorderableListCoreProps<T> extends ReorderableListProps<T> {
|
|
|
43
43
|
|
|
44
44
|
const ReorderableListCore = <T,>(
|
|
45
45
|
{
|
|
46
|
-
data,
|
|
47
46
|
autoscrollThreshold = 0.1,
|
|
47
|
+
autoscrollThresholdOffset,
|
|
48
48
|
autoscrollSpeedScale = 1,
|
|
49
49
|
autoscrollDelay = AUTOSCROLL_CONFIG.delay,
|
|
50
50
|
animationDuration = 200,
|
|
@@ -54,17 +54,17 @@ const ReorderableListCore = <T,>(
|
|
|
54
54
|
onScroll,
|
|
55
55
|
onDragStart,
|
|
56
56
|
onDragEnd,
|
|
57
|
-
keyExtractor,
|
|
58
|
-
extraData,
|
|
59
57
|
scrollViewContainerRef,
|
|
60
58
|
scrollViewHeightY,
|
|
61
59
|
scrollViewScrollOffsetY,
|
|
62
60
|
scrollViewScrollEnabled,
|
|
63
|
-
scrollEnabled,
|
|
64
61
|
initialScrollViewScrollEnabled,
|
|
65
62
|
scrollable,
|
|
66
63
|
outerScrollGesture,
|
|
67
64
|
cellAnimations,
|
|
65
|
+
shouldUpdateActiveItem,
|
|
66
|
+
panEnabled = true,
|
|
67
|
+
panActivateAfterLongPress,
|
|
68
68
|
...rest
|
|
69
69
|
}: ReorderableListCoreProps<T>,
|
|
70
70
|
ref: React.ForwardedRef<FlatList<T>>,
|
|
@@ -84,6 +84,7 @@ const ReorderableListCore = <T,>(
|
|
|
84
84
|
} = useReorderableListCore({
|
|
85
85
|
ref,
|
|
86
86
|
autoscrollThreshold,
|
|
87
|
+
autoscrollThresholdOffset,
|
|
87
88
|
autoscrollSpeedScale,
|
|
88
89
|
autoscrollDelay,
|
|
89
90
|
animationDuration,
|
|
@@ -99,13 +100,16 @@ const ReorderableListCore = <T,>(
|
|
|
99
100
|
// flatlist will default to true if we pass explicitly undefined,
|
|
100
101
|
// but internally we would treat it as false, so we force true
|
|
101
102
|
initialScrollEnabled:
|
|
102
|
-
typeof scrollEnabled === 'undefined' ? true : scrollEnabled,
|
|
103
|
+
typeof rest.scrollEnabled === 'undefined' ? true : rest.scrollEnabled,
|
|
103
104
|
initialScrollViewScrollEnabled:
|
|
104
105
|
typeof initialScrollViewScrollEnabled === 'undefined'
|
|
105
106
|
? true
|
|
106
107
|
: initialScrollViewScrollEnabled,
|
|
107
108
|
nestedScrollable: scrollable,
|
|
108
109
|
cellAnimations,
|
|
110
|
+
shouldUpdateActiveItem,
|
|
111
|
+
panEnabled,
|
|
112
|
+
panActivateAfterLongPress,
|
|
109
113
|
});
|
|
110
114
|
|
|
111
115
|
const combinedGesture = useMemo(() => {
|
|
@@ -145,17 +149,13 @@ const ReorderableListCore = <T,>(
|
|
|
145
149
|
<AnimatedFlatList
|
|
146
150
|
{...rest}
|
|
147
151
|
ref={handleRef}
|
|
148
|
-
data={data}
|
|
149
152
|
CellRendererComponent={renderAnimatedCell}
|
|
150
153
|
onLayout={handleFlatListLayout}
|
|
151
154
|
onScroll={composedScrollHandler}
|
|
152
155
|
scrollEventThrottle={1}
|
|
153
156
|
horizontal={false}
|
|
154
157
|
removeClippedSubviews={false}
|
|
155
|
-
keyExtractor={keyExtractor}
|
|
156
|
-
extraData={extraData}
|
|
157
158
|
numColumns={1}
|
|
158
|
-
scrollEnabled={scrollEnabled}
|
|
159
159
|
/>
|
|
160
160
|
</GestureDetector>
|
|
161
161
|
</ReorderableListContext.Provider>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {useCallback, useEffect, useMemo} from 'react';
|
|
1
|
+
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
|
2
2
|
import {
|
|
3
3
|
FlatList,
|
|
4
4
|
LayoutChangeEvent,
|
|
@@ -43,6 +43,7 @@ const hasAutomaticBatching = version.length
|
|
|
43
43
|
interface UseReorderableListCoreArgs<T> {
|
|
44
44
|
ref: React.ForwardedRef<FlatList<T>>;
|
|
45
45
|
autoscrollThreshold: number;
|
|
46
|
+
autoscrollThresholdOffset: {top?: number; bottom?: number} | undefined;
|
|
46
47
|
autoscrollSpeedScale: number;
|
|
47
48
|
autoscrollDelay: number;
|
|
48
49
|
animationDuration: number;
|
|
@@ -59,11 +60,15 @@ interface UseReorderableListCoreArgs<T> {
|
|
|
59
60
|
initialScrollViewScrollEnabled: boolean | undefined;
|
|
60
61
|
nestedScrollable: boolean | undefined;
|
|
61
62
|
cellAnimations: ReorderableListCellAnimations | undefined;
|
|
63
|
+
shouldUpdateActiveItem: boolean | undefined;
|
|
64
|
+
panEnabled: boolean;
|
|
65
|
+
panActivateAfterLongPress: number | undefined;
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
export const useReorderableListCore = <T>({
|
|
65
69
|
ref,
|
|
66
70
|
autoscrollThreshold,
|
|
71
|
+
autoscrollThresholdOffset,
|
|
67
72
|
autoscrollSpeedScale,
|
|
68
73
|
autoscrollDelay,
|
|
69
74
|
animationDuration,
|
|
@@ -80,8 +85,12 @@ export const useReorderableListCore = <T>({
|
|
|
80
85
|
initialScrollViewScrollEnabled,
|
|
81
86
|
nestedScrollable,
|
|
82
87
|
cellAnimations,
|
|
88
|
+
shouldUpdateActiveItem,
|
|
89
|
+
panActivateAfterLongPress,
|
|
90
|
+
panEnabled,
|
|
83
91
|
}: UseReorderableListCoreArgs<T>) => {
|
|
84
92
|
const flatListRef = useAnimatedRef<FlatList>();
|
|
93
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
85
94
|
const scrollEnabled = useSharedValue(initialScrollEnabled);
|
|
86
95
|
const gestureState = useSharedValue<State>(State.UNDETERMINED);
|
|
87
96
|
const currentY = useSharedValue(0);
|
|
@@ -112,7 +121,6 @@ export const useReorderableListCore = <T>({
|
|
|
112
121
|
const duration = useSharedValue(animationDuration);
|
|
113
122
|
const scaleDefault = useSharedValue(1);
|
|
114
123
|
const opacityDefault = useSharedValue(1);
|
|
115
|
-
const {scale, opacity} = cellAnimations || {};
|
|
116
124
|
|
|
117
125
|
useEffect(() => {
|
|
118
126
|
duration.value = animationDuration;
|
|
@@ -124,17 +132,27 @@ export const useReorderableListCore = <T>({
|
|
|
124
132
|
currentIndex,
|
|
125
133
|
draggedIndex,
|
|
126
134
|
dragEndHandlers,
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
activeIndex,
|
|
136
|
+
cellAnimations: {
|
|
137
|
+
...cellAnimations,
|
|
138
|
+
transform:
|
|
139
|
+
cellAnimations && 'transform' in cellAnimations
|
|
140
|
+
? cellAnimations.transform
|
|
141
|
+
: [{scale: scaleDefault}],
|
|
142
|
+
opacity:
|
|
143
|
+
cellAnimations && 'opacity' in cellAnimations
|
|
144
|
+
? cellAnimations.opacity
|
|
145
|
+
: opacityDefault,
|
|
146
|
+
},
|
|
129
147
|
}),
|
|
130
148
|
[
|
|
131
149
|
draggedHeight,
|
|
132
150
|
currentIndex,
|
|
133
151
|
draggedIndex,
|
|
134
152
|
dragEndHandlers,
|
|
135
|
-
|
|
153
|
+
activeIndex,
|
|
154
|
+
cellAnimations,
|
|
136
155
|
scaleDefault,
|
|
137
|
-
opacity,
|
|
138
156
|
opacityDefault,
|
|
139
157
|
],
|
|
140
158
|
);
|
|
@@ -177,9 +195,21 @@ export const useReorderableListCore = <T>({
|
|
|
177
195
|
],
|
|
178
196
|
);
|
|
179
197
|
|
|
198
|
+
const panGestureHandlerWithOptions = useMemo(() => {
|
|
199
|
+
if (typeof panActivateAfterLongPress === 'number') {
|
|
200
|
+
panGestureHandler.activateAfterLongPress(panActivateAfterLongPress);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!panEnabled) {
|
|
204
|
+
panGestureHandler.enabled(panEnabled);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return panGestureHandler;
|
|
208
|
+
}, [panActivateAfterLongPress, panEnabled, panGestureHandler]);
|
|
209
|
+
|
|
180
210
|
const gestureHandler = useMemo(
|
|
181
|
-
() => Gesture.Simultaneous(Gesture.Native(),
|
|
182
|
-
[
|
|
211
|
+
() => Gesture.Simultaneous(Gesture.Native(), panGestureHandlerWithOptions),
|
|
212
|
+
[panGestureHandlerWithOptions],
|
|
183
213
|
);
|
|
184
214
|
|
|
185
215
|
const setScrollEnabled = useCallback(
|
|
@@ -338,19 +368,19 @@ export const useReorderableListCore = <T>({
|
|
|
338
368
|
(type: 'start' | 'end') => {
|
|
339
369
|
'worklet';
|
|
340
370
|
|
|
341
|
-
// if
|
|
342
|
-
if (
|
|
371
|
+
// if no custom scale run default
|
|
372
|
+
if (!(cellAnimations && 'transformtra' in cellAnimations)) {
|
|
343
373
|
const scaleConfig = SCALE_ANIMATION_CONFIG_DEFAULT[type];
|
|
344
374
|
scaleDefault.value = withTiming(scaleConfig.toValue, scaleConfig);
|
|
345
375
|
}
|
|
346
376
|
|
|
347
|
-
// if
|
|
348
|
-
if (
|
|
377
|
+
// if no custom opacity run the default
|
|
378
|
+
if (!(cellAnimations && 'opacity' in cellAnimations)) {
|
|
349
379
|
const opacityConfig = OPACITY_ANIMATION_CONFIG_DEFAULT[type];
|
|
350
380
|
opacityDefault.value = withTiming(opacityConfig.toValue, opacityConfig);
|
|
351
381
|
}
|
|
352
382
|
},
|
|
353
|
-
[
|
|
383
|
+
[cellAnimations, scaleDefault, opacityDefault],
|
|
354
384
|
);
|
|
355
385
|
|
|
356
386
|
useAnimatedReaction(
|
|
@@ -367,6 +397,10 @@ export const useReorderableListCore = <T>({
|
|
|
367
397
|
// enable back scroll on releasing
|
|
368
398
|
runOnJS(setScrollEnabled)(true);
|
|
369
399
|
|
|
400
|
+
if (shouldUpdateActiveItem) {
|
|
401
|
+
runOnJS(setActiveIndex)(-1);
|
|
402
|
+
}
|
|
403
|
+
|
|
370
404
|
// trigger onDragEnd event
|
|
371
405
|
let e = {from: draggedIndex.value, to: currentIndex.value};
|
|
372
406
|
onDragEnd?.(e);
|
|
@@ -442,24 +476,33 @@ export const useReorderableListCore = <T>({
|
|
|
442
476
|
const calculateThresholdArea = useCallback(
|
|
443
477
|
(hiddenArea: {top: number; bottom: number}) => {
|
|
444
478
|
'worklet';
|
|
479
|
+
const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
|
|
480
|
+
const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
|
|
445
481
|
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
446
482
|
const visibleHeight =
|
|
447
|
-
flatListHeightY.value -
|
|
483
|
+
flatListHeightY.value -
|
|
484
|
+
(hiddenArea.top + hiddenArea.bottom) -
|
|
485
|
+
(offsetTop + offsetBottom);
|
|
448
486
|
|
|
449
|
-
const
|
|
450
|
-
const
|
|
487
|
+
const area = visibleHeight * threshold;
|
|
488
|
+
const top = area + offsetTop;
|
|
489
|
+
const bottom = flatListHeightY.value - area - offsetBottom;
|
|
451
490
|
|
|
452
491
|
return {top, bottom};
|
|
453
492
|
},
|
|
454
|
-
[autoscrollThreshold, flatListHeightY],
|
|
493
|
+
[autoscrollThreshold, autoscrollThresholdOffset, flatListHeightY],
|
|
455
494
|
);
|
|
456
495
|
|
|
457
496
|
const calculateThresholdAreaParent = useCallback(
|
|
458
497
|
(hiddenArea: {top: number; bottom: number}) => {
|
|
459
498
|
'worklet';
|
|
499
|
+
const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
|
|
500
|
+
const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
|
|
460
501
|
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
461
|
-
|
|
462
|
-
const
|
|
502
|
+
|
|
503
|
+
const area = flatListHeightY.value * threshold;
|
|
504
|
+
const top = area + offsetTop;
|
|
505
|
+
const bottom = flatListHeightY.value - area - offsetBottom;
|
|
463
506
|
|
|
464
507
|
// if the hidden area is 0 then we don't have a threshold area
|
|
465
508
|
// we might have floating errors like 0.0001 which we should ignore
|
|
@@ -468,7 +511,7 @@ export const useReorderableListCore = <T>({
|
|
|
468
511
|
bottom: hiddenArea.bottom > 0.1 ? bottom - hiddenArea.bottom : 0,
|
|
469
512
|
};
|
|
470
513
|
},
|
|
471
|
-
[autoscrollThreshold, flatListHeightY],
|
|
514
|
+
[autoscrollThreshold, autoscrollThresholdOffset, flatListHeightY],
|
|
472
515
|
);
|
|
473
516
|
|
|
474
517
|
const shouldScrollParent = useCallback(
|
|
@@ -644,6 +687,10 @@ export const useReorderableListCore = <T>({
|
|
|
644
687
|
// after scrolling the parent list it would offset the new dragged item in another nested list
|
|
645
688
|
resetSharedValues();
|
|
646
689
|
|
|
690
|
+
if (shouldUpdateActiveItem) {
|
|
691
|
+
runOnJS(setActiveIndex)(index);
|
|
692
|
+
}
|
|
693
|
+
|
|
647
694
|
dragInitialScrollOffsetY.value = flatListScrollOffsetY.value;
|
|
648
695
|
scrollViewDragInitialScrollOffsetY.value = scrollViewScrollOffsetY
|
|
649
696
|
? scrollViewScrollOffsetY.value
|
|
@@ -664,6 +711,7 @@ export const useReorderableListCore = <T>({
|
|
|
664
711
|
},
|
|
665
712
|
[
|
|
666
713
|
resetSharedValues,
|
|
714
|
+
shouldUpdateActiveItem,
|
|
667
715
|
dragInitialScrollOffsetY,
|
|
668
716
|
scrollViewScrollOffsetY,
|
|
669
717
|
scrollViewDragInitialScrollOffsetY,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flattens an object containing `SharedValue`s by extracting their underlying values.
|
|
3
|
+
*
|
|
4
|
+
* @param target - An object to which the flattened shared values and every other field will be mapped to.
|
|
5
|
+
* @param source - The object containing, possibly among others, the shared values.
|
|
6
|
+
* @param excludedKeys - The keys to exclude from flattening and mapping.
|
|
7
|
+
*
|
|
8
|
+
* @returns The object to which the fields where flattened and mapped to.
|
|
9
|
+
*/
|
|
10
|
+
export const applyAnimatedStyles = (
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
target: Record<string, any>,
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
source: Record<string, any>,
|
|
15
|
+
excludedKeys: string[] = [],
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
): Record<string, any> => {
|
|
18
|
+
'worklet';
|
|
19
|
+
|
|
20
|
+
let keys = Object.keys(source);
|
|
21
|
+
|
|
22
|
+
for (let key of keys) {
|
|
23
|
+
if (excludedKeys.includes(key)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let value = source[key];
|
|
28
|
+
|
|
29
|
+
target[key] =
|
|
30
|
+
value !== null && typeof value === 'object' && 'value' in value
|
|
31
|
+
? value.value
|
|
32
|
+
: value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return target;
|
|
36
|
+
};
|
|
@@ -2,12 +2,14 @@ import React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import type {SharedValue} from 'react-native-reanimated';
|
|
4
4
|
|
|
5
|
+
import {ReorderableListCellAnimations} from '../types';
|
|
6
|
+
|
|
5
7
|
interface ReorderableListContextData {
|
|
6
8
|
currentIndex: SharedValue<number>;
|
|
7
9
|
draggedHeight: SharedValue<number>;
|
|
8
10
|
dragEndHandlers: SharedValue<((from: number, to: number) => void)[][]>;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
activeIndex: number;
|
|
12
|
+
cellAnimations: ReorderableListCellAnimations;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export const ReorderableListContext = React.createContext<
|
package/src/hooks/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ScrollViewContainer,
|
|
5
5
|
} from './components';
|
|
6
6
|
import {
|
|
7
|
+
useIsActive,
|
|
7
8
|
useReorderableDrag,
|
|
8
9
|
useReorderableDragEnd,
|
|
9
10
|
useReorderableDragStart,
|
|
@@ -19,6 +20,7 @@ import type {
|
|
|
19
20
|
import {reorderItems} from './utils';
|
|
20
21
|
|
|
21
22
|
export {
|
|
23
|
+
useIsActive,
|
|
22
24
|
useReorderableDrag,
|
|
23
25
|
useReorderableDragStart,
|
|
24
26
|
useReorderableDragEnd,
|
package/src/types/misc.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import {SharedValue} from 'react-native-reanimated';
|
|
2
|
+
|
|
1
3
|
export enum ReorderableListState {
|
|
2
4
|
IDLE = 0,
|
|
3
5
|
DRAGGED,
|
|
4
6
|
RELEASED,
|
|
5
7
|
AUTOSCROLL,
|
|
6
8
|
}
|
|
9
|
+
|
|
10
|
+
export type SharedValueOrType<T> = {
|
|
11
|
+
[TKey in keyof T]?: SharedValue<T[TKey]> | T[TKey];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type MaximumOneOf<T, K extends keyof T = keyof T> = K extends keyof T
|
|
15
|
+
? {[P in K]: T[K]} & {[P in Exclude<keyof T, K>]?: never}
|
|
16
|
+
: never;
|
package/src/types/props.ts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
FlatListProps,
|
|
3
|
+
MatrixTransform,
|
|
4
|
+
PerspectiveTransform,
|
|
5
|
+
RotateTransform,
|
|
6
|
+
RotateXTransform,
|
|
7
|
+
RotateYTransform,
|
|
8
|
+
RotateZTransform,
|
|
9
|
+
ScaleTransform,
|
|
10
|
+
ScaleXTransform,
|
|
11
|
+
ScaleYTransform,
|
|
12
|
+
ScrollViewProps,
|
|
13
|
+
SkewXTransform,
|
|
14
|
+
SkewYTransform,
|
|
15
|
+
TranslateXTransform,
|
|
16
|
+
TranslateYTransform,
|
|
17
|
+
ViewStyle,
|
|
18
|
+
} from 'react-native';
|
|
2
19
|
|
|
3
20
|
import {SharedValue, useAnimatedScrollHandler} from 'react-native-reanimated';
|
|
4
21
|
|
|
22
|
+
import {MaximumOneOf, SharedValueOrType} from './misc';
|
|
23
|
+
|
|
5
24
|
export interface ReorderableListReorderEvent {
|
|
6
25
|
/**
|
|
7
26
|
* Index of the dragged item.
|
|
@@ -43,11 +62,16 @@ export interface ReorderableListProps<T>
|
|
|
43
62
|
extends Omit<FlatListProps<T>, OmittedProps> {
|
|
44
63
|
data: T[];
|
|
45
64
|
/**
|
|
46
|
-
* Threshold
|
|
65
|
+
* Threshold at the extremety of the list which triggers autoscroll when an item is dragged to it.
|
|
47
66
|
* A value of 0.1 means that 10% of the area at the top and 10% at the bottom of the list will trigger autoscroll
|
|
48
67
|
* when an item is dragged to it. Min value: `0`. Max value: `0.4`. Default: `0.1`.
|
|
49
68
|
*/
|
|
50
69
|
autoscrollThreshold?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Amount by which the threshold is offset at the extremety of the list.
|
|
72
|
+
* For example, setting `{top: 50}` will make the autoscroll trigger 50 pixels earlier at the top.
|
|
73
|
+
*/
|
|
74
|
+
autoscrollThresholdOffset?: {top?: number; bottom?: number};
|
|
51
75
|
/**
|
|
52
76
|
* Scales the autoscroll spreed at which the list scrolls when an item is dragged to the scroll areas. Default: `1`.
|
|
53
77
|
*/
|
|
@@ -71,9 +95,21 @@ export interface ReorderableListProps<T>
|
|
|
71
95
|
*/
|
|
72
96
|
animationDuration?: number;
|
|
73
97
|
/**
|
|
74
|
-
* Allows passing an object with shared values that can animate a cell by using the `onDragStart` and `onDragEnd` events.
|
|
98
|
+
* Allows passing an object with values and/or shared values that can animate a cell, for example by using the `onDragStart` and `onDragEnd` events. Supports view style properties. Override opacity and/or transform to disable the default animation, e.g. `{opacity: 1, transform: []}`.
|
|
75
99
|
*/
|
|
76
100
|
cellAnimations?: ReorderableListCellAnimations;
|
|
101
|
+
/**
|
|
102
|
+
* Whether the active item should be updated. Enables usage of `useIsActive` hook. Default: `false`.
|
|
103
|
+
*/
|
|
104
|
+
shouldUpdateActiveItem?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Wether the pan gestures necessary for dragging are enabled. Default: `true`.
|
|
107
|
+
*/
|
|
108
|
+
panEnabled?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Duration in milliseconds of a long press on the list before pan gestures, necessary for dragging, are allowed to activate.
|
|
111
|
+
*/
|
|
112
|
+
panActivateAfterLongPress?: number;
|
|
77
113
|
/**
|
|
78
114
|
* Event fired after an item is released and the list is reordered.
|
|
79
115
|
*/
|
|
@@ -92,15 +128,42 @@ export interface ReorderableListProps<T>
|
|
|
92
128
|
onDragEnd?: (event: ReorderableListDragEndEvent) => void;
|
|
93
129
|
}
|
|
94
130
|
|
|
95
|
-
export
|
|
131
|
+
export type Transforms = PerspectiveTransform &
|
|
132
|
+
RotateTransform &
|
|
133
|
+
RotateXTransform &
|
|
134
|
+
RotateYTransform &
|
|
135
|
+
RotateZTransform &
|
|
136
|
+
ScaleTransform &
|
|
137
|
+
ScaleXTransform &
|
|
138
|
+
ScaleYTransform &
|
|
139
|
+
TranslateXTransform &
|
|
140
|
+
TranslateYTransform &
|
|
141
|
+
SkewXTransform &
|
|
142
|
+
SkewYTransform &
|
|
143
|
+
MatrixTransform;
|
|
144
|
+
|
|
145
|
+
export type ReorderableListCellAnimatedStyles = Omit<
|
|
146
|
+
{
|
|
147
|
+
[StyleKey in keyof ViewStyle]?:
|
|
148
|
+
| SharedValue<ViewStyle[StyleKey]>
|
|
149
|
+
| ViewStyle[StyleKey];
|
|
150
|
+
},
|
|
151
|
+
// omit custom type and type with JSDoc
|
|
152
|
+
'transform' | 'opacity'
|
|
153
|
+
>;
|
|
154
|
+
|
|
155
|
+
export interface ReorderableListCellAnimations
|
|
156
|
+
extends ReorderableListCellAnimatedStyles {
|
|
96
157
|
/**
|
|
97
|
-
*
|
|
158
|
+
* Transform animations for a dragged item.
|
|
159
|
+
* Disable default animation by overriding transform, e.g. `[]` or `[{ scale: customSharedValue }]`.
|
|
98
160
|
*/
|
|
99
|
-
|
|
161
|
+
transform?: Readonly<MaximumOneOf<SharedValueOrType<Transforms>>[]>;
|
|
100
162
|
/**
|
|
101
|
-
* Shared value to animate the
|
|
163
|
+
* Shared value to animate the opacity of a dragged item.
|
|
164
|
+
* Disable default animation by overriding opacity, e.g `1`.
|
|
102
165
|
*/
|
|
103
|
-
|
|
166
|
+
opacity?: SharedValue<number> | number;
|
|
104
167
|
}
|
|
105
168
|
|
|
106
169
|
export interface ScrollViewContainerProps
|