@react-navigation/stack 8.0.0-alpha.5 → 8.0.0-alpha.51

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 (133) hide show
  1. package/lib/module/TransitionConfigs/CardStyleInterpolators.js +36 -0
  2. package/lib/module/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
  3. package/lib/module/index.js +2 -2
  4. package/lib/module/index.js.map +1 -1
  5. package/lib/module/navigators/createStackNavigator.js +3 -7
  6. package/lib/module/navigators/createStackNavigator.js.map +1 -1
  7. package/lib/module/utils/GestureHandlerContext.js +5 -0
  8. package/lib/module/utils/GestureHandlerContext.js.map +1 -0
  9. package/lib/module/utils/gestureActivationCriteria.js +10 -8
  10. package/lib/module/utils/gestureActivationCriteria.js.map +1 -1
  11. package/lib/module/utils/useCardAnimation.js +1 -1
  12. package/lib/module/utils/useCardAnimation.js.map +1 -1
  13. package/lib/module/utils/useGestureHandler.js +9 -0
  14. package/lib/module/utils/useGestureHandler.js.map +1 -0
  15. package/lib/module/utils/useKeyboardManager.js +71 -26
  16. package/lib/module/utils/useKeyboardManager.js.map +1 -1
  17. package/lib/module/views/GestureHandler.js +15 -14
  18. package/lib/module/views/GestureHandler.js.map +1 -1
  19. package/lib/module/views/GestureHandlerNative.js +16 -10
  20. package/lib/module/views/GestureHandlerNative.js.map +1 -1
  21. package/lib/module/views/Header/Header.js +2 -2
  22. package/lib/module/views/Header/Header.js.map +1 -1
  23. package/lib/module/views/Header/HeaderContainer.js +52 -18
  24. package/lib/module/views/Header/HeaderContainer.js.map +1 -1
  25. package/lib/module/views/Header/HeaderSegment.js +3 -3
  26. package/lib/module/views/Header/HeaderSegment.js.map +1 -1
  27. package/lib/module/views/Stack/Card.js +108 -93
  28. package/lib/module/views/Stack/Card.js.map +1 -1
  29. package/lib/module/views/Stack/CardContainer.js +72 -98
  30. package/lib/module/views/Stack/CardContainer.js.map +1 -1
  31. package/lib/module/views/Stack/CardContent.js +2 -0
  32. package/lib/module/views/Stack/CardContent.js.map +1 -1
  33. package/lib/module/views/Stack/CardStack.js +183 -132
  34. package/lib/module/views/Stack/CardStack.js.map +1 -1
  35. package/lib/module/views/Stack/StackView.js +103 -54
  36. package/lib/module/views/Stack/StackView.js.map +1 -1
  37. package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts +1 -1
  38. package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts.map +1 -1
  39. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts +1 -1
  40. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts.map +1 -1
  41. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts +1 -1
  42. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -1
  43. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts +1 -1
  44. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts.map +1 -1
  45. package/lib/typescript/src/index.d.ts +12 -12
  46. package/lib/typescript/src/index.d.ts.map +1 -1
  47. package/lib/typescript/src/navigators/createStackNavigator.d.ts +10 -15
  48. package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
  49. package/lib/typescript/src/types.d.ts +52 -55
  50. package/lib/typescript/src/types.d.ts.map +1 -1
  51. package/lib/typescript/src/utils/CardAnimationContext.d.ts +1 -1
  52. package/lib/typescript/src/utils/CardAnimationContext.d.ts.map +1 -1
  53. package/lib/typescript/src/utils/GestureHandlerContext.d.ts +3 -0
  54. package/lib/typescript/src/utils/GestureHandlerContext.d.ts.map +1 -0
  55. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts +4 -51
  56. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts.map +1 -1
  57. package/lib/typescript/src/utils/getDistanceForDirection.d.ts +1 -1
  58. package/lib/typescript/src/utils/getDistanceForDirection.d.ts.map +1 -1
  59. package/lib/typescript/src/utils/getInvertedMultiplier.d.ts +1 -1
  60. package/lib/typescript/src/utils/getInvertedMultiplier.d.ts.map +1 -1
  61. package/lib/typescript/src/utils/getModalRoutesKeys.d.ts +1 -1
  62. package/lib/typescript/src/utils/getModalRoutesKeys.d.ts.map +1 -1
  63. package/lib/typescript/src/utils/getShadowStyle.d.ts +5 -5
  64. package/lib/typescript/src/utils/useCardAnimation.d.ts +1 -1
  65. package/lib/typescript/src/utils/useCardAnimation.d.ts.map +1 -1
  66. package/lib/typescript/src/utils/useGestureHandler.d.ts +2 -0
  67. package/lib/typescript/src/utils/useGestureHandler.d.ts.map +1 -0
  68. package/lib/typescript/src/utils/useKeyboardManager.d.ts +12 -2
  69. package/lib/typescript/src/utils/useKeyboardManager.d.ts.map +1 -1
  70. package/lib/typescript/src/views/GestureHandler.android.d.ts +1 -1
  71. package/lib/typescript/src/views/GestureHandler.android.d.ts.map +1 -1
  72. package/lib/typescript/src/views/GestureHandler.d.ts +7 -11
  73. package/lib/typescript/src/views/GestureHandler.d.ts.map +1 -1
  74. package/lib/typescript/src/views/GestureHandler.ios.d.ts +1 -1
  75. package/lib/typescript/src/views/GestureHandler.ios.d.ts.map +1 -1
  76. package/lib/typescript/src/views/GestureHandlerNative.d.ts +9 -4
  77. package/lib/typescript/src/views/GestureHandlerNative.d.ts.map +1 -1
  78. package/lib/typescript/src/views/Header/Header.d.ts +2 -2
  79. package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
  80. package/lib/typescript/src/views/Header/HeaderContainer.d.ts +9 -3
  81. package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
  82. package/lib/typescript/src/views/Header/HeaderSegment.d.ts +5 -4
  83. package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
  84. package/lib/typescript/src/views/Stack/Card.d.ts +5 -5
  85. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  86. package/lib/typescript/src/views/Stack/CardContainer.d.ts +5 -7
  87. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  88. package/lib/typescript/src/views/Stack/CardContent.d.ts +1 -1
  89. package/lib/typescript/src/views/Stack/CardContent.d.ts.map +1 -1
  90. package/lib/typescript/src/views/Stack/CardStack.d.ts +9 -6
  91. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  92. package/lib/typescript/src/views/Stack/StackView.d.ts +14 -17
  93. package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
  94. package/package.json +23 -24
  95. package/src/TransitionConfigs/CardStyleInterpolators.tsx +44 -0
  96. package/src/index.tsx +3 -2
  97. package/src/navigators/createStackNavigator.tsx +9 -40
  98. package/src/types.tsx +79 -75
  99. package/src/utils/GestureHandlerContext.tsx +5 -0
  100. package/src/utils/gestureActivationCriteria.tsx +14 -10
  101. package/src/utils/useCardAnimation.tsx +1 -1
  102. package/src/utils/useGestureHandler.tsx +9 -0
  103. package/src/utils/useKeyboardManager.tsx +96 -33
  104. package/src/views/GestureHandler.tsx +27 -16
  105. package/src/views/GestureHandlerNative.tsx +26 -12
  106. package/src/views/Header/Header.tsx +2 -2
  107. package/src/views/Header/HeaderContainer.tsx +69 -33
  108. package/src/views/Header/HeaderSegment.tsx +6 -7
  109. package/src/views/Stack/Card.tsx +154 -119
  110. package/src/views/Stack/CardContainer.tsx +86 -127
  111. package/src/views/Stack/CardContent.tsx +1 -0
  112. package/src/views/Stack/CardStack.tsx +409 -330
  113. package/src/views/Stack/StackView.tsx +176 -79
  114. package/lib/module/utils/GestureHandlerRefContext.js +0 -5
  115. package/lib/module/utils/GestureHandlerRefContext.js.map +0 -1
  116. package/lib/module/utils/findLastIndex.js +0 -11
  117. package/lib/module/utils/findLastIndex.js.map +0 -1
  118. package/lib/module/utils/useGestureHandlerRef.js +0 -12
  119. package/lib/module/utils/useGestureHandlerRef.js.map +0 -1
  120. package/lib/module/views/Stack/CardA11yWrapper.js +0 -43
  121. package/lib/module/views/Stack/CardA11yWrapper.js.map +0 -1
  122. package/lib/typescript/src/utils/GestureHandlerRefContext.d.ts +0 -3
  123. package/lib/typescript/src/utils/GestureHandlerRefContext.d.ts.map +0 -1
  124. package/lib/typescript/src/utils/findLastIndex.d.ts +0 -2
  125. package/lib/typescript/src/utils/findLastIndex.d.ts.map +0 -1
  126. package/lib/typescript/src/utils/useGestureHandlerRef.d.ts +0 -3
  127. package/lib/typescript/src/utils/useGestureHandlerRef.d.ts.map +0 -1
  128. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts +0 -15
  129. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts.map +0 -1
  130. package/src/utils/GestureHandlerRefContext.tsx +0 -5
  131. package/src/utils/findLastIndex.tsx +0 -9
  132. package/src/utils/useGestureHandlerRef.tsx +0 -15
  133. package/src/views/Stack/CardA11yWrapper.tsx +0 -67
package/src/types.tsx CHANGED
@@ -1,9 +1,9 @@
1
1
  import type {
2
- HeaderBackButton,
3
2
  HeaderBackButtonDisplayMode,
4
3
  HeaderBackButtonProps,
5
4
  HeaderOptions,
6
5
  HeaderTitleProps,
6
+ Icon,
7
7
  } from '@react-navigation/elements';
8
8
  import type {
9
9
  DefaultNavigatorOptions,
@@ -138,12 +138,12 @@ export type SceneProgress = {
138
138
  * Progress value for the screen after this one in the stack.
139
139
  * This can be `undefined` in case the screen animating is the last one.
140
140
  */
141
- next?: Animated.AnimatedInterpolation<number>;
141
+ next?: Animated.AnimatedInterpolation<number> | undefined;
142
142
  /**
143
143
  * Progress value for the screen before this one in the stack.
144
144
  * This can be `undefined` in case the screen animating is the first one.
145
145
  */
146
- previous?: Animated.AnimatedInterpolation<number>;
146
+ previous?: Animated.AnimatedInterpolation<number> | undefined;
147
147
  };
148
148
 
149
149
  export type StackHeaderMode = 'float' | 'screen';
@@ -187,14 +187,14 @@ export type StackHeaderOptions = Omit<
187
187
  * Defaults to the previous screen's title, or "Back" if there's not enough space.
188
188
  * Use `headerBackButtonDisplayMode` to customize the behavior.
189
189
  */
190
- headerBackTitle?: string;
190
+ headerBackTitle?: string | undefined;
191
191
  /**
192
192
  * Title string used by the back button when `headerBackTitle` doesn't fit on the screen.
193
193
  * Use `headerBackButtonDisplayMode` to customize the behavior.
194
194
  *
195
195
  * Defaults to "Back".
196
196
  */
197
- headerBackTruncatedTitle?: string;
197
+ headerBackTruncatedTitle?: string | undefined;
198
198
  /**
199
199
  * How the back button displays icon and title.
200
200
  *
@@ -211,27 +211,47 @@ export type StackHeaderOptions = Omit<
211
211
  */
212
212
  headerBackTitleStyle?: StyleProp<TextStyle>;
213
213
  /**
214
- * Function which returns a React Element to display custom image in header's back button.
215
- * It receives the `tintColor` in in the options object as an argument. object.
216
- * Defaults to Image component with a the default back icon image for the platform (a chevron on iOS and an arrow on Android).
217
- */
218
- headerBackImage?: React.ComponentProps<typeof HeaderBackButton>['backImage'];
214
+ * Icon to display in the header in the back button.
215
+ *
216
+ * Supported types:
217
+ * - image: custom image source
218
+ * - sfSymbol: SF Symbol icon (iOS only)
219
+ * - materialSymbol: material symbol icon (Android only)
220
+ * - React Node: function that returns a React Element
221
+ *
222
+ * Defaults to back icon image for the platform
223
+ * - A chevron on iOS
224
+ * - An arrow on Android
225
+ *
226
+ * @example
227
+ * ```js
228
+ * headerBackIcon: {
229
+ * type: 'image',
230
+ * source: require('./back-icon.png'),
231
+ * }
232
+ * ```
233
+ */
234
+ headerBackIcon?:
235
+ | Icon
236
+ | ((props: { tintColor: ColorValue | undefined }) => React.ReactNode);
219
237
  };
220
238
 
221
239
  export type StackHeaderProps = {
222
240
  /**
223
241
  * Options for the back button.
224
242
  */
225
- back?: {
226
- /**
227
- * Title of the previous screen.
228
- */
229
- title: string | undefined;
230
- /**
231
- * The `href` to use for the anchor tag on web
232
- */
233
- href: string | undefined;
234
- };
243
+ back?:
244
+ | {
245
+ /**
246
+ * Title of the previous screen.
247
+ */
248
+ title: string | undefined;
249
+ /**
250
+ * The `href` to use for the anchor tag on web
251
+ */
252
+ href: string | undefined;
253
+ }
254
+ | undefined;
235
255
  /**
236
256
  * Animated nodes representing the progress of the animation.
237
257
  */
@@ -258,26 +278,26 @@ export type StackHeaderRightProps = {
258
278
  /**
259
279
  * Tint color for the header button.
260
280
  */
261
- tintColor?: ColorValue;
281
+ tintColor?: ColorValue | undefined;
262
282
  /**
263
283
  * Color for material ripple (Android >= 5.0 only).
264
284
  */
265
- pressColor?: ColorValue;
285
+ pressColor?: ColorValue | undefined;
266
286
  /**
267
287
  * Opacity when the button is pressed, used when ripple is not supported.
268
288
  */
269
- pressOpacity?: number;
289
+ pressOpacity?: number | undefined;
270
290
  /**
271
291
  * Whether it's possible to navigate back in stack.
272
292
  */
273
- canGoBack?: boolean;
293
+ canGoBack?: boolean | undefined;
274
294
  };
275
295
 
276
296
  export type StackHeaderLeftProps = HeaderBackButtonProps & {
277
297
  /**
278
298
  * Whether it's possible to navigate back in stack.
279
299
  */
280
- canGoBack?: boolean;
300
+ canGoBack?: boolean | undefined;
281
301
  };
282
302
 
283
303
  export type StackDescriptor = Descriptor<
@@ -326,15 +346,6 @@ export type StackNavigationOptions = StackHeaderOptions &
326
346
  /**
327
347
  * Style object for the card in stack.
328
348
  * You can provide a custom background color to use instead of the default background here.
329
- *
330
- * You can also specify `{ backgroundColor: 'transparent' }` to make the previous screen visible underneath.
331
- * This is useful to implement things like modal dialogs.
332
- *
333
- * You should also specify `detachPreviousScreen: false` in options when using a transparent background
334
- * so that the previous screen isn't detached and stays below the current screen.
335
- *
336
- * You might also need to change the animation of the screen using `cardStyleInterpolator`
337
- * so that the previous screen isn't transformed or invisible.
338
349
  */
339
350
  cardStyle?: StyleProp<ViewStyle>;
340
351
  /**
@@ -348,7 +359,6 @@ export type StackNavigationOptions = StackHeaderOptions &
348
359
  * - `transparentModal`: Similar to `modal`. This changes following things:
349
360
  * - Sets `headerMode` to `screen` for the screen unless specified otherwise.
350
361
  * - Sets background color of the screen to transparent, so previous screen is visible
351
- * - Adjusts the `detachPreviousScreen` option so that the previous screen stays rendered.
352
362
  * - Prevents the previous screen from animating from its last position.
353
363
  * - Changes the screen animation to a vertical slide animation.
354
364
  *
@@ -390,57 +400,43 @@ export type StackNavigationOptions = StackHeaderOptions &
390
400
  * Not supported on Web.
391
401
  */
392
402
  gestureVelocityImpact?: number;
393
- /**
394
- * Whether to detach the previous screen from the view hierarchy to save memory.
395
- * Set it to `false` if you need the previous screen to be seen through the active screen.
396
- * Only applicable if `detachInactiveScreens` isn't set to `false`.
397
- * Defaults to `false` for the last screen for modals, otherwise `true`.
398
- */
399
- detachPreviousScreen?: boolean;
400
403
  /**
401
404
  * If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen from this screen.
402
405
  * Defaults to `true`.
403
406
  */
404
407
  keyboardHandlingEnabled?: boolean;
408
+
405
409
  /**
406
- * Whether inactive screens should be suspended from re-rendering. Defaults to `false`.
407
- * Defaults to `true` when `enableFreeze()` is run at the top of the application.
408
- * Requires `react-native-screens` version >=3.16.0.
410
+ * What should happen when screens become inactive.
411
+ * - `pause`: Effects are cleaned up
412
+ * - `unmount`: Screen is unmounted
413
+ * - `none`: Screen renders normally
409
414
  *
410
- * Only supported on iOS and Android.
411
- */
412
- freezeOnBlur?: boolean;
413
- /**
414
- * Whether the home indicator should prefer to stay hidden on this screen. Defaults to `false`.
415
+ * Defaults to `pause`.
416
+ *
417
+ * Preloaded screens won't be paused until after navigated to.
418
+ * This makes sure that effects are run to initialize the screen.
415
419
  *
416
- * @platform ios
420
+ * Screens with nested navigators and last 2 screens won't be unmounted.
417
421
  */
418
- autoHideHomeIndicator?: boolean;
422
+ inactiveBehavior?: 'pause' | 'unmount' | 'none' | undefined;
419
423
  };
420
424
 
421
- export type StackNavigationConfig = {
422
- /**
423
- * Whether inactive screens should be detached from the view hierarchy to save memory.
424
- * This will have no effect if you disable `react-native-screens`.
425
- *
426
- * Defaults to `true`.
427
- */
428
- detachInactiveScreens?: boolean;
429
- };
425
+ export type StackNavigationConfig = {};
430
426
 
431
427
  export type TransitionSpec =
432
428
  | {
433
429
  animation: 'spring';
434
430
  config: Omit<
435
431
  Animated.SpringAnimationConfig,
436
- 'toValue' | keyof Animated.AnimationConfig
432
+ 'toValue' | 'useNativeDriver' | 'isInteraction' | 'velocity'
437
433
  >;
438
434
  }
439
435
  | {
440
436
  animation: 'timing';
441
437
  config: Omit<
442
438
  Animated.TimingAnimationConfig,
443
- 'toValue' | keyof Animated.AnimationConfig
439
+ 'toValue' | 'useNativeDriver' | 'isInteraction'
444
440
  >;
445
441
  };
446
442
 
@@ -458,12 +454,14 @@ export type StackCardInterpolationProps = {
458
454
  * Values for the screen after this one in the stack.
459
455
  * This can be `undefined` in case the screen animating is the last one.
460
456
  */
461
- next?: {
462
- /**
463
- * Animated node representing the progress value of the next screen.
464
- */
465
- progress: Animated.AnimatedInterpolation<number>;
466
- };
457
+ next?:
458
+ | {
459
+ /**
460
+ * Animated node representing the progress value of the next screen.
461
+ */
462
+ progress: Animated.AnimatedInterpolation<number>;
463
+ }
464
+ | undefined;
467
465
  /**
468
466
  * The index of the card with this interpolation in the stack.
469
467
  */
@@ -513,6 +511,10 @@ export type StackCardInterpolatedStyle = {
513
511
  * Interpolated style for the view representing the semi-transparent overlay below the card.
514
512
  */
515
513
  overlayStyle?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
514
+ /**
515
+ * Interpolated style for dim on top of the card content.
516
+ */
517
+ dimStyle?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
516
518
  /**
517
519
  * Interpolated style representing the card shadow.
518
520
  */
@@ -537,12 +539,14 @@ export type StackHeaderInterpolationProps = {
537
539
  * Values for the screen after this one in the stack.
538
540
  * This can be `undefined` in case the screen animating is the last one.
539
541
  */
540
- next?: {
541
- /**
542
- * Animated node representing the progress value of the next screen.
543
- */
544
- progress: Animated.AnimatedInterpolation<number>;
545
- };
542
+ next?:
543
+ | {
544
+ /**
545
+ * Animated node representing the progress value of the next screen.
546
+ */
547
+ progress: Animated.AnimatedInterpolation<number>;
548
+ }
549
+ | undefined;
546
550
  /**
547
551
  * Writing direction of the layout.
548
552
  */
@@ -0,0 +1,5 @@
1
+ import * as React from 'react';
2
+
3
+ export const GestureHandlerContext = React.createContext<
4
+ import('react-native-gesture-handler').PanGesture | null
5
+ >(null);
@@ -1,4 +1,5 @@
1
1
  import type { LocaleDirection } from '@react-navigation/native';
2
+ import type { PanGestureConfig } from 'react-native-gesture-handler';
2
3
 
3
4
  import type { GestureDirection, Layout } from '../types';
4
5
  import { getInvertedMultiplier } from './getInvertedMultiplier';
@@ -17,9 +18,9 @@ export const gestureActivationCriteria = ({
17
18
  }: {
18
19
  direction: LocaleDirection;
19
20
  gestureDirection: GestureDirection;
20
- gestureResponseDistance?: number;
21
+ gestureResponseDistance?: number | undefined;
21
22
  layout: Layout;
22
- }) => {
23
+ }): PanGestureConfig => {
23
24
  const enableTrackpadTwoFingerGesture = true;
24
25
 
25
26
  const distance =
@@ -30,17 +31,20 @@ export const gestureActivationCriteria = ({
30
31
  ? GESTURE_RESPONSE_DISTANCE_VERTICAL
31
32
  : GESTURE_RESPONSE_DISTANCE_HORIZONTAL;
32
33
 
34
+ const failOffsetX: [number, number] = [-15, 15];
35
+ const failOffsetY: [number, number] = [-20, 20];
36
+
33
37
  if (gestureDirection === 'vertical') {
34
38
  return {
35
- maxDeltaX: 15,
36
- minOffsetY: 5,
39
+ failOffsetX,
40
+ activeOffsetY: 5,
37
41
  hitSlop: { bottom: -layout.height + distance },
38
42
  enableTrackpadTwoFingerGesture,
39
43
  };
40
44
  } else if (gestureDirection === 'vertical-inverted') {
41
45
  return {
42
- maxDeltaX: 15,
43
- minOffsetY: -5,
46
+ failOffsetX,
47
+ activeOffsetY: -5,
44
48
  hitSlop: { top: -layout.height + distance },
45
49
  enableTrackpadTwoFingerGesture,
46
50
  };
@@ -53,15 +57,15 @@ export const gestureActivationCriteria = ({
53
57
 
54
58
  if (invertedMultiplier === 1) {
55
59
  return {
56
- minOffsetX: 5,
57
- maxDeltaY: 20,
60
+ activeOffsetX: 5,
61
+ failOffsetY,
58
62
  hitSlop: { right: hitSlop },
59
63
  enableTrackpadTwoFingerGesture,
60
64
  };
61
65
  } else {
62
66
  return {
63
- minOffsetX: -5,
64
- maxDeltaY: 20,
67
+ activeOffsetX: -5,
68
+ failOffsetY,
65
69
  hitSlop: { left: hitSlop },
66
70
  enableTrackpadTwoFingerGesture,
67
71
  };
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { CardAnimationContext } from './CardAnimationContext';
4
4
 
5
5
  export function useCardAnimation() {
6
- const animation = React.useContext(CardAnimationContext);
6
+ const animation = React.use(CardAnimationContext);
7
7
 
8
8
  if (animation === undefined) {
9
9
  throw new Error(
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+
3
+ import { GestureHandlerContext } from './GestureHandlerContext';
4
+
5
+ export function useGestureHandler() {
6
+ const gesture = React.useContext(GestureHandlerContext);
7
+
8
+ return gesture;
9
+ }
@@ -1,12 +1,23 @@
1
1
  import * as React from 'react';
2
2
  import { type HostInstance, Keyboard, TextInput } from 'react-native';
3
3
 
4
- export function useKeyboardManager(isEnabled: () => boolean) {
4
+ export function useKeyboardManager({
5
+ enabled,
6
+ focused,
7
+ contentRef,
8
+ }: {
9
+ enabled: boolean;
10
+ focused: boolean;
11
+ contentRef: React.RefObject<HostInstance | null>;
12
+ }) {
5
13
  // Numeric id of the previously focused text input
6
14
  // When a gesture didn't change the tab, we can restore the focused input with this
7
15
  const previouslyFocusedTextInputRef = React.useRef<HostInstance>(undefined);
8
16
  const startTimestampRef = React.useRef<number>(0);
9
- const keyboardTimeoutRef = React.useRef<NodeJS.Timeout>(undefined);
17
+ const keyboardTimeoutRef =
18
+ React.useRef<ReturnType<typeof setTimeout>>(undefined);
19
+ const enabledRef = React.useRef(enabled);
20
+ const focusedRef = React.useRef(focused);
10
21
 
11
22
  const clearKeyboardTimeout = React.useCallback(() => {
12
23
  if (keyboardTimeoutRef.current !== undefined) {
@@ -16,7 +27,7 @@ export function useKeyboardManager(isEnabled: () => boolean) {
16
27
  }, []);
17
28
 
18
29
  const onPageChangeStart = React.useCallback(() => {
19
- if (!isEnabled()) {
30
+ if (!enabledRef.current || !focusedRef.current) {
20
31
  return;
21
32
  }
22
33
 
@@ -32,37 +43,10 @@ export function useKeyboardManager(isEnabled: () => boolean) {
32
43
 
33
44
  // Store timestamp for touch start
34
45
  startTimestampRef.current = Date.now();
35
- }, [clearKeyboardTimeout, isEnabled]);
36
-
37
- const onPageChangeConfirm = React.useCallback(
38
- (force: boolean) => {
39
- if (!isEnabled()) {
40
- return;
41
- }
42
-
43
- clearKeyboardTimeout();
44
-
45
- if (force) {
46
- // Always dismiss input, even if we don't have a ref to it
47
- // We might not have the ref if onPageChangeStart was never called
48
- // This can happen if page change was not from a gesture
49
- Keyboard.dismiss();
50
- } else {
51
- const input = previouslyFocusedTextInputRef.current;
52
-
53
- // Dismiss the keyboard only if an input was a focused before
54
- // This makes sure we don't dismiss input on going back and focusing an input
55
- input?.blur();
56
- }
57
-
58
- // Cleanup the ID on successful page change
59
- previouslyFocusedTextInputRef.current = undefined;
60
- },
61
- [clearKeyboardTimeout, isEnabled]
62
- );
46
+ }, [clearKeyboardTimeout]);
63
47
 
64
48
  const onPageChangeCancel = React.useCallback(() => {
65
- if (!isEnabled()) {
49
+ if (!enabledRef.current || !focusedRef.current) {
66
50
  return;
67
51
  }
68
52
 
@@ -89,7 +73,86 @@ export function useKeyboardManager(isEnabled: () => boolean) {
89
73
  previouslyFocusedTextInputRef.current = undefined;
90
74
  }
91
75
  }
92
- }, [clearKeyboardTimeout, isEnabled]);
76
+ }, [clearKeyboardTimeout]);
77
+
78
+ const onPageChangeConfirm = React.useCallback(
79
+ ({
80
+ gesture,
81
+ active,
82
+ closing,
83
+ }: {
84
+ gesture: boolean;
85
+ active: boolean;
86
+ closing: boolean;
87
+ }) => {
88
+ if (!enabledRef.current || !focusedRef.current) {
89
+ return;
90
+ }
91
+
92
+ if (!closing) {
93
+ onPageChangeCancel();
94
+ return;
95
+ }
96
+
97
+ clearKeyboardTimeout();
98
+
99
+ if (!gesture) {
100
+ // Always dismiss input, even if we don't have a ref to it
101
+ // We might not have the ref if onPageChangeStart was never called
102
+ // This can happen if page change was not from a gesture
103
+ Keyboard.dismiss();
104
+ } else if (active) {
105
+ const input = previouslyFocusedTextInputRef.current;
106
+
107
+ // Dismiss the keyboard only if an input was a focused before
108
+ // This makes sure we don't dismiss input on going back and focusing an input
109
+ input?.blur();
110
+ }
111
+
112
+ // Cleanup the ID on successful page change
113
+ previouslyFocusedTextInputRef.current = undefined;
114
+ },
115
+ [clearKeyboardTimeout, onPageChangeCancel]
116
+ );
117
+
118
+ // Dismiss keyboard when screen loses focus (e.g. when pushing a new screen).
119
+ // This handles the "navigate forward" case so we don't dismiss the new screen's
120
+ // auto-focused input from handleTransition.
121
+ React.useLayoutEffect(() => {
122
+ if (enabledRef.current && !focused) {
123
+ Keyboard.dismiss();
124
+ }
125
+ }, [focused]);
126
+
127
+ // Dismiss keyboard if native focus is restored to an input in an unfocused screen.
128
+ // This can happen after dismissing a native alert when `autoFocus` is used on iOS.
129
+ React.useEffect(() => {
130
+ const blurInputInScreen = () => {
131
+ if (focusedRef.current || !enabledRef.current) {
132
+ return;
133
+ }
134
+
135
+ const input = TextInput.State.currentlyFocusedInput();
136
+
137
+ if (input && contentRef.current?.contains(input)) {
138
+ input.blur();
139
+ }
140
+ };
141
+
142
+ const subscriptions = [
143
+ Keyboard.addListener('keyboardWillShow', blurInputInScreen),
144
+ Keyboard.addListener('keyboardDidShow', blurInputInScreen),
145
+ ];
146
+
147
+ return () => {
148
+ subscriptions.forEach((subscription) => subscription.remove());
149
+ };
150
+ }, [contentRef]);
151
+
152
+ React.useLayoutEffect(() => {
153
+ enabledRef.current = enabled;
154
+ focusedRef.current = focused;
155
+ });
93
156
 
94
157
  React.useEffect(() => {
95
158
  return () => clearKeyboardTimeout();
@@ -1,23 +1,34 @@
1
1
  import * as React from 'react';
2
2
  import { View } from 'react-native';
3
- import type { PanGestureHandlerProperties } from 'react-native-gesture-handler';
3
+ import type {
4
+ PanGesture,
5
+ PanGestureConfig,
6
+ } from 'react-native-gesture-handler';
4
7
 
5
- const Dummy: any = ({ children }: { children: React.ReactNode }) => (
6
- <>{children}</>
7
- );
8
+ import { GestureHandlerContext } from '../utils/GestureHandlerContext';
8
9
 
9
- export const PanGestureHandler =
10
- Dummy as React.ComponentType<PanGestureHandlerProperties>;
10
+ export function GestureDetector({
11
+ gesture,
12
+ children,
13
+ }: {
14
+ gesture: PanGesture | undefined;
15
+ children: React.ReactNode;
16
+ }) {
17
+ return (
18
+ <GestureHandlerContext.Provider value={gesture ?? null}>
19
+ {children}
20
+ </GestureHandlerContext.Provider>
21
+ );
22
+ }
11
23
 
12
- export const GestureHandlerRootView = View;
24
+ // eslint-disable-next-line @eslint-react/hooks-extra/no-unnecessary-use-prefix, @eslint-react/hooks-extra/ensure-custom-hooks-using-other-hooks
25
+ export function usePanGesture(_config: PanGestureConfig) {
26
+ return undefined;
27
+ }
13
28
 
14
- export const GestureState = {
15
- UNDETERMINED: 0,
16
- FAILED: 1,
17
- BEGAN: 2,
18
- CANCELLED: 3,
19
- ACTIVE: 4,
20
- END: 5,
21
- };
29
+ export const GestureHandlerRootView = View;
22
30
 
23
- export type { PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
31
+ export type {
32
+ PanGesture,
33
+ PanGestureActiveEvent,
34
+ } from 'react-native-gesture-handler';
@@ -1,23 +1,37 @@
1
1
  import * as React from 'react';
2
2
  import {
3
- PanGestureHandler as PanGestureHandlerNative,
4
- type PanGestureHandlerProperties,
3
+ GestureDetector as GestureDetectorNative,
4
+ type PanGesture,
5
+ usePanGesture,
5
6
  } from 'react-native-gesture-handler';
6
7
 
7
- import { GestureHandlerRefContext } from '../utils/GestureHandlerRefContext';
8
+ import { GestureHandlerContext } from '../utils/GestureHandlerContext';
8
9
 
9
- export function PanGestureHandler(props: PanGestureHandlerProperties) {
10
- const gestureRef = React.useRef<PanGestureHandlerNative>(null);
10
+ export function GestureDetector({
11
+ gesture,
12
+ children,
13
+ }: {
14
+ gesture: PanGesture | undefined;
15
+ children: React.ReactNode;
16
+ }) {
17
+ if (gesture == null) {
18
+ throw new Error(
19
+ 'The provided gesture is undefined. A valid gesture must be passed to the GestureDetector on native platforms.'
20
+ );
21
+ }
11
22
 
12
23
  return (
13
- <GestureHandlerRefContext.Provider value={gestureRef}>
14
- <PanGestureHandlerNative {...props} ref={gestureRef} />
15
- </GestureHandlerRefContext.Provider>
24
+ <GestureHandlerContext.Provider value={gesture}>
25
+ <GestureDetectorNative gesture={gesture}>
26
+ {children}
27
+ </GestureDetectorNative>
28
+ </GestureHandlerContext.Provider>
16
29
  );
17
30
  }
18
31
 
19
- export type { PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
20
- export {
21
- GestureHandlerRootView,
22
- State as GestureState,
32
+ export { usePanGesture };
33
+ export type {
34
+ PanGesture,
35
+ PanGestureActiveEvent,
23
36
  } from 'react-native-gesture-handler';
37
+ export { GestureHandlerRootView } from 'react-native-gesture-handler';
@@ -41,8 +41,8 @@ export const Header = React.memo(function Header({
41
41
  [navigation, route.key]
42
42
  );
43
43
 
44
- const isModal = React.useContext(ModalPresentationContext);
45
- const isParentHeaderShown = React.useContext(HeaderShownContext);
44
+ const isModal = React.use(ModalPresentationContext);
45
+ const isParentHeaderShown = React.use(HeaderShownContext);
46
46
 
47
47
  const statusBarHeight =
48
48
  options.headerStatusBarHeight !== undefined