react-native-gesture-handler 2.3.2 → 2.4.2

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.
Files changed (166) hide show
  1. package/RNGestureHandler.podspec +2 -1
  2. package/android/build.gradle +38 -6
  3. package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandler.kt +14 -2
  4. package/android/noreanimated/src/main/java/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt +10 -0
  5. package/android/reanimated/src/main/java/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt +17 -0
  6. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.kt +3 -41
  7. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.kt +6 -0
  8. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +10 -54
  9. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt +2 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.kt +6 -0
  11. package/ios/RNGHTouchEventType.h +9 -0
  12. package/ios/RNGestureHandler.h +2 -2
  13. package/ios/RNGestureHandler.m +21 -8
  14. package/ios/RNGestureHandlerButton.h +1 -0
  15. package/ios/RNGestureHandlerButton.m +9 -1
  16. package/ios/RNGestureHandlerButtonComponentView.mm +14 -1
  17. package/ios/RNGestureHandlerButtonManager.m +4 -1
  18. package/ios/RNGestureHandlerEvents.h +2 -2
  19. package/ios/RNGestureHandlerEvents.m +2 -2
  20. package/ios/RNGestureHandlerManager.h +2 -0
  21. package/ios/RNGestureHandlerManager.mm +30 -20
  22. package/ios/RNGestureHandlerModule.mm +18 -0
  23. package/ios/RNGestureHandlerPointerTracker.h +2 -2
  24. package/ios/RNGestureHandlerPointerTracker.m +9 -6
  25. package/ios/RNGestureHandlerRegistry.h +1 -0
  26. package/ios/RNGestureHandlerRegistry.m +10 -0
  27. package/lib/commonjs/GestureHandlerRootView.android.js +7 -1
  28. package/lib/commonjs/GestureHandlerRootView.android.js.map +1 -1
  29. package/lib/commonjs/GestureHandlerRootView.js +6 -0
  30. package/lib/commonjs/GestureHandlerRootView.js.map +1 -1
  31. package/lib/commonjs/GestureHandlerRootView.web.js +19 -0
  32. package/lib/commonjs/GestureHandlerRootView.web.js.map +1 -0
  33. package/lib/commonjs/RNGestureHandlerModule.js +5 -0
  34. package/lib/commonjs/RNGestureHandlerModule.js.map +1 -1
  35. package/lib/commonjs/RNGestureHandlerModule.web.js +4 -1
  36. package/lib/commonjs/RNGestureHandlerModule.web.js.map +1 -1
  37. package/lib/commonjs/{EventType.js → TouchEventType.js} +4 -4
  38. package/lib/commonjs/TouchEventType.js.map +1 -0
  39. package/lib/commonjs/components/DrawerLayout.js +38 -11
  40. package/lib/commonjs/components/DrawerLayout.js.map +1 -1
  41. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  42. package/lib/commonjs/components/GestureHandlerButton.js +1 -1
  43. package/lib/commonjs/components/GestureHandlerButton.js.map +1 -1
  44. package/lib/commonjs/components/touchables/GenericTouchable.js +2 -0
  45. package/lib/commonjs/components/touchables/GenericTouchable.js.map +1 -1
  46. package/lib/commonjs/fabric/RNGestureHandlerButtonNativeComponent.js +4 -6
  47. package/lib/commonjs/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  48. package/lib/commonjs/fabric/RNGestureHandlerRootViewNativeComponent.js +4 -6
  49. package/lib/commonjs/fabric/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
  50. package/lib/commonjs/getShadowNodeFromRef.js +12 -9
  51. package/lib/commonjs/getShadowNodeFromRef.js.map +1 -1
  52. package/lib/commonjs/handlers/ForceTouchGestureHandler.js +2 -1
  53. package/lib/commonjs/handlers/ForceTouchGestureHandler.js.map +1 -1
  54. package/lib/commonjs/handlers/createHandler.js +25 -20
  55. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  56. package/lib/commonjs/handlers/gestureHandlerCommon.js +18 -1
  57. package/lib/commonjs/handlers/gestureHandlerCommon.js.map +1 -1
  58. package/lib/commonjs/handlers/gestures/GestureDetector.js +120 -80
  59. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
  60. package/lib/commonjs/handlers/gestures/eventReceiver.js +6 -5
  61. package/lib/commonjs/handlers/gestures/eventReceiver.js.map +1 -1
  62. package/lib/commonjs/handlers/gestures/gesture.js +24 -4
  63. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  64. package/lib/commonjs/init.js +10 -1
  65. package/lib/commonjs/init.js.map +1 -1
  66. package/lib/commonjs/mocks.js +2 -0
  67. package/lib/commonjs/mocks.js.map +1 -1
  68. package/lib/commonjs/utils.js +23 -1
  69. package/lib/commonjs/utils.js.map +1 -1
  70. package/lib/commonjs/web/GestureHandler.js +4 -1
  71. package/lib/commonjs/web/GestureHandler.js.map +1 -1
  72. package/lib/commonjs/web/utils.js.map +1 -1
  73. package/lib/module/GestureHandlerRootView.android.js +7 -2
  74. package/lib/module/GestureHandlerRootView.android.js.map +1 -1
  75. package/lib/module/GestureHandlerRootView.js +5 -0
  76. package/lib/module/GestureHandlerRootView.js.map +1 -1
  77. package/lib/module/GestureHandlerRootView.web.js +6 -0
  78. package/lib/module/GestureHandlerRootView.web.js.map +1 -0
  79. package/lib/module/RNGestureHandlerModule.js +5 -0
  80. package/lib/module/RNGestureHandlerModule.js.map +1 -1
  81. package/lib/module/RNGestureHandlerModule.web.js +4 -1
  82. package/lib/module/RNGestureHandlerModule.web.js.map +1 -1
  83. package/lib/module/{EventType.js → TouchEventType.js} +2 -2
  84. package/lib/module/TouchEventType.js.map +1 -0
  85. package/lib/module/components/DrawerLayout.js +38 -11
  86. package/lib/module/components/DrawerLayout.js.map +1 -1
  87. package/lib/module/components/GestureButtons.js.map +1 -1
  88. package/lib/module/components/GestureHandlerButton.js +2 -2
  89. package/lib/module/components/GestureHandlerButton.js.map +1 -1
  90. package/lib/module/components/touchables/GenericTouchable.js +2 -0
  91. package/lib/module/components/touchables/GenericTouchable.js.map +1 -1
  92. package/lib/module/fabric/RNGestureHandlerButtonNativeComponent.js +5 -7
  93. package/lib/module/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  94. package/lib/module/fabric/RNGestureHandlerRootViewNativeComponent.js +5 -8
  95. package/lib/module/fabric/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
  96. package/lib/module/getShadowNodeFromRef.js +11 -8
  97. package/lib/module/getShadowNodeFromRef.js.map +1 -1
  98. package/lib/module/handlers/ForceTouchGestureHandler.js +1 -1
  99. package/lib/module/handlers/ForceTouchGestureHandler.js.map +1 -1
  100. package/lib/module/handlers/createHandler.js +25 -22
  101. package/lib/module/handlers/createHandler.js.map +1 -1
  102. package/lib/module/handlers/gestureHandlerCommon.js +11 -1
  103. package/lib/module/handlers/gestureHandlerCommon.js.map +1 -1
  104. package/lib/module/handlers/gestures/GestureDetector.js +120 -81
  105. package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
  106. package/lib/module/handlers/gestures/eventReceiver.js +6 -7
  107. package/lib/module/handlers/gestures/eventReceiver.js.map +1 -1
  108. package/lib/module/handlers/gestures/gesture.js +23 -4
  109. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  110. package/lib/module/init.js +6 -1
  111. package/lib/module/init.js.map +1 -1
  112. package/lib/module/mocks.js +2 -0
  113. package/lib/module/mocks.js.map +1 -1
  114. package/lib/module/utils.js +17 -1
  115. package/lib/module/utils.js.map +1 -1
  116. package/lib/module/web/GestureHandler.js +4 -1
  117. package/lib/module/web/GestureHandler.js.map +1 -1
  118. package/lib/module/web/utils.js.map +1 -1
  119. package/lib/typescript/GestureHandlerRootView.web.d.ts +5 -0
  120. package/lib/typescript/RNGestureHandlerModule.d.ts +1 -0
  121. package/lib/typescript/RNGestureHandlerModule.web.d.ts +1 -0
  122. package/lib/typescript/{EventType.d.ts → TouchEventType.d.ts} +2 -2
  123. package/lib/typescript/components/DrawerLayout.d.ts +3 -0
  124. package/lib/typescript/components/GestureButtons.d.ts +18 -6
  125. package/lib/typescript/fabric/RNGestureHandlerButtonNativeComponent.d.ts +13 -0
  126. package/lib/typescript/fabric/RNGestureHandlerRootViewNativeComponent.d.ts +5 -0
  127. package/lib/typescript/handlers/ForceTouchGestureHandler.d.ts +2 -2
  128. package/lib/typescript/handlers/NativeViewGestureHandler.d.ts +1 -1
  129. package/lib/typescript/handlers/gestureHandlerCommon.d.ts +6 -3
  130. package/lib/typescript/handlers/gestures/GestureDetector.d.ts +2 -4
  131. package/lib/typescript/handlers/gestures/eventReceiver.d.ts +2 -0
  132. package/lib/typescript/handlers/gestures/gesture.d.ts +5 -0
  133. package/lib/typescript/init.d.ts +1 -0
  134. package/lib/typescript/mocks.d.ts +1 -0
  135. package/lib/typescript/utils.d.ts +2 -0
  136. package/lib/typescript/web/GestureHandler.d.ts +1 -1
  137. package/package.json +4 -2
  138. package/src/GestureHandlerRootView.android.tsx +8 -2
  139. package/src/GestureHandlerRootView.tsx +6 -0
  140. package/src/GestureHandlerRootView.web.tsx +12 -0
  141. package/src/RNGestureHandlerModule.ts +7 -0
  142. package/src/RNGestureHandlerModule.web.ts +2 -0
  143. package/src/{EventType.ts → TouchEventType.ts} +2 -2
  144. package/src/components/DrawerLayout.tsx +34 -10
  145. package/src/components/GestureButtons.tsx +21 -7
  146. package/src/components/GestureHandlerButton.tsx +2 -2
  147. package/src/components/touchables/GenericTouchable.tsx +2 -0
  148. package/src/fabric/RNGestureHandlerButtonNativeComponent.ts +27 -0
  149. package/src/fabric/RNGestureHandlerRootViewNativeComponent.ts +12 -0
  150. package/src/getShadowNodeFromRef.ts +12 -9
  151. package/src/handlers/ForceTouchGestureHandler.ts +3 -2
  152. package/src/handlers/createHandler.ts +30 -26
  153. package/src/handlers/gestureHandlerCommon.ts +21 -2
  154. package/src/handlers/gestures/GestureDetector.tsx +164 -105
  155. package/src/handlers/gestures/eventReceiver.ts +6 -6
  156. package/src/handlers/gestures/gesture.ts +29 -2
  157. package/src/init.ts +8 -1
  158. package/src/mocks.ts +2 -0
  159. package/src/utils.ts +20 -0
  160. package/src/web/GestureHandler.ts +7 -1
  161. package/src/web/utils.ts +1 -1
  162. package/ios/RNTouchEventType.h +0 -9
  163. package/lib/commonjs/EventType.js.map +0 -1
  164. package/lib/module/EventType.js.map +0 -1
  165. package/src/fabric/RNGestureHandlerButtonNativeComponent.js +0 -27
  166. package/src/fabric/RNGestureHandlerRootViewNativeComponent.js +0 -19
@@ -6,16 +6,18 @@ import * as React from 'react';
6
6
  import { Platform, findNodeHandle as findNodeHandleRN } from 'react-native';
7
7
 
8
8
  import { State } from '../State';
9
- import { EventType } from '../EventType';
9
+ import { TouchEventType } from '../TouchEventType';
10
10
  import { ValueOf } from '../typeUtils';
11
11
  import { handlerIDToTag } from './handlersRegistry';
12
12
  import { toArray } from '../utils';
13
+ import RNGestureHandlerModule from '../RNGestureHandlerModule';
13
14
 
14
15
  const commonProps = [
15
16
  'id',
16
17
  'enabled',
17
18
  'shouldCancelWhenOutside',
18
19
  'hitSlop',
20
+ 'cancelsTouchesInView',
19
21
  ] as const;
20
22
 
21
23
  const componentInteractionProps = ['waitFor', 'simultaneousHandlers'] as const;
@@ -83,7 +85,7 @@ export type GestureTouchEvent = {
83
85
  handlerTag: number;
84
86
  numberOfTouches: number;
85
87
  state: ValueOf<typeof State>;
86
- eventType: EventType;
88
+ eventType: TouchEventType;
87
89
  allTouches: TouchData[];
88
90
  changedTouches: TouchData[];
89
91
  };
@@ -111,6 +113,7 @@ export type BaseGestureHandlerProps<
111
113
  waitFor?: React.Ref<unknown> | React.Ref<unknown>[];
112
114
  simultaneousHandlers?: React.Ref<unknown> | React.Ref<unknown>[];
113
115
  testID?: string;
116
+ cancelsTouchesInView?: boolean;
114
117
  // TODO(TS) - fix event types
115
118
  onBegan?: (event: HandlerStateChangeEvent) => void;
116
119
  onFailed?: (event: HandlerStateChangeEvent) => void;
@@ -123,6 +126,8 @@ export type BaseGestureHandlerProps<
123
126
  onHandlerStateChange?: (
124
127
  event: HandlerStateChangeEvent<ExtraEventPayloadT>
125
128
  ) => void;
129
+ // implicit `children` prop has been removed in @types/react^18.0.0
130
+ children?: React.ReactNode;
126
131
  };
127
132
 
128
133
  function isConfigParam(param: unknown, name: string) {
@@ -180,3 +185,17 @@ export function findNodeHandle(
180
185
  if (Platform.OS === 'web') return node;
181
186
  return findNodeHandleRN(node);
182
187
  }
188
+
189
+ let scheduledFlushOperationsId: ReturnType<
190
+ typeof requestAnimationFrame
191
+ > | null = null;
192
+
193
+ export function scheduleFlushOperations() {
194
+ if (scheduledFlushOperationsId === null) {
195
+ scheduledFlushOperationsId = requestAnimationFrame(() => {
196
+ RNGestureHandlerModule.flushOperations();
197
+
198
+ scheduledFlushOperationsId = null;
199
+ });
200
+ }
201
+ }
@@ -16,6 +16,8 @@ import {
16
16
  GestureTouchEvent,
17
17
  GestureUpdateEvent,
18
18
  GestureStateChangeEvent,
19
+ HandlerStateChangeEvent,
20
+ scheduleFlushOperations,
19
21
  } from '../gestureHandlerCommon';
20
22
  import {
21
23
  GestureStateManager,
@@ -30,15 +32,18 @@ import {
30
32
  } from '../PanGestureHandler';
31
33
  import { tapGestureHandlerProps } from '../TapGestureHandler';
32
34
  import { State } from '../../State';
33
- import { EventType } from '../../EventType';
35
+ import { TouchEventType } from '../../TouchEventType';
34
36
  import { ComposedGesture } from './gestureComposition';
35
37
  import { ActionType } from '../../ActionType';
36
38
  import { isFabric, tagMessage } from '../../utils';
37
39
  import { getShadowNodeFromRef } from '../../getShadowNodeFromRef';
40
+ import { Platform } from 'react-native';
41
+ import type RNGestureHandlerModuleWeb from '../../RNGestureHandlerModule.web';
42
+ import { onGestureHandlerEvent } from './eventReceiver';
38
43
 
39
- declare global {
40
- function isFormsStackingContext(node: unknown): boolean | null; // JSI function
41
- }
44
+ declare const global: {
45
+ isFormsStackingContext: (node: unknown) => boolean | null; // JSI function
46
+ };
42
47
 
43
48
  const ALLOWED_PROPS = [
44
49
  ...baseGestureHandlerWithMonitorProps,
@@ -84,6 +89,8 @@ function dropHandlers(preparedGesture: GestureConfigReference) {
84
89
 
85
90
  unregisterHandler(handler.handlerTag, handler.config.testId);
86
91
  }
92
+
93
+ scheduleFlushOperations();
87
94
  }
88
95
 
89
96
  function checkGestureCallbacksForWorklets(gesture: GestureType) {
@@ -107,11 +114,16 @@ function checkGestureCallbacksForWorklets(gesture: GestureType) {
107
114
  }
108
115
  }
109
116
 
117
+ interface WebEventHandler {
118
+ onGestureHandlerEvent: (event: HandlerStateChangeEvent<unknown>) => void;
119
+ }
120
+
110
121
  interface AttachHandlersConfig {
111
122
  preparedGesture: GestureConfigReference;
112
123
  gestureConfig: ComposedGesture | GestureType | undefined;
113
124
  gesture: GestureType[];
114
125
  viewTag: number;
126
+ webEventHandlersRef: React.RefObject<WebEventHandler>;
115
127
  }
116
128
 
117
129
  function attachHandlers({
@@ -119,6 +131,7 @@ function attachHandlers({
119
131
  gestureConfig,
120
132
  gesture,
121
133
  viewTag,
134
+ webEventHandlersRef,
122
135
  }: AttachHandlersConfig) {
123
136
  if (!preparedGesture.firstExecution) {
124
137
  gestureConfig?.initialize();
@@ -142,10 +155,12 @@ function attachHandlers({
142
155
  );
143
156
 
144
157
  registerHandler(handler.handlerTag, handler, handler.config.testId);
158
+ }
145
159
 
146
- // use setImmediate to extract handlerTags, because all refs should be initialized
147
- // when it's ran
148
- setImmediate(() => {
160
+ // use setImmediate to extract handlerTags, because all refs should be initialized
161
+ // when it's ran
162
+ setImmediate(() => {
163
+ for (const handler of gesture) {
149
164
  let requireToFail: number[] = [];
150
165
  if (handler.config.requireToFail) {
151
166
  requireToFail = extractValidHandlerTags(handler.config.requireToFail);
@@ -165,8 +180,11 @@ function attachHandlers({
165
180
  waitFor: requireToFail,
166
181
  })
167
182
  );
168
- });
169
- }
183
+ }
184
+
185
+ scheduleFlushOperations();
186
+ });
187
+
170
188
  preparedGesture.config = gesture;
171
189
 
172
190
  for (const gesture of preparedGesture.config) {
@@ -174,11 +192,20 @@ function attachHandlers({
174
192
  ? ActionType.REANIMATED_WORKLET
175
193
  : ActionType.JS_FUNCTION_NEW_API;
176
194
 
177
- RNGestureHandlerModule.attachGestureHandler(
178
- gesture.handlerTag,
179
- viewTag,
180
- actionType
181
- );
195
+ if (Platform.OS === 'web') {
196
+ (RNGestureHandlerModule.attachGestureHandler as typeof RNGestureHandlerModuleWeb.attachGestureHandler)(
197
+ gesture.handlerTag,
198
+ viewTag,
199
+ ActionType.JS_FUNCTION_OLD_API, // ignored on web
200
+ webEventHandlersRef
201
+ );
202
+ } else {
203
+ RNGestureHandlerModule.attachGestureHandler(
204
+ gesture.handlerTag,
205
+ viewTag,
206
+ actionType
207
+ );
208
+ }
182
209
  }
183
210
 
184
211
  if (preparedGesture.animatedHandlers) {
@@ -241,12 +268,37 @@ function updateHandlers(
241
268
  }
242
269
 
243
270
  if (preparedGesture.animatedHandlers) {
244
- preparedGesture.animatedHandlers.value = (preparedGesture.config
271
+ const previousHandlersValue =
272
+ preparedGesture.animatedHandlers.value ?? [];
273
+ const newHandlersValue = (preparedGesture.config
245
274
  .filter((g) => g.shouldUseReanimated) // ignore gestures that shouldn't run on UI
246
275
  .map((g) => g.handlers) as unknown) as HandlerCallbacks<
247
276
  Record<string, unknown>
248
277
  >[];
278
+
279
+ // if amount of gesture configs changes, we need to update the callbacks in shared value
280
+ let shouldUpdateSharedValue =
281
+ previousHandlersValue.length !== newHandlersValue.length;
282
+
283
+ if (!shouldUpdateSharedValue) {
284
+ // if the amount is the same, we need to check if any of the configs inside has changed
285
+ for (let i = 0; i < newHandlersValue.length; i++) {
286
+ if (
287
+ // we can use the `gestureId` prop as it's unique for every config instance
288
+ newHandlersValue[i].gestureId !== previousHandlersValue[i].gestureId
289
+ ) {
290
+ shouldUpdateSharedValue = true;
291
+ break;
292
+ }
293
+ }
294
+ }
295
+
296
+ if (shouldUpdateSharedValue) {
297
+ preparedGesture.animatedHandlers.value = newHandlersValue;
298
+ }
249
299
  }
300
+
301
+ scheduleFlushOperations();
250
302
  });
251
303
  }
252
304
 
@@ -270,88 +322,90 @@ function needsToReattach(
270
322
  return false;
271
323
  }
272
324
 
273
- function useAnimatedGesture(
274
- preparedGesture: GestureConfigReference,
275
- needsRebuild: boolean
276
- ) {
277
- if (!Reanimated) {
278
- return;
279
- }
325
+ function isStateChangeEvent(
326
+ event: GestureUpdateEvent | GestureStateChangeEvent | GestureTouchEvent
327
+ ): event is GestureStateChangeEvent {
328
+ 'worklet';
329
+ // @ts-ignore Yes, the oldState prop is missing on GestureTouchEvent, that's the point
330
+ return event.oldState != null;
331
+ }
280
332
 
281
- function isStateChangeEvent(
282
- event: GestureUpdateEvent | GestureStateChangeEvent | GestureTouchEvent
283
- ): event is GestureStateChangeEvent {
284
- 'worklet';
285
- // @ts-ignore Yes, the oldState prop is missing on GestureTouchEvent, that's the point
286
- return event.oldState != null;
287
- }
333
+ function isTouchEvent(
334
+ event: GestureUpdateEvent | GestureStateChangeEvent | GestureTouchEvent
335
+ ): event is GestureTouchEvent {
336
+ 'worklet';
337
+ return event.eventType != null;
338
+ }
288
339
 
289
- function isTouchEvent(
290
- event: GestureUpdateEvent | GestureStateChangeEvent | GestureTouchEvent
291
- ): event is GestureTouchEvent {
292
- 'worklet';
293
- return event.eventType != null;
340
+ function getHandler(
341
+ type: CALLBACK_TYPE,
342
+ gesture: HandlerCallbacks<Record<string, unknown>>
343
+ ) {
344
+ 'worklet';
345
+ switch (type) {
346
+ case CALLBACK_TYPE.BEGAN:
347
+ return gesture.onBegin;
348
+ case CALLBACK_TYPE.START:
349
+ return gesture.onStart;
350
+ case CALLBACK_TYPE.UPDATE:
351
+ return gesture.onUpdate;
352
+ case CALLBACK_TYPE.CHANGE:
353
+ return gesture.onChange;
354
+ case CALLBACK_TYPE.END:
355
+ return gesture.onEnd;
356
+ case CALLBACK_TYPE.FINALIZE:
357
+ return gesture.onFinalize;
358
+ case CALLBACK_TYPE.TOUCHES_DOWN:
359
+ return gesture.onTouchesDown;
360
+ case CALLBACK_TYPE.TOUCHES_MOVE:
361
+ return gesture.onTouchesMove;
362
+ case CALLBACK_TYPE.TOUCHES_UP:
363
+ return gesture.onTouchesUp;
364
+ case CALLBACK_TYPE.TOUCHES_CANCELLED:
365
+ return gesture.onTouchesCancelled;
294
366
  }
367
+ }
295
368
 
296
- function getHandler(
297
- type: CALLBACK_TYPE,
298
- gesture: HandlerCallbacks<Record<string, unknown>>
299
- ) {
300
- 'worklet';
301
- switch (type) {
302
- case CALLBACK_TYPE.BEGAN:
303
- return gesture.onBegin;
304
- case CALLBACK_TYPE.START:
305
- return gesture.onStart;
306
- case CALLBACK_TYPE.UPDATE:
307
- return gesture.onUpdate;
308
- case CALLBACK_TYPE.CHANGE:
309
- return gesture.onChange;
310
- case CALLBACK_TYPE.END:
311
- return gesture.onEnd;
312
- case CALLBACK_TYPE.FINALIZE:
313
- return gesture.onFinalize;
314
- case CALLBACK_TYPE.TOUCHES_DOWN:
315
- return gesture.onTouchesDown;
316
- case CALLBACK_TYPE.TOUCHES_MOVE:
317
- return gesture.onTouchesMove;
318
- case CALLBACK_TYPE.TOUCHES_UP:
319
- return gesture.onTouchesUp;
320
- case CALLBACK_TYPE.TOUCHES_CANCELLED:
321
- return gesture.onTouchesCancelled;
322
- }
369
+ function touchEventTypeToCallbackType(
370
+ eventType: TouchEventType
371
+ ): CALLBACK_TYPE {
372
+ 'worklet';
373
+ switch (eventType) {
374
+ case TouchEventType.TOUCHES_DOWN:
375
+ return CALLBACK_TYPE.TOUCHES_DOWN;
376
+ case TouchEventType.TOUCHES_MOVE:
377
+ return CALLBACK_TYPE.TOUCHES_MOVE;
378
+ case TouchEventType.TOUCHES_UP:
379
+ return CALLBACK_TYPE.TOUCHES_UP;
380
+ case TouchEventType.TOUCHES_CANCELLED:
381
+ return CALLBACK_TYPE.TOUCHES_CANCELLED;
323
382
  }
383
+ return CALLBACK_TYPE.UNDEFINED;
384
+ }
324
385
 
325
- function touchEventTypeToCallbackType(eventType: EventType): CALLBACK_TYPE {
326
- 'worklet';
327
- switch (eventType) {
328
- case EventType.TOUCHES_DOWN:
329
- return CALLBACK_TYPE.TOUCHES_DOWN;
330
- case EventType.TOUCHES_MOVE:
331
- return CALLBACK_TYPE.TOUCHES_MOVE;
332
- case EventType.TOUCHES_UP:
333
- return CALLBACK_TYPE.TOUCHES_UP;
334
- case EventType.TOUCHES_CANCELLED:
335
- return CALLBACK_TYPE.TOUCHES_CANCELLED;
336
- }
337
- return CALLBACK_TYPE.UNDEFINED;
386
+ function runWorklet(
387
+ type: CALLBACK_TYPE,
388
+ gesture: HandlerCallbacks<Record<string, unknown>>,
389
+ event: GestureStateChangeEvent | GestureUpdateEvent | GestureTouchEvent,
390
+ ...args: any[]
391
+ ) {
392
+ 'worklet';
393
+ const handler = getHandler(type, gesture);
394
+ if (gesture.isWorklet[type]) {
395
+ // @ts-ignore Logic below makes sure the correct event is send to the
396
+ // correct handler.
397
+ handler?.(event, ...args);
398
+ } else if (handler) {
399
+ console.warn(tagMessage('Animated gesture callback must be a worklet'));
338
400
  }
401
+ }
339
402
 
340
- function runWorklet(
341
- type: CALLBACK_TYPE,
342
- gesture: HandlerCallbacks<Record<string, unknown>>,
343
- event: GestureStateChangeEvent | GestureUpdateEvent | GestureTouchEvent,
344
- ...args: any[]
345
- ) {
346
- 'worklet';
347
- const handler = getHandler(type, gesture);
348
- if (gesture.isWorklet[type]) {
349
- // @ts-ignore Logic below makes sure the correct event is send to the
350
- // correct handler.
351
- handler?.(event, ...args);
352
- } else if (handler) {
353
- console.warn(tagMessage('Animated gesture callback must be a worklet'));
354
- }
403
+ function useAnimatedGesture(
404
+ preparedGesture: GestureConfigReference,
405
+ needsRebuild: boolean
406
+ ) {
407
+ if (!Reanimated) {
408
+ return;
355
409
  }
356
410
 
357
411
  // Hooks are called conditionally, but the condition is whether the
@@ -418,7 +472,7 @@ function useAnimatedGesture(
418
472
  stateControllers[i] = GestureStateManager.create(event.handlerTag);
419
473
  }
420
474
 
421
- if (event.eventType !== EventType.UNDETERMINED) {
475
+ if (event.eventType !== TouchEventType.UNDETERMINED) {
422
476
  runWorklet(
423
477
  touchEventTypeToCallbackType(event.eventType),
424
478
  gesture,
@@ -459,15 +513,19 @@ function useAnimatedGesture(
459
513
 
460
514
  interface GestureDetectorProps {
461
515
  gesture?: ComposedGesture | GestureType;
516
+ children?: React.ReactNode;
462
517
  }
463
- export const GestureDetector: React.FunctionComponent<GestureDetectorProps> = (
464
- props
465
- ) => {
518
+ export const GestureDetector = (props: GestureDetectorProps) => {
466
519
  const gestureConfig = props.gesture;
467
520
  const gesture = gestureConfig?.toGestureArray?.() ?? [];
468
521
  const useReanimatedHook = gesture.some((g) => g.shouldUseReanimated);
469
522
  const viewRef = useRef(null);
470
523
  const firstRenderRef = useRef(true);
524
+ const webEventHandlersRef = useRef<WebEventHandler>({
525
+ onGestureHandlerEvent: (e: HandlerStateChangeEvent<unknown>) => {
526
+ onGestureHandlerEvent(e.nativeEvent);
527
+ },
528
+ });
471
529
 
472
530
  const preparedGesture = React.useRef<GestureConfigReference>({
473
531
  config: gesture,
@@ -508,6 +566,7 @@ export const GestureDetector: React.FunctionComponent<GestureDetectorProps> = (
508
566
  gestureConfig,
509
567
  gesture,
510
568
  viewTag,
569
+ webEventHandlersRef,
511
570
  });
512
571
 
513
572
  return () => {
@@ -526,6 +585,7 @@ export const GestureDetector: React.FunctionComponent<GestureDetectorProps> = (
526
585
  gestureConfig,
527
586
  gesture,
528
587
  viewTag,
588
+ webEventHandlersRef,
529
589
  });
530
590
  } else {
531
591
  updateHandlers(preparedGesture, gestureConfig, gesture);
@@ -543,17 +603,12 @@ export const GestureDetector: React.FunctionComponent<GestureDetectorProps> = (
543
603
  if (isFabric()) {
544
604
  const node = getShadowNodeFromRef(ref);
545
605
  if (global.isFormsStackingContext(node) === false) {
546
- setImmediate(() => {
547
- // For some weird reason, console.error on iOS delays
548
- // the execution of RNGestureHandlerModule.attachGestureHandler,
549
- // so that's why we use setImmediate here.
550
- console.error(
551
- tagMessage(
552
- 'GestureDetector has received a child that may get view-flattened. ' +
553
- '\nTo prevent it from misbehaving you need to wrap the child with a `<View collapsable={false}>`.'
554
- )
555
- );
556
- });
606
+ console.error(
607
+ tagMessage(
608
+ 'GestureDetector has received a child that may get view-flattened. ' +
609
+ '\nTo prevent it from misbehaving you need to wrap the child with a `<View collapsable={false}>`.'
610
+ )
611
+ );
557
612
  }
558
613
  }
559
614
  }
@@ -572,7 +627,11 @@ export const GestureDetector: React.FunctionComponent<GestureDetectorProps> = (
572
627
  }
573
628
  };
574
629
 
575
- class Wrap extends React.Component<{ onGestureHandlerEvent?: unknown }> {
630
+ class Wrap extends React.Component<{
631
+ onGestureHandlerEvent?: unknown;
632
+ // implicit `children` prop has been removed in @types/react^18.0.0
633
+ children?: React.ReactNode;
634
+ }> {
576
635
  render() {
577
636
  // I don't think that fighting with types over such a simple function is worth it
578
637
  // The only thing it does is add 'collapsable: false' to the child component
@@ -1,6 +1,6 @@
1
1
  import { DeviceEventEmitter, EmitterSubscription } from 'react-native';
2
2
  import { State } from '../../State';
3
- import { EventType } from '../../EventType';
3
+ import { TouchEventType } from '../../TouchEventType';
4
4
  import {
5
5
  GestureTouchEvent,
6
6
  GestureUpdateEvent,
@@ -48,7 +48,7 @@ function isTouchEvent(
48
48
  return event.eventType != null;
49
49
  }
50
50
 
51
- function onGestureHandlerEvent(
51
+ export function onGestureHandlerEvent(
52
52
  event: GestureUpdateEvent | GestureStateChangeEvent | GestureTouchEvent
53
53
  ) {
54
54
  const handler = findHandler(event.handlerTag) as BaseGesture<
@@ -87,16 +87,16 @@ function onGestureHandlerEvent(
87
87
  }
88
88
  } else if (isTouchEvent(event)) {
89
89
  switch (event.eventType) {
90
- case EventType.TOUCHES_DOWN:
90
+ case TouchEventType.TOUCHES_DOWN:
91
91
  handler.handlers?.onTouchesDown?.(event, dummyStateManager);
92
92
  break;
93
- case EventType.TOUCHES_MOVE:
93
+ case TouchEventType.TOUCHES_MOVE:
94
94
  handler.handlers?.onTouchesMove?.(event, dummyStateManager);
95
95
  break;
96
- case EventType.TOUCHES_UP:
96
+ case TouchEventType.TOUCHES_UP:
97
97
  handler.handlers?.onTouchesUp?.(event, dummyStateManager);
98
98
  break;
99
- case EventType.TOUCHES_CANCELLED:
99
+ case TouchEventType.TOUCHES_CANCELLED:
100
100
  handler.handlers?.onTouchesCancelled?.(event, dummyStateManager);
101
101
  break;
102
102
  }
@@ -15,6 +15,7 @@ import { PinchGestureHandlerEventPayload } from '../PinchGestureHandler';
15
15
  import { RotationGestureHandlerEventPayload } from '../RotationGestureHandler';
16
16
  import { TapGestureHandlerEventPayload } from '../TapGestureHandler';
17
17
  import { NativeViewGestureHandlerPayload } from '../NativeViewGestureHandler';
18
+ import { isRemoteDebuggingEnabled } from '../../utils';
18
19
 
19
20
  export type GestureType =
20
21
  | BaseGesture<Record<string, unknown>>
@@ -43,6 +44,7 @@ export interface BaseGestureConfig
43
44
  manualActivation?: boolean;
44
45
  runOnJS?: boolean;
45
46
  testId?: string;
47
+ cancelsTouchesInView?: boolean;
46
48
  }
47
49
 
48
50
  type TouchEventHandlerType = (
@@ -51,6 +53,7 @@ type TouchEventHandlerType = (
51
53
  ) => void;
52
54
 
53
55
  export type HandlerCallbacks<EventPayloadT extends Record<string, unknown>> = {
56
+ gestureId: number;
54
57
  handlerTag: number;
55
58
  onBegin?: (event: GestureStateChangeEvent<EventPayloadT>) => void;
56
59
  onStart?: (event: GestureStateChangeEvent<EventPayloadT>) => void;
@@ -113,17 +116,32 @@ export abstract class Gesture {
113
116
  abstract prepare(): void;
114
117
  }
115
118
 
119
+ let nextGestureId = 0;
116
120
  export abstract class BaseGesture<
117
121
  EventPayloadT extends Record<string, unknown>
118
122
  > extends Gesture {
123
+ private gestureId = -1;
119
124
  public handlerTag = -1;
120
125
  public handlerName = '';
121
126
  public config: BaseGestureConfig = {};
122
127
  public handlers: HandlerCallbacks<EventPayloadT> = {
128
+ gestureId: -1,
123
129
  handlerTag: -1,
124
130
  isWorklet: [],
125
131
  };
126
132
 
133
+ constructor() {
134
+ super();
135
+
136
+ // Used to check whether the gesture config has been updated when wrapping it
137
+ // with `useMemo`. Since every config will have a unique id, when the dependencies
138
+ // don't change, the config won't be recreated and the id will stay the same.
139
+ // If the id is different, it means that the config has changed and the gesture
140
+ // needs to be updated.
141
+ this.gestureId = nextGestureId++;
142
+ this.handlers.gestureId = this.gestureId;
143
+ }
144
+
127
145
  private addDependency(
128
146
  key: 'simultaneousWith' | 'requireToFail',
129
147
  gesture: Exclude<GestureRef, number>
@@ -260,6 +278,11 @@ export abstract class BaseGesture<
260
278
  return this;
261
279
  }
262
280
 
281
+ cancelsTouchesInView(value: boolean) {
282
+ this.config.cancelsTouchesInView = value;
283
+ return this;
284
+ }
285
+
263
286
  initialize() {
264
287
  this.handlerTag = getNextHandlerTag();
265
288
 
@@ -278,9 +301,13 @@ export abstract class BaseGesture<
278
301
  prepare() {}
279
302
 
280
303
  get shouldUseReanimated(): boolean {
281
- // use Reanimated when runOnJS isn't set explicitly and all defined callbacks are worklets
304
+ // use Reanimated when runOnJS isn't set explicitly,
305
+ // and all defined callbacks are worklets,
306
+ // and remote debugging is disabled
282
307
  return (
283
- this.config.runOnJS !== true && !this.handlers.isWorklet.includes(false)
308
+ this.config.runOnJS !== true &&
309
+ !this.handlers.isWorklet.includes(false) &&
310
+ !isRemoteDebuggingEnabled()
284
311
  );
285
312
  }
286
313
  }
package/src/init.ts CHANGED
@@ -2,10 +2,17 @@ import { startListening } from './handlers/gestures/eventReceiver';
2
2
  import RNGestureHandlerModule from './RNGestureHandlerModule';
3
3
  import { isFabric } from './utils';
4
4
 
5
+ let fabricInitialized = false;
6
+
5
7
  export function initialize() {
6
8
  startListening();
9
+ }
7
10
 
8
- if (isFabric()) {
11
+ // since isFabric() may give wrong results before the first render, we call this
12
+ // method during render of GestureHandlerRootView
13
+ export function maybeInitializeFabric() {
14
+ if (isFabric() && !fabricInitialized) {
9
15
  RNGestureHandlerModule.install();
16
+ fabricInitialized = true;
10
17
  }
11
18
  }
package/src/mocks.ts CHANGED
@@ -21,6 +21,7 @@ const attachGestureHandler = NOOP;
21
21
  const createGestureHandler = NOOP;
22
22
  const dropGestureHandler = NOOP;
23
23
  const updateGestureHandler = NOOP;
24
+ const flushOperations = NOOP;
24
25
  const NativeViewGestureHandler = View;
25
26
  const TapGestureHandler = View;
26
27
  const ForceTouchGestureHandler = View;
@@ -59,6 +60,7 @@ export default {
59
60
  createGestureHandler,
60
61
  dropGestureHandler,
61
62
  updateGestureHandler,
63
+ flushOperations,
62
64
  // probably can be removed
63
65
  Directions,
64
66
  State,
package/src/utils.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { version as rnVersion } from 'react-native/package.json';
2
+
1
3
  export function toArray<T>(object: T | T[]): T[] {
2
4
  if (!Array.isArray(object)) {
3
5
  return [object];
@@ -32,6 +34,7 @@ export function hasProperty(object: object, key: string) {
32
34
  }
33
35
 
34
36
  export function isJestEnv(): boolean {
37
+ // @ts-ignore Do not use `@types/node` because it will prioritise Node types over RN types which breaks the types (ex. setTimeout) in React Native projects.
35
38
  return hasProperty(global, 'process') && !!process.env.JEST_WORKER_ID;
36
39
  }
37
40
 
@@ -39,7 +42,24 @@ export function tagMessage(msg: string) {
39
42
  return `[react-native-gesture-handler] ${msg}`;
40
43
  }
41
44
 
45
+ // helper method to check whether Fabric is enabled, however global.nativeFabricUIManager
46
+ // may not be initialized before the first render
42
47
  export function isFabric(): boolean {
43
48
  // @ts-expect-error nativeFabricUIManager is not yet included in the RN types
44
49
  return !!global?.nativeFabricUIManager;
45
50
  }
51
+
52
+ export function shouldUseCodegenNativeComponent(): boolean {
53
+ const [majorStr, minorStr] = rnVersion.split('.');
54
+ const major = Number.parseInt(majorStr);
55
+ const minor = Number.parseInt(minorStr);
56
+
57
+ // use codegenNativeComponent starting with RN 0.68
58
+ return minor >= 68 || major > 0;
59
+ }
60
+
61
+ export function isRemoteDebuggingEnabled(): boolean {
62
+ // react-native-reanimated checks if in remote debugging in the same way
63
+ // @ts-ignore global is available but node types are not included
64
+ return !(global as any).nativeCallSyncHook || (global as any).__REMOTEDEV__;
65
+ }
@@ -182,7 +182,13 @@ abstract class GestureHandler {
182
182
  // onHandlerStateChange only
183
183
  handlerTag: this.handlerTag,
184
184
  target: this.ref,
185
- oldState: this.oldState,
185
+ // send oldState only when the state was changed, or is different than ACTIVE
186
+ // GestureDetector relies on the presence of `oldState` to differentiate between
187
+ // update events and state change events
188
+ oldState:
189
+ state !== this.previousState || state != 4
190
+ ? this.oldState
191
+ : undefined,
186
192
  },
187
193
  timeStamp: Date.now(),
188
194
  };