@react-navigation/stack 8.0.0-alpha.12 → 8.0.0-alpha.14
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.
- package/lib/module/views/Stack/CardA11yWrapper.js +1 -2
- package/lib/module/views/Stack/CardA11yWrapper.js.map +1 -1
- package/lib/module/views/Stack/CardContainer.js +3 -4
- package/lib/module/views/Stack/CardContainer.js.map +1 -1
- package/lib/module/views/Stack/CardStack.js +56 -117
- package/lib/module/views/Stack/CardStack.js.map +1 -1
- package/lib/module/views/Stack/StackView.js +13 -14
- package/lib/module/views/Stack/StackView.js.map +1 -1
- package/lib/typescript/src/types.d.ts +20 -42
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/gestureActivationCriteria.d.ts +1 -1
- package/lib/typescript/src/utils/gestureActivationCriteria.d.ts.map +1 -1
- package/lib/typescript/src/views/Header/HeaderSegment.d.ts +2 -2
- package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/Card.d.ts +3 -3
- package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts +0 -1
- package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardContainer.d.ts +2 -2
- package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardStack.d.ts +1 -1
- package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/StackView.d.ts +5 -15
- package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/types.tsx +46 -61
- package/src/utils/gestureActivationCriteria.tsx +1 -1
- package/src/views/Header/HeaderSegment.tsx +2 -2
- package/src/views/Stack/Card.tsx +3 -3
- package/src/views/Stack/CardA11yWrapper.tsx +2 -14
- package/src/views/Stack/CardContainer.tsx +3 -4
- package/src/views/Stack/CardStack.tsx +82 -153
- 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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
416
|
+
* What should happen when screens become inactive.
|
|
417
|
+
* - `pause`: Effects are cleaned up.
|
|
418
|
+
* - `none`: Screen renders normally
|
|
427
419
|
*
|
|
428
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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
|
};
|
package/src/views/Stack/Card.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
-
{
|
|
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 {
|
|
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,
|
|
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
|
-
<
|
|
716
|
-
|
|
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
|
|
766
|
-
|
|
767
|
-
|
|
674
|
+
const isRemoving =
|
|
675
|
+
replacingRouteKeys.includes(route.key) ||
|
|
676
|
+
closingRouteKeys.includes(route.key);
|
|
768
677
|
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
|
|
678
|
+
const isFocusing =
|
|
679
|
+
openingRouteKeys.includes(route.key) ||
|
|
680
|
+
[...closingRouteKeys, ...replacingRouteKeys].includes(
|
|
681
|
+
self[index + 1]?.key
|
|
682
|
+
);
|
|
772
683
|
|
|
773
684
|
return (
|
|
774
|
-
<
|
|
685
|
+
<CardContainer
|
|
775
686
|
key={route.key}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
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
|
-
<
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
-
</
|
|
750
|
+
</View>
|
|
822
751
|
</View>
|
|
823
752
|
);
|
|
824
753
|
}
|