react-native-gesture-handler 2.16.2 → 2.17.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (212) hide show
  1. package/README.md +9 -3
  2. package/android/build.gradle +103 -0
  3. package/android/gradle.properties +7 -0
  4. package/android/paper/src/main/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java +7 -7
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt +16 -8
  6. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +9 -5
  7. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerInteractionManager.kt +4 -0
  8. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt +1 -1
  9. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerTouchEvent.kt +1 -0
  10. package/apple/RNGestureHandlerButtonComponentView.mm +10 -0
  11. package/apple/RNGestureHandlerModule.mm +2 -3
  12. package/lib/commonjs/components/GestureButtons.js +27 -12
  13. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  14. package/lib/commonjs/handlers/createHandler.js +1 -3
  15. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  16. package/lib/commonjs/handlers/gestureHandlerCommon.js +3 -3
  17. package/lib/commonjs/handlers/gestureHandlerCommon.js.map +1 -1
  18. package/lib/commonjs/handlers/gestures/GestureDetector/Wrap.js +42 -0
  19. package/lib/commonjs/handlers/gestures/GestureDetector/Wrap.js.map +1 -0
  20. package/lib/commonjs/handlers/gestures/GestureDetector/attachHandlers.js +83 -0
  21. package/lib/commonjs/handlers/gestures/GestureDetector/attachHandlers.js.map +1 -0
  22. package/lib/commonjs/handlers/gestures/GestureDetector/dropHandlers.js +25 -0
  23. package/lib/commonjs/handlers/gestures/GestureDetector/dropHandlers.js.map +1 -0
  24. package/lib/commonjs/handlers/gestures/GestureDetector/index.js +143 -0
  25. package/lib/commonjs/handlers/gestures/GestureDetector/index.js.map +1 -0
  26. package/lib/commonjs/handlers/gestures/GestureDetector/needsToReattach.js +25 -0
  27. package/lib/commonjs/handlers/gestures/GestureDetector/needsToReattach.js.map +1 -0
  28. package/lib/commonjs/handlers/gestures/GestureDetector/types.js +6 -0
  29. package/lib/commonjs/handlers/gestures/GestureDetector/types.js.map +1 -0
  30. package/lib/commonjs/handlers/gestures/GestureDetector/updateHandlers.js +80 -0
  31. package/lib/commonjs/handlers/gestures/GestureDetector/updateHandlers.js.map +1 -0
  32. package/lib/commonjs/handlers/gestures/GestureDetector/useAnimatedGesture.js +180 -0
  33. package/lib/commonjs/handlers/gestures/GestureDetector/useAnimatedGesture.js.map +1 -0
  34. package/lib/commonjs/handlers/gestures/GestureDetector/useDetectorUpdater.js +55 -0
  35. package/lib/commonjs/handlers/gestures/GestureDetector/useDetectorUpdater.js.map +1 -0
  36. package/lib/commonjs/handlers/gestures/GestureDetector/useViewRefHandler.js +47 -0
  37. package/lib/commonjs/handlers/gestures/GestureDetector/useViewRefHandler.js.map +1 -0
  38. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js +176 -0
  39. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js.map +1 -0
  40. package/lib/commonjs/handlers/gestures/gestureComposition.js +3 -1
  41. package/lib/commonjs/handlers/gestures/gestureComposition.js.map +1 -1
  42. package/lib/commonjs/handlers/gestures/gestureStateManager.js +8 -0
  43. package/lib/commonjs/handlers/gestures/gestureStateManager.js.map +1 -1
  44. package/lib/commonjs/handlers/gestures/reanimatedWrapper.js.map +1 -1
  45. package/lib/commonjs/utils.js +36 -0
  46. package/lib/commonjs/utils.js.map +1 -1
  47. package/lib/commonjs/web/detectors/RotationGestureDetector.js +6 -8
  48. package/lib/commonjs/web/detectors/RotationGestureDetector.js.map +1 -1
  49. package/lib/commonjs/web/detectors/ScaleGestureDetector.js +5 -6
  50. package/lib/commonjs/web/detectors/ScaleGestureDetector.js.map +1 -1
  51. package/lib/commonjs/web/handlers/FlingGestureHandler.js +1 -0
  52. package/lib/commonjs/web/handlers/FlingGestureHandler.js.map +1 -1
  53. package/lib/commonjs/web/handlers/GestureHandler.js +56 -64
  54. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  55. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +1 -0
  56. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  57. package/lib/commonjs/web/handlers/ManualGestureHandler.js +1 -0
  58. package/lib/commonjs/web/handlers/ManualGestureHandler.js.map +1 -1
  59. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +7 -4
  60. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  61. package/lib/commonjs/web/handlers/PanGestureHandler.js +28 -18
  62. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  63. package/lib/commonjs/web/handlers/PinchGestureHandler.js +1 -0
  64. package/lib/commonjs/web/handlers/PinchGestureHandler.js.map +1 -1
  65. package/lib/commonjs/web/handlers/RotationGestureHandler.js +1 -0
  66. package/lib/commonjs/web/handlers/RotationGestureHandler.js.map +1 -1
  67. package/lib/commonjs/web/handlers/TapGestureHandler.js +18 -12
  68. package/lib/commonjs/web/handlers/TapGestureHandler.js.map +1 -1
  69. package/lib/commonjs/web/interfaces.js.map +1 -1
  70. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js +1 -6
  71. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  72. package/lib/commonjs/web/tools/PointerEventManager.js +7 -2
  73. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  74. package/lib/commonjs/web/tools/PointerTracker.js +89 -57
  75. package/lib/commonjs/web/tools/PointerTracker.js.map +1 -1
  76. package/lib/commonjs/web/tools/TouchEventManager.js +6 -2
  77. package/lib/commonjs/web/tools/TouchEventManager.js.map +1 -1
  78. package/lib/commonjs/web/tools/Vector.js +2 -1
  79. package/lib/commonjs/web/tools/Vector.js.map +1 -1
  80. package/lib/commonjs/web/utils.js +31 -0
  81. package/lib/commonjs/web/utils.js.map +1 -1
  82. package/lib/module/components/GestureButtons.js +24 -6
  83. package/lib/module/components/GestureButtons.js.map +1 -1
  84. package/lib/module/handlers/createHandler.js +2 -4
  85. package/lib/module/handlers/createHandler.js.map +1 -1
  86. package/lib/module/handlers/gestureHandlerCommon.js +1 -1
  87. package/lib/module/handlers/gestureHandlerCommon.js.map +1 -1
  88. package/lib/module/handlers/gestures/GestureDetector/Wrap.js +26 -0
  89. package/lib/module/handlers/gestures/GestureDetector/Wrap.js.map +1 -0
  90. package/lib/module/handlers/gestures/GestureDetector/attachHandlers.js +65 -0
  91. package/lib/module/handlers/gestures/GestureDetector/attachHandlers.js.map +1 -0
  92. package/lib/module/handlers/gestures/GestureDetector/dropHandlers.js +12 -0
  93. package/lib/module/handlers/gestures/GestureDetector/dropHandlers.js.map +1 -0
  94. package/lib/module/handlers/gestures/GestureDetector/index.js +115 -0
  95. package/lib/module/handlers/gestures/GestureDetector/index.js.map +1 -0
  96. package/lib/module/handlers/gestures/GestureDetector/needsToReattach.js +18 -0
  97. package/lib/module/handlers/gestures/GestureDetector/needsToReattach.js.map +1 -0
  98. package/lib/module/handlers/gestures/GestureDetector/types.js +2 -0
  99. package/lib/module/handlers/gestures/GestureDetector/types.js.map +1 -0
  100. package/lib/module/handlers/gestures/GestureDetector/updateHandlers.js +64 -0
  101. package/lib/module/handlers/gestures/GestureDetector/updateHandlers.js.map +1 -0
  102. package/lib/module/handlers/gestures/GestureDetector/useAnimatedGesture.js +165 -0
  103. package/lib/module/handlers/gestures/GestureDetector/useAnimatedGesture.js.map +1 -0
  104. package/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js +41 -0
  105. package/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js.map +1 -0
  106. package/lib/module/handlers/gestures/GestureDetector/useViewRefHandler.js +36 -0
  107. package/lib/module/handlers/gestures/GestureDetector/useViewRefHandler.js.map +1 -0
  108. package/lib/module/handlers/gestures/GestureDetector/utils.js +142 -0
  109. package/lib/module/handlers/gestures/GestureDetector/utils.js.map +1 -0
  110. package/lib/module/handlers/gestures/gestureComposition.js +3 -1
  111. package/lib/module/handlers/gestures/gestureComposition.js.map +1 -1
  112. package/lib/module/handlers/gestures/gestureStateManager.js +8 -0
  113. package/lib/module/handlers/gestures/gestureStateManager.js.map +1 -1
  114. package/lib/module/handlers/gestures/reanimatedWrapper.js.map +1 -1
  115. package/lib/module/utils.js +34 -0
  116. package/lib/module/utils.js.map +1 -1
  117. package/lib/module/web/detectors/RotationGestureDetector.js +6 -8
  118. package/lib/module/web/detectors/RotationGestureDetector.js.map +1 -1
  119. package/lib/module/web/detectors/ScaleGestureDetector.js +5 -6
  120. package/lib/module/web/detectors/ScaleGestureDetector.js.map +1 -1
  121. package/lib/module/web/handlers/FlingGestureHandler.js +1 -0
  122. package/lib/module/web/handlers/FlingGestureHandler.js.map +1 -1
  123. package/lib/module/web/handlers/GestureHandler.js +56 -64
  124. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  125. package/lib/module/web/handlers/LongPressGestureHandler.js +1 -0
  126. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  127. package/lib/module/web/handlers/ManualGestureHandler.js +1 -0
  128. package/lib/module/web/handlers/ManualGestureHandler.js.map +1 -1
  129. package/lib/module/web/handlers/NativeViewGestureHandler.js +7 -4
  130. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  131. package/lib/module/web/handlers/PanGestureHandler.js +28 -18
  132. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  133. package/lib/module/web/handlers/PinchGestureHandler.js +1 -0
  134. package/lib/module/web/handlers/PinchGestureHandler.js.map +1 -1
  135. package/lib/module/web/handlers/RotationGestureHandler.js +1 -0
  136. package/lib/module/web/handlers/RotationGestureHandler.js.map +1 -1
  137. package/lib/module/web/handlers/TapGestureHandler.js +18 -12
  138. package/lib/module/web/handlers/TapGestureHandler.js.map +1 -1
  139. package/lib/module/web/interfaces.js.map +1 -1
  140. package/lib/module/web/tools/GestureHandlerOrchestrator.js +1 -6
  141. package/lib/module/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  142. package/lib/module/web/tools/PointerEventManager.js +8 -3
  143. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  144. package/lib/module/web/tools/PointerTracker.js +89 -57
  145. package/lib/module/web/tools/PointerTracker.js.map +1 -1
  146. package/lib/module/web/tools/TouchEventManager.js +7 -3
  147. package/lib/module/web/tools/TouchEventManager.js.map +1 -1
  148. package/lib/module/web/tools/Vector.js +2 -1
  149. package/lib/module/web/tools/Vector.js.map +1 -1
  150. package/lib/module/web/utils.js +29 -0
  151. package/lib/module/web/utils.js.map +1 -1
  152. package/lib/typescript/components/GestureButtons.d.ts +3 -34
  153. package/lib/typescript/handlers/gestureHandlerCommon.d.ts +3 -2
  154. package/lib/typescript/handlers/gestures/GestureDetector/Wrap.d.ts +13 -0
  155. package/lib/typescript/handlers/gestures/GestureDetector/attachHandlers.d.ts +13 -0
  156. package/lib/typescript/handlers/gestures/GestureDetector/dropHandlers.d.ts +2 -0
  157. package/lib/typescript/handlers/gestures/{GestureDetector.d.ts → GestureDetector/index.d.ts} +4 -12
  158. package/lib/typescript/handlers/gestures/GestureDetector/needsToReattach.d.ts +3 -0
  159. package/lib/typescript/handlers/gestures/GestureDetector/types.d.ts +20 -0
  160. package/lib/typescript/handlers/gestures/GestureDetector/updateHandlers.d.ts +4 -0
  161. package/lib/typescript/handlers/gestures/GestureDetector/useAnimatedGesture.d.ts +2 -0
  162. package/lib/typescript/handlers/gestures/GestureDetector/useDetectorUpdater.d.ts +5 -0
  163. package/lib/typescript/handlers/gestures/GestureDetector/useViewRefHandler.d.ts +3 -0
  164. package/lib/typescript/handlers/gestures/GestureDetector/utils.d.ts +12 -0
  165. package/lib/typescript/handlers/gestures/reanimatedWrapper.d.ts +1 -1
  166. package/lib/typescript/utils.d.ts +10 -0
  167. package/lib/typescript/web/handlers/GestureHandler.d.ts +1 -0
  168. package/lib/typescript/web/interfaces.d.ts +1 -0
  169. package/lib/typescript/web/tools/PointerTracker.d.ts +34 -31
  170. package/lib/typescript/web/utils.d.ts +4 -0
  171. package/package.json +5 -5
  172. package/src/components/GestureButtons.tsx +36 -4
  173. package/src/handlers/createHandler.tsx +1 -3
  174. package/src/handlers/gestureHandlerCommon.ts +4 -1
  175. package/src/handlers/gestures/GestureDetector/Wrap.tsx +35 -0
  176. package/src/handlers/gestures/GestureDetector/attachHandlers.ts +112 -0
  177. package/src/handlers/gestures/GestureDetector/dropHandlers.ts +14 -0
  178. package/src/handlers/gestures/GestureDetector/index.tsx +187 -0
  179. package/src/handlers/gestures/GestureDetector/needsToReattach.ts +27 -0
  180. package/src/handlers/gestures/GestureDetector/types.ts +32 -0
  181. package/src/handlers/gestures/GestureDetector/updateHandlers.ts +94 -0
  182. package/src/handlers/gestures/GestureDetector/useAnimatedGesture.ts +206 -0
  183. package/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts +69 -0
  184. package/src/handlers/gestures/GestureDetector/useViewRefHandler.ts +54 -0
  185. package/src/handlers/gestures/GestureDetector/utils.ts +185 -0
  186. package/src/handlers/gestures/gestureComposition.ts +2 -0
  187. package/src/handlers/gestures/gestureStateManager.ts +12 -4
  188. package/src/handlers/gestures/reanimatedWrapper.ts +19 -17
  189. package/src/utils.ts +39 -0
  190. package/src/web/detectors/RotationGestureDetector.ts +6 -8
  191. package/src/web/detectors/ScaleGestureDetector.ts +5 -6
  192. package/src/web/handlers/FlingGestureHandler.ts +2 -0
  193. package/src/web/handlers/GestureHandler.ts +53 -62
  194. package/src/web/handlers/LongPressGestureHandler.ts +2 -0
  195. package/src/web/handlers/ManualGestureHandler.ts +2 -0
  196. package/src/web/handlers/NativeViewGestureHandler.ts +8 -4
  197. package/src/web/handlers/PanGestureHandler.ts +32 -19
  198. package/src/web/handlers/PinchGestureHandler.ts +2 -0
  199. package/src/web/handlers/RotationGestureHandler.ts +2 -0
  200. package/src/web/handlers/TapGestureHandler.ts +20 -12
  201. package/src/web/interfaces.ts +1 -0
  202. package/src/web/tools/GestureHandlerOrchestrator.ts +1 -7
  203. package/src/web/tools/PointerEventManager.ts +10 -3
  204. package/src/web/tools/PointerTracker.ts +81 -74
  205. package/src/web/tools/TouchEventManager.ts +5 -3
  206. package/src/web/tools/Vector.ts +2 -4
  207. package/src/web/utils.ts +34 -0
  208. package/lib/commonjs/handlers/gestures/GestureDetector.js +0 -704
  209. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +0 -1
  210. package/lib/module/handlers/gestures/GestureDetector.js +0 -654
  211. package/lib/module/handlers/gestures/GestureDetector.js.map +0 -1
  212. package/src/handlers/gestures/GestureDetector.tsx +0 -889
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { Reanimated } from '../reanimatedWrapper';
3
+ import { tagMessage } from '../../../utils';
4
+
5
+ export class Wrap extends React.Component<{
6
+ onGestureHandlerEvent?: unknown;
7
+ // implicit `children` prop has been removed in @types/react^18.0.0
8
+ children?: React.ReactNode;
9
+ }> {
10
+ render() {
11
+ try {
12
+ // I don't think that fighting with types over such a simple function is worth it
13
+ // The only thing it does is add 'collapsable: false' to the child component
14
+ // to make sure it is in the native view hierarchy so the detector can find
15
+ // correct viewTag to attach to.
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ const child: any = React.Children.only(this.props.children);
18
+ return React.cloneElement(
19
+ child,
20
+ { collapsable: false },
21
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
22
+ child.props.children
23
+ );
24
+ } catch (e) {
25
+ throw new Error(
26
+ tagMessage(
27
+ `GestureDetector got more than one view as a child. If you want the gesture to work on multiple views, wrap them with a common parent and attach the gesture to that view.`
28
+ )
29
+ );
30
+ }
31
+ }
32
+ }
33
+
34
+ export const AnimatedWrap =
35
+ Reanimated?.default?.createAnimatedComponent(Wrap) ?? Wrap;
@@ -0,0 +1,112 @@
1
+ import React from 'react';
2
+ import { GestureType, HandlerCallbacks } from '../gesture';
3
+ import { registerHandler } from '../../handlersRegistry';
4
+ import RNGestureHandlerModule from '../../../RNGestureHandlerModule';
5
+ import {
6
+ filterConfig,
7
+ scheduleFlushOperations,
8
+ } from '../../gestureHandlerCommon';
9
+ import { ComposedGesture } from '../gestureComposition';
10
+ import { ActionType } from '../../../ActionType';
11
+ import { Platform } from 'react-native';
12
+ import type RNGestureHandlerModuleWeb from '../../../RNGestureHandlerModule.web';
13
+ import { ghQueueMicrotask } from '../../../ghQueueMicrotask';
14
+ import { AttachedGestureState, WebEventHandler } from './types';
15
+ import {
16
+ extractGestureRelations,
17
+ checkGestureCallbacksForWorklets,
18
+ ALLOWED_PROPS,
19
+ } from './utils';
20
+
21
+ interface AttachHandlersConfig {
22
+ preparedGesture: AttachedGestureState;
23
+ gestureConfig: ComposedGesture | GestureType;
24
+ gesturesToAttach: GestureType[];
25
+ viewTag: number;
26
+ webEventHandlersRef: React.RefObject<WebEventHandler>;
27
+ }
28
+
29
+ export function attachHandlers({
30
+ preparedGesture,
31
+ gestureConfig,
32
+ gesturesToAttach,
33
+ viewTag,
34
+ webEventHandlersRef,
35
+ }: AttachHandlersConfig) {
36
+ gestureConfig.initialize();
37
+
38
+ // use queueMicrotask to extract handlerTags, because all refs should be initialized
39
+ // when it's ran
40
+ ghQueueMicrotask(() => {
41
+ if (!preparedGesture.isMounted) {
42
+ return;
43
+ }
44
+ gestureConfig.prepare();
45
+ });
46
+
47
+ for (const handler of gesturesToAttach) {
48
+ checkGestureCallbacksForWorklets(handler);
49
+ RNGestureHandlerModule.createGestureHandler(
50
+ handler.handlerName,
51
+ handler.handlerTag,
52
+ filterConfig(handler.config, ALLOWED_PROPS)
53
+ );
54
+
55
+ registerHandler(handler.handlerTag, handler, handler.config.testId);
56
+ }
57
+
58
+ // use queueMicrotask to extract handlerTags, because all refs should be initialized
59
+ // when it's ran
60
+ ghQueueMicrotask(() => {
61
+ if (!preparedGesture.isMounted) {
62
+ return;
63
+ }
64
+ for (const handler of gesturesToAttach) {
65
+ RNGestureHandlerModule.updateGestureHandler(
66
+ handler.handlerTag,
67
+ filterConfig(
68
+ handler.config,
69
+ ALLOWED_PROPS,
70
+ extractGestureRelations(handler)
71
+ )
72
+ );
73
+ }
74
+
75
+ scheduleFlushOperations();
76
+ });
77
+
78
+ for (const gesture of gesturesToAttach) {
79
+ const actionType = gesture.shouldUseReanimated
80
+ ? ActionType.REANIMATED_WORKLET
81
+ : ActionType.JS_FUNCTION_NEW_API;
82
+
83
+ if (Platform.OS === 'web') {
84
+ (
85
+ RNGestureHandlerModule.attachGestureHandler as typeof RNGestureHandlerModuleWeb.attachGestureHandler
86
+ )(
87
+ gesture.handlerTag,
88
+ viewTag,
89
+ ActionType.JS_FUNCTION_OLD_API, // ignored on web
90
+ webEventHandlersRef
91
+ );
92
+ } else {
93
+ RNGestureHandlerModule.attachGestureHandler(
94
+ gesture.handlerTag,
95
+ viewTag,
96
+ actionType
97
+ );
98
+ }
99
+ }
100
+
101
+ preparedGesture.attachedGestures = gesturesToAttach;
102
+
103
+ if (preparedGesture.animatedHandlers) {
104
+ const isAnimatedGesture = (g: GestureType) => g.shouldUseReanimated;
105
+
106
+ preparedGesture.animatedHandlers.value = gesturesToAttach
107
+ .filter(isAnimatedGesture)
108
+ .map((g) => g.handlers) as unknown as HandlerCallbacks<
109
+ Record<string, unknown>
110
+ >[];
111
+ }
112
+ }
@@ -0,0 +1,14 @@
1
+ import { unregisterHandler } from '../../handlersRegistry';
2
+ import RNGestureHandlerModule from '../../../RNGestureHandlerModule';
3
+ import { scheduleFlushOperations } from '../../gestureHandlerCommon';
4
+ import { AttachedGestureState } from './types';
5
+
6
+ export function dropHandlers(preparedGesture: AttachedGestureState) {
7
+ for (const handler of preparedGesture.attachedGestures) {
8
+ RNGestureHandlerModule.dropGestureHandler(handler.handlerTag);
9
+
10
+ unregisterHandler(handler.handlerTag, handler.config.testId);
11
+ }
12
+
13
+ scheduleFlushOperations();
14
+ }
@@ -0,0 +1,187 @@
1
+ /* eslint-disable react/no-unused-prop-types */
2
+ import React, {
3
+ useContext,
4
+ useEffect,
5
+ useLayoutEffect,
6
+ useMemo,
7
+ useRef,
8
+ } from 'react';
9
+ import { Platform, findNodeHandle } from 'react-native';
10
+ import { GestureType } from '../gesture';
11
+ import { UserSelect, TouchAction } from '../../gestureHandlerCommon';
12
+ import { ComposedGesture } from '../gestureComposition';
13
+ import { isJestEnv } from '../../../utils';
14
+
15
+ import GestureHandlerRootViewContext from '../../../GestureHandlerRootViewContext';
16
+ import { AttachedGestureState, GestureDetectorState } from './types';
17
+ import { useAnimatedGesture } from './useAnimatedGesture';
18
+ import { attachHandlers } from './attachHandlers';
19
+ import { needsToReattach } from './needsToReattach';
20
+ import { dropHandlers } from './dropHandlers';
21
+ import { useWebEventHandlers } from './utils';
22
+ import { Wrap, AnimatedWrap } from './Wrap';
23
+ import { useDetectorUpdater } from './useDetectorUpdater';
24
+ import { useViewRefHandler } from './useViewRefHandler';
25
+
26
+ function propagateDetectorConfig(
27
+ props: GestureDetectorProps,
28
+ gesture: ComposedGesture | GestureType
29
+ ) {
30
+ const keysToPropagate: (keyof GestureDetectorProps)[] = [
31
+ 'userSelect',
32
+ 'enableContextMenu',
33
+ 'touchAction',
34
+ ];
35
+
36
+ for (const key of keysToPropagate) {
37
+ const value = props[key];
38
+ if (value === undefined) {
39
+ continue;
40
+ }
41
+
42
+ for (const g of gesture.toGestureArray()) {
43
+ const config = g.config as { [key: string]: unknown };
44
+ config[key] = value;
45
+ }
46
+ }
47
+ }
48
+
49
+ interface GestureDetectorProps {
50
+ children?: React.ReactNode;
51
+ /**
52
+ * A gesture object containing the configuration and callbacks.
53
+ * Can be any of:
54
+ * - base gestures (`Tap`, `Pan`, ...)
55
+ * - `ComposedGesture` (`Race`, `Simultaneous`, `Exclusive`)
56
+ */
57
+ gesture: ComposedGesture | GestureType;
58
+ /**
59
+ * #### Web only
60
+ * This parameter allows to specify which `userSelect` property should be applied to underlying view.
61
+ * Possible values are `"none" | "auto" | "text"`. Default value is set to `"none"`.
62
+ */
63
+ userSelect?: UserSelect;
64
+ /**
65
+ * #### Web only
66
+ * Specifies whether context menu should be enabled after clicking on underlying view with right mouse button.
67
+ * Default value is set to `false`.
68
+ */
69
+ enableContextMenu?: boolean;
70
+ /**
71
+ * #### Web only
72
+ * This parameter allows to specify which `touchAction` property should be applied to underlying view.
73
+ * Supports all CSS touch-action values (e.g. `"none"`, `"pan-y"`). Default value is set to `"none"`.
74
+ */
75
+ touchAction?: TouchAction;
76
+ }
77
+
78
+ /**
79
+ * `GestureDetector` is responsible for creating and updating native gesture handlers based on the config of provided gesture.
80
+ *
81
+ * ### Props
82
+ * - `gesture`
83
+ * - `userSelect` (**Web only**)
84
+ * - `enableContextMenu` (**Web only**)
85
+ * - `touchAction` (**Web only**)
86
+ *
87
+ * ### Remarks
88
+ * - Gesture Detector will use first native view in its subtree to recognize gestures, however if this view is used only to group its children it may get automatically collapsed.
89
+ * - Using the same instance of a gesture across multiple Gesture Detectors is not possible.
90
+ *
91
+ * @see https://docs.swmansion.com/react-native-gesture-handler/docs/gestures/gesture-detector
92
+ */
93
+ export const GestureDetector = (props: GestureDetectorProps) => {
94
+ const rootViewContext = useContext(GestureHandlerRootViewContext);
95
+ if (__DEV__ && !rootViewContext && !isJestEnv() && Platform.OS !== 'web') {
96
+ throw new Error(
97
+ 'GestureDetector must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/installation for more details.'
98
+ );
99
+ }
100
+
101
+ // Gesture config should be wrapped with useMemo to prevent unnecessary re-renders
102
+ const gestureConfig = props.gesture;
103
+ propagateDetectorConfig(props, gestureConfig);
104
+
105
+ const gesturesToAttach = useMemo(
106
+ () => gestureConfig.toGestureArray(),
107
+ [gestureConfig]
108
+ );
109
+ const shouldUseReanimated = gesturesToAttach.some(
110
+ (g) => g.shouldUseReanimated
111
+ );
112
+
113
+ const webEventHandlersRef = useWebEventHandlers();
114
+ // store state in ref to prevent unnecessary renders
115
+ const state = useRef<GestureDetectorState>({
116
+ firstRender: true,
117
+ viewRef: null,
118
+ previousViewTag: -1,
119
+ forceRebuildReanimatedEvent: false,
120
+ }).current;
121
+
122
+ const preparedGesture = React.useRef<AttachedGestureState>({
123
+ attachedGestures: [],
124
+ animatedEventHandler: null,
125
+ animatedHandlers: null,
126
+ shouldUseReanimated: shouldUseReanimated,
127
+ isMounted: false,
128
+ }).current;
129
+
130
+ const updateAttachedGestures = useDetectorUpdater(
131
+ state,
132
+ preparedGesture,
133
+ gesturesToAttach,
134
+ gestureConfig,
135
+ webEventHandlersRef
136
+ );
137
+
138
+ const refHandler = useViewRefHandler(state, updateAttachedGestures);
139
+
140
+ // Reanimated event should be rebuilt only when gestures are reattached, otherwise
141
+ // config update will be enough as all necessary items are stored in shared values anyway
142
+ const needsToRebuildReanimatedEvent =
143
+ state.firstRender ||
144
+ state.forceRebuildReanimatedEvent ||
145
+ needsToReattach(preparedGesture, gesturesToAttach);
146
+ state.forceRebuildReanimatedEvent = false;
147
+
148
+ useAnimatedGesture(preparedGesture, needsToRebuildReanimatedEvent);
149
+
150
+ useLayoutEffect(() => {
151
+ const viewTag = findNodeHandle(state.viewRef) as number;
152
+ preparedGesture.isMounted = true;
153
+
154
+ attachHandlers({
155
+ preparedGesture,
156
+ gestureConfig,
157
+ gesturesToAttach,
158
+ webEventHandlersRef,
159
+ viewTag,
160
+ });
161
+
162
+ return () => {
163
+ preparedGesture.isMounted = false;
164
+ dropHandlers(preparedGesture);
165
+ };
166
+ }, []);
167
+
168
+ useEffect(() => {
169
+ if (state.firstRender) {
170
+ state.firstRender = false;
171
+ } else {
172
+ updateAttachedGestures();
173
+ }
174
+ }, [props]);
175
+
176
+ if (shouldUseReanimated) {
177
+ return (
178
+ <AnimatedWrap
179
+ ref={refHandler}
180
+ onGestureHandlerEvent={preparedGesture.animatedEventHandler}>
181
+ {props.children}
182
+ </AnimatedWrap>
183
+ );
184
+ } else {
185
+ return <Wrap ref={refHandler}>{props.children}</Wrap>;
186
+ }
187
+ };
@@ -0,0 +1,27 @@
1
+ import { GestureType } from '../gesture';
2
+ import { AttachedGestureState } from './types';
3
+
4
+ // Checks whether the gesture should be reattached to the view, this will happen when:
5
+ // - The number of gestures in the preparedGesture is different than the number of gestures in the gesture
6
+ // - The handlerName is different in any of the gestures
7
+ // - At least one of the gestures changed the thread it runs on
8
+ export function needsToReattach(
9
+ preparedGesture: AttachedGestureState,
10
+ newGestures: GestureType[]
11
+ ) {
12
+ if (newGestures.length !== preparedGesture.attachedGestures.length) {
13
+ return true;
14
+ }
15
+ for (let i = 0; i < newGestures.length; i++) {
16
+ if (
17
+ newGestures[i].handlerName !==
18
+ preparedGesture.attachedGestures[i].handlerName ||
19
+ newGestures[i].shouldUseReanimated !==
20
+ preparedGesture.attachedGestures[i].shouldUseReanimated
21
+ ) {
22
+ return true;
23
+ }
24
+ }
25
+
26
+ return false;
27
+ }
@@ -0,0 +1,32 @@
1
+ import { GestureType, HandlerCallbacks } from '../gesture';
2
+ import { SharedValue } from '../reanimatedWrapper';
3
+ import { HandlerStateChangeEvent } from '../../gestureHandlerCommon';
4
+
5
+ export interface AttachedGestureState {
6
+ // Array of gestures that should be attached to the view under that gesture detector
7
+ attachedGestures: GestureType[];
8
+ // Event handler for the gesture, returned by `useEvent` from Reanimated
9
+ animatedEventHandler: unknown;
10
+ // Shared value that's responsible for transferring the callbacks to the UI thread handler
11
+ animatedHandlers: SharedValue<
12
+ HandlerCallbacks<Record<string, unknown>>[] | null
13
+ > | null;
14
+ // Whether `useAnimatedGesture` should be called inside detector
15
+ shouldUseReanimated: boolean;
16
+ // Whether the GestureDetector is mounted
17
+ isMounted: boolean;
18
+ }
19
+
20
+ export interface GestureDetectorState {
21
+ firstRender: boolean;
22
+ viewRef: React.Component | null;
23
+ previousViewTag: number;
24
+ forceRebuildReanimatedEvent: boolean;
25
+ }
26
+
27
+ export interface WebEventHandler {
28
+ onGestureHandlerEvent: (event: HandlerStateChangeEvent<unknown>) => void;
29
+ onGestureHandlerStateChange?: (
30
+ event: HandlerStateChangeEvent<unknown>
31
+ ) => void;
32
+ }
@@ -0,0 +1,94 @@
1
+ import { GestureType, HandlerCallbacks } from '../gesture';
2
+ import { registerHandler } from '../../handlersRegistry';
3
+ import RNGestureHandlerModule from '../../../RNGestureHandlerModule';
4
+ import {
5
+ filterConfig,
6
+ scheduleFlushOperations,
7
+ } from '../../gestureHandlerCommon';
8
+ import { ComposedGesture } from '../gestureComposition';
9
+ import { ghQueueMicrotask } from '../../../ghQueueMicrotask';
10
+ import { AttachedGestureState } from './types';
11
+ import {
12
+ extractGestureRelations,
13
+ checkGestureCallbacksForWorklets,
14
+ ALLOWED_PROPS,
15
+ } from './utils';
16
+
17
+ export function updateHandlers(
18
+ preparedGesture: AttachedGestureState,
19
+ gestureConfig: ComposedGesture | GestureType,
20
+ newGestures: GestureType[]
21
+ ) {
22
+ gestureConfig.prepare();
23
+
24
+ for (let i = 0; i < newGestures.length; i++) {
25
+ const handler = preparedGesture.attachedGestures[i];
26
+ checkGestureCallbacksForWorklets(handler);
27
+
28
+ // only update handlerTag when it's actually different, it may be the same
29
+ // if gesture config object is wrapped with useMemo
30
+ if (newGestures[i].handlerTag !== handler.handlerTag) {
31
+ newGestures[i].handlerTag = handler.handlerTag;
32
+ newGestures[i].handlers.handlerTag = handler.handlerTag;
33
+ }
34
+ }
35
+
36
+ // use queueMicrotask to extract handlerTags, because when it's ran, all refs should be updated
37
+ // and handlerTags in BaseGesture references should be updated in the loop above (we need to wait
38
+ // in case of external relations)
39
+ ghQueueMicrotask(() => {
40
+ if (!preparedGesture.isMounted) {
41
+ return;
42
+ }
43
+ for (let i = 0; i < newGestures.length; i++) {
44
+ const handler = preparedGesture.attachedGestures[i];
45
+
46
+ handler.config = newGestures[i].config;
47
+ handler.handlers = newGestures[i].handlers;
48
+
49
+ RNGestureHandlerModule.updateGestureHandler(
50
+ handler.handlerTag,
51
+ filterConfig(
52
+ handler.config,
53
+ ALLOWED_PROPS,
54
+ extractGestureRelations(handler)
55
+ )
56
+ );
57
+
58
+ registerHandler(handler.handlerTag, handler, handler.config.testId);
59
+ }
60
+
61
+ if (preparedGesture.animatedHandlers) {
62
+ const previousHandlersValue =
63
+ preparedGesture.animatedHandlers.value ?? [];
64
+ const newHandlersValue = preparedGesture.attachedGestures
65
+ .filter((g) => g.shouldUseReanimated) // ignore gestures that shouldn't run on UI
66
+ .map((g) => g.handlers) as unknown as HandlerCallbacks<
67
+ Record<string, unknown>
68
+ >[];
69
+
70
+ // if amount of gesture configs changes, we need to update the callbacks in shared value
71
+ let shouldUpdateSharedValue =
72
+ previousHandlersValue.length !== newHandlersValue.length;
73
+
74
+ if (!shouldUpdateSharedValue) {
75
+ // if the amount is the same, we need to check if any of the configs inside has changed
76
+ for (let i = 0; i < newHandlersValue.length; i++) {
77
+ if (
78
+ // we can use the `gestureId` prop as it's unique for every config instance
79
+ newHandlersValue[i].gestureId !== previousHandlersValue[i].gestureId
80
+ ) {
81
+ shouldUpdateSharedValue = true;
82
+ break;
83
+ }
84
+ }
85
+ }
86
+
87
+ if (shouldUpdateSharedValue) {
88
+ preparedGesture.animatedHandlers.value = newHandlersValue;
89
+ }
90
+ }
91
+
92
+ scheduleFlushOperations();
93
+ });
94
+ }