react-native-gesture-handler 3.2.0-nightly-20260811-cc704f09a → 3.2.0

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 (98) hide show
  1. package/android/build.gradle +21 -6
  2. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +30 -66
  3. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +4 -2
  4. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +1 -2
  5. package/apple/RNGestureHandler.mm +31 -23
  6. package/apple/RNGestureHandlerButtonComponentView.mm +10 -6
  7. package/lib/module/components/GestureHandlerButton.web.js +3 -2
  8. package/lib/module/components/GestureHandlerButton.web.js.map +1 -1
  9. package/lib/module/components/ReanimatedDrawerLayout.js +3 -0
  10. package/lib/module/components/ReanimatedDrawerLayout.js.map +1 -1
  11. package/lib/module/components/touchables/TouchableOpacity.js +1 -0
  12. package/lib/module/components/touchables/TouchableOpacity.js.map +1 -1
  13. package/lib/module/handlers/hitSlop.js +101 -0
  14. package/lib/module/handlers/hitSlop.js.map +1 -0
  15. package/lib/module/handlers/utils.js +3 -7
  16. package/lib/module/handlers/utils.js.map +1 -1
  17. package/lib/module/specs/RNGestureHandlerDetectorNativeComponent.ts +1 -1
  18. package/lib/module/specs/RNGestureHandlerRootViewNativeComponent.ts +1 -1
  19. package/lib/module/v3/components/Pressable.js +23 -312
  20. package/lib/module/v3/components/Pressable.js.map +1 -1
  21. package/lib/module/v3/components/PressableWithTouchable.js +259 -0
  22. package/lib/module/v3/components/PressableWithTouchable.js.map +1 -0
  23. package/lib/module/v3/components/StatefulPressable.js +338 -0
  24. package/lib/module/v3/components/StatefulPressable.js.map +1 -0
  25. package/lib/module/v3/components/pointerStyle.js +6 -0
  26. package/lib/module/v3/components/pointerStyle.js.map +1 -0
  27. package/lib/module/v3/components/pointerStyle.web.js +9 -0
  28. package/lib/module/v3/components/pointerStyle.web.js.map +1 -0
  29. package/lib/module/v3/hooks/utils/configUtils.js +3 -1
  30. package/lib/module/v3/hooks/utils/configUtils.js.map +1 -1
  31. package/lib/module/v3/hooks/utils/reanimatedUtils.js +14 -3
  32. package/lib/module/v3/hooks/utils/reanimatedUtils.js.map +1 -1
  33. package/lib/module/web/handlers/GestureHandler.js +21 -44
  34. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  35. package/lib/module/web/interfaces.js.map +1 -1
  36. package/lib/typescript/components/GestureComponents.web.d.ts +12 -4
  37. package/lib/typescript/components/GestureComponents.web.d.ts.map +1 -1
  38. package/lib/typescript/components/GestureHandlerButton.web.d.ts.map +1 -1
  39. package/lib/typescript/components/ReanimatedDrawerLayout.d.ts.map +1 -1
  40. package/lib/typescript/components/touchables/TouchableHighlight.d.ts +1 -1
  41. package/lib/typescript/components/touchables/TouchableHighlight.d.ts.map +1 -1
  42. package/lib/typescript/components/touchables/TouchableOpacity.d.ts.map +1 -1
  43. package/lib/typescript/handlers/hitSlop.d.ts +51 -0
  44. package/lib/typescript/handlers/hitSlop.d.ts.map +1 -0
  45. package/lib/typescript/handlers/utils.d.ts.map +1 -1
  46. package/lib/typescript/mocks/hostDetector.d.ts +5 -2
  47. package/lib/typescript/mocks/hostDetector.d.ts.map +1 -1
  48. package/lib/typescript/specs/RNGestureHandlerDetectorNativeComponent.d.ts +1 -1
  49. package/lib/typescript/specs/RNGestureHandlerDetectorNativeComponent.d.ts.map +1 -1
  50. package/lib/typescript/specs/RNGestureHandlerRootViewNativeComponent.d.ts +1 -1
  51. package/lib/typescript/specs/RNGestureHandlerRootViewNativeComponent.d.ts.map +1 -1
  52. package/lib/typescript/v3/components/GestureComponents.web.d.ts +16 -8
  53. package/lib/typescript/v3/components/GestureComponents.web.d.ts.map +1 -1
  54. package/lib/typescript/v3/components/Pressable.d.ts +13 -0
  55. package/lib/typescript/v3/components/Pressable.d.ts.map +1 -1
  56. package/lib/typescript/v3/components/PressableWithTouchable.d.ts +5 -0
  57. package/lib/typescript/v3/components/PressableWithTouchable.d.ts.map +1 -0
  58. package/lib/typescript/v3/components/StatefulPressable.d.ts +5 -0
  59. package/lib/typescript/v3/components/StatefulPressable.d.ts.map +1 -0
  60. package/lib/typescript/v3/components/pointerStyle.d.ts +3 -0
  61. package/lib/typescript/v3/components/pointerStyle.d.ts.map +1 -0
  62. package/lib/typescript/v3/components/pointerStyle.web.d.ts +3 -0
  63. package/lib/typescript/v3/components/pointerStyle.web.d.ts.map +1 -0
  64. package/lib/typescript/v3/detectors/ReanimatedNativeDetector.d.ts +3 -1
  65. package/lib/typescript/v3/detectors/ReanimatedNativeDetector.d.ts.map +1 -1
  66. package/lib/typescript/v3/detectors/ReanimatedNativeDetector.web.d.ts +3 -1
  67. package/lib/typescript/v3/detectors/ReanimatedNativeDetector.web.d.ts.map +1 -1
  68. package/lib/typescript/v3/detectors/common.d.ts +2 -2
  69. package/lib/typescript/v3/detectors/common.d.ts.map +1 -1
  70. package/lib/typescript/v3/hooks/utils/configUtils.d.ts.map +1 -1
  71. package/lib/typescript/v3/hooks/utils/reanimatedUtils.d.ts.map +1 -1
  72. package/lib/typescript/v3/types/ConfigTypes.d.ts +2 -1
  73. package/lib/typescript/v3/types/ConfigTypes.d.ts.map +1 -1
  74. package/lib/typescript/v3/types/EventTypes.d.ts +3 -2
  75. package/lib/typescript/v3/types/EventTypes.d.ts.map +1 -1
  76. package/lib/typescript/web/handlers/GestureHandler.d.ts +0 -1
  77. package/lib/typescript/web/handlers/GestureHandler.d.ts.map +1 -1
  78. package/lib/typescript/web/interfaces.d.ts +3 -12
  79. package/lib/typescript/web/interfaces.d.ts.map +1 -1
  80. package/package.json +6 -6
  81. package/src/components/GestureHandlerButton.web.tsx +3 -2
  82. package/src/components/ReanimatedDrawerLayout.tsx +3 -0
  83. package/src/components/touchables/TouchableOpacity.tsx +1 -0
  84. package/src/handlers/hitSlop.ts +146 -0
  85. package/src/handlers/utils.ts +4 -2
  86. package/src/specs/RNGestureHandlerDetectorNativeComponent.ts +1 -1
  87. package/src/specs/RNGestureHandlerRootViewNativeComponent.ts +1 -1
  88. package/src/v3/components/Pressable.tsx +28 -448
  89. package/src/v3/components/PressableWithTouchable.tsx +326 -0
  90. package/src/v3/components/StatefulPressable.tsx +476 -0
  91. package/src/v3/components/pointerStyle.ts +5 -0
  92. package/src/v3/components/pointerStyle.web.ts +6 -0
  93. package/src/v3/hooks/utils/configUtils.ts +7 -1
  94. package/src/v3/hooks/utils/reanimatedUtils.ts +17 -8
  95. package/src/v3/types/ConfigTypes.ts +2 -1
  96. package/src/v3/types/EventTypes.ts +7 -3
  97. package/src/web/handlers/GestureHandler.ts +26 -77
  98. package/src/web/interfaces.ts +3 -13
@@ -4,7 +4,9 @@ import { findNodeHandle as findNodeHandleRN, Platform } from 'react-native';
4
4
  import { ghQueueMicrotask } from '../ghQueueMicrotask';
5
5
  import RNGestureHandlerModule from '../RNGestureHandlerModule';
6
6
  import { toArray } from '../utils';
7
+ import type { HitSlop } from './gestureHandlerCommon';
7
8
  import { handlerIDToTag } from './handlersRegistry';
9
+ import { normalizeHitSlop } from './hitSlop';
8
10
 
9
11
  function isConfigParam(param: unknown, name: string) {
10
12
  // param !== Object(param) returns false if `param` is a function
@@ -34,8 +36,8 @@ export function filterConfig(
34
36
  if (isConfigParam(value, key)) {
35
37
  if (key === 'simultaneousHandlers' || key === 'waitFor') {
36
38
  value = transformIntoHandlerTags(props[key]);
37
- } else if (key === 'hitSlop' && typeof value !== 'object') {
38
- value = { top: value, left: value, bottom: value, right: value };
39
+ } else if (key === 'hitSlop') {
40
+ value = normalizeHitSlop(value as HitSlop);
39
41
  }
40
42
  filteredConfig[key] = value;
41
43
  }
@@ -67,7 +67,7 @@ export interface NativeProps extends ViewProps {
67
67
  | undefined;
68
68
 
69
69
  handlerTags: CodegenTypes.Int32[];
70
- moduleId: CodegenTypes.Int32;
70
+ moduleId?: CodegenTypes.WithDefault<CodegenTypes.Int32, -1>;
71
71
  virtualChildren: VirtualChildrenProps[];
72
72
 
73
73
  pointerEvents?: CodegenTypes.WithDefault<
@@ -7,7 +7,7 @@ export interface RootViewNativeProps extends ViewProps {
7
7
  }
8
8
 
9
9
  interface NativeProps extends ViewProps {
10
- moduleId: CodegenTypes.Int32;
10
+ moduleId?: CodegenTypes.WithDefault<CodegenTypes.Int32, -1>;
11
11
  unstable_forceActive?: boolean;
12
12
  }
13
13
 
@@ -1,452 +1,32 @@
1
- import React, {
2
- use,
3
- useCallback,
4
- useEffect,
5
- useMemo,
6
- useRef,
7
- useState,
8
- } from 'react';
9
- import type {
10
- Insets,
11
- LayoutChangeEvent,
12
- StyleProp,
13
- ViewStyle,
14
- } from 'react-native';
15
- import { Platform } from 'react-native';
16
-
17
- import type {
18
- PressableDimensions,
19
- PressableEvent,
20
- PressableProps,
21
- } from '../../components/Pressable/PressableProps';
22
- import {
23
- getStatesConfig,
24
- StateMachineEvent,
25
- } from '../../components/Pressable/stateDefinitions';
26
- import { PressableStateMachine } from '../../components/Pressable/StateMachine';
27
- import {
28
- addInsets,
29
- gestureToPressableEvent,
30
- gestureTouchToPressableEvent,
31
- isTouchWithinInset,
32
- numberAsInset,
33
- viewCenterToPressableEvent,
34
- } from '../../components/Pressable/utils';
35
- import { getTVProps } from '../../components/utils';
36
- import { PressabilityDebugView } from '../../handlers/PressabilityDebugView';
37
- import { useIsScreenReaderEnabled } from '../../useIsScreenReaderEnabled';
38
- import { INT32_MAX, isTestEnv } from '../../utils';
39
- import { GestureDetector } from '../detectors';
40
- import {
41
- useHoverGesture,
42
- useLongPressGesture,
43
- useNativeGesture,
44
- useSimultaneousGestures,
45
- } from '../hooks';
46
- import {
47
- isKeyboardDismissingTap,
48
- JSResponderContext,
49
- } from '../scrollViewInterop';
50
- import { PureNativeButton } from './GestureButtons';
51
-
52
- const DEFAULT_LONG_PRESS_DURATION = 500;
53
- const IS_TEST_ENV = isTestEnv();
54
-
1
+ import React from 'react';
2
+
3
+ import type { PressableProps } from '../../components/Pressable/PressableProps';
4
+ import PressableWithTouchable from './PressableWithTouchable';
5
+ import StatefulPressable from './StatefulPressable';
6
+
7
+ /**
8
+ * `Pressable` dispatches between two implementations:
9
+ *
10
+ * - {@link StatefulPressable} — the state-machine engine, used whenever any of
11
+ * the `simultaneousWith` / `requireToFail` / `block` relation props is passed,
12
+ * since coordinating the press with an external gesture needs the composed
13
+ * gesture recognizers.
14
+ * - {@link PressableWithTouchable} the simpler engine built on the native
15
+ * button `Touchable`, used for everything else (the common case).
16
+ *
17
+ * The choice is re-evaluated each render: toggling a relation prop at runtime
18
+ * swaps engines, which remounts and drops any in-progress press.
19
+ */
55
20
  const Pressable = (props: PressableProps) => {
56
- const {
57
- testOnly_pressed,
58
- hitSlop,
59
- pressRetentionOffset,
60
- delayHoverIn,
61
- delayHoverOut,
62
- delayLongPress,
63
- unstable_pressDelay,
64
- onHoverIn,
65
- onHoverOut,
66
- onPress,
67
- onPressIn,
68
- onPressOut,
69
- onLongPress,
70
- onLayout,
71
- style,
72
- children,
73
- android_disableSound,
74
- android_ripple,
75
- disabled,
76
- accessible,
77
- simultaneousWith,
78
- requireToFail,
79
- block,
80
- ref,
81
- ...remainingProps
82
- } = props;
83
-
84
- const [pressedState, setPressedState] = useState(testOnly_pressed ?? false);
85
-
86
- const longPressTimeoutRef = useRef<number | null>(null);
87
- const pressDelayTimeoutRef = useRef<number | null>(null);
88
- const isOnPressAllowed = useRef<boolean>(true);
89
- const jsResponderContext = use(JSResponderContext);
90
- const isCurrentlyPressed = useRef<boolean>(false);
91
- const dimensions = useRef<PressableDimensions>({
92
- width: 0,
93
- height: 0,
94
- });
95
-
96
- // When the touch that begins a press is the one dismissing the keyboard
97
- // (keyboardShouldPersistTaps="never"), the press is swallowed to match RN's
98
- // touchables.
99
- const dropKeyboardTapRef = useRef<boolean | null>(null);
100
-
101
- const normalizedHitSlop: Insets = useMemo(
102
- () =>
103
- typeof hitSlop === 'number'
104
- ? numberAsInset(hitSlop)
105
- : (hitSlop ?? numberAsInset(0)),
106
- [hitSlop]
107
- );
108
- const normalizedPressRetentionOffset: Insets = useMemo(
109
- () =>
110
- typeof pressRetentionOffset === 'number'
111
- ? numberAsInset(pressRetentionOffset)
112
- : (pressRetentionOffset ?? {}),
113
- [pressRetentionOffset]
114
- );
115
- const appliedHitSlop = addInsets(
116
- normalizedHitSlop,
117
- normalizedPressRetentionOffset
118
- );
119
-
120
- const cancelLongPress = useCallback(() => {
121
- if (longPressTimeoutRef.current) {
122
- clearTimeout(longPressTimeoutRef.current);
123
- longPressTimeoutRef.current = null;
124
- isOnPressAllowed.current = true;
125
- }
126
- }, []);
127
-
128
- const cancelDelayedPress = useCallback(() => {
129
- if (pressDelayTimeoutRef.current) {
130
- clearTimeout(pressDelayTimeoutRef.current);
131
- pressDelayTimeoutRef.current = null;
132
- }
133
- }, []);
134
-
135
- const startLongPress = useCallback(
136
- (event: PressableEvent) => {
137
- if (onLongPress) {
138
- cancelLongPress();
139
- longPressTimeoutRef.current = setTimeout(() => {
140
- isOnPressAllowed.current = false;
141
- onLongPress(event);
142
- }, delayLongPress ?? DEFAULT_LONG_PRESS_DURATION);
143
- }
144
- },
145
- [onLongPress, cancelLongPress, delayLongPress]
146
- );
147
- const innerHandlePressIn = useCallback(
148
- (event: PressableEvent) => {
149
- onPressIn?.(event);
150
- startLongPress(event);
151
- setPressedState(true);
152
- if (pressDelayTimeoutRef.current) {
153
- clearTimeout(pressDelayTimeoutRef.current);
154
- pressDelayTimeoutRef.current = null;
155
- }
156
- },
157
- [onPressIn, startLongPress]
158
- );
159
-
160
- const handleFinalize = useCallback(() => {
161
- isCurrentlyPressed.current = false;
162
- dropKeyboardTapRef.current = null;
163
- cancelLongPress();
164
- cancelDelayedPress();
165
- setPressedState(false);
166
- }, [cancelDelayedPress, cancelLongPress]);
167
-
168
- const captureKeyboardDismiss = useCallback(() => {
169
- dropKeyboardTapRef.current ??= isKeyboardDismissingTap(jsResponderContext);
170
- }, [jsResponderContext]);
171
-
172
- const handlePressIn = useCallback(
173
- (event: PressableEvent, skipBoundsCheck = false) => {
174
- if (
175
- !skipBoundsCheck &&
176
- !isTouchWithinInset(
177
- dimensions.current,
178
- normalizedHitSlop,
179
- event.nativeEvent.changedTouches.at(-1)
180
- )
181
- ) {
182
- // Ignoring pressIn within pressRetentionOffset
183
- return;
184
- }
185
-
186
- isCurrentlyPressed.current = true;
187
- if (unstable_pressDelay) {
188
- pressDelayTimeoutRef.current = setTimeout(() => {
189
- innerHandlePressIn(event);
190
- }, unstable_pressDelay);
191
- } else {
192
- innerHandlePressIn(event);
193
- }
194
- },
195
- [innerHandlePressIn, normalizedHitSlop, unstable_pressDelay]
196
- );
197
-
198
- const handlePressOut = useCallback(
199
- (event: PressableEvent, success: boolean = true) => {
200
- if (!isCurrentlyPressed.current) {
201
- // Some prop configurations may lead to handlePressOut being called mutliple times.
202
- return;
203
- }
204
-
205
- isCurrentlyPressed.current = false;
206
-
207
- if (pressDelayTimeoutRef.current) {
208
- innerHandlePressIn(event);
209
- }
210
-
211
- onPressOut?.(event);
212
-
213
- if (isOnPressAllowed.current && success) {
214
- onPress?.(event);
215
- }
216
-
217
- handleFinalize();
218
- },
219
- [handleFinalize, innerHandlePressIn, onPress, onPressOut]
220
- );
221
-
222
- const stateMachine = useMemo(() => new PressableStateMachine(), []);
223
- const isScreenReaderEnabled = useIsScreenReaderEnabled();
224
-
225
- useEffect(() => {
226
- const configuration = getStatesConfig(
227
- handlePressIn,
228
- handlePressOut,
229
- isScreenReaderEnabled
230
- );
231
- stateMachine.setStates(configuration);
232
- }, [handlePressIn, handlePressOut, stateMachine, isScreenReaderEnabled]);
233
-
234
- const hoverInTimeout = useRef<number | null>(null);
235
- const hoverOutTimeout = useRef<number | null>(null);
236
-
237
- const hoverGesture = useHoverGesture({
238
- manualActivation: true, // Prevents Hover blocking Native gesture on web
239
- cancelsTouchesInView: false,
240
- onBegin: (event) => {
241
- if (hoverOutTimeout.current) {
242
- clearTimeout(hoverOutTimeout.current);
243
- }
244
- if (delayHoverIn) {
245
- hoverInTimeout.current = setTimeout(
246
- () => onHoverIn?.(gestureToPressableEvent(event)),
247
- delayHoverIn
248
- );
249
- return;
250
- }
251
- onHoverIn?.(gestureToPressableEvent(event));
252
- },
253
- onFinalize: (event) => {
254
- if (hoverInTimeout.current) {
255
- clearTimeout(hoverInTimeout.current);
256
- }
257
- if (delayHoverOut) {
258
- hoverOutTimeout.current = setTimeout(
259
- () => onHoverOut?.(gestureToPressableEvent(event)),
260
- delayHoverOut
261
- );
262
- return;
263
- }
264
- onHoverOut?.(gestureToPressableEvent(event));
265
- },
266
- enabled: disabled !== true,
267
- disableReanimated: true,
268
- simultaneousWith,
269
- block,
270
- requireToFail,
271
- hitSlop: appliedHitSlop,
272
- });
273
-
274
- const pressAndTouchGesture = useLongPressGesture({
275
- minDuration: Platform.OS === 'web' ? 0 : INT32_MAX, // Long press handles finalize on web, thus it must activate right away
276
- maxDistance: INT32_MAX, // Stops long press from cancelling on touch move
277
- cancelsTouchesInView: false,
278
- onTouchesDown: (event) => {
279
- captureKeyboardDismiss();
280
-
281
- if (dropKeyboardTapRef.current) {
282
- return;
283
- }
284
-
285
- const pressableEvent = gestureTouchToPressableEvent(event);
286
- stateMachine.handleEvent(
287
- StateMachineEvent.LONG_PRESS_TOUCHES_DOWN,
288
- pressableEvent
289
- );
290
- },
291
- onTouchesUp: () => {
292
- if (Platform.OS === 'android' && !isScreenReaderEnabled) {
293
- // Prevents potential soft-locks
294
- stateMachine.reset();
295
- handleFinalize();
296
- }
297
- },
298
- onTouchesCancel: (event) => {
299
- const pressableEvent = gestureTouchToPressableEvent(event);
300
- stateMachine.reset();
301
- handlePressOut(pressableEvent, false);
302
- },
303
- onFinalize: (event) => {
304
- if (Platform.OS !== 'web') {
305
- return;
306
- }
307
-
308
- stateMachine.handleEvent(
309
- event.canceled ? StateMachineEvent.CANCEL : StateMachineEvent.FINALIZE
310
- );
311
-
312
- handleFinalize();
313
- },
314
- enabled: disabled !== true,
315
- disableReanimated: true,
316
- simultaneousWith: simultaneousWith,
317
- block: block,
318
- requireToFail: requireToFail,
319
- hitSlop: appliedHitSlop,
320
- });
321
-
322
- // RNButton is placed inside ButtonGesture to enable Android's ripple and to capture non-propagating events
323
- const buttonGesture = useNativeGesture({
324
- onTouchesCancel: (event) => {
325
- if (Platform.OS !== 'macos' && Platform.OS !== 'web') {
326
- // On MacOS cancel occurs in middle of gesture
327
- // On Web cancel occurs on mouse move, which is unwanted
328
- const pressableEvent = gestureTouchToPressableEvent(event);
329
- stateMachine.reset();
330
- handlePressOut(pressableEvent, false);
331
- }
332
- },
333
- onBegin: () => {
334
- captureKeyboardDismiss();
335
-
336
- if (dropKeyboardTapRef.current) {
337
- return;
338
- }
339
-
340
- if (Platform.isTV) {
341
- // tvOS drives this native gesture from the focus-engine Select press.
342
- // The press state machine is touch-based and never
343
- // receives LONG_PRESS_TOUCHES_DOWN here, so bypass it and drive the press handlers directly.
344
- // A focus-driven press has no coordinates, so skip the hit-slop bounds check entirely.
345
- handlePressIn(viewCenterToPressableEvent(dimensions.current), true);
346
- return;
347
- }
348
- if (Platform.OS === 'android' && isScreenReaderEnabled) {
349
- stateMachine.handleEvent(
350
- StateMachineEvent.NATIVE_BEGIN,
351
- viewCenterToPressableEvent(dimensions.current)
352
- );
353
- return;
354
- }
355
- stateMachine.handleEvent(StateMachineEvent.NATIVE_BEGIN);
356
- },
357
- onActivate: () => {
358
- if (!Platform.isTV && Platform.OS !== 'android') {
359
- stateMachine.handleEvent(StateMachineEvent.NATIVE_START);
360
- }
361
- },
362
- onFinalize: (event) => {
363
- // On Web we use LongPress.onFinalize instead of Native.onFinalize,
364
- // as Native cancels on mouse move, and LongPress does not.
365
- if (Platform.OS === 'web') {
366
- return;
367
- }
368
-
369
- if (Platform.isTV) {
370
- handlePressOut(
371
- viewCenterToPressableEvent(dimensions.current),
372
- !event.canceled
373
- );
374
- handleFinalize();
375
- return;
376
- }
377
-
378
- stateMachine.handleEvent(
379
- event.canceled ? StateMachineEvent.CANCEL : StateMachineEvent.FINALIZE
380
- );
381
-
382
- handleFinalize();
383
- },
384
- enabled: disabled !== true,
385
- disableReanimated: true,
386
- simultaneousWith,
387
- block,
388
- requireToFail,
389
- hitSlop: appliedHitSlop,
390
- shouldActivateOnStart: Platform.OS === 'web',
391
- });
392
-
393
- const gesture = useSimultaneousGestures(
394
- buttonGesture,
395
- pressAndTouchGesture,
396
- hoverGesture
397
- );
398
-
399
- // `cursor: 'pointer'` on `RNButton` crashes iOS
400
- const pointerStyle: StyleProp<ViewStyle> =
401
- Platform.OS === 'web' ? { cursor: 'pointer' } : {};
402
-
403
- const styleProp =
404
- typeof style === 'function' ? style({ pressed: pressedState }) : style;
405
-
406
- const childrenProp =
407
- typeof children === 'function'
408
- ? children({ pressed: pressedState })
409
- : children;
410
-
411
- const rippleColor = useMemo(() => {
412
- const defaultRippleColor = android_ripple ? undefined : 'transparent';
413
- return android_ripple?.color ?? defaultRippleColor;
414
- }, [android_ripple]);
415
-
416
- const setDimensions = useCallback(
417
- (event: LayoutChangeEvent) => {
418
- onLayout?.(event);
419
- dimensions.current = event.nativeEvent.layout;
420
- },
421
- [onLayout]
422
- );
423
-
424
- const tvProps = getTVProps(remainingProps);
425
-
426
- return (
427
- <GestureDetector gesture={gesture}>
428
- <PureNativeButton
429
- {...remainingProps}
430
- ref={ref as React.Ref<React.ComponentRef<typeof PureNativeButton>>}
431
- {...tvProps}
432
- onLayout={setDimensions}
433
- accessible={accessible !== false}
434
- hitSlop={appliedHitSlop}
435
- enabled={disabled !== true}
436
- touchSoundDisabled={android_disableSound ?? undefined}
437
- rippleColor={rippleColor}
438
- rippleRadius={android_ripple?.radius ?? undefined}
439
- style={[pointerStyle, styleProp]}
440
- testOnly_onPress={IS_TEST_ENV ? onPress : undefined}
441
- testOnly_onPressIn={IS_TEST_ENV ? onPressIn : undefined}
442
- testOnly_onPressOut={IS_TEST_ENV ? onPressOut : undefined}
443
- testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}>
444
- {childrenProp}
445
- {__DEV__ ? (
446
- <PressabilityDebugView color="red" hitSlop={normalizedHitSlop} />
447
- ) : null}
448
- </PureNativeButton>
449
- </GestureDetector>
21
+ const usesRelations =
22
+ props.simultaneousWith != null ||
23
+ props.requireToFail != null ||
24
+ props.block != null;
25
+
26
+ return usesRelations ? (
27
+ <StatefulPressable {...props} />
28
+ ) : (
29
+ <PressableWithTouchable {...props} />
450
30
  );
451
31
  };
452
32