@react-native-oh-tpl/react-native-gesture-handler 2.12.6-1 → 2.12.6-2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. package/harmony/gesture_handler/LICENSE +21 -0
  2. package/harmony/gesture_handler/OAT.xml +44 -0
  3. package/harmony/gesture_handler/README.OpenSource +11 -0
  4. package/harmony/gesture_handler/README.md +1 -0
  5. package/harmony/gesture_handler/build-profile.json5 +7 -7
  6. package/harmony/gesture_handler/hvigorfile.ts +2 -2
  7. package/harmony/gesture_handler/index.ets +2 -2
  8. package/harmony/gesture_handler/oh-package.json5 +13 -11
  9. package/harmony/gesture_handler/src/main/cpp/CMakeLists.txt +8 -8
  10. package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.cpp +33 -33
  11. package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.h +14 -14
  12. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerButtonComponentDescriptor.h +60 -60
  13. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.cpp +17 -17
  14. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.h +11 -11
  15. package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerRootViewComponentDescriptor.h +60 -60
  16. package/harmony/gesture_handler/src/main/ets/CircularBuffer.ts +42 -42
  17. package/harmony/gesture_handler/src/main/ets/Event.ts +67 -67
  18. package/harmony/gesture_handler/src/main/ets/EventDispatcher.ts +37 -37
  19. package/harmony/gesture_handler/src/main/ets/GestureHandler.ts +663 -663
  20. package/harmony/gesture_handler/src/main/ets/GestureHandlerArkUIAdapter.ets +201 -201
  21. package/harmony/gesture_handler/src/main/ets/GestureHandlerFactory.ts +44 -44
  22. package/harmony/gesture_handler/src/main/ets/GestureHandlerOrchestrator.ts +280 -280
  23. package/harmony/gesture_handler/src/main/ets/GestureHandlerPackage.ts +22 -22
  24. package/harmony/gesture_handler/src/main/ets/GestureHandlerRegistry.ts +27 -27
  25. package/harmony/gesture_handler/src/main/ets/InteractionManager.ts +108 -108
  26. package/harmony/gesture_handler/src/main/ets/LeastSquareSolver.ts +182 -182
  27. package/harmony/gesture_handler/src/main/ets/NativeViewGestureHandler.ts +114 -114
  28. package/harmony/gesture_handler/src/main/ets/OutgoingEvent.ts +33 -33
  29. package/harmony/gesture_handler/src/main/ets/PanGestureHandler.ts +327 -327
  30. package/harmony/gesture_handler/src/main/ets/PointerTracker.ts +239 -239
  31. package/harmony/gesture_handler/src/main/ets/RNGHError.ts +4 -4
  32. package/harmony/gesture_handler/src/main/ets/RNGHLogger.ts +28 -28
  33. package/harmony/gesture_handler/src/main/ets/RNGHRootTouchHandler.ets +57 -57
  34. package/harmony/gesture_handler/src/main/ets/RNGestureHandlerButton.ets +36 -36
  35. package/harmony/gesture_handler/src/main/ets/RNGestureHandlerModule.ts +125 -125
  36. package/harmony/gesture_handler/src/main/ets/RNGestureHandlerRootView.ets +56 -55
  37. package/harmony/gesture_handler/src/main/ets/RNOHScrollLocker.ts +10 -10
  38. package/harmony/gesture_handler/src/main/ets/State.ts +46 -46
  39. package/harmony/gesture_handler/src/main/ets/TapGestureHandler.ts +205 -205
  40. package/harmony/gesture_handler/src/main/ets/Vector2D.ts +36 -36
  41. package/harmony/gesture_handler/src/main/ets/VelocityTracker.ts +98 -98
  42. package/harmony/gesture_handler/src/main/ets/View.ts +70 -70
  43. package/harmony/gesture_handler/src/main/ets/ViewRegistry.ts +42 -42
  44. package/harmony/gesture_handler/src/main/ets/pages/Index.ets +16 -16
  45. package/harmony/gesture_handler/src/main/ets/webviewability/WebviewAbility.ts +41 -41
  46. package/harmony/gesture_handler/src/main/module.json5 +6 -6
  47. package/harmony/gesture_handler/src/main/resources/base/element/color.json +7 -7
  48. package/harmony/gesture_handler/src/main/resources/base/element/string.json +15 -15
  49. package/harmony/gesture_handler/src/main/resources/base/profile/main_pages.json +5 -5
  50. package/harmony/gesture_handler/src/main/resources/en_US/element/string.json +15 -15
  51. package/harmony/gesture_handler/src/main/resources/zh_CN/element/string.json +15 -15
  52. package/harmony/gesture_handler.har +0 -0
  53. package/lib/commonjs/components/touchables/GenericTouchable.js +9 -9
  54. package/lib/commonjs/components/touchables/TouchableOpacity.js +2 -2
  55. package/lib/commonjs/handlers/createNativeWrapper.js +6 -6
  56. package/lib/commonjs/handlers/gestures/GestureDetector.js +3 -3
  57. package/lib/module/components/touchables/GenericTouchable.js +9 -9
  58. package/lib/module/components/touchables/TouchableOpacity.js +2 -2
  59. package/lib/module/handlers/createNativeWrapper.js +6 -6
  60. package/lib/module/handlers/gestures/GestureDetector.js +3 -3
  61. package/package.json +70 -70
  62. package/src/RNGestureHandlerModule.ts +6 -6
  63. package/src/components/GestureButtons.tsx +334 -334
  64. package/src/components/GestureHandlerButton.tsx +5 -5
  65. package/src/components/GestureHandlerRootView.tsx +34 -34
  66. package/src/components/RNGestureHandlerButton.tsx +23 -23
  67. package/src/components/touchables/GenericTouchable.tsx +301 -301
  68. package/src/components/touchables/TouchableOpacity.tsx +76 -76
  69. package/src/components/touchables/TouchableWithoutFeedback.tsx +14 -14
  70. package/src/components/touchables/index.ts +7 -7
  71. package/src/handlers/NativeViewGestureHandler.ts +55 -55
  72. package/src/handlers/PanGestureHandler.ts +327 -327
  73. package/src/handlers/TapGestureHandler.ts +95 -95
  74. package/src/handlers/createHandler.tsx +535 -535
  75. package/src/handlers/createNativeWrapper.tsx +81 -81
  76. package/src/handlers/gestureHandlerCommon.ts +15 -15
  77. package/src/handlers/gestures/GestureDetector.tsx +823 -823
  78. package/src/index.ts +172 -172
  79. package/src/init.ts +18 -18
@@ -1,535 +1,535 @@
1
- // RNGH: patching the import to RNGestureHandlerModule
2
-
3
- import * as React from 'react';
4
- import {
5
- Platform,
6
- UIManager,
7
- DeviceEventEmitter,
8
- EmitterSubscription,
9
- } from 'react-native';
10
- // @ts-ignore - it isn't typed by TS & don't have definitelyTyped types
11
- import deepEqual from 'lodash/isEqual';
12
- import {RNGestureHandlerModule} from '../RNGestureHandlerModule'; // RNGH: patch
13
- import type RNGestureHandlerModuleWeb from 'react-native-gesture-handler/src/RNGestureHandlerModule.web';
14
- import { State } from 'react-native-gesture-handler/src/State';
15
- import {
16
- handlerIDToTag,
17
- getNextHandlerTag,
18
- registerOldGestureHandler,
19
- } from 'react-native-gesture-handler/src/handlers/handlersRegistry';
20
-
21
- import {
22
- BaseGestureHandlerProps,
23
- filterConfig,
24
- GestureEvent,
25
- HandlerStateChangeEvent,
26
- findNodeHandle,
27
- // scheduleFlushOperations, // RNGH: patch
28
- } from 'react-native-gesture-handler/src/handlers/gestureHandlerCommon';
29
- import { scheduleFlushOperations } from "../handlers/gestureHandlerCommon" // RNGH: patch
30
- import { ValueOf } from 'react-native-gesture-handler/src/typeUtils';
31
- import { isFabric, isJestEnv, tagMessage } from 'react-native-gesture-handler/src/utils';
32
- import { ActionType } from 'react-native-gesture-handler/src/ActionType';
33
- import { PressabilityDebugView } from 'react-native-gesture-handler/src/handlers/PressabilityDebugView';
34
- import GestureHandlerRootViewContext from 'react-native-gesture-handler/src/GestureHandlerRootViewContext';
35
-
36
- const UIManagerAny = UIManager as any;
37
-
38
- const customGHEventsConfigFabricAndroid = {
39
- topOnGestureHandlerEvent: { registrationName: 'onGestureHandlerEvent' },
40
- topOnGestureHandlerStateChange: {
41
- registrationName: 'onGestureHandlerStateChange',
42
- },
43
- };
44
-
45
- const customGHEventsConfig = {
46
- onGestureHandlerEvent: { registrationName: 'onGestureHandlerEvent' },
47
- onGestureHandlerStateChange: {
48
- registrationName: 'onGestureHandlerStateChange',
49
- },
50
-
51
- // When using React Native Gesture Handler for Animated.event with useNativeDriver: true
52
- // on Android with Fabric enabled, the native part still sends the native events to JS
53
- // but prefixed with "top". We cannot simply rename the events above so they are prefixed
54
- // with "top" instead of "on" because in such case Animated.events would not be registered.
55
- // That's why we need to register another pair of event names.
56
- // The incoming events will be queued but never handled.
57
- // Without this piece of code below, you'll get the following JS error:
58
- // Unsupported top level event type "topOnGestureHandlerEvent" dispatched
59
- ...(isFabric() &&
60
- Platform.OS === 'android' &&
61
- customGHEventsConfigFabricAndroid),
62
- };
63
-
64
- // Add gesture specific events to genericDirectEventTypes object exported from UIManager
65
- // native module.
66
- // Once new event types are registered with react it is possible to dispatch these
67
- // events to all kind of native views.
68
- UIManagerAny.genericDirectEventTypes = {
69
- ...UIManagerAny.genericDirectEventTypes,
70
- ...customGHEventsConfig,
71
- };
72
- // In newer versions of RN the `genericDirectEventTypes` is located in the object
73
- // returned by UIManager.getViewManagerConfig('getConstants') or in older RN UIManager.getConstants(), we need to add it there as well to make
74
- // it compatible with RN 61+
75
- const UIManagerConstants =
76
- UIManagerAny.getViewManagerConfig?.('getConstants') ??
77
- UIManagerAny.getConstants?.();
78
-
79
- if (UIManagerConstants) {
80
- UIManagerConstants.genericDirectEventTypes = {
81
- ...UIManagerConstants.genericDirectEventTypes,
82
- ...customGHEventsConfig,
83
- };
84
- }
85
-
86
- // Wrap JS responder calls and notify gesture handler manager
87
- const {
88
- setJSResponder: oldSetJSResponder = () => {
89
- //no operation
90
- },
91
- clearJSResponder: oldClearJSResponder = () => {
92
- //no operation
93
- },
94
- } = UIManagerAny;
95
- UIManagerAny.setJSResponder = (tag: number, blockNativeResponder: boolean) => {
96
- RNGestureHandlerModule.handleSetJSResponder(tag, blockNativeResponder);
97
- oldSetJSResponder(tag, blockNativeResponder);
98
- };
99
- UIManagerAny.clearJSResponder = () => {
100
- RNGestureHandlerModule.handleClearJSResponder();
101
- oldClearJSResponder();
102
- };
103
-
104
- let allowTouches = true;
105
- const DEV_ON_ANDROID = __DEV__ && Platform.OS === 'android';
106
- // Toggled inspector blocks touch events in order to allow inspecting on Android
107
- // This needs to be a global variable in order to set initial state for `allowTouches` property in Handler component
108
- if (DEV_ON_ANDROID) {
109
- DeviceEventEmitter.addListener('toggleElementInspector', () => {
110
- allowTouches = !allowTouches;
111
- });
112
- }
113
-
114
- type HandlerProps<T extends Record<string, unknown>> = Readonly<
115
- React.PropsWithChildren<BaseGestureHandlerProps<T>>
116
- >;
117
- function hasUnresolvedRefs<T extends Record<string, unknown>>(
118
- props: HandlerProps<T>
119
- ) {
120
- // TODO(TS) - add type for extract arg
121
- const extract = (refs: any | any[]) => {
122
- if (!Array.isArray(refs)) {
123
- return refs && refs.current === null;
124
- }
125
- return refs.some((r) => r && r.current === null);
126
- };
127
- return extract(props['simultaneousHandlers']) || extract(props['waitFor']);
128
- }
129
-
130
- const stateToPropMappings = {
131
- [State.UNDETERMINED]: undefined,
132
- [State.BEGAN]: 'onBegan',
133
- [State.FAILED]: 'onFailed',
134
- [State.CANCELLED]: 'onCancelled',
135
- [State.ACTIVE]: 'onActivated',
136
- [State.END]: 'onEnded',
137
- } as const;
138
-
139
- type CreateHandlerArgs<HandlerPropsT extends Record<string, unknown>> =
140
- Readonly<{
141
- name: string;
142
- allowedProps: Readonly<Extract<keyof HandlerPropsT, string>[]>;
143
- config: Readonly<Record<string, unknown>>;
144
- transformProps?: (props: HandlerPropsT) => HandlerPropsT;
145
- customNativeProps?: Readonly<string[]>;
146
- }>;
147
-
148
- // TODO(TS) fix event types
149
- type InternalEventHandlers = {
150
- onGestureHandlerEvent?: (event: any) => void;
151
- onGestureHandlerStateChange?: (event: any) => void;
152
- };
153
-
154
- const UNRESOLVED_REFS_RETRY_LIMIT = 1;
155
-
156
- // TODO(TS) - make sure that BaseGestureHandlerProps doesn't need other generic parameter to work with custom properties.
157
- export default function createHandler<
158
- T extends BaseGestureHandlerProps<U>,
159
- U extends Record<string, unknown>
160
- >({
161
- name,
162
- allowedProps = [],
163
- config = {},
164
- transformProps,
165
- customNativeProps = [],
166
- }: CreateHandlerArgs<T>): React.ComponentType<T & React.RefAttributes<any>> {
167
- interface HandlerState {
168
- allowTouches: boolean;
169
- }
170
- class Handler extends React.Component<
171
- T & InternalEventHandlers,
172
- HandlerState
173
- > {
174
- static displayName = name;
175
- static contextType = GestureHandlerRootViewContext;
176
-
177
- private handlerTag: number;
178
- private config: Record<string, unknown>;
179
- private propsRef: React.MutableRefObject<unknown>;
180
- private isMountedRef: React.MutableRefObject<boolean | null>;
181
- private viewNode: any;
182
- private viewTag?: number;
183
- private inspectorToggleListener?: EmitterSubscription;
184
-
185
- constructor(props: T & InternalEventHandlers) {
186
- super(props);
187
- this.handlerTag = getNextHandlerTag();
188
- this.config = {};
189
- this.propsRef = React.createRef();
190
- this.isMountedRef = React.createRef();
191
- this.state = { allowTouches };
192
- if (props.id) {
193
- if (handlerIDToTag[props.id] !== undefined) {
194
- throw new Error(`Handler with ID "${props.id}" already registered`);
195
- }
196
- handlerIDToTag[props.id] = this.handlerTag;
197
- }
198
- }
199
-
200
- componentDidMount() {
201
- const props: HandlerProps<U> = this.props;
202
- this.isMountedRef.current = true;
203
-
204
- if (DEV_ON_ANDROID) {
205
- this.inspectorToggleListener = DeviceEventEmitter.addListener(
206
- 'toggleElementInspector',
207
- () => {
208
- this.setState((_) => ({ allowTouches }));
209
- this.update(UNRESOLVED_REFS_RETRY_LIMIT);
210
- }
211
- );
212
- }
213
- if (hasUnresolvedRefs(props)) {
214
- // If there are unresolved refs (e.g. ".current" has not yet been set)
215
- // passed as `simultaneousHandlers` or `waitFor`, we enqueue a call to
216
- // _update method that will try to update native handler props using
217
- // queueMicrotask. This makes it so update() function gets called after all
218
- // react components are mounted and we expect the missing ref object to
219
- // be resolved by then.
220
- queueMicrotask(() => {
221
- this.update(UNRESOLVED_REFS_RETRY_LIMIT);
222
- });
223
- }
224
-
225
- this.createGestureHandler(
226
- filterConfig(
227
- transformProps ? transformProps(this.props) : this.props,
228
- [...allowedProps, ...customNativeProps],
229
- config
230
- )
231
- );
232
-
233
- this.attachGestureHandler(findNodeHandle(this.viewNode) as number); // TODO(TS) - check if this can be null
234
- }
235
-
236
- componentDidUpdate() {
237
- const viewTag = findNodeHandle(this.viewNode);
238
- if (this.viewTag !== viewTag) {
239
- this.attachGestureHandler(viewTag as number); // TODO(TS) - check interaction between _viewTag & findNodeHandle
240
- }
241
- this.update(UNRESOLVED_REFS_RETRY_LIMIT);
242
- }
243
-
244
- componentWillUnmount() {
245
- this.inspectorToggleListener?.remove();
246
- this.isMountedRef.current = false;
247
- RNGestureHandlerModule.dropGestureHandler(this.handlerTag);
248
- scheduleFlushOperations();
249
- // We can't use this.props.id directly due to TS generic type narrowing bug, see https://github.com/microsoft/TypeScript/issues/13995 for more context
250
- const handlerID: string | undefined = this.props.id;
251
- if (handlerID) {
252
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
253
- delete handlerIDToTag[handlerID];
254
- }
255
- }
256
-
257
- private onGestureHandlerEvent = (event: GestureEvent<U>) => {
258
- if (event.nativeEvent.handlerTag === this.handlerTag) {
259
- if (typeof this.props.onGestureEvent === 'function') {
260
- this.props.onGestureEvent?.(event);
261
- }
262
- } else {
263
- this.props.onGestureHandlerEvent?.(event);
264
- }
265
- };
266
-
267
- // TODO(TS) - make sure this is right type for event
268
- private onGestureHandlerStateChange = (
269
- event: HandlerStateChangeEvent<U>
270
- ) => {
271
- if (event.nativeEvent.handlerTag === this.handlerTag) {
272
- if (typeof this.props.onHandlerStateChange === 'function') {
273
- this.props.onHandlerStateChange?.(event);
274
- }
275
-
276
- const state: ValueOf<typeof State> = event.nativeEvent.state;
277
- const stateEventName = stateToPropMappings[state];
278
- const eventHandler = stateEventName && this.props[stateEventName];
279
- if (eventHandler && typeof eventHandler === 'function') {
280
- eventHandler(event);
281
- }
282
- } else {
283
- this.props.onGestureHandlerStateChange?.(event);
284
- }
285
- };
286
-
287
- private refHandler = (node: any) => {
288
- this.viewNode = node;
289
-
290
- const child = React.Children.only(this.props.children);
291
- // TODO(TS) fix ref type
292
- const { ref }: any = child;
293
- if (ref !== null) {
294
- if (typeof ref === 'function') {
295
- ref(node);
296
- } else {
297
- ref.current = node;
298
- }
299
- }
300
- };
301
-
302
- private createGestureHandler = (
303
- newConfig: Readonly<Record<string, unknown>>
304
- ) => {
305
- this.config = newConfig;
306
-
307
- RNGestureHandlerModule.createGestureHandler(
308
- name,
309
- this.handlerTag,
310
- newConfig
311
- );
312
- };
313
-
314
- private attachGestureHandler = (newViewTag: number) => {
315
- this.viewTag = newViewTag;
316
-
317
- if (Platform.OS === 'web') {
318
- // typecast due to dynamic resolution, attachGestureHandler should have web version signature in this branch
319
- (
320
- RNGestureHandlerModule.attachGestureHandler as typeof RNGestureHandlerModuleWeb.attachGestureHandler
321
- )(
322
- this.handlerTag,
323
- newViewTag,
324
- ActionType.JS_FUNCTION_OLD_API, // ignored on web
325
- this.propsRef
326
- );
327
- } else {
328
- registerOldGestureHandler(this.handlerTag, {
329
- onGestureEvent: this.onGestureHandlerEvent,
330
- onGestureStateChange: this.onGestureHandlerStateChange,
331
- });
332
-
333
- const actionType = (() => {
334
- if (
335
- (this.props?.onGestureEvent &&
336
- 'current' in this.props.onGestureEvent) ||
337
- (this.props?.onHandlerStateChange &&
338
- 'current' in this.props.onHandlerStateChange)
339
- ) {
340
- // Reanimated worklet
341
- return ActionType.REANIMATED_WORKLET;
342
- } else if (
343
- this.props?.onGestureEvent &&
344
- '__isNative' in this.props.onGestureEvent
345
- ) {
346
- // Animated.event with useNativeDriver: true
347
- return ActionType.NATIVE_ANIMATED_EVENT;
348
- } else {
349
- // JS callback or Animated.event with useNativeDriver: false
350
- return ActionType.JS_FUNCTION_OLD_API;
351
- }
352
- })();
353
-
354
- RNGestureHandlerModule.attachGestureHandler(
355
- this.handlerTag,
356
- newViewTag,
357
- actionType
358
- );
359
- }
360
-
361
- scheduleFlushOperations();
362
- };
363
-
364
- private updateGestureHandler = (
365
- newConfig: Readonly<Record<string, unknown>>
366
- ) => {
367
- this.config = newConfig;
368
-
369
- RNGestureHandlerModule.updateGestureHandler(this.handlerTag, newConfig);
370
- scheduleFlushOperations();
371
- };
372
-
373
- private update(remainingTries: number) {
374
- if (!this.isMountedRef.current) {
375
- return;
376
- }
377
-
378
- const props: HandlerProps<U> = this.props;
379
-
380
- // When ref is set via a function i.e. `ref={(r) => refObject.current = r}` instead of
381
- // `ref={refObject}` it's possible that it won't be resolved in time. Seems like trying
382
- // again is easy enough fix.
383
- if (hasUnresolvedRefs(props) && remainingTries > 0) {
384
- queueMicrotask(() => {
385
- this.update(remainingTries - 1);
386
- });
387
- } else {
388
- const newConfig = filterConfig(
389
- transformProps ? transformProps(this.props) : this.props,
390
- [...allowedProps, ...customNativeProps],
391
- config
392
- );
393
- if (!deepEqual(this.config, newConfig)) {
394
- this.updateGestureHandler(newConfig);
395
- }
396
- }
397
- }
398
-
399
- setNativeProps(updates: any) {
400
- const mergedProps = { ...this.props, ...updates };
401
- const newConfig = filterConfig(
402
- transformProps ? transformProps(mergedProps) : mergedProps,
403
- [...allowedProps, ...customNativeProps],
404
- config
405
- );
406
- this.updateGestureHandler(newConfig);
407
- }
408
-
409
- render() {
410
- if (__DEV__ && !this.context && !isJestEnv() && Platform.OS !== 'web' && (Platform.OS as any) !== "harmony") { // RNOH: patch
411
- throw new Error(
412
- name +
413
- ' 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.'
414
- );
415
- }
416
-
417
- let gestureEventHandler = this.onGestureHandlerEvent;
418
- // Another instance of https://github.com/microsoft/TypeScript/issues/13995
419
- type OnGestureEventHandlers = {
420
- onGestureEvent?: BaseGestureHandlerProps<U>['onGestureEvent'];
421
- onGestureHandlerEvent?: InternalEventHandlers['onGestureHandlerEvent'];
422
- };
423
- const { onGestureEvent, onGestureHandlerEvent }: OnGestureEventHandlers =
424
- this.props;
425
- if (onGestureEvent && typeof onGestureEvent !== 'function') {
426
- // If it's not a method it should be an native Animated.event
427
- // object. We set it directly as the handler for the view
428
- // In this case nested handlers are not going to be supported
429
- if (onGestureHandlerEvent) {
430
- throw new Error(
431
- 'Nesting touch handlers with native animated driver is not supported yet'
432
- );
433
- }
434
- gestureEventHandler = onGestureEvent;
435
- } else {
436
- if (
437
- onGestureHandlerEvent &&
438
- typeof onGestureHandlerEvent !== 'function'
439
- ) {
440
- throw new Error(
441
- 'Nesting touch handlers with native animated driver is not supported yet'
442
- );
443
- }
444
- }
445
-
446
- let gestureStateEventHandler = this.onGestureHandlerStateChange;
447
- // Another instance of https://github.com/microsoft/TypeScript/issues/13995
448
- type OnGestureStateChangeHandlers = {
449
- onHandlerStateChange?: BaseGestureHandlerProps<U>['onHandlerStateChange'];
450
- onGestureHandlerStateChange?: InternalEventHandlers['onGestureHandlerStateChange'];
451
- };
452
- const {
453
- onHandlerStateChange,
454
- onGestureHandlerStateChange,
455
- }: OnGestureStateChangeHandlers = this.props;
456
- if (onHandlerStateChange && typeof onHandlerStateChange !== 'function') {
457
- // If it's not a method it should be an native Animated.event
458
- // object. We set it directly as the handler for the view
459
- // In this case nested handlers are not going to be supported
460
- if (onGestureHandlerStateChange) {
461
- throw new Error(
462
- 'Nesting touch handlers with native animated driver is not supported yet'
463
- );
464
- }
465
- gestureStateEventHandler = onHandlerStateChange;
466
- } else {
467
- if (
468
- onGestureHandlerStateChange &&
469
- typeof onGestureHandlerStateChange !== 'function'
470
- ) {
471
- throw new Error(
472
- 'Nesting touch handlers with native animated driver is not supported yet'
473
- );
474
- }
475
- }
476
- const events = {
477
- onGestureHandlerEvent: this.state.allowTouches
478
- ? gestureEventHandler
479
- : undefined,
480
- onGestureHandlerStateChange: this.state.allowTouches
481
- ? gestureStateEventHandler
482
- : undefined,
483
- };
484
-
485
- this.propsRef.current = events;
486
-
487
- let child: any = null;
488
- try {
489
- child = React.Children.only(this.props.children);
490
- } catch (e) {
491
- throw new Error(
492
- tagMessage(
493
- `${name} 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.`
494
- )
495
- );
496
- }
497
-
498
- let grandChildren = child.props.children;
499
- if (
500
- __DEV__ &&
501
- child.type &&
502
- (child.type === 'RNGestureHandlerButton' ||
503
- child.type.name === 'View' ||
504
- child.type.displayName === 'View')
505
- ) {
506
- grandChildren = React.Children.toArray(grandChildren);
507
- grandChildren.push(
508
- <PressabilityDebugView
509
- key="pressabilityDebugView"
510
- color="mediumspringgreen"
511
- hitSlop={child.props.hitSlop}
512
- />
513
- );
514
- }
515
-
516
- return React.cloneElement(
517
- child,
518
- {
519
- ref: this.refHandler,
520
- collapsable: false,
521
- ...(isJestEnv()
522
- ? {
523
- handlerType: name,
524
- handlerTag: this.handlerTag,
525
- }
526
- : {}),
527
- testID: this.props.testID ?? child.props.testID,
528
- ...events,
529
- },
530
- grandChildren
531
- );
532
- }
533
- }
534
- return Handler;
535
- }
1
+ // RNGH: patching the import to RNGestureHandlerModule
2
+
3
+ import * as React from 'react';
4
+ import {
5
+ Platform,
6
+ UIManager,
7
+ DeviceEventEmitter,
8
+ EmitterSubscription,
9
+ } from 'react-native';
10
+ // @ts-ignore - it isn't typed by TS & don't have definitelyTyped types
11
+ import deepEqual from 'lodash/isEqual';
12
+ import {RNGestureHandlerModule} from '../RNGestureHandlerModule'; // RNGH: patch
13
+ import type RNGestureHandlerModuleWeb from 'react-native-gesture-handler/src/RNGestureHandlerModule.web';
14
+ import { State } from 'react-native-gesture-handler/src/State';
15
+ import {
16
+ handlerIDToTag,
17
+ getNextHandlerTag,
18
+ registerOldGestureHandler,
19
+ } from 'react-native-gesture-handler/src/handlers/handlersRegistry';
20
+
21
+ import {
22
+ BaseGestureHandlerProps,
23
+ filterConfig,
24
+ GestureEvent,
25
+ HandlerStateChangeEvent,
26
+ findNodeHandle,
27
+ // scheduleFlushOperations, // RNGH: patch
28
+ } from 'react-native-gesture-handler/src/handlers/gestureHandlerCommon';
29
+ import { scheduleFlushOperations } from "../handlers/gestureHandlerCommon" // RNGH: patch
30
+ import { ValueOf } from 'react-native-gesture-handler/src/typeUtils';
31
+ import { isFabric, isJestEnv, tagMessage } from 'react-native-gesture-handler/src/utils';
32
+ import { ActionType } from 'react-native-gesture-handler/src/ActionType';
33
+ import { PressabilityDebugView } from 'react-native-gesture-handler/src/handlers/PressabilityDebugView';
34
+ import GestureHandlerRootViewContext from 'react-native-gesture-handler/src/GestureHandlerRootViewContext';
35
+
36
+ const UIManagerAny = UIManager as any;
37
+
38
+ const customGHEventsConfigFabricAndroid = {
39
+ topOnGestureHandlerEvent: { registrationName: 'onGestureHandlerEvent' },
40
+ topOnGestureHandlerStateChange: {
41
+ registrationName: 'onGestureHandlerStateChange',
42
+ },
43
+ };
44
+
45
+ const customGHEventsConfig = {
46
+ onGestureHandlerEvent: { registrationName: 'onGestureHandlerEvent' },
47
+ onGestureHandlerStateChange: {
48
+ registrationName: 'onGestureHandlerStateChange',
49
+ },
50
+
51
+ // When using React Native Gesture Handler for Animated.event with useNativeDriver: true
52
+ // on Android with Fabric enabled, the native part still sends the native events to JS
53
+ // but prefixed with "top". We cannot simply rename the events above so they are prefixed
54
+ // with "top" instead of "on" because in such case Animated.events would not be registered.
55
+ // That's why we need to register another pair of event names.
56
+ // The incoming events will be queued but never handled.
57
+ // Without this piece of code below, you'll get the following JS error:
58
+ // Unsupported top level event type "topOnGestureHandlerEvent" dispatched
59
+ ...(isFabric() &&
60
+ Platform.OS === 'android' &&
61
+ customGHEventsConfigFabricAndroid),
62
+ };
63
+
64
+ // Add gesture specific events to genericDirectEventTypes object exported from UIManager
65
+ // native module.
66
+ // Once new event types are registered with react it is possible to dispatch these
67
+ // events to all kind of native views.
68
+ UIManagerAny.genericDirectEventTypes = {
69
+ ...UIManagerAny.genericDirectEventTypes,
70
+ ...customGHEventsConfig,
71
+ };
72
+ // In newer versions of RN the `genericDirectEventTypes` is located in the object
73
+ // returned by UIManager.getViewManagerConfig('getConstants') or in older RN UIManager.getConstants(), we need to add it there as well to make
74
+ // it compatible with RN 61+
75
+ const UIManagerConstants =
76
+ UIManagerAny.getViewManagerConfig?.('getConstants') ??
77
+ UIManagerAny.getConstants?.();
78
+
79
+ if (UIManagerConstants) {
80
+ UIManagerConstants.genericDirectEventTypes = {
81
+ ...UIManagerConstants.genericDirectEventTypes,
82
+ ...customGHEventsConfig,
83
+ };
84
+ }
85
+
86
+ // Wrap JS responder calls and notify gesture handler manager
87
+ const {
88
+ setJSResponder: oldSetJSResponder = () => {
89
+ //no operation
90
+ },
91
+ clearJSResponder: oldClearJSResponder = () => {
92
+ //no operation
93
+ },
94
+ } = UIManagerAny;
95
+ UIManagerAny.setJSResponder = (tag: number, blockNativeResponder: boolean) => {
96
+ RNGestureHandlerModule.handleSetJSResponder(tag, blockNativeResponder);
97
+ oldSetJSResponder(tag, blockNativeResponder);
98
+ };
99
+ UIManagerAny.clearJSResponder = () => {
100
+ RNGestureHandlerModule.handleClearJSResponder();
101
+ oldClearJSResponder();
102
+ };
103
+
104
+ let allowTouches = true;
105
+ const DEV_ON_ANDROID = __DEV__ && Platform.OS === 'android';
106
+ // Toggled inspector blocks touch events in order to allow inspecting on Android
107
+ // This needs to be a global variable in order to set initial state for `allowTouches` property in Handler component
108
+ if (DEV_ON_ANDROID) {
109
+ DeviceEventEmitter.addListener('toggleElementInspector', () => {
110
+ allowTouches = !allowTouches;
111
+ });
112
+ }
113
+
114
+ type HandlerProps<T extends Record<string, unknown>> = Readonly<
115
+ React.PropsWithChildren<BaseGestureHandlerProps<T>>
116
+ >;
117
+ function hasUnresolvedRefs<T extends Record<string, unknown>>(
118
+ props: HandlerProps<T>
119
+ ) {
120
+ // TODO(TS) - add type for extract arg
121
+ const extract = (refs: any | any[]) => {
122
+ if (!Array.isArray(refs)) {
123
+ return refs && refs.current === null;
124
+ }
125
+ return refs.some((r) => r && r.current === null);
126
+ };
127
+ return extract(props['simultaneousHandlers']) || extract(props['waitFor']);
128
+ }
129
+
130
+ const stateToPropMappings = {
131
+ [State.UNDETERMINED]: undefined,
132
+ [State.BEGAN]: 'onBegan',
133
+ [State.FAILED]: 'onFailed',
134
+ [State.CANCELLED]: 'onCancelled',
135
+ [State.ACTIVE]: 'onActivated',
136
+ [State.END]: 'onEnded',
137
+ } as const;
138
+
139
+ type CreateHandlerArgs<HandlerPropsT extends Record<string, unknown>> =
140
+ Readonly<{
141
+ name: string;
142
+ allowedProps: Readonly<Extract<keyof HandlerPropsT, string>[]>;
143
+ config: Readonly<Record<string, unknown>>;
144
+ transformProps?: (props: HandlerPropsT) => HandlerPropsT;
145
+ customNativeProps?: Readonly<string[]>;
146
+ }>;
147
+
148
+ // TODO(TS) fix event types
149
+ type InternalEventHandlers = {
150
+ onGestureHandlerEvent?: (event: any) => void;
151
+ onGestureHandlerStateChange?: (event: any) => void;
152
+ };
153
+
154
+ const UNRESOLVED_REFS_RETRY_LIMIT = 1;
155
+
156
+ // TODO(TS) - make sure that BaseGestureHandlerProps doesn't need other generic parameter to work with custom properties.
157
+ export default function createHandler<
158
+ T extends BaseGestureHandlerProps<U>,
159
+ U extends Record<string, unknown>
160
+ >({
161
+ name,
162
+ allowedProps = [],
163
+ config = {},
164
+ transformProps,
165
+ customNativeProps = [],
166
+ }: CreateHandlerArgs<T>): React.ComponentType<T & React.RefAttributes<any>> {
167
+ interface HandlerState {
168
+ allowTouches: boolean;
169
+ }
170
+ class Handler extends React.Component<
171
+ T & InternalEventHandlers,
172
+ HandlerState
173
+ > {
174
+ static displayName = name;
175
+ static contextType = GestureHandlerRootViewContext;
176
+
177
+ private handlerTag: number;
178
+ private config: Record<string, unknown>;
179
+ private propsRef: React.MutableRefObject<unknown>;
180
+ private isMountedRef: React.MutableRefObject<boolean | null>;
181
+ private viewNode: any;
182
+ private viewTag?: number;
183
+ private inspectorToggleListener?: EmitterSubscription;
184
+
185
+ constructor(props: T & InternalEventHandlers) {
186
+ super(props);
187
+ this.handlerTag = getNextHandlerTag();
188
+ this.config = {};
189
+ this.propsRef = React.createRef();
190
+ this.isMountedRef = React.createRef();
191
+ this.state = { allowTouches };
192
+ if (props.id) {
193
+ if (handlerIDToTag[props.id] !== undefined) {
194
+ throw new Error(`Handler with ID "${props.id}" already registered`);
195
+ }
196
+ handlerIDToTag[props.id] = this.handlerTag;
197
+ }
198
+ }
199
+
200
+ componentDidMount() {
201
+ const props: HandlerProps<U> = this.props;
202
+ this.isMountedRef.current = true;
203
+
204
+ if (DEV_ON_ANDROID) {
205
+ this.inspectorToggleListener = DeviceEventEmitter.addListener(
206
+ 'toggleElementInspector',
207
+ () => {
208
+ this.setState((_) => ({ allowTouches }));
209
+ this.update(UNRESOLVED_REFS_RETRY_LIMIT);
210
+ }
211
+ );
212
+ }
213
+ if (hasUnresolvedRefs(props)) {
214
+ // If there are unresolved refs (e.g. ".current" has not yet been set)
215
+ // passed as `simultaneousHandlers` or `waitFor`, we enqueue a call to
216
+ // _update method that will try to update native handler props using
217
+ // queueMicrotask. This makes it so update() function gets called after all
218
+ // react components are mounted and we expect the missing ref object to
219
+ // be resolved by then.
220
+ queueMicrotask(() => {
221
+ this.update(UNRESOLVED_REFS_RETRY_LIMIT);
222
+ });
223
+ }
224
+
225
+ this.createGestureHandler(
226
+ filterConfig(
227
+ transformProps ? transformProps(this.props) : this.props,
228
+ [...allowedProps, ...customNativeProps],
229
+ config
230
+ )
231
+ );
232
+
233
+ this.attachGestureHandler(findNodeHandle(this.viewNode) as number); // TODO(TS) - check if this can be null
234
+ }
235
+
236
+ componentDidUpdate() {
237
+ const viewTag = findNodeHandle(this.viewNode);
238
+ if (this.viewTag !== viewTag) {
239
+ this.attachGestureHandler(viewTag as number); // TODO(TS) - check interaction between _viewTag & findNodeHandle
240
+ }
241
+ this.update(UNRESOLVED_REFS_RETRY_LIMIT);
242
+ }
243
+
244
+ componentWillUnmount() {
245
+ this.inspectorToggleListener?.remove();
246
+ this.isMountedRef.current = false;
247
+ RNGestureHandlerModule.dropGestureHandler(this.handlerTag);
248
+ scheduleFlushOperations();
249
+ // We can't use this.props.id directly due to TS generic type narrowing bug, see https://github.com/microsoft/TypeScript/issues/13995 for more context
250
+ const handlerID: string | undefined = this.props.id;
251
+ if (handlerID) {
252
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
253
+ delete handlerIDToTag[handlerID];
254
+ }
255
+ }
256
+
257
+ private onGestureHandlerEvent = (event: GestureEvent<U>) => {
258
+ if (event.nativeEvent.handlerTag === this.handlerTag) {
259
+ if (typeof this.props.onGestureEvent === 'function') {
260
+ this.props.onGestureEvent?.(event);
261
+ }
262
+ } else {
263
+ this.props.onGestureHandlerEvent?.(event);
264
+ }
265
+ };
266
+
267
+ // TODO(TS) - make sure this is right type for event
268
+ private onGestureHandlerStateChange = (
269
+ event: HandlerStateChangeEvent<U>
270
+ ) => {
271
+ if (event.nativeEvent.handlerTag === this.handlerTag) {
272
+ if (typeof this.props.onHandlerStateChange === 'function') {
273
+ this.props.onHandlerStateChange?.(event);
274
+ }
275
+
276
+ const state: ValueOf<typeof State> = event.nativeEvent.state;
277
+ const stateEventName = stateToPropMappings[state];
278
+ const eventHandler = stateEventName && this.props[stateEventName];
279
+ if (eventHandler && typeof eventHandler === 'function') {
280
+ eventHandler(event);
281
+ }
282
+ } else {
283
+ this.props.onGestureHandlerStateChange?.(event);
284
+ }
285
+ };
286
+
287
+ private refHandler = (node: any) => {
288
+ this.viewNode = node;
289
+
290
+ const child = React.Children.only(this.props.children);
291
+ // TODO(TS) fix ref type
292
+ const { ref }: any = child;
293
+ if (ref !== null) {
294
+ if (typeof ref === 'function') {
295
+ ref(node);
296
+ } else {
297
+ ref.current = node;
298
+ }
299
+ }
300
+ };
301
+
302
+ private createGestureHandler = (
303
+ newConfig: Readonly<Record<string, unknown>>
304
+ ) => {
305
+ this.config = newConfig;
306
+
307
+ RNGestureHandlerModule.createGestureHandler(
308
+ name,
309
+ this.handlerTag,
310
+ newConfig
311
+ );
312
+ };
313
+
314
+ private attachGestureHandler = (newViewTag: number) => {
315
+ this.viewTag = newViewTag;
316
+
317
+ if (Platform.OS === 'web') {
318
+ // typecast due to dynamic resolution, attachGestureHandler should have web version signature in this branch
319
+ (
320
+ RNGestureHandlerModule.attachGestureHandler as typeof RNGestureHandlerModuleWeb.attachGestureHandler
321
+ )(
322
+ this.handlerTag,
323
+ newViewTag,
324
+ ActionType.JS_FUNCTION_OLD_API, // ignored on web
325
+ this.propsRef
326
+ );
327
+ } else {
328
+ registerOldGestureHandler(this.handlerTag, {
329
+ onGestureEvent: this.onGestureHandlerEvent,
330
+ onGestureStateChange: this.onGestureHandlerStateChange,
331
+ });
332
+
333
+ const actionType = (() => {
334
+ if (
335
+ (this.props?.onGestureEvent &&
336
+ 'current' in this.props.onGestureEvent) ||
337
+ (this.props?.onHandlerStateChange &&
338
+ 'current' in this.props.onHandlerStateChange)
339
+ ) {
340
+ // Reanimated worklet
341
+ return ActionType.REANIMATED_WORKLET;
342
+ } else if (
343
+ this.props?.onGestureEvent &&
344
+ '__isNative' in this.props.onGestureEvent
345
+ ) {
346
+ // Animated.event with useNativeDriver: true
347
+ return ActionType.NATIVE_ANIMATED_EVENT;
348
+ } else {
349
+ // JS callback or Animated.event with useNativeDriver: false
350
+ return ActionType.JS_FUNCTION_OLD_API;
351
+ }
352
+ })();
353
+
354
+ RNGestureHandlerModule.attachGestureHandler(
355
+ this.handlerTag,
356
+ newViewTag,
357
+ actionType
358
+ );
359
+ }
360
+
361
+ scheduleFlushOperations();
362
+ };
363
+
364
+ private updateGestureHandler = (
365
+ newConfig: Readonly<Record<string, unknown>>
366
+ ) => {
367
+ this.config = newConfig;
368
+
369
+ RNGestureHandlerModule.updateGestureHandler(this.handlerTag, newConfig);
370
+ scheduleFlushOperations();
371
+ };
372
+
373
+ private update(remainingTries: number) {
374
+ if (!this.isMountedRef.current) {
375
+ return;
376
+ }
377
+
378
+ const props: HandlerProps<U> = this.props;
379
+
380
+ // When ref is set via a function i.e. `ref={(r) => refObject.current = r}` instead of
381
+ // `ref={refObject}` it's possible that it won't be resolved in time. Seems like trying
382
+ // again is easy enough fix.
383
+ if (hasUnresolvedRefs(props) && remainingTries > 0) {
384
+ queueMicrotask(() => {
385
+ this.update(remainingTries - 1);
386
+ });
387
+ } else {
388
+ const newConfig = filterConfig(
389
+ transformProps ? transformProps(this.props) : this.props,
390
+ [...allowedProps, ...customNativeProps],
391
+ config
392
+ );
393
+ if (!deepEqual(this.config, newConfig)) {
394
+ this.updateGestureHandler(newConfig);
395
+ }
396
+ }
397
+ }
398
+
399
+ setNativeProps(updates: any) {
400
+ const mergedProps = { ...this.props, ...updates };
401
+ const newConfig = filterConfig(
402
+ transformProps ? transformProps(mergedProps) : mergedProps,
403
+ [...allowedProps, ...customNativeProps],
404
+ config
405
+ );
406
+ this.updateGestureHandler(newConfig);
407
+ }
408
+
409
+ render() {
410
+ if (__DEV__ && !this.context && !isJestEnv() && Platform.OS !== 'web' && (Platform.OS as any) !== "harmony") { // RNOH: patch
411
+ throw new Error(
412
+ name +
413
+ ' 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.'
414
+ );
415
+ }
416
+
417
+ let gestureEventHandler = this.onGestureHandlerEvent;
418
+ // Another instance of https://github.com/microsoft/TypeScript/issues/13995
419
+ type OnGestureEventHandlers = {
420
+ onGestureEvent?: BaseGestureHandlerProps<U>['onGestureEvent'];
421
+ onGestureHandlerEvent?: InternalEventHandlers['onGestureHandlerEvent'];
422
+ };
423
+ const { onGestureEvent, onGestureHandlerEvent }: OnGestureEventHandlers =
424
+ this.props;
425
+ if (onGestureEvent && typeof onGestureEvent !== 'function') {
426
+ // If it's not a method it should be an native Animated.event
427
+ // object. We set it directly as the handler for the view
428
+ // In this case nested handlers are not going to be supported
429
+ if (onGestureHandlerEvent) {
430
+ throw new Error(
431
+ 'Nesting touch handlers with native animated driver is not supported yet'
432
+ );
433
+ }
434
+ gestureEventHandler = onGestureEvent;
435
+ } else {
436
+ if (
437
+ onGestureHandlerEvent &&
438
+ typeof onGestureHandlerEvent !== 'function'
439
+ ) {
440
+ throw new Error(
441
+ 'Nesting touch handlers with native animated driver is not supported yet'
442
+ );
443
+ }
444
+ }
445
+
446
+ let gestureStateEventHandler = this.onGestureHandlerStateChange;
447
+ // Another instance of https://github.com/microsoft/TypeScript/issues/13995
448
+ type OnGestureStateChangeHandlers = {
449
+ onHandlerStateChange?: BaseGestureHandlerProps<U>['onHandlerStateChange'];
450
+ onGestureHandlerStateChange?: InternalEventHandlers['onGestureHandlerStateChange'];
451
+ };
452
+ const {
453
+ onHandlerStateChange,
454
+ onGestureHandlerStateChange,
455
+ }: OnGestureStateChangeHandlers = this.props;
456
+ if (onHandlerStateChange && typeof onHandlerStateChange !== 'function') {
457
+ // If it's not a method it should be an native Animated.event
458
+ // object. We set it directly as the handler for the view
459
+ // In this case nested handlers are not going to be supported
460
+ if (onGestureHandlerStateChange) {
461
+ throw new Error(
462
+ 'Nesting touch handlers with native animated driver is not supported yet'
463
+ );
464
+ }
465
+ gestureStateEventHandler = onHandlerStateChange;
466
+ } else {
467
+ if (
468
+ onGestureHandlerStateChange &&
469
+ typeof onGestureHandlerStateChange !== 'function'
470
+ ) {
471
+ throw new Error(
472
+ 'Nesting touch handlers with native animated driver is not supported yet'
473
+ );
474
+ }
475
+ }
476
+ const events = {
477
+ onGestureHandlerEvent: this.state.allowTouches
478
+ ? gestureEventHandler
479
+ : undefined,
480
+ onGestureHandlerStateChange: this.state.allowTouches
481
+ ? gestureStateEventHandler
482
+ : undefined,
483
+ };
484
+
485
+ this.propsRef.current = events;
486
+
487
+ let child: any = null;
488
+ try {
489
+ child = React.Children.only(this.props.children);
490
+ } catch (e) {
491
+ throw new Error(
492
+ tagMessage(
493
+ `${name} 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.`
494
+ )
495
+ );
496
+ }
497
+
498
+ let grandChildren = child.props.children;
499
+ if (
500
+ __DEV__ &&
501
+ child.type &&
502
+ (child.type === 'RNGestureHandlerButton' ||
503
+ child.type.name === 'View' ||
504
+ child.type.displayName === 'View')
505
+ ) {
506
+ grandChildren = React.Children.toArray(grandChildren);
507
+ grandChildren.push(
508
+ <PressabilityDebugView
509
+ key="pressabilityDebugView"
510
+ color="mediumspringgreen"
511
+ hitSlop={child.props.hitSlop}
512
+ />
513
+ );
514
+ }
515
+
516
+ return React.cloneElement(
517
+ child,
518
+ {
519
+ ref: this.refHandler,
520
+ collapsable: false,
521
+ ...(isJestEnv()
522
+ ? {
523
+ handlerType: name,
524
+ handlerTag: this.handlerTag,
525
+ }
526
+ : {}),
527
+ testID: this.props.testID ?? child.props.testID,
528
+ ...events,
529
+ },
530
+ grandChildren
531
+ );
532
+ }
533
+ }
534
+ return Handler;
535
+ }