react-native-gesture-handler 2.3.2 → 2.4.2

Sign up to get free protection for your applications and to get access to all the features.
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
  };