@react-navigation/stack 7.0.0-alpha.7 → 7.0.0-alpha.8
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/commonjs/navigators/createStackNavigator.js +4 -0
- package/lib/commonjs/navigators/createStackNavigator.js.map +1 -1
- package/lib/commonjs/views/Header/HeaderContainer.js +1 -1
- package/lib/commonjs/views/Header/HeaderContainer.js.map +1 -1
- package/lib/commonjs/views/Stack/Card.js +12 -9
- package/lib/commonjs/views/Stack/Card.js.map +1 -1
- package/lib/commonjs/views/Stack/CardContainer.js +4 -5
- package/lib/commonjs/views/Stack/CardContainer.js.map +1 -1
- package/lib/commonjs/views/Stack/CardStack.js +29 -20
- package/lib/commonjs/views/Stack/CardStack.js.map +1 -1
- package/lib/commonjs/views/Stack/StackView.js +20 -26
- package/lib/commonjs/views/Stack/StackView.js.map +1 -1
- package/lib/module/navigators/createStackNavigator.js +4 -0
- package/lib/module/navigators/createStackNavigator.js.map +1 -1
- package/lib/module/views/Header/HeaderContainer.js +2 -2
- package/lib/module/views/Header/HeaderContainer.js.map +1 -1
- package/lib/module/views/Stack/Card.js +12 -9
- package/lib/module/views/Stack/Card.js.map +1 -1
- package/lib/module/views/Stack/CardContainer.js +5 -6
- package/lib/module/views/Stack/CardContainer.js.map +1 -1
- package/lib/module/views/Stack/CardStack.js +29 -20
- package/lib/module/views/Stack/CardStack.js.map +1 -1
- package/lib/module/views/Stack/StackView.js +20 -26
- package/lib/module/views/Stack/StackView.js.map +1 -1
- package/lib/typescript/src/navigators/createStackNavigator.d.ts +1 -1
- package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/Card.d.ts +1 -0
- package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardContainer.d.ts +2 -4
- package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardStack.d.ts +1 -3
- package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/StackView.d.ts +5 -77
- package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/navigators/createStackNavigator.tsx +4 -1
- package/src/views/Header/HeaderContainer.tsx +2 -2
- package/src/views/Stack/Card.tsx +16 -6
- package/src/views/Stack/CardContainer.tsx +6 -5
- package/src/views/Stack/CardStack.tsx +176 -149
- package/src/views/Stack/StackView.tsx +13 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StackView.d.ts","sourceRoot":"","sources":["../../../../../src/views/Stack/StackView.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"StackView.d.ts","sourceRoot":"","sources":["../../../../../src/views/Stack/StackView.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,SAAS,EAEd,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AASrB,KAAK,KAAK,GAAG,qBAAqB,GAAG;IACnC,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,oBAAoB,CAAC,aAAa,CAAC,CAAC;IAC3C,UAAU,EAAE,sBAAsB,CAAC;IACnC,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,EAAE,CACR,KAAK,EAAE,SAAS,CAAC,aAAa,CAAC,EAC/B,WAAW,EAAE,OAAO,KACjB,eAAe,CAAC;CACtB,CAAC;AAEF,KAAK,KAAK,GAAG;IAEX,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;IAExB,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;IAEhC,mBAAmB,EAAE,kBAAkB,CAAC;IAExC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAE3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAE3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAG7B,WAAW,EAAE,kBAAkB,CAAC;CACjC,CAAC;AAWF,qBAAa,SAAU,SAAQ,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;IAC1D,MAAM,CAAC,wBAAwB,CAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EACtB,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;IAmNxB,KAAK,EAAE,KAAK,CAQV;IAEF,OAAO,CAAC,gBAAgB,CAYtB;IAEF,OAAO,CAAC,YAAY,CAElB;IAEF,OAAO,CAAC,eAAe,CAwCrB;IAEF,OAAO,CAAC,gBAAgB,CAwBtB;IAEF,OAAO,CAAC,qBAAqB,CAQxB;IAEL,OAAO,CAAC,mBAAmB,CAQtB;IAEL,OAAO,CAAC,kBAAkB,CAKxB;IAEF,OAAO,CAAC,gBAAgB,CAKtB;IAEF,OAAO,CAAC,mBAAmB,CAKzB;IAEF,MAAM;CAyDP"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-navigation/stack",
|
|
3
3
|
"description": "Stack navigator component for iOS and Android with animated transitions and gestures",
|
|
4
|
-
"version": "7.0.0-alpha.
|
|
4
|
+
"version": "7.0.0-alpha.8",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native-component",
|
|
7
7
|
"react-component",
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"clean": "del lib"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@react-navigation/elements": "^2.0.0-alpha.
|
|
43
|
+
"@react-navigation/elements": "^2.0.0-alpha.5",
|
|
44
44
|
"color": "^4.2.3"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@react-navigation/native": "^7.0.0-alpha.
|
|
47
|
+
"@react-navigation/native": "^7.0.0-alpha.7",
|
|
48
48
|
"@testing-library/react-native": "^12.3.1",
|
|
49
49
|
"@types/color": "^3.0.5",
|
|
50
50
|
"@types/react": "~18.2.33",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"typescript": "^5.2.2"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@react-navigation/native": "^7.0.0-alpha.
|
|
61
|
+
"@react-navigation/native": "^7.0.0-alpha.7",
|
|
62
62
|
"react": "*",
|
|
63
63
|
"react-native": "0.72.6",
|
|
64
64
|
"react-native-gesture-handler": "~2.12.0",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
]
|
|
80
80
|
]
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "d0e6a2cd79d2c6aff0cf54e46e31edc407c3c46b"
|
|
83
83
|
}
|
|
@@ -37,11 +37,12 @@ function StackNavigator({
|
|
|
37
37
|
layout,
|
|
38
38
|
screenListeners,
|
|
39
39
|
screenOptions,
|
|
40
|
+
screenLayout,
|
|
40
41
|
...rest
|
|
41
42
|
}: Props) {
|
|
42
43
|
const { direction } = useLocale();
|
|
43
44
|
|
|
44
|
-
const { state, descriptors, navigation, NavigationContent } =
|
|
45
|
+
const { state, describe, descriptors, navigation, NavigationContent } =
|
|
45
46
|
useNavigationBuilder<
|
|
46
47
|
StackNavigationState<ParamListBase>,
|
|
47
48
|
StackRouterOptions,
|
|
@@ -55,6 +56,7 @@ function StackNavigator({
|
|
|
55
56
|
layout,
|
|
56
57
|
screenListeners,
|
|
57
58
|
screenOptions,
|
|
59
|
+
screenLayout,
|
|
58
60
|
getStateForRouteNamesChange,
|
|
59
61
|
});
|
|
60
62
|
|
|
@@ -90,6 +92,7 @@ function StackNavigator({
|
|
|
90
92
|
{...rest}
|
|
91
93
|
direction={direction}
|
|
92
94
|
state={state}
|
|
95
|
+
describe={describe}
|
|
93
96
|
descriptors={descriptors}
|
|
94
97
|
navigation={navigation}
|
|
95
98
|
/>
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
NavigationRouteContext,
|
|
5
5
|
type ParamListBase,
|
|
6
6
|
type Route,
|
|
7
|
-
|
|
7
|
+
useLinkBuilder,
|
|
8
8
|
} from '@react-navigation/native';
|
|
9
9
|
import * as React from 'react';
|
|
10
10
|
import {
|
|
@@ -54,7 +54,7 @@ export function HeaderContainer({
|
|
|
54
54
|
}: Props) {
|
|
55
55
|
const focusedRoute = getFocusedRoute();
|
|
56
56
|
const parentHeaderBack = React.useContext(HeaderBackContext);
|
|
57
|
-
const { buildHref } =
|
|
57
|
+
const { buildHref } = useLinkBuilder();
|
|
58
58
|
|
|
59
59
|
return (
|
|
60
60
|
<Animated.View pointerEvents="box-none" style={style}>
|
package/src/views/Stack/Card.tsx
CHANGED
|
@@ -61,6 +61,7 @@ type Props = ViewProps & {
|
|
|
61
61
|
open: TransitionSpec;
|
|
62
62
|
close: TransitionSpec;
|
|
63
63
|
};
|
|
64
|
+
preloaded: boolean;
|
|
64
65
|
styleInterpolator: StackCardStyleInterpolator;
|
|
65
66
|
containerStyle?: StyleProp<ViewStyle>;
|
|
66
67
|
contentStyle?: StyleProp<ViewStyle>;
|
|
@@ -104,7 +105,11 @@ export class Card extends React.Component<Props> {
|
|
|
104
105
|
};
|
|
105
106
|
|
|
106
107
|
componentDidMount() {
|
|
107
|
-
|
|
108
|
+
if (!this.props.preloaded) {
|
|
109
|
+
this.animate({
|
|
110
|
+
closing: this.props.closing,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
108
113
|
this.isCurrentlyMounted = true;
|
|
109
114
|
}
|
|
110
115
|
|
|
@@ -133,7 +138,7 @@ export class Card extends React.Component<Props> {
|
|
|
133
138
|
this.lastToValue !== toValue
|
|
134
139
|
) {
|
|
135
140
|
// We need to trigger the animation when route was closed
|
|
136
|
-
//
|
|
141
|
+
// The route might have been closed by a `POP` action or by a gesture
|
|
137
142
|
// When route was closed due to a gesture, the animation would've happened already
|
|
138
143
|
// It's still important to trigger the animation so that `onClose` is called
|
|
139
144
|
// If `onClose` is not called, cleanup step won't be performed for gestures
|
|
@@ -142,7 +147,7 @@ export class Card extends React.Component<Props> {
|
|
|
142
147
|
}
|
|
143
148
|
|
|
144
149
|
componentWillUnmount() {
|
|
145
|
-
this.props.gesture
|
|
150
|
+
this.props.gesture?.stopAnimation();
|
|
146
151
|
this.isCurrentlyMounted = false;
|
|
147
152
|
this.handleEndInteraction();
|
|
148
153
|
}
|
|
@@ -178,7 +183,7 @@ export class Card extends React.Component<Props> {
|
|
|
178
183
|
closing: boolean;
|
|
179
184
|
velocity?: number;
|
|
180
185
|
}) => {
|
|
181
|
-
const {
|
|
186
|
+
const { transitionSpec, onOpen, onClose, onTransition, gesture } =
|
|
182
187
|
this.props;
|
|
183
188
|
|
|
184
189
|
const toValue = this.getAnimateToValue({
|
|
@@ -232,13 +237,15 @@ export class Card extends React.Component<Props> {
|
|
|
232
237
|
layout,
|
|
233
238
|
gestureDirection,
|
|
234
239
|
direction,
|
|
240
|
+
preloaded,
|
|
235
241
|
}: {
|
|
236
242
|
closing?: boolean;
|
|
237
243
|
layout: Layout;
|
|
238
244
|
gestureDirection: GestureDirection;
|
|
239
245
|
direction: LocaleDirection;
|
|
246
|
+
preloaded: boolean;
|
|
240
247
|
}) => {
|
|
241
|
-
if (!closing) {
|
|
248
|
+
if (!closing && !preloaded) {
|
|
242
249
|
return 0;
|
|
243
250
|
}
|
|
244
251
|
|
|
@@ -298,7 +305,10 @@ export class Card extends React.Component<Props> {
|
|
|
298
305
|
? nativeEvent.velocityY
|
|
299
306
|
: nativeEvent.velocityX;
|
|
300
307
|
|
|
301
|
-
this.animate({
|
|
308
|
+
this.animate({
|
|
309
|
+
closing: this.props.closing,
|
|
310
|
+
velocity,
|
|
311
|
+
});
|
|
302
312
|
|
|
303
313
|
onGestureCanceled?.();
|
|
304
314
|
break;
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from '@react-navigation/elements';
|
|
7
7
|
import {
|
|
8
8
|
type Route,
|
|
9
|
-
|
|
9
|
+
useLinkBuilder,
|
|
10
10
|
useLocale,
|
|
11
11
|
useTheme,
|
|
12
12
|
} from '@react-navigation/native';
|
|
@@ -28,6 +28,7 @@ type Props = {
|
|
|
28
28
|
modal: boolean;
|
|
29
29
|
layout: Layout;
|
|
30
30
|
gesture: Animated.Value;
|
|
31
|
+
preloaded: boolean;
|
|
31
32
|
scene: Scene;
|
|
32
33
|
safeAreaInsetTop: number;
|
|
33
34
|
safeAreaInsetRight: number;
|
|
@@ -36,7 +37,6 @@ type Props = {
|
|
|
36
37
|
getPreviousScene: (props: { route: Route<string> }) => Scene | undefined;
|
|
37
38
|
getFocusedRoute: () => Route<string>;
|
|
38
39
|
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
|
39
|
-
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
|
40
40
|
onOpenRoute: (props: { route: Route<string> }) => void;
|
|
41
41
|
onCloseRoute: (props: { route: Route<string> }) => void;
|
|
42
42
|
onTransitionStart: (
|
|
@@ -84,8 +84,8 @@ function CardContainerInner({
|
|
|
84
84
|
onGestureStart,
|
|
85
85
|
onTransitionEnd,
|
|
86
86
|
onTransitionStart,
|
|
87
|
+
preloaded,
|
|
87
88
|
renderHeader,
|
|
88
|
-
renderScene,
|
|
89
89
|
safeAreaInsetBottom,
|
|
90
90
|
safeAreaInsetLeft,
|
|
91
91
|
safeAreaInsetRight,
|
|
@@ -205,7 +205,7 @@ function CardContainerInner({
|
|
|
205
205
|
transitionSpec,
|
|
206
206
|
} = scene.descriptor.options;
|
|
207
207
|
|
|
208
|
-
const { buildHref } =
|
|
208
|
+
const { buildHref } = useLinkBuilder();
|
|
209
209
|
const previousScene = getPreviousScene({ route: scene.descriptor.route });
|
|
210
210
|
|
|
211
211
|
let backTitle: string | undefined;
|
|
@@ -252,6 +252,7 @@ function CardContainerInner({
|
|
|
252
252
|
importantForAccessibility={focused ? 'auto' : 'no-hide-descendants'}
|
|
253
253
|
pointerEvents={active ? 'box-none' : pointerEvents}
|
|
254
254
|
pageOverflowEnabled={headerMode !== 'float' && presentation !== 'modal'}
|
|
255
|
+
preloaded={preloaded}
|
|
255
256
|
containerStyle={
|
|
256
257
|
hasAbsoluteFloatHeader && headerMode !== 'screen'
|
|
257
258
|
? { marginTop: headerHeight }
|
|
@@ -294,7 +295,7 @@ function CardContainerInner({
|
|
|
294
295
|
<HeaderHeightContext.Provider
|
|
295
296
|
value={headerShown ? headerHeight : parentHeaderHeight ?? 0}
|
|
296
297
|
>
|
|
297
|
-
{
|
|
298
|
+
{scene.descriptor.render()}
|
|
298
299
|
</HeaderHeightContext.Provider>
|
|
299
300
|
</HeaderShownContext.Provider>
|
|
300
301
|
</HeaderBackContext.Provider>
|
|
@@ -52,6 +52,8 @@ type Props = {
|
|
|
52
52
|
insets: EdgeInsets;
|
|
53
53
|
state: StackNavigationState<ParamListBase>;
|
|
54
54
|
descriptors: StackDescriptorMap;
|
|
55
|
+
// eslint-disable-next-line react/no-unused-prop-types
|
|
56
|
+
preloadedDescriptors: StackDescriptorMap;
|
|
55
57
|
routes: Route<string>[];
|
|
56
58
|
// eslint-disable-next-line react/no-unused-prop-types
|
|
57
59
|
openingRouteKeys: string[];
|
|
@@ -62,7 +64,6 @@ type Props = {
|
|
|
62
64
|
route: Route<string>;
|
|
63
65
|
}) => Route<string> | undefined;
|
|
64
66
|
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
|
65
|
-
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
|
66
67
|
isParentHeaderShown: boolean;
|
|
67
68
|
isParentModal: boolean;
|
|
68
69
|
onTransitionStart: (
|
|
@@ -174,7 +175,7 @@ const getHeaderHeights = (
|
|
|
174
175
|
|
|
175
176
|
const getDistanceFromOptions = (
|
|
176
177
|
layout: Layout,
|
|
177
|
-
descriptor: StackDescriptor,
|
|
178
|
+
descriptor: StackDescriptor | undefined,
|
|
178
179
|
isRTL: boolean
|
|
179
180
|
) => {
|
|
180
181
|
const {
|
|
@@ -190,7 +191,7 @@ const getDistanceFromOptions = (
|
|
|
190
191
|
const getProgressFromGesture = (
|
|
191
192
|
gesture: Animated.Value,
|
|
192
193
|
layout: Layout,
|
|
193
|
-
descriptor: StackDescriptor,
|
|
194
|
+
descriptor: StackDescriptor | undefined,
|
|
194
195
|
isRTL: boolean
|
|
195
196
|
) => {
|
|
196
197
|
const distance = getDistanceFromOptions(
|
|
@@ -229,15 +230,20 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
229
230
|
return null;
|
|
230
231
|
}
|
|
231
232
|
|
|
232
|
-
const gestures =
|
|
233
|
-
|
|
233
|
+
const gestures = [
|
|
234
|
+
...props.routes,
|
|
235
|
+
...props.state.preloadedRoutes,
|
|
236
|
+
].reduce<GestureValues>((acc, curr) => {
|
|
237
|
+
const descriptor =
|
|
238
|
+
props.descriptors[curr.key] || props.preloadedDescriptors[curr.key];
|
|
234
239
|
const { animationEnabled } = descriptor?.options || {};
|
|
235
240
|
|
|
236
241
|
acc[curr.key] =
|
|
237
242
|
state.gestures[curr.key] ||
|
|
238
243
|
new Animated.Value(
|
|
239
|
-
props.openingRouteKeys.includes(curr.key) &&
|
|
240
|
-
|
|
244
|
+
(props.openingRouteKeys.includes(curr.key) &&
|
|
245
|
+
animationEnabled !== false) ||
|
|
246
|
+
props.state.preloadedRoutes.includes(curr)
|
|
241
247
|
? getDistanceFromOptions(
|
|
242
248
|
state.layout,
|
|
243
249
|
descriptor,
|
|
@@ -249,147 +255,156 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
249
255
|
return acc;
|
|
250
256
|
}, {});
|
|
251
257
|
|
|
252
|
-
const scenes = props.routes.map(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
optionsForTransitionConfig
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
258
|
+
const scenes = [...props.routes, ...props.state.preloadedRoutes].map(
|
|
259
|
+
(route, index, self) => {
|
|
260
|
+
// For preloaded screens, we don't care about the previous and the next screen
|
|
261
|
+
const isPreloaded = props.state.preloadedRoutes.includes(route);
|
|
262
|
+
const previousRoute = isPreloaded ? undefined : self[index - 1];
|
|
263
|
+
const nextRoute = isPreloaded ? undefined : self[index + 1];
|
|
264
|
+
|
|
265
|
+
const oldScene = state.scenes[index];
|
|
266
|
+
|
|
267
|
+
const currentGesture = gestures[route.key];
|
|
268
|
+
const previousGesture = previousRoute
|
|
269
|
+
? gestures[previousRoute.key]
|
|
270
|
+
: undefined;
|
|
271
|
+
const nextGesture = nextRoute ? gestures[nextRoute.key] : undefined;
|
|
272
|
+
|
|
273
|
+
const descriptor =
|
|
274
|
+
(isPreloaded ? props.preloadedDescriptors : props.descriptors)[
|
|
275
|
+
route.key
|
|
276
|
+
] ||
|
|
277
|
+
state.descriptors[route.key] ||
|
|
278
|
+
(oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR);
|
|
279
|
+
|
|
280
|
+
const nextDescriptor =
|
|
281
|
+
nextRoute &&
|
|
282
|
+
(props.descriptors[nextRoute?.key] ||
|
|
283
|
+
state.descriptors[nextRoute?.key]);
|
|
284
|
+
|
|
285
|
+
const previousDescriptor =
|
|
286
|
+
previousRoute &&
|
|
287
|
+
(props.descriptors[previousRoute?.key] ||
|
|
288
|
+
state.descriptors[previousRoute?.key]);
|
|
289
|
+
|
|
290
|
+
// When a screen is not the last, it should use next screen's transition config
|
|
291
|
+
// Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
|
|
292
|
+
// For example combining a slide and a modal transition would look wrong otherwise
|
|
293
|
+
// With this approach, combining different transition styles in the same navigator mostly looks right
|
|
294
|
+
// This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
|
|
295
|
+
// but the majority of the transitions look alright
|
|
296
|
+
const optionsForTransitionConfig =
|
|
297
|
+
index !== self.length - 1 &&
|
|
298
|
+
nextDescriptor &&
|
|
299
|
+
nextDescriptor.options.presentation !== 'transparentModal'
|
|
300
|
+
? nextDescriptor.options
|
|
301
|
+
: descriptor.options;
|
|
302
|
+
|
|
303
|
+
const defaultTransitionPreset =
|
|
304
|
+
optionsForTransitionConfig.presentation === 'modal'
|
|
305
|
+
? ModalTransition
|
|
306
|
+
: optionsForTransitionConfig.presentation === 'transparentModal'
|
|
307
|
+
? ModalFadeTransition
|
|
308
|
+
: DefaultTransition;
|
|
309
|
+
|
|
310
|
+
const {
|
|
311
|
+
animationEnabled = Platform.OS !== 'web' &&
|
|
312
|
+
Platform.OS !== 'windows' &&
|
|
313
|
+
Platform.OS !== 'macos',
|
|
314
|
+
gestureEnabled = Platform.OS === 'ios' && animationEnabled,
|
|
315
|
+
gestureDirection = defaultTransitionPreset.gestureDirection,
|
|
316
|
+
transitionSpec = defaultTransitionPreset.transitionSpec,
|
|
317
|
+
cardStyleInterpolator = animationEnabled === false
|
|
318
|
+
? forNoAnimationCard
|
|
319
|
+
: defaultTransitionPreset.cardStyleInterpolator,
|
|
320
|
+
headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
|
|
321
|
+
cardOverlayEnabled = (Platform.OS !== 'ios' &&
|
|
322
|
+
optionsForTransitionConfig.presentation !== 'transparentModal') ||
|
|
323
|
+
getIsModalPresentation(cardStyleInterpolator),
|
|
324
|
+
} = optionsForTransitionConfig;
|
|
325
|
+
|
|
326
|
+
const headerMode: StackHeaderMode =
|
|
327
|
+
descriptor.options.headerMode ??
|
|
328
|
+
(!(
|
|
329
|
+
optionsForTransitionConfig.presentation === 'modal' ||
|
|
330
|
+
optionsForTransitionConfig.presentation === 'transparentModal' ||
|
|
331
|
+
nextDescriptor?.options.presentation === 'modal' ||
|
|
332
|
+
nextDescriptor?.options.presentation === 'transparentModal' ||
|
|
333
|
+
getIsModalPresentation(cardStyleInterpolator)
|
|
334
|
+
) &&
|
|
335
|
+
Platform.OS === 'ios' &&
|
|
336
|
+
descriptor.options.header === undefined
|
|
337
|
+
? 'float'
|
|
338
|
+
: 'screen');
|
|
339
|
+
|
|
340
|
+
const isRTL = props.direction === 'rtl';
|
|
341
|
+
|
|
342
|
+
const scene = {
|
|
343
|
+
route,
|
|
344
|
+
descriptor: {
|
|
345
|
+
...descriptor,
|
|
346
|
+
options: {
|
|
347
|
+
...descriptor.options,
|
|
348
|
+
animationEnabled,
|
|
349
|
+
cardOverlayEnabled,
|
|
350
|
+
cardStyleInterpolator,
|
|
351
|
+
gestureDirection,
|
|
352
|
+
gestureEnabled,
|
|
353
|
+
headerStyleInterpolator,
|
|
354
|
+
transitionSpec,
|
|
355
|
+
headerMode,
|
|
356
|
+
},
|
|
342
357
|
},
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
358
|
+
progress: {
|
|
359
|
+
current: getProgressFromGesture(
|
|
360
|
+
currentGesture,
|
|
361
|
+
state.layout,
|
|
362
|
+
descriptor,
|
|
363
|
+
isRTL
|
|
364
|
+
),
|
|
365
|
+
next:
|
|
366
|
+
nextGesture &&
|
|
367
|
+
nextDescriptor?.options.presentation !== 'transparentModal'
|
|
368
|
+
? getProgressFromGesture(
|
|
369
|
+
nextGesture,
|
|
370
|
+
state.layout,
|
|
371
|
+
nextDescriptor,
|
|
372
|
+
isRTL
|
|
373
|
+
)
|
|
374
|
+
: undefined,
|
|
375
|
+
previous: previousGesture
|
|
354
376
|
? getProgressFromGesture(
|
|
355
|
-
|
|
377
|
+
previousGesture,
|
|
356
378
|
state.layout,
|
|
357
|
-
|
|
379
|
+
previousDescriptor,
|
|
358
380
|
isRTL
|
|
359
381
|
)
|
|
360
382
|
: undefined,
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
383
|
+
},
|
|
384
|
+
__memo: [
|
|
385
|
+
state.layout,
|
|
386
|
+
descriptor,
|
|
387
|
+
nextDescriptor,
|
|
388
|
+
previousDescriptor,
|
|
389
|
+
currentGesture,
|
|
390
|
+
nextGesture,
|
|
391
|
+
previousGesture,
|
|
392
|
+
],
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
if (
|
|
396
|
+
oldScene &&
|
|
397
|
+
scene.__memo.every((it, i) => {
|
|
398
|
+
// @ts-expect-error: we haven't added __memo to the annotation to prevent usage elsewhere
|
|
399
|
+
return oldScene.__memo[i] === it;
|
|
400
|
+
})
|
|
401
|
+
) {
|
|
402
|
+
return oldScene;
|
|
403
|
+
}
|
|
380
404
|
|
|
381
|
-
|
|
382
|
-
oldScene &&
|
|
383
|
-
scene.__memo.every((it, i) => {
|
|
384
|
-
// @ts-expect-error: we haven't added __memo to the annotation to prevent usage elsewhere
|
|
385
|
-
return oldScene.__memo[i] === it;
|
|
386
|
-
})
|
|
387
|
-
) {
|
|
388
|
-
return oldScene;
|
|
405
|
+
return scene;
|
|
389
406
|
}
|
|
390
|
-
|
|
391
|
-
return scene;
|
|
392
|
-
});
|
|
407
|
+
);
|
|
393
408
|
|
|
394
409
|
return {
|
|
395
410
|
routes: props.routes,
|
|
@@ -504,7 +519,6 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
504
519
|
onOpenRoute,
|
|
505
520
|
onCloseRoute,
|
|
506
521
|
renderHeader,
|
|
507
|
-
renderScene,
|
|
508
522
|
isParentHeaderShown,
|
|
509
523
|
isParentModal,
|
|
510
524
|
onTransitionStart,
|
|
@@ -599,10 +613,23 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
599
613
|
style={styles.container}
|
|
600
614
|
onLayout={this.handleLayout}
|
|
601
615
|
>
|
|
602
|
-
{routes.map((route, index
|
|
616
|
+
{[...routes, ...state.preloadedRoutes].map((route, index) => {
|
|
603
617
|
const focused = focusedRoute.key === route.key;
|
|
604
618
|
const gesture = gestures[route.key];
|
|
605
619
|
const scene = scenes[index];
|
|
620
|
+
// It is possible that for a short period the route appears in both arrays.
|
|
621
|
+
// Particularly, if the screen is removed with `retain`, then it needs a moment to execute the animation.
|
|
622
|
+
// However, due to the router action, it immediately populates the `preloadedRoutes` array.
|
|
623
|
+
// Practically, the logic below takes care that it is rendered only once.
|
|
624
|
+
const isPreloaded =
|
|
625
|
+
state.preloadedRoutes.includes(route) && !routes.includes(route);
|
|
626
|
+
if (
|
|
627
|
+
state.preloadedRoutes.includes(route) &&
|
|
628
|
+
routes.includes(route) &&
|
|
629
|
+
index >= routes.length
|
|
630
|
+
) {
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
606
633
|
|
|
607
634
|
// For the screens that shouldn't be active, the value is 0
|
|
608
635
|
// For those that should be active, but are not the top screen, the value is 1
|
|
@@ -614,15 +641,15 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
614
641
|
| 1
|
|
615
642
|
| 2 = 1;
|
|
616
643
|
|
|
617
|
-
if (index <
|
|
644
|
+
if (index < routes.length - activeScreensLimit - 1 || isPreloaded) {
|
|
618
645
|
// screen should be inactive because it is too deep in the stack
|
|
619
646
|
isScreenActive = STATE_INACTIVE;
|
|
620
647
|
} else {
|
|
621
|
-
const sceneForActivity = scenes[
|
|
648
|
+
const sceneForActivity = scenes[routes.length - 1];
|
|
622
649
|
const outputValue =
|
|
623
|
-
index ===
|
|
650
|
+
index === routes.length - 1
|
|
624
651
|
? STATE_ON_TOP // the screen is on top after the transition
|
|
625
|
-
: index >=
|
|
652
|
+
: index >= routes.length - activeScreensLimit
|
|
626
653
|
? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
|
|
627
654
|
: STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
|
|
628
655
|
isScreenActive = sceneForActivity
|
|
@@ -667,7 +694,7 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
667
694
|
return (
|
|
668
695
|
<MaybeScreen
|
|
669
696
|
key={route.key}
|
|
670
|
-
style={StyleSheet.absoluteFill}
|
|
697
|
+
style={[StyleSheet.absoluteFill]}
|
|
671
698
|
enabled={detachInactiveScreens}
|
|
672
699
|
active={isScreenActive}
|
|
673
700
|
freezeOnBlur={freezeOnBlur}
|
|
@@ -677,7 +704,7 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
677
704
|
index={index}
|
|
678
705
|
interpolationIndex={interpolationIndex}
|
|
679
706
|
modal={isModal}
|
|
680
|
-
active={index ===
|
|
707
|
+
active={index === routes.length - 1}
|
|
681
708
|
focused={focused}
|
|
682
709
|
closing={closingRouteKeys.includes(route.key)}
|
|
683
710
|
layout={layout}
|
|
@@ -699,13 +726,13 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
699
726
|
isFloatHeaderAbsolute && !headerTransparent
|
|
700
727
|
}
|
|
701
728
|
renderHeader={renderHeader}
|
|
702
|
-
renderScene={renderScene}
|
|
703
729
|
onOpenRoute={onOpenRoute}
|
|
704
730
|
onCloseRoute={onCloseRoute}
|
|
705
731
|
onTransitionStart={onTransitionStart}
|
|
706
732
|
onTransitionEnd={onTransitionEnd}
|
|
707
733
|
isNextScreenTransparent={isNextScreenTransparent}
|
|
708
734
|
detachCurrentScreen={detachCurrentScreen}
|
|
735
|
+
preloaded={isPreloaded}
|
|
709
736
|
/>
|
|
710
737
|
</MaybeScreen>
|
|
711
738
|
);
|