@react-navigation/stack 8.0.0-alpha.3 → 8.0.0-alpha.30

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 (67) hide show
  1. package/lib/module/index.js.map +1 -1
  2. package/lib/module/navigators/createStackNavigator.js +3 -7
  3. package/lib/module/navigators/createStackNavigator.js.map +1 -1
  4. package/lib/module/utils/useCardAnimation.js +1 -1
  5. package/lib/module/utils/useCardAnimation.js.map +1 -1
  6. package/lib/module/utils/useGestureHandlerRef.js +1 -1
  7. package/lib/module/utils/useGestureHandlerRef.js.map +1 -1
  8. package/lib/module/utils/useKeyboardManager.js +50 -26
  9. package/lib/module/utils/useKeyboardManager.js.map +1 -1
  10. package/lib/module/views/Header/Header.js +2 -2
  11. package/lib/module/views/Header/Header.js.map +1 -1
  12. package/lib/module/views/Header/HeaderContainer.js +32 -16
  13. package/lib/module/views/Header/HeaderContainer.js.map +1 -1
  14. package/lib/module/views/Header/HeaderSegment.js +2 -2
  15. package/lib/module/views/Header/HeaderSegment.js.map +1 -1
  16. package/lib/module/views/Stack/Card.js +25 -20
  17. package/lib/module/views/Stack/Card.js.map +1 -1
  18. package/lib/module/views/Stack/CardA11yWrapper.js +6 -7
  19. package/lib/module/views/Stack/CardA11yWrapper.js.map +1 -1
  20. package/lib/module/views/Stack/CardContainer.js +18 -19
  21. package/lib/module/views/Stack/CardContainer.js.map +1 -1
  22. package/lib/module/views/Stack/CardStack.js +105 -133
  23. package/lib/module/views/Stack/CardStack.js.map +1 -1
  24. package/lib/module/views/Stack/StackView.js +82 -49
  25. package/lib/module/views/Stack/StackView.js.map +1 -1
  26. package/lib/typescript/src/index.d.ts +1 -1
  27. package/lib/typescript/src/index.d.ts.map +1 -1
  28. package/lib/typescript/src/navigators/createStackNavigator.d.ts +8 -14
  29. package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
  30. package/lib/typescript/src/types.d.ts +46 -53
  31. package/lib/typescript/src/types.d.ts.map +1 -1
  32. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts +1 -1
  33. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts.map +1 -1
  34. package/lib/typescript/src/utils/useKeyboardManager.d.ts +9 -2
  35. package/lib/typescript/src/utils/useKeyboardManager.d.ts.map +1 -1
  36. package/lib/typescript/src/views/Header/Header.d.ts +1 -1
  37. package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
  38. package/lib/typescript/src/views/Header/HeaderContainer.d.ts +2 -1
  39. package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
  40. package/lib/typescript/src/views/Header/HeaderSegment.d.ts +2 -2
  41. package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
  42. package/lib/typescript/src/views/Stack/Card.d.ts +3 -3
  43. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  44. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts +2 -2
  45. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts.map +1 -1
  46. package/lib/typescript/src/views/Stack/CardContainer.d.ts +2 -2
  47. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  48. package/lib/typescript/src/views/Stack/CardStack.d.ts +1 -1
  49. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  50. package/lib/typescript/src/views/Stack/StackView.d.ts +6 -9
  51. package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
  52. package/package.json +20 -22
  53. package/src/index.tsx +1 -0
  54. package/src/navigators/createStackNavigator.tsx +9 -40
  55. package/src/types.tsx +73 -73
  56. package/src/utils/gestureActivationCriteria.tsx +1 -1
  57. package/src/utils/useCardAnimation.tsx +1 -1
  58. package/src/utils/useGestureHandlerRef.tsx +1 -1
  59. package/src/utils/useKeyboardManager.tsx +67 -33
  60. package/src/views/Header/Header.tsx +2 -2
  61. package/src/views/Header/HeaderContainer.tsx +37 -18
  62. package/src/views/Header/HeaderSegment.tsx +4 -4
  63. package/src/views/Stack/Card.tsx +32 -23
  64. package/src/views/Stack/CardA11yWrapper.tsx +40 -51
  65. package/src/views/Stack/CardContainer.tsx +10 -21
  66. package/src/views/Stack/CardStack.tsx +291 -328
  67. package/src/views/Stack/StackView.tsx +138 -66
@@ -58,7 +58,7 @@ type Props = {
58
58
  overlayEnabled: boolean;
59
59
  shadowEnabled: boolean | undefined;
60
60
  gestureEnabled: boolean;
61
- gestureResponseDistance?: number;
61
+ gestureResponseDistance?: number | undefined;
62
62
  gestureVelocityImpact: number | undefined;
63
63
  transitionSpec: {
64
64
  open: TransitionSpec;
@@ -66,8 +66,8 @@ type Props = {
66
66
  };
67
67
  preloaded: boolean;
68
68
  styleInterpolator: StackCardStyleInterpolator;
69
- containerStyle?: StyleProp<ViewStyle>;
70
- contentStyle?: StyleProp<ViewStyle>;
69
+ containerStyle?: StyleProp<ViewStyle> | undefined;
70
+ contentStyle?: StyleProp<ViewStyle> | undefined;
71
71
  };
72
72
 
73
73
  const GESTURE_VELOCITY_IMPACT = 0.3;
@@ -151,14 +151,14 @@ function Card({
151
151
  containerStyle: customContainerStyle,
152
152
  contentStyle,
153
153
  }: Props) {
154
- const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
155
-
156
154
  const didInitiallyAnimate = React.useRef(false);
157
155
  const lastToValueRef = React.useRef<number | undefined>(undefined);
158
156
 
159
157
  const animationHandleRef = React.useRef<number | undefined>(undefined);
160
158
  const pendingGestureCallbackRef =
161
159
  React.useRef<ReturnType<typeof setTimeout>>(undefined);
160
+ const pendingOnCloseCallbackRef =
161
+ React.useRef<ReturnType<typeof setTimeout>>(undefined);
162
162
 
163
163
  const [isClosing] = React.useState(() => new Animated.Value(FALSE));
164
164
 
@@ -218,10 +218,8 @@ function Card({
218
218
  }
219
219
 
220
220
  animationHandleRef.current = requestAnimationFrame(() => {
221
- if (didInitiallyAnimate.current) {
222
- // Make sure to re-open screen if it wasn't removed
223
- forceUpdate();
224
- }
221
+ // Make sure to re-open screen if it wasn't removed
222
+ maybeAnimate();
225
223
  });
226
224
  };
227
225
 
@@ -249,6 +247,8 @@ function Card({
249
247
  ({ nativeEvent }: PanGestureHandlerGestureEvent) => {
250
248
  switch (nativeEvent.state) {
251
249
  case GestureState.ACTIVE:
250
+ clearTimeout(pendingGestureCallbackRef.current);
251
+ clearTimeout(pendingOnCloseCallbackRef.current);
252
252
  isSwiping.setValue(TRUE);
253
253
  onGestureBegin?.();
254
254
  break;
@@ -305,10 +305,13 @@ function Card({
305
305
  pendingGestureCallbackRef.current = setTimeout(() => {
306
306
  onClose();
307
307
 
308
- // Trigger an update after we dispatch the action to remove the screen
309
- // This will make sure that we check if the screen didn't get removed so we can cancel the animation
310
- forceUpdate();
311
- }, 32);
308
+ // Check if the screen is still closing with a delay
309
+ // So state update from onClose has a chance to go through
310
+ // If route wasn't removed after onClose, re-open it
311
+ pendingOnCloseCallbackRef.current = setTimeout(() => {
312
+ maybeAnimate();
313
+ }, 32);
314
+ }, 16);
312
315
  }
313
316
 
314
317
  onGestureEnd?.();
@@ -350,17 +353,15 @@ function Card({
350
353
  }
351
354
 
352
355
  clearTimeout(pendingGestureCallbackRef.current);
356
+ clearTimeout(pendingOnCloseCallbackRef.current);
353
357
  };
354
-
355
- // We only want to clean up the animation on unmount
356
358
  }, []);
357
359
 
358
- const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
360
+ const timeoutRef = React.useRef<ReturnType<typeof setTimeout>>(undefined);
359
361
 
360
- React.useEffect(() => {
361
- if (preloaded) {
362
- return;
363
- }
362
+ const maybeAnimate = useLatestCallback(() => {
363
+ clearTimeout(pendingGestureCallbackRef.current);
364
+ clearTimeout(pendingOnCloseCallbackRef.current);
364
365
 
365
366
  if (!didInitiallyAnimate.current) {
366
367
  // Animate the card in on initial mount
@@ -368,9 +369,8 @@ function Card({
368
369
  // rending of the screen is done. This is especially important
369
370
  // in the new architecture
370
371
  // cf., https://github.com/react-navigation/react-navigation/issues/12401
371
- if (timeoutRef.current) {
372
- clearTimeout(timeoutRef.current);
373
- }
372
+ clearTimeout(timeoutRef.current);
373
+
374
374
  timeoutRef.current = setTimeout(() => {
375
375
  didInitiallyAnimate.current = true;
376
376
  animate({ closing });
@@ -410,6 +410,14 @@ function Card({
410
410
  animate({ closing });
411
411
  }
412
412
  }
413
+ });
414
+
415
+ React.useEffect(() => {
416
+ if (preloaded) {
417
+ return;
418
+ }
419
+
420
+ maybeAnimate();
413
421
 
414
422
  previousPropsRef.current = {
415
423
  opening,
@@ -428,6 +436,7 @@ function Card({
428
436
  layout,
429
437
  opening,
430
438
  preloaded,
439
+ maybeAnimate,
431
440
  ]);
432
441
 
433
442
  const interpolationProps = React.useMemo(
@@ -6,62 +6,51 @@ type Props = {
6
6
  active: boolean;
7
7
  animated: boolean;
8
8
  isNextScreenTransparent: boolean;
9
- detachCurrentScreen: boolean;
10
9
  children: React.ReactNode;
10
+ ref?: React.Ref<CardA11yWrapperRef>;
11
11
  };
12
12
 
13
13
  export type CardA11yWrapperRef = { setInert: (value: boolean) => void };
14
14
 
15
- export const CardA11yWrapper = React.forwardRef(
16
- (
17
- {
18
- focused,
19
- active,
20
- animated,
21
- isNextScreenTransparent,
22
- detachCurrentScreen,
23
- children,
24
- }: Props,
25
- ref: React.Ref<CardA11yWrapperRef>
26
- ) => {
27
- // Manage this in separate component to avoid re-rendering card during gestures
28
- // Otherwise the gesture animation will be interrupted as state hasn't updated yet
29
- const [inert, setInert] = React.useState(false);
15
+ export function CardA11yWrapper({
16
+ focused,
17
+ active,
18
+ animated,
19
+ isNextScreenTransparent,
20
+ children,
21
+ ref,
22
+ }: Props) {
23
+ // Manage this in separate component to avoid re-rendering card during gestures
24
+ // Otherwise the gesture animation will be interrupted as state hasn't updated yet
25
+ const [inert, setInert] = React.useState(false);
30
26
 
31
- React.useImperativeHandle(ref, () => ({ setInert }), []);
27
+ React.useImperativeHandle(ref, () => ({ setInert }), []);
32
28
 
33
- const isHidden =
34
- !animated &&
35
- isNextScreenTransparent === false &&
36
- detachCurrentScreen !== false &&
37
- !focused;
29
+ const isHidden = !animated && isNextScreenTransparent === false && !focused;
38
30
 
39
- return (
40
- <View
41
- aria-hidden={!focused}
42
- style={[
43
- StyleSheet.absoluteFill,
44
- {
45
- pointerEvents: (animated ? inert : !focused) ? 'none' : 'box-none',
46
- // This is necessary to avoid unfocused larger pages increasing scroll area
47
- // The issue can be seen on the web when a smaller screen is pushed over a larger one
48
- overflow: active ? undefined : 'hidden',
49
- // We use visibility on web
50
- display: Platform.OS !== 'web' && isHidden ? 'none' : 'flex',
51
- // Hide unfocused screens when animation isn't enabled
52
- // This is also necessary for a11y on web
53
- // @ts-expect-error visibility is only available on web
54
- visibility: isHidden ? 'hidden' : 'visible',
55
- },
56
- ]}
57
- // Make sure this view is not removed on the new architecture, as it causes focus loss during navigation on Android.
58
- // This can happen when the view flattening results in different trees - due to `overflow` style changing in a parent.
59
- collapsable={false}
60
- >
61
- {children}
62
- </View>
63
- );
64
- }
65
- );
66
-
67
- CardA11yWrapper.displayName = 'CardA11yWrapper';
31
+ return (
32
+ <View
33
+ aria-hidden={!focused}
34
+ style={[
35
+ StyleSheet.absoluteFill,
36
+ {
37
+ pointerEvents: (animated ? inert : !focused) ? 'none' : 'box-none',
38
+ // This is necessary to avoid unfocused larger pages increasing scroll area
39
+ // The issue can be seen on the web when a smaller screen is pushed over a larger one
40
+ overflow: active ? undefined : 'hidden',
41
+ // We use visibility on web
42
+ display: Platform.OS !== 'web' && isHidden ? 'none' : 'flex',
43
+ // Hide unfocused screens when animation isn't enabled
44
+ // This is also necessary for a11y on web
45
+ // @ts-expect-error visibility is only available on web
46
+ visibility: isHidden ? 'hidden' : 'visible',
47
+ },
48
+ ]}
49
+ // Make sure this view is not removed on the new architecture, as it causes focus loss during navigation on Android.
50
+ // This can happen when the view flattening results in different trees - due to `overflow` style changing in a parent.
51
+ collapsable={false}
52
+ >
53
+ {children}
54
+ </View>
55
+ );
56
+ }
@@ -57,7 +57,7 @@ type Props = {
57
57
  }) => void;
58
58
  isParentHeaderShown: boolean;
59
59
  isNextScreenTransparent: boolean;
60
- detachCurrentScreen: boolean;
60
+ children: React.ReactNode;
61
61
  };
62
62
 
63
63
  const EPSILON = 0.1;
@@ -78,7 +78,6 @@ function CardContainerInner({
78
78
  onHeaderHeightChange,
79
79
  isParentHeaderShown,
80
80
  isNextScreenTransparent,
81
- detachCurrentScreen,
82
81
  layout,
83
82
  onCloseRoute,
84
83
  onOpenRoute,
@@ -94,23 +93,19 @@ function CardContainerInner({
94
93
  safeAreaInsetRight,
95
94
  safeAreaInsetTop,
96
95
  scene,
96
+ children,
97
97
  }: Props) {
98
98
  const wrapperRef = React.useRef<CardA11yWrapperRef>(null);
99
99
 
100
100
  const { direction } = useLocale();
101
101
 
102
- const parentHeaderHeight = React.useContext(HeaderHeightContext);
102
+ const parentHeaderHeight = React.use(HeaderHeightContext);
103
+
104
+ const { options } = scene.descriptor;
105
+ const enabled = focused && options.keyboardHandlingEnabled !== false;
103
106
 
104
107
  const { onPageChangeStart, onPageChangeCancel, onPageChangeConfirm } =
105
- useKeyboardManager(
106
- React.useCallback(() => {
107
- const { options, navigation } = scene.descriptor;
108
-
109
- return (
110
- navigation.isFocused() && options.keyboardHandlingEnabled !== false
111
- );
112
- }, [scene.descriptor])
113
- );
108
+ useKeyboardManager({ enabled, focused });
114
109
 
115
110
  const handleOpen = () => {
116
111
  const { route } = scene.descriptor;
@@ -157,13 +152,7 @@ function CardContainerInner({
157
152
 
158
153
  const { route } = scene.descriptor;
159
154
 
160
- if (!gesture) {
161
- onPageChangeConfirm?.(true);
162
- } else if (active && closing) {
163
- onPageChangeConfirm?.(false);
164
- } else {
165
- onPageChangeCancel?.();
166
- }
155
+ onPageChangeConfirm?.({ gesture, active, closing });
167
156
 
168
157
  onTransitionStart?.({ route }, closing);
169
158
  };
@@ -242,7 +231,6 @@ function CardContainerInner({
242
231
  active={active}
243
232
  animated={animated}
244
233
  isNextScreenTransparent={isNextScreenTransparent}
245
- detachCurrentScreen={detachCurrentScreen}
246
234
  >
247
235
  <Card
248
236
  animated={animated}
@@ -295,6 +283,7 @@ function CardContainerInner({
295
283
  scenes: [previousScene, scene],
296
284
  getPreviousScene,
297
285
  getFocusedRoute,
286
+ contentHeight: headerHeight,
298
287
  onContentHeightChange: onHeaderHeightChange,
299
288
  style: styles.header,
300
289
  })
@@ -311,7 +300,7 @@ function CardContainerInner({
311
300
  : (parentHeaderHeight ?? 0)
312
301
  }
313
302
  >
314
- {scene.descriptor.render()}
303
+ {children}
315
304
  </HeaderHeightContext.Provider>
316
305
  </HeaderShownContext.Provider>
317
306
  </HeaderBackContext.Provider>