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

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 +51 -17
  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/CardContainer.js +69 -98
  19. package/lib/module/views/Stack/CardContainer.js.map +1 -1
  20. package/lib/module/views/Stack/CardStack.js +134 -116
  21. package/lib/module/views/Stack/CardStack.js.map +1 -1
  22. package/lib/module/views/Stack/StackView.js +82 -49
  23. package/lib/module/views/Stack/StackView.js.map +1 -1
  24. package/lib/typescript/src/index.d.ts +1 -1
  25. package/lib/typescript/src/index.d.ts.map +1 -1
  26. package/lib/typescript/src/navigators/createStackNavigator.d.ts +8 -14
  27. package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
  28. package/lib/typescript/src/types.d.ts +46 -53
  29. package/lib/typescript/src/types.d.ts.map +1 -1
  30. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts +1 -1
  31. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts.map +1 -1
  32. package/lib/typescript/src/utils/useKeyboardManager.d.ts +9 -2
  33. package/lib/typescript/src/utils/useKeyboardManager.d.ts.map +1 -1
  34. package/lib/typescript/src/views/Header/Header.d.ts +1 -1
  35. package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
  36. package/lib/typescript/src/views/Header/HeaderContainer.d.ts +7 -2
  37. package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
  38. package/lib/typescript/src/views/Header/HeaderSegment.d.ts +2 -2
  39. package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
  40. package/lib/typescript/src/views/Stack/Card.d.ts +3 -3
  41. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  42. package/lib/typescript/src/views/Stack/CardContainer.d.ts +4 -6
  43. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  44. package/lib/typescript/src/views/Stack/CardStack.d.ts +4 -3
  45. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  46. package/lib/typescript/src/views/Stack/StackView.d.ts +6 -9
  47. package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
  48. package/package.json +20 -22
  49. package/src/index.tsx +1 -0
  50. package/src/navigators/createStackNavigator.tsx +9 -40
  51. package/src/types.tsx +73 -73
  52. package/src/utils/gestureActivationCriteria.tsx +1 -1
  53. package/src/utils/useCardAnimation.tsx +1 -1
  54. package/src/utils/useGestureHandlerRef.tsx +1 -1
  55. package/src/utils/useKeyboardManager.tsx +67 -33
  56. package/src/views/Header/Header.tsx +2 -2
  57. package/src/views/Header/HeaderContainer.tsx +66 -20
  58. package/src/views/Header/HeaderSegment.tsx +4 -4
  59. package/src/views/Stack/Card.tsx +32 -23
  60. package/src/views/Stack/CardContainer.tsx +81 -127
  61. package/src/views/Stack/CardStack.tsx +334 -318
  62. package/src/views/Stack/StackView.tsx +138 -66
  63. package/lib/module/views/Stack/CardA11yWrapper.js +0 -43
  64. package/lib/module/views/Stack/CardA11yWrapper.js.map +0 -1
  65. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts +0 -15
  66. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts.map +0 -1
  67. package/src/views/Stack/CardA11yWrapper.tsx +0 -67
@@ -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(
@@ -16,9 +16,11 @@ import { Animated, StyleSheet, View } from 'react-native';
16
16
  import type { Layout, Scene } from '../../types';
17
17
  import { ModalPresentationContext } from '../../utils/ModalPresentationContext';
18
18
  import { useKeyboardManager } from '../../utils/useKeyboardManager';
19
- import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
19
+ import type {
20
+ HeaderHeight,
21
+ Props as HeaderContainerProps,
22
+ } from '../Header/HeaderContainer';
20
23
  import { Card } from './Card';
21
- import { CardA11yWrapper, type CardA11yWrapperRef } from './CardA11yWrapper';
22
24
 
23
25
  type Props = {
24
26
  interpolationIndex: number;
@@ -49,19 +51,15 @@ type Props = {
49
51
  onGestureStart: (props: { route: Route<string> }) => void;
50
52
  onGestureEnd: (props: { route: Route<string> }) => void;
51
53
  onGestureCancel: (props: { route: Route<string> }) => void;
52
- hasAbsoluteFloatHeader: boolean;
53
- headerHeight: number;
54
+ headerHeight: HeaderHeight | undefined;
54
55
  onHeaderHeightChange: (props: {
55
56
  route: Route<string>;
56
57
  height: number;
57
58
  }) => void;
58
59
  isParentHeaderShown: boolean;
59
- isNextScreenTransparent: boolean;
60
- detachCurrentScreen: boolean;
60
+ children: React.ReactNode;
61
61
  };
62
62
 
63
- const EPSILON = 0.1;
64
-
65
63
  function CardContainerInner({
66
64
  interpolationIndex,
67
65
  index,
@@ -73,12 +71,9 @@ function CardContainerInner({
73
71
  modal,
74
72
  getPreviousScene,
75
73
  getFocusedRoute,
76
- hasAbsoluteFloatHeader,
77
74
  headerHeight,
78
75
  onHeaderHeightChange,
79
76
  isParentHeaderShown,
80
- isNextScreenTransparent,
81
- detachCurrentScreen,
82
77
  layout,
83
78
  onCloseRoute,
84
79
  onOpenRoute,
@@ -94,23 +89,17 @@ function CardContainerInner({
94
89
  safeAreaInsetRight,
95
90
  safeAreaInsetTop,
96
91
  scene,
92
+ children,
97
93
  }: Props) {
98
- const wrapperRef = React.useRef<CardA11yWrapperRef>(null);
99
-
100
94
  const { direction } = useLocale();
101
95
 
102
- const parentHeaderHeight = React.useContext(HeaderHeightContext);
96
+ const parentHeaderHeight = React.use(HeaderHeightContext);
103
97
 
104
- const { onPageChangeStart, onPageChangeCancel, onPageChangeConfirm } =
105
- useKeyboardManager(
106
- React.useCallback(() => {
107
- const { options, navigation } = scene.descriptor;
98
+ const { options } = scene.descriptor;
99
+ const enabled = focused && options.keyboardHandlingEnabled !== false;
108
100
 
109
- return (
110
- navigation.isFocused() && options.keyboardHandlingEnabled !== false
111
- );
112
- }, [scene.descriptor])
113
- );
101
+ const { onPageChangeStart, onPageChangeCancel, onPageChangeConfirm } =
102
+ useKeyboardManager({ enabled, focused });
114
103
 
115
104
  const handleOpen = () => {
116
105
  const { route } = scene.descriptor;
@@ -153,17 +142,9 @@ function CardContainerInner({
153
142
  closing: boolean;
154
143
  gesture: boolean;
155
144
  }) => {
156
- wrapperRef.current?.setInert(closing);
157
-
158
145
  const { route } = scene.descriptor;
159
146
 
160
- if (!gesture) {
161
- onPageChangeConfirm?.(true);
162
- } else if (active && closing) {
163
- onPageChangeConfirm?.(false);
164
- } else {
165
- onPageChangeCancel?.();
166
- }
147
+ onPageChangeConfirm?.({ gesture, active, closing });
167
148
 
168
149
  onTransitionStart?.({ route }, closing);
169
150
  };
@@ -177,20 +158,6 @@ function CardContainerInner({
177
158
 
178
159
  const { colors } = useTheme();
179
160
 
180
- React.useEffect(() => {
181
- const listener = scene.progress.next?.addListener?.(
182
- ({ value }: { value: number }) => {
183
- wrapperRef.current?.setInert(value > EPSILON);
184
- }
185
- );
186
-
187
- return () => {
188
- if (listener) {
189
- scene.progress.next?.removeListener?.(listener);
190
- }
191
- };
192
- }, [scene.progress.next]);
193
-
194
161
  const {
195
162
  presentation,
196
163
  animation,
@@ -236,90 +203,77 @@ function CardContainerInner({
236
203
  const animated = animation !== 'none';
237
204
 
238
205
  return (
239
- <CardA11yWrapper
240
- ref={wrapperRef}
241
- focused={focused}
242
- active={active}
206
+ <Card
243
207
  animated={animated}
244
- isNextScreenTransparent={isNextScreenTransparent}
245
- detachCurrentScreen={detachCurrentScreen}
208
+ interpolationIndex={interpolationIndex}
209
+ gestureDirection={gestureDirection}
210
+ layout={layout}
211
+ insets={insets}
212
+ direction={direction}
213
+ gesture={gesture}
214
+ current={scene.progress.current}
215
+ next={scene.progress.next}
216
+ opening={opening}
217
+ closing={closing}
218
+ onOpen={handleOpen}
219
+ onClose={handleClose}
220
+ overlay={cardOverlay}
221
+ overlayEnabled={cardOverlayEnabled}
222
+ shadowEnabled={cardShadowEnabled}
223
+ onTransition={handleTransition}
224
+ onGestureBegin={handleGestureBegin}
225
+ onGestureCanceled={handleGestureCanceled}
226
+ onGestureEnd={handleGestureEnd}
227
+ gestureEnabled={index === 0 ? false : gestureEnabled}
228
+ gestureResponseDistance={gestureResponseDistance}
229
+ gestureVelocityImpact={gestureVelocityImpact}
230
+ transitionSpec={transitionSpec}
231
+ styleInterpolator={cardStyleInterpolator}
232
+ pageOverflowEnabled={headerMode !== 'float' && presentation !== 'modal'}
233
+ preloaded={preloaded}
234
+ contentStyle={[
235
+ {
236
+ backgroundColor:
237
+ presentation === 'transparentModal'
238
+ ? 'transparent'
239
+ : colors.background,
240
+ },
241
+ cardStyle,
242
+ ]}
246
243
  >
247
- <Card
248
- animated={animated}
249
- interpolationIndex={interpolationIndex}
250
- gestureDirection={gestureDirection}
251
- layout={layout}
252
- insets={insets}
253
- direction={direction}
254
- gesture={gesture}
255
- current={scene.progress.current}
256
- next={scene.progress.next}
257
- opening={opening}
258
- closing={closing}
259
- onOpen={handleOpen}
260
- onClose={handleClose}
261
- overlay={cardOverlay}
262
- overlayEnabled={cardOverlayEnabled}
263
- shadowEnabled={cardShadowEnabled}
264
- onTransition={handleTransition}
265
- onGestureBegin={handleGestureBegin}
266
- onGestureCanceled={handleGestureCanceled}
267
- onGestureEnd={handleGestureEnd}
268
- gestureEnabled={index === 0 ? false : gestureEnabled}
269
- gestureResponseDistance={gestureResponseDistance}
270
- gestureVelocityImpact={gestureVelocityImpact}
271
- transitionSpec={transitionSpec}
272
- styleInterpolator={cardStyleInterpolator}
273
- pageOverflowEnabled={headerMode !== 'float' && presentation !== 'modal'}
274
- preloaded={preloaded}
275
- containerStyle={
276
- hasAbsoluteFloatHeader && headerMode !== 'screen'
277
- ? { marginTop: headerHeight }
278
- : null
279
- }
280
- contentStyle={[
281
- {
282
- backgroundColor:
283
- presentation === 'transparentModal'
284
- ? 'transparent'
285
- : colors.background,
286
- },
287
- cardStyle,
288
- ]}
289
- >
290
- <View style={styles.container}>
291
- <ModalPresentationContext.Provider value={modal}>
292
- {headerMode !== 'float'
293
- ? renderHeader({
294
- mode: 'screen',
295
- scenes: [previousScene, scene],
296
- getPreviousScene,
297
- getFocusedRoute,
298
- onContentHeightChange: onHeaderHeightChange,
299
- style: styles.header,
300
- })
301
- : null}
302
- <View style={styles.scene}>
303
- <HeaderBackContext.Provider value={headerBack}>
304
- <HeaderShownContext.Provider
305
- value={isParentHeaderShown || headerShown !== false}
244
+ <View style={styles.container}>
245
+ <ModalPresentationContext.Provider value={modal}>
246
+ {headerMode !== 'float'
247
+ ? renderHeader({
248
+ mode: 'screen',
249
+ scenes: [previousScene, scene],
250
+ getPreviousScene,
251
+ getFocusedRoute,
252
+ contentHeight: headerHeight,
253
+ onContentHeightChange: onHeaderHeightChange,
254
+ style: styles.header,
255
+ })
256
+ : null}
257
+ <View style={styles.scene}>
258
+ <HeaderBackContext.Provider value={headerBack}>
259
+ <HeaderShownContext.Provider
260
+ value={isParentHeaderShown || headerShown !== false}
261
+ >
262
+ <HeaderHeightContext.Provider
263
+ value={
264
+ headerShown !== false
265
+ ? (headerHeight?.value ?? 0)
266
+ : (parentHeaderHeight ?? 0)
267
+ }
306
268
  >
307
- <HeaderHeightContext.Provider
308
- value={
309
- headerShown !== false
310
- ? headerHeight
311
- : (parentHeaderHeight ?? 0)
312
- }
313
- >
314
- {scene.descriptor.render()}
315
- </HeaderHeightContext.Provider>
316
- </HeaderShownContext.Provider>
317
- </HeaderBackContext.Provider>
318
- </View>
319
- </ModalPresentationContext.Provider>
320
- </View>
321
- </Card>
322
- </CardA11yWrapper>
269
+ {children}
270
+ </HeaderHeightContext.Provider>
271
+ </HeaderShownContext.Provider>
272
+ </HeaderBackContext.Provider>
273
+ </View>
274
+ </ModalPresentationContext.Provider>
275
+ </View>
276
+ </Card>
323
277
  );
324
278
  }
325
279