@react-navigation/stack 8.0.0-alpha.12 → 8.0.0-alpha.13

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 (33) hide show
  1. package/lib/module/views/Stack/CardA11yWrapper.js +1 -2
  2. package/lib/module/views/Stack/CardA11yWrapper.js.map +1 -1
  3. package/lib/module/views/Stack/CardContainer.js +3 -4
  4. package/lib/module/views/Stack/CardContainer.js.map +1 -1
  5. package/lib/module/views/Stack/CardStack.js +56 -117
  6. package/lib/module/views/Stack/CardStack.js.map +1 -1
  7. package/lib/module/views/Stack/StackView.js +13 -14
  8. package/lib/module/views/Stack/StackView.js.map +1 -1
  9. package/lib/typescript/src/types.d.ts +20 -42
  10. package/lib/typescript/src/types.d.ts.map +1 -1
  11. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts +1 -1
  12. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts.map +1 -1
  13. package/lib/typescript/src/views/Header/HeaderSegment.d.ts +2 -2
  14. package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
  15. package/lib/typescript/src/views/Stack/Card.d.ts +3 -3
  16. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  17. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts +0 -1
  18. package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts.map +1 -1
  19. package/lib/typescript/src/views/Stack/CardContainer.d.ts +2 -2
  20. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  21. package/lib/typescript/src/views/Stack/CardStack.d.ts +1 -1
  22. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  23. package/lib/typescript/src/views/Stack/StackView.d.ts +5 -15
  24. package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
  25. package/package.json +13 -13
  26. package/src/types.tsx +46 -61
  27. package/src/utils/gestureActivationCriteria.tsx +1 -1
  28. package/src/views/Header/HeaderSegment.tsx +2 -2
  29. package/src/views/Stack/Card.tsx +3 -3
  30. package/src/views/Stack/CardA11yWrapper.tsx +2 -14
  31. package/src/views/Stack/CardContainer.tsx +3 -4
  32. package/src/views/Stack/CardStack.tsx +82 -153
  33. package/src/views/Stack/StackView.tsx +24 -17
package/src/types.tsx CHANGED
@@ -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
  *
@@ -240,16 +240,18 @@ export type StackHeaderProps = {
240
240
  /**
241
241
  * Options for the back button.
242
242
  */
243
- back?: {
244
- /**
245
- * Title of the previous screen.
246
- */
247
- title: string | undefined;
248
- /**
249
- * The `href` to use for the anchor tag on web
250
- */
251
- href: string | undefined;
252
- };
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;
253
255
  /**
254
256
  * Animated nodes representing the progress of the animation.
255
257
  */
@@ -276,26 +278,26 @@ export type StackHeaderRightProps = {
276
278
  /**
277
279
  * Tint color for the header button.
278
280
  */
279
- tintColor?: ColorValue;
281
+ tintColor?: ColorValue | undefined;
280
282
  /**
281
283
  * Color for material ripple (Android >= 5.0 only).
282
284
  */
283
- pressColor?: ColorValue;
285
+ pressColor?: ColorValue | undefined;
284
286
  /**
285
287
  * Opacity when the button is pressed, used when ripple is not supported.
286
288
  */
287
- pressOpacity?: number;
289
+ pressOpacity?: number | undefined;
288
290
  /**
289
291
  * Whether it's possible to navigate back in stack.
290
292
  */
291
- canGoBack?: boolean;
293
+ canGoBack?: boolean | undefined;
292
294
  };
293
295
 
294
296
  export type StackHeaderLeftProps = HeaderBackButtonProps & {
295
297
  /**
296
298
  * Whether it's possible to navigate back in stack.
297
299
  */
298
- canGoBack?: boolean;
300
+ canGoBack?: boolean | undefined;
299
301
  };
300
302
 
301
303
  export type StackDescriptor = Descriptor<
@@ -348,9 +350,6 @@ export type StackNavigationOptions = StackHeaderOptions &
348
350
  * You can also specify `{ backgroundColor: 'transparent' }` to make the previous screen visible underneath.
349
351
  * This is useful to implement things like modal dialogs.
350
352
  *
351
- * You should also specify `detachPreviousScreen: false` in options when using a transparent background
352
- * so that the previous screen isn't detached and stays below the current screen.
353
- *
354
353
  * You might also need to change the animation of the screen using `cardStyleInterpolator`
355
354
  * so that the previous screen isn't transformed or invisible.
356
355
  */
@@ -366,7 +365,6 @@ export type StackNavigationOptions = StackHeaderOptions &
366
365
  * - `transparentModal`: Similar to `modal`. This changes following things:
367
366
  * - Sets `headerMode` to `screen` for the screen unless specified otherwise.
368
367
  * - Sets background color of the screen to transparent, so previous screen is visible
369
- * - Adjusts the `detachPreviousScreen` option so that the previous screen stays rendered.
370
368
  * - Prevents the previous screen from animating from its last position.
371
369
  * - Changes the screen animation to a vertical slide animation.
372
370
  *
@@ -408,43 +406,26 @@ export type StackNavigationOptions = StackHeaderOptions &
408
406
  * Not supported on Web.
409
407
  */
410
408
  gestureVelocityImpact?: number;
411
- /**
412
- * Whether to detach the previous screen from the view hierarchy to save memory.
413
- * Set it to `false` if you need the previous screen to be seen through the active screen.
414
- * Only applicable if `detachInactiveScreens` isn't set to `false`.
415
- * Defaults to `false` for the last screen for modals, otherwise `true`.
416
- */
417
- detachPreviousScreen?: boolean;
418
409
  /**
419
410
  * If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen from this screen.
420
411
  * Defaults to `true`.
421
412
  */
422
413
  keyboardHandlingEnabled?: boolean;
414
+
423
415
  /**
424
- * Whether inactive screens should be suspended from re-rendering. Defaults to `false`.
425
- * Defaults to `true` when `enableFreeze()` is run at the top of the application.
426
- * Requires `react-native-screens` version >=3.16.0.
416
+ * What should happen when screens become inactive.
417
+ * - `pause`: Effects are cleaned up.
418
+ * - `none`: Screen renders normally
427
419
  *
428
- * Only supported on iOS and Android.
429
- */
430
- freezeOnBlur?: boolean;
431
- /**
432
- * Whether the home indicator should prefer to stay hidden on this screen. Defaults to `false`.
420
+ * Defaults to `pause`.
433
421
  *
434
- * @platform ios
422
+ * Preloaded screens won't be paused until after navigated to.
423
+ * This makes sure that effects are run to initialize the screen.
435
424
  */
436
- autoHideHomeIndicator?: boolean;
425
+ inactiveBehavior?: 'pause' | 'none';
437
426
  };
438
427
 
439
- export type StackNavigationConfig = {
440
- /**
441
- * Whether inactive screens should be detached from the view hierarchy to save memory.
442
- * This will have no effect if you disable `react-native-screens`.
443
- *
444
- * Defaults to `true`.
445
- */
446
- detachInactiveScreens?: boolean;
447
- };
428
+ export type StackNavigationConfig = {};
448
429
 
449
430
  export type TransitionSpec =
450
431
  | {
@@ -476,12 +457,14 @@ export type StackCardInterpolationProps = {
476
457
  * Values for the screen after this one in the stack.
477
458
  * This can be `undefined` in case the screen animating is the last one.
478
459
  */
479
- next?: {
480
- /**
481
- * Animated node representing the progress value of the next screen.
482
- */
483
- progress: Animated.AnimatedInterpolation<number>;
484
- };
460
+ next?:
461
+ | {
462
+ /**
463
+ * Animated node representing the progress value of the next screen.
464
+ */
465
+ progress: Animated.AnimatedInterpolation<number>;
466
+ }
467
+ | undefined;
485
468
  /**
486
469
  * The index of the card with this interpolation in the stack.
487
470
  */
@@ -555,12 +538,14 @@ export type StackHeaderInterpolationProps = {
555
538
  * Values for the screen after this one in the stack.
556
539
  * This can be `undefined` in case the screen animating is the last one.
557
540
  */
558
- next?: {
559
- /**
560
- * Animated node representing the progress value of the next screen.
561
- */
562
- progress: Animated.AnimatedInterpolation<number>;
563
- };
541
+ next?:
542
+ | {
543
+ /**
544
+ * Animated node representing the progress value of the next screen.
545
+ */
546
+ progress: Animated.AnimatedInterpolation<number>;
547
+ }
548
+ | undefined;
564
549
  /**
565
550
  * Writing direction of the layout.
566
551
  */
@@ -17,7 +17,7 @@ export const gestureActivationCriteria = ({
17
17
  }: {
18
18
  direction: LocaleDirection;
19
19
  gestureDirection: GestureDirection;
20
- gestureResponseDistance?: number;
20
+ gestureResponseDistance?: number | undefined;
21
21
  layout: Layout;
22
22
  }) => {
23
23
  const enableTrackpadTwoFingerGesture = true;
@@ -20,8 +20,8 @@ type Props = Omit<StackHeaderOptions, 'headerStatusBarHeight'> & {
20
20
  headerStatusBarHeight: number;
21
21
  title: string;
22
22
  modal: boolean;
23
- onGoBack?: () => void;
24
- backHref?: string;
23
+ onGoBack?: (() => void) | undefined;
24
+ backHref?: string | undefined;
25
25
  progress: SceneProgress;
26
26
  styleInterpolator: StackHeaderStyleInterpolator;
27
27
  };
@@ -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;
@@ -6,7 +6,6 @@ type Props = {
6
6
  active: boolean;
7
7
  animated: boolean;
8
8
  isNextScreenTransparent: boolean;
9
- detachCurrentScreen: boolean;
10
9
  children: React.ReactNode;
11
10
  };
12
11
 
@@ -14,14 +13,7 @@ export type CardA11yWrapperRef = { setInert: (value: boolean) => void };
14
13
 
15
14
  export const CardA11yWrapper = React.forwardRef(
16
15
  (
17
- {
18
- focused,
19
- active,
20
- animated,
21
- isNextScreenTransparent,
22
- detachCurrentScreen,
23
- children,
24
- }: Props,
16
+ { focused, active, animated, isNextScreenTransparent, children }: Props,
25
17
  ref: React.Ref<CardA11yWrapperRef>
26
18
  ) => {
27
19
  // Manage this in separate component to avoid re-rendering card during gestures
@@ -30,11 +22,7 @@ export const CardA11yWrapper = React.forwardRef(
30
22
 
31
23
  React.useImperativeHandle(ref, () => ({ setInert }), []);
32
24
 
33
- const isHidden =
34
- !animated &&
35
- isNextScreenTransparent === false &&
36
- detachCurrentScreen !== false &&
37
- !focused;
25
+ const isHidden = !animated && isNextScreenTransparent === false && !focused;
38
26
 
39
27
  return (
40
28
  <View
@@ -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,6 +93,7 @@ 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
 
@@ -242,7 +242,6 @@ function CardContainerInner({
242
242
  active={active}
243
243
  animated={animated}
244
244
  isNextScreenTransparent={isNextScreenTransparent}
245
- detachCurrentScreen={detachCurrentScreen}
246
245
  >
247
246
  <Card
248
247
  animated={animated}
@@ -311,7 +310,7 @@ function CardContainerInner({
311
310
  : (parentHeaderHeight ?? 0)
312
311
  }
313
312
  >
314
- {scene.descriptor.render()}
313
+ {children}
315
314
  </HeaderHeightContext.Provider>
316
315
  </HeaderShownContext.Provider>
317
316
  </HeaderBackContext.Provider>
@@ -1,5 +1,8 @@
1
1
  import { getDefaultHeaderHeight } from '@react-navigation/elements';
2
- import { SafeAreaProviderCompat } from '@react-navigation/elements/internal';
2
+ import {
3
+ ActivityView,
4
+ SafeAreaProviderCompat,
5
+ } from '@react-navigation/elements/internal';
3
6
  import type {
4
7
  LocaleDirection,
5
8
  ParamListBase,
@@ -15,7 +18,6 @@ import {
15
18
  View,
16
19
  } from 'react-native';
17
20
  import type { EdgeInsets } from 'react-native-safe-area-context';
18
- import { Screen, ScreenContainer } from 'react-native-screens';
19
21
 
20
22
  import {
21
23
  forModalPresentationIOS,
@@ -44,7 +46,6 @@ import type {
44
46
  StackNavigationOptions,
45
47
  TransitionPreset,
46
48
  } from '../../types';
47
- import { findLastIndex } from '../../utils/findLastIndex';
48
49
  import { getDistanceForDirection } from '../../utils/getDistanceForDirection';
49
50
  import { getModalRouteKeys } from '../../utils/getModalRoutesKeys';
50
51
  import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
@@ -62,6 +63,7 @@ type Props = {
62
63
  routes: Route<string>[];
63
64
  openingRouteKeys: string[];
64
65
  closingRouteKeys: string[];
66
+ replacingRouteKeys: string[];
65
67
  onOpenRoute: (props: { route: Route<string> }) => void;
66
68
  onCloseRoute: (props: { route: Route<string> }) => void;
67
69
  getPreviousRoute: (props: {
@@ -87,7 +89,6 @@ type State = {
87
89
  scenes: Scene[];
88
90
  gestures: GestureValues;
89
91
  layout: Layout;
90
- activeStates: (0 | 1 | Animated.AnimatedInterpolation<0 | 1>)[];
91
92
  headerHeights: Record<string, number>;
92
93
  };
93
94
 
@@ -107,12 +108,6 @@ const NAMED_TRANSITIONS_PRESETS = {
107
108
  }),
108
109
  } as const satisfies Record<StackAnimationName, TransitionPreset>;
109
110
 
110
- const EPSILON = 1e-5;
111
-
112
- const STATE_INACTIVE = 0;
113
- const STATE_TRANSITIONING_OR_BELOW_TOP = 1;
114
- const STATE_ON_TOP = 2;
115
-
116
111
  const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
117
112
 
118
113
  const getInterpolationIndex = (scenes: Scene[], index: number) => {
@@ -465,88 +460,11 @@ export class CardStack extends React.Component<Props, State> {
465
460
  }
466
461
  );
467
462
 
468
- let activeStates = state.activeStates;
469
-
470
- if (props.routes.length !== state.routes.length) {
471
- let activeScreensLimit = 1;
472
-
473
- for (let i = props.routes.length - 1; i >= 0; i--) {
474
- const { options } = scenes[i].descriptor;
475
-
476
- const {
477
- // By default, we don't want to detach the previous screen of the active one for modals
478
- detachPreviousScreen = options.presentation === 'transparentModal'
479
- ? false
480
- : getIsModalPresentation(options.cardStyleInterpolator)
481
- ? i !==
482
- findLastIndex(scenes, (scene) => {
483
- const { cardStyleInterpolator } = scene.descriptor.options;
484
-
485
- return (
486
- cardStyleInterpolator === forModalPresentationIOS ||
487
- cardStyleInterpolator?.name === 'forModalPresentationIOS'
488
- );
489
- })
490
- : true,
491
- } = options;
492
-
493
- if (detachPreviousScreen === false) {
494
- activeScreensLimit++;
495
- } else {
496
- // Check at least last 2 screens before stopping
497
- // This will make sure that screen isn't detached when another screen is animating on top of the transparent one
498
- // e.g. opaque -> transparent -> opaque
499
- if (i <= props.routes.length - 2) {
500
- break;
501
- }
502
- }
503
- }
504
-
505
- activeStates = props.routes.map((_, index, self) => {
506
- // The activity state represents state of the screen:
507
- // 0 - inactive, the screen is detached
508
- // 1 - transitioning or below the top screen, the screen is mounted but interaction is disabled
509
- // 2 - on top of the stack, the screen is mounted and interaction is enabled
510
- let activityState:
511
- | Animated.AnimatedInterpolation<0 | 1 | 2>
512
- | 0
513
- | 1
514
- | 2;
515
-
516
- const lastActiveState = state.activeStates[index];
517
- const activeAfterTransition = index >= self.length - activeScreensLimit;
518
-
519
- if (lastActiveState === STATE_INACTIVE && !activeAfterTransition) {
520
- // screen was inactive before and it will still be inactive after the transition
521
- activityState = STATE_INACTIVE;
522
- } else {
523
- const sceneForActivity = scenes[self.length - 1];
524
- const outputValue =
525
- index === self.length - 1
526
- ? STATE_ON_TOP // the screen is on top after the transition
527
- : activeAfterTransition
528
- ? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
529
- : STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
530
-
531
- activityState = sceneForActivity
532
- ? sceneForActivity.progress.current.interpolate({
533
- inputRange: [0, 1 - EPSILON, 1],
534
- outputRange: [1, 1, outputValue],
535
- extrapolate: 'clamp',
536
- })
537
- : STATE_TRANSITIONING_OR_BELOW_TOP;
538
- }
539
-
540
- return activityState;
541
- });
542
- }
543
-
544
463
  return {
545
464
  routes: props.routes,
546
465
  scenes,
547
466
  gestures,
548
467
  descriptors: props.descriptors,
549
- activeStates,
550
468
  headerHeights: getHeaderHeights(
551
469
  scenes,
552
470
  props.insets,
@@ -567,7 +485,6 @@ export class CardStack extends React.Component<Props, State> {
567
485
  gestures: {},
568
486
  layout: SafeAreaProviderCompat.initialMetrics.frame,
569
487
  descriptors: this.props.descriptors,
570
- activeStates: [],
571
488
  // Used when card's header is null and mode is float to make transition
572
489
  // between screens with headers and those without headers smooth.
573
490
  // This is not a great heuristic here. We don't know synchronously
@@ -654,23 +571,20 @@ export class CardStack extends React.Component<Props, State> {
654
571
  routes,
655
572
  openingRouteKeys,
656
573
  closingRouteKeys,
574
+ replacingRouteKeys,
657
575
  onOpenRoute,
658
576
  onCloseRoute,
577
+ onGestureStart,
578
+ onGestureEnd,
579
+ onGestureCancel,
659
580
  renderHeader,
660
581
  isParentHeaderShown,
661
582
  isParentModal,
662
583
  onTransitionStart,
663
584
  onTransitionEnd,
664
- onGestureStart,
665
- onGestureEnd,
666
- onGestureCancel,
667
- detachInactiveScreens = Platform.OS === 'web' ||
668
- Platform.OS === 'android' ||
669
- Platform.OS === 'ios',
670
585
  } = this.props;
671
586
 
672
- const { scenes, layout, gestures, activeStates, headerHeights } =
673
- this.state;
587
+ const { scenes, layout, gestures, headerHeights } = this.state;
674
588
 
675
589
  const focusedRoute = state.routes[state.index];
676
590
 
@@ -712,12 +626,8 @@ export class CardStack extends React.Component<Props, State> {
712
626
  ],
713
627
  ],
714
628
  })}
715
- <ScreenContainer
716
- enabled={detachInactiveScreens}
717
- style={styles.container}
718
- onLayout={this.handleLayout}
719
- >
720
- {[...routes, ...state.preloadedRoutes].map((route, index) => {
629
+ <View style={styles.container} onLayout={this.handleLayout}>
630
+ {[...routes, ...state.preloadedRoutes].map((route, index, self) => {
721
631
  const focused = focusedRoute.key === route.key;
722
632
  const gesture = gestures[route.key];
723
633
  const scene = scenes[index];
@@ -736,10 +646,9 @@ export class CardStack extends React.Component<Props, State> {
736
646
  }
737
647
 
738
648
  const {
649
+ inactiveBehavior = 'pause',
739
650
  headerShown = true,
740
651
  headerTransparent,
741
- freezeOnBlur,
742
- autoHideHomeIndicator,
743
652
  } = scene.descriptor.options;
744
653
 
745
654
  const safeAreaInsetTop = insets.top;
@@ -762,63 +671,83 @@ export class CardStack extends React.Component<Props, State> {
762
671
  scenes[index + 1]?.descriptor.options.presentation ===
763
672
  'transparentModal';
764
673
 
765
- const detachCurrentScreen =
766
- scenes[index + 1]?.descriptor.options.detachPreviousScreen !==
767
- false;
674
+ const isRemoving =
675
+ replacingRouteKeys.includes(route.key) ||
676
+ closingRouteKeys.includes(route.key);
768
677
 
769
- const activityState = isPreloaded
770
- ? STATE_INACTIVE
771
- : activeStates[index];
678
+ const isFocusing =
679
+ openingRouteKeys.includes(route.key) ||
680
+ [...closingRouteKeys, ...replacingRouteKeys].includes(
681
+ self[index + 1]?.key
682
+ );
772
683
 
773
684
  return (
774
- <Screen
685
+ <CardContainer
775
686
  key={route.key}
776
- style={[StyleSheet.absoluteFill, { pointerEvents: 'box-none' }]}
777
- enabled={detachInactiveScreens}
778
- activityState={activityState}
779
- freezeOnBlur={freezeOnBlur}
780
- shouldFreeze={activityState === STATE_INACTIVE && !isPreloaded}
781
- homeIndicatorHidden={autoHideHomeIndicator}
687
+ index={index}
688
+ interpolationIndex={interpolationIndex}
689
+ modal={isModal}
690
+ active={index === routes.length - 1}
691
+ focused={focused}
692
+ opening={openingRouteKeys.includes(route.key)}
693
+ closing={closingRouteKeys.includes(route.key)}
694
+ layout={layout}
695
+ gesture={gesture}
696
+ scene={scene}
697
+ safeAreaInsetTop={safeAreaInsetTop}
698
+ safeAreaInsetRight={safeAreaInsetRight}
699
+ safeAreaInsetBottom={safeAreaInsetBottom}
700
+ safeAreaInsetLeft={safeAreaInsetLeft}
701
+ onGestureStart={onGestureStart}
702
+ onGestureCancel={onGestureCancel}
703
+ onGestureEnd={onGestureEnd}
704
+ headerHeight={headerHeight}
705
+ isParentHeaderShown={isParentHeaderShown}
706
+ onHeaderHeightChange={this.handleHeaderLayout}
707
+ getPreviousScene={this.getPreviousScene}
708
+ getFocusedRoute={this.getFocusedRoute}
709
+ hasAbsoluteFloatHeader={
710
+ isFloatHeaderAbsolute && !headerTransparent
711
+ }
712
+ renderHeader={renderHeader}
713
+ onOpenRoute={onOpenRoute}
714
+ onCloseRoute={onCloseRoute}
715
+ onTransitionStart={onTransitionStart}
716
+ onTransitionEnd={onTransitionEnd}
717
+ isNextScreenTransparent={isNextScreenTransparent}
718
+ preloaded={isPreloaded}
782
719
  >
783
- <CardContainer
784
- index={index}
785
- interpolationIndex={interpolationIndex}
786
- modal={isModal}
787
- active={index === routes.length - 1}
788
- focused={focused}
789
- opening={openingRouteKeys.includes(route.key)}
790
- closing={closingRouteKeys.includes(route.key)}
791
- layout={layout}
792
- gesture={gesture}
793
- scene={scene}
794
- safeAreaInsetTop={safeAreaInsetTop}
795
- safeAreaInsetRight={safeAreaInsetRight}
796
- safeAreaInsetBottom={safeAreaInsetBottom}
797
- safeAreaInsetLeft={safeAreaInsetLeft}
798
- onGestureStart={onGestureStart}
799
- onGestureCancel={onGestureCancel}
800
- onGestureEnd={onGestureEnd}
801
- headerHeight={headerHeight}
802
- isParentHeaderShown={isParentHeaderShown}
803
- onHeaderHeightChange={this.handleHeaderLayout}
804
- getPreviousScene={this.getPreviousScene}
805
- getFocusedRoute={this.getFocusedRoute}
806
- hasAbsoluteFloatHeader={
807
- isFloatHeaderAbsolute && !headerTransparent
720
+ <ActivityView
721
+ mode={
722
+ // Render focused and animating screens normally
723
+ focused || isFocusing
724
+ ? 'normal'
725
+ : // Unpause preloaded screens so updates are visible
726
+ // This lets preloaded screens initialize
727
+ // And avoids things like pressable animation from being frozen
728
+ inactiveBehavior === 'none' ||
729
+ isPreloaded ||
730
+ isRemoving ||
731
+ isNextScreenTransparent
732
+ ? 'inert'
733
+ : 'paused'
734
+ }
735
+ visible={
736
+ // keep animating, preloaded & last two screens visible for smoother transitions
737
+ isFocusing ||
738
+ isRemoving ||
739
+ isPreloaded ||
740
+ isNextScreenTransparent ||
741
+ index >= routes.length - 2
808
742
  }
809
- renderHeader={renderHeader}
810
- onOpenRoute={onOpenRoute}
811
- onCloseRoute={onCloseRoute}
812
- onTransitionStart={onTransitionStart}
813
- onTransitionEnd={onTransitionEnd}
814
- isNextScreenTransparent={isNextScreenTransparent}
815
- detachCurrentScreen={detachCurrentScreen}
816
- preloaded={isPreloaded}
817
- />
818
- </Screen>
743
+ style={StyleSheet.absoluteFill}
744
+ >
745
+ {scene.descriptor.render()}
746
+ </ActivityView>
747
+ </CardContainer>
819
748
  );
820
749
  })}
821
- </ScreenContainer>
750
+ </View>
822
751
  </View>
823
752
  );
824
753
  }