1
1
/* eslint-disable react-hooks/exhaustive-deps */
2
2
import { map } from 'lodash' ;
3
- import React , { PropsWithChildren , useCallback , useContext } from 'react' ;
3
+ import React , { PropsWithChildren , useContext } from 'react' ;
4
4
import {
5
5
useSharedValue ,
6
6
useAnimatedReaction ,
@@ -10,14 +10,13 @@ import {
10
10
useAnimatedStyle ,
11
11
withSpring
12
12
} from 'react-native-reanimated' ;
13
- import { GestureDetector , GestureUpdateEvent , PanGestureHandlerEventPayload } from 'react-native-gesture-handler' ;
13
+ import { GestureDetector , Gesture } from 'react-native-gesture-handler' ;
14
14
import View from '../view' ;
15
15
import { Shadows , Colors } from '../../style' ;
16
16
import { useDidUpdate } from 'hooks' ;
17
17
import SortableListContext from './SortableListContext' ;
18
18
import usePresenter from './usePresenter' ;
19
- import useDragAfterLongPressGesture from './useDragAfterLongPressGesture' ;
20
-
19
+ import { HapticService , HapticType } from '../../services' ;
21
20
export interface SortableListItemProps {
22
21
index : number ;
23
22
}
@@ -32,12 +31,13 @@ const animationConfig = {
32
31
const SortableListItem = ( props : Props ) => {
33
32
const { children, index} = props ;
34
33
35
- const { data, itemHeight, onItemLayout, itemsOrder, onChange, enableHaptic} =
36
- useContext ( SortableListContext ) ;
34
+ const { data, itemHeight, onItemLayout, itemsOrder, onChange, enableHaptic} = useContext ( SortableListContext ) ;
37
35
const { getTranslationByIndexChange, getItemIndexById, getIndexByPosition, getIdByItemIndex} = usePresenter ( ) ;
38
36
const id : string = data [ index ] . id ;
39
37
const initialIndex = useSharedValue < number > ( map ( data , 'id' ) . indexOf ( id ) ) ;
40
38
const translateY = useSharedValue < number > ( 0 ) ;
39
+
40
+ const isDragging = useSharedValue ( false ) ;
41
41
const tempTranslateY = useSharedValue < number > ( 0 ) ;
42
42
const tempItemsOrder = useSharedValue < string [ ] > ( itemsOrder . value ) ;
43
43
const dataManuallyChanged = useSharedValue < boolean > ( false ) ;
@@ -76,57 +76,58 @@ const SortableListItem = (props: Props) => {
76
76
}
77
77
} ) ;
78
78
79
- const onDragStart = useCallback ( ( ) => {
80
- 'worklet' ;
81
- tempTranslateY . value = translateY . value ;
82
- tempItemsOrder . value = itemsOrder . value ;
83
- } , [ ] ) ;
84
-
85
- const onDragUpdate = useCallback ( ( event : GestureUpdateEvent < PanGestureHandlerEventPayload > ) => {
86
- 'worklet' ;
87
- translateY . value = tempTranslateY . value + event . translationY ;
88
-
89
- // Swapping items
90
- const newIndex = getIndexByPosition ( translateY . value , itemHeight . value ) + initialIndex . value ;
91
- const oldIndex = getItemIndexById ( itemsOrder . value , id ) ;
92
-
93
- if ( newIndex !== oldIndex ) {
94
- const itemIdToSwap = getIdByItemIndex ( itemsOrder . value , newIndex ) ;
95
-
96
- if ( itemIdToSwap !== undefined ) {
97
- const newItemsOrder = [ ...itemsOrder . value ] ;
98
- newItemsOrder [ newIndex ] = id ;
99
- newItemsOrder [ oldIndex ] = itemIdToSwap ;
100
- itemsOrder . value = newItemsOrder ;
79
+ const dragOnLongPressGesture = Gesture . Pan ( )
80
+ . activateAfterLongPress ( 250 )
81
+ . onStart ( ( ) => {
82
+ isDragging . value = true ;
83
+ tempTranslateY . value = translateY . value ;
84
+ tempItemsOrder . value = itemsOrder . value ;
85
+ } )
86
+ . onTouchesMove ( ( ) => {
87
+ if ( enableHaptic && ! isDragging . value ) {
88
+ runOnJS ( HapticService . triggerHaptic ) ( HapticType . selection , 'SortableList' ) ;
101
89
}
102
- }
103
- } , [ ] ) ;
104
-
105
- const onDragEnd = useCallback ( ( ) => {
106
- 'worklet' ;
107
- const translation = getTranslationByIndexChange ( getItemIndexById ( itemsOrder . value , id ) ,
108
- getItemIndexById ( tempItemsOrder . value , id ) ,
109
- itemHeight . value ) ;
110
-
111
- translateY . value = withTiming ( tempTranslateY . value + translation , animationConfig , ( ) => {
112
- if ( tempItemsOrder . value . toString ( ) !== itemsOrder . value . toString ( ) ) {
113
- runOnJS ( onChange ) ( ) ;
90
+ } )
91
+ . onUpdate ( event => {
92
+ translateY . value = tempTranslateY . value + event . translationY ;
93
+
94
+ // Swapping items
95
+ const newIndex = getIndexByPosition ( translateY . value , itemHeight . value ) + initialIndex . value ;
96
+ const oldIndex = getItemIndexById ( itemsOrder . value , id ) ;
97
+
98
+ if ( newIndex !== oldIndex ) {
99
+ const itemIdToSwap = getIdByItemIndex ( itemsOrder . value , newIndex ) ;
100
+
101
+ if ( itemIdToSwap !== undefined ) {
102
+ const newItemsOrder = [ ...itemsOrder . value ] ;
103
+ newItemsOrder [ newIndex ] = id ;
104
+ newItemsOrder [ oldIndex ] = itemIdToSwap ;
105
+ itemsOrder . value = newItemsOrder ;
106
+ }
107
+ }
108
+ } )
109
+ . onEnd ( ( ) => {
110
+ const translation = getTranslationByIndexChange ( getItemIndexById ( itemsOrder . value , id ) ,
111
+ getItemIndexById ( tempItemsOrder . value , id ) ,
112
+ itemHeight . value ) ;
113
+
114
+ translateY . value = withTiming ( tempTranslateY . value + translation , animationConfig , ( ) => {
115
+ if ( tempItemsOrder . value . toString ( ) !== itemsOrder . value . toString ( ) ) {
116
+ runOnJS ( onChange ) ( ) ;
117
+ }
118
+ } ) ;
119
+ } )
120
+ . onFinalize ( ( ) => {
121
+ if ( isDragging . value ) {
122
+ isDragging . value = false ;
114
123
}
115
124
} ) ;
116
- } , [ ] ) ;
117
-
118
- const { dragAfterLongPressGesture, isFloating} = useDragAfterLongPressGesture ( {
119
- onDragStart,
120
- onDragUpdate,
121
- onDragEnd,
122
- hapticComponentName : enableHaptic ? 'SortableList' : null
123
- } ) ;
124
125
125
126
const draggedAnimatedStyle = useAnimatedStyle ( ( ) => {
126
- const scaleY = withSpring ( isFloating . value ? 1.1 : 1 ) ;
127
- const zIndex = isFloating . value ? 100 : withTiming ( 0 , animationConfig ) ;
128
- const opacity = isFloating . value ? 0.95 : 1 ;
129
- const shadow = isFloating . value
127
+ const scaleY = withSpring ( isDragging . value ? 1.1 : 1 ) ;
128
+ const zIndex = isDragging . value ? 100 : withTiming ( 0 , animationConfig ) ;
129
+ const opacity = isDragging . value ? 0.95 : 1 ;
130
+ const shadow = isDragging . value
130
131
? {
131
132
...Shadows . sh30 . bottom ,
132
133
...Shadows . sh30 . top
@@ -146,7 +147,7 @@ const SortableListItem = (props: Props) => {
146
147
} ) ;
147
148
148
149
return (
149
- < GestureDetector gesture = { dragAfterLongPressGesture } >
150
+ < GestureDetector gesture = { dragOnLongPressGesture } >
150
151
< View reanimated style = { draggedAnimatedStyle } onLayout = { index === 0 ? onItemLayout : undefined } >
151
152
{ children }
152
153
</ View >
0 commit comments