@react-navigation/stack 7.0.0-alpha.2 → 7.0.0-alpha.20
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/TransitionConfigs/CardStyleInterpolators.js +29 -14
- package/lib/commonjs/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
- package/lib/commonjs/TransitionConfigs/HeaderStyleInterpolators.js +19 -12
- package/lib/commonjs/TransitionConfigs/HeaderStyleInterpolators.js.map +1 -1
- package/lib/commonjs/TransitionConfigs/TransitionPresets.js +20 -22
- package/lib/commonjs/TransitionConfigs/TransitionPresets.js.map +1 -1
- package/lib/commonjs/TransitionConfigs/TransitionSpecs.js +7 -14
- package/lib/commonjs/TransitionConfigs/TransitionSpecs.js.map +1 -1
- package/lib/commonjs/index.js +2 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/navigators/createStackNavigator.js +35 -25
- package/lib/commonjs/navigators/createStackNavigator.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/utils/CardAnimationContext.js +3 -4
- package/lib/commonjs/utils/CardAnimationContext.js.map +1 -1
- package/lib/commonjs/utils/GestureHandlerRefContext.js +3 -4
- package/lib/commonjs/utils/GestureHandlerRefContext.js.map +1 -1
- package/lib/commonjs/utils/ModalPresentationContext.js +3 -4
- package/lib/commonjs/utils/ModalPresentationContext.js.map +1 -1
- package/lib/commonjs/utils/conditional.js.map +1 -1
- package/lib/commonjs/utils/debounce.js.map +1 -1
- package/lib/commonjs/utils/findLastIndex.js +1 -1
- package/lib/commonjs/utils/findLastIndex.js.map +1 -1
- package/lib/commonjs/utils/getDistanceForDirection.js +2 -2
- package/lib/commonjs/utils/getDistanceForDirection.js.map +1 -1
- package/lib/commonjs/utils/getInvertedMultiplier.js +3 -4
- package/lib/commonjs/utils/getInvertedMultiplier.js.map +1 -1
- package/lib/commonjs/utils/getModalRoutesKeys.js +17 -0
- package/lib/commonjs/utils/getModalRoutesKeys.js.map +1 -0
- package/lib/commonjs/utils/memoize.js.map +1 -1
- package/lib/commonjs/utils/useCardAnimation.js +2 -2
- package/lib/commonjs/utils/useCardAnimation.js.map +1 -1
- package/lib/commonjs/utils/useGestureHandlerRef.js +2 -2
- package/lib/commonjs/utils/useGestureHandlerRef.js.map +1 -1
- package/lib/commonjs/utils/useKeyboardManager.js +6 -6
- package/lib/commonjs/utils/useKeyboardManager.js.map +1 -1
- package/lib/commonjs/views/GestureHandler.android.js.map +1 -1
- package/lib/commonjs/views/GestureHandler.ios.js.map +1 -1
- package/lib/commonjs/views/GestureHandler.js +5 -8
- package/lib/commonjs/views/GestureHandler.js.map +1 -1
- package/lib/commonjs/views/GestureHandlerNative.js +2 -2
- package/lib/commonjs/views/GestureHandlerNative.js.map +1 -1
- package/lib/commonjs/views/Header/Header.js +4 -4
- package/lib/commonjs/views/Header/Header.js.map +1 -1
- package/lib/commonjs/views/Header/HeaderContainer.js +14 -11
- package/lib/commonjs/views/Header/HeaderContainer.js.map +1 -1
- package/lib/commonjs/views/Header/HeaderSegment.js +9 -2
- package/lib/commonjs/views/Header/HeaderSegment.js.map +1 -1
- package/lib/commonjs/views/Screens.js +2 -2
- package/lib/commonjs/views/Screens.js.map +1 -1
- package/lib/commonjs/views/Stack/Card.js +55 -48
- package/lib/commonjs/views/Stack/Card.js.map +1 -1
- package/lib/commonjs/views/Stack/CardContainer.js +27 -23
- package/lib/commonjs/views/Stack/CardContainer.js.map +1 -1
- package/lib/commonjs/views/Stack/CardSheet.js +24 -4
- package/lib/commonjs/views/Stack/CardSheet.js.map +1 -1
- package/lib/commonjs/views/Stack/CardStack.js +99 -73
- package/lib/commonjs/views/Stack/CardStack.js.map +1 -1
- package/lib/commonjs/views/Stack/StackView.js +27 -31
- package/lib/commonjs/views/Stack/StackView.js.map +1 -1
- package/lib/module/TransitionConfigs/CardStyleInterpolators.js +28 -14
- package/lib/module/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
- package/lib/module/TransitionConfigs/HeaderStyleInterpolators.js +20 -13
- package/lib/module/TransitionConfigs/HeaderStyleInterpolators.js.map +1 -1
- package/lib/module/TransitionConfigs/TransitionPresets.js +10 -2
- package/lib/module/TransitionConfigs/TransitionPresets.js.map +1 -1
- package/lib/module/TransitionConfigs/TransitionSpecs.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/navigators/createStackNavigator.js +33 -22
- package/lib/module/navigators/createStackNavigator.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/CardAnimationContext.js.map +1 -1
- package/lib/module/utils/GestureHandlerRefContext.js.map +1 -1
- package/lib/module/utils/ModalPresentationContext.js.map +1 -1
- package/lib/module/utils/conditional.js.map +1 -1
- package/lib/module/utils/debounce.js.map +1 -1
- package/lib/module/utils/findLastIndex.js +1 -1
- package/lib/module/utils/findLastIndex.js.map +1 -1
- package/lib/module/utils/getDistanceForDirection.js +2 -2
- package/lib/module/utils/getDistanceForDirection.js.map +1 -1
- package/lib/module/utils/getInvertedMultiplier.js +3 -4
- package/lib/module/utils/getInvertedMultiplier.js.map +1 -1
- package/lib/module/utils/getModalRoutesKeys.js +10 -0
- package/lib/module/utils/getModalRoutesKeys.js.map +1 -0
- package/lib/module/utils/memoize.js.map +1 -1
- package/lib/module/utils/useCardAnimation.js.map +1 -1
- package/lib/module/utils/useGestureHandlerRef.js.map +1 -1
- package/lib/module/utils/useKeyboardManager.js +4 -4
- package/lib/module/utils/useKeyboardManager.js.map +1 -1
- package/lib/module/views/GestureHandler.android.js.map +1 -1
- package/lib/module/views/GestureHandler.ios.js.map +1 -1
- package/lib/module/views/GestureHandler.js.map +1 -1
- package/lib/module/views/GestureHandlerNative.js.map +1 -1
- package/lib/module/views/Header/Header.js +1 -0
- package/lib/module/views/Header/Header.js.map +1 -1
- package/lib/module/views/Header/HeaderContainer.js +13 -10
- package/lib/module/views/Header/HeaderContainer.js.map +1 -1
- package/lib/module/views/Header/HeaderSegment.js +7 -0
- package/lib/module/views/Header/HeaderSegment.js.map +1 -1
- package/lib/module/views/Screens.js.map +1 -1
- package/lib/module/views/Stack/Card.js +52 -44
- package/lib/module/views/Stack/Card.js.map +1 -1
- package/lib/module/views/Stack/CardContainer.js +25 -20
- package/lib/module/views/Stack/CardContainer.js.map +1 -1
- package/lib/module/views/Stack/CardSheet.js +21 -0
- package/lib/module/views/Stack/CardSheet.js.map +1 -1
- package/lib/module/views/Stack/CardStack.js +95 -68
- package/lib/module/views/Stack/CardStack.js.map +1 -1
- package/lib/module/views/Stack/StackView.js +25 -29
- package/lib/module/views/Stack/StackView.js.map +1 -1
- package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts +4 -0
- package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts.map +1 -1
- package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts +3 -3
- package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts.map +1 -1
- package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts +4 -0
- package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/navigators/createStackNavigator.d.ts +15 -9
- package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +70 -15
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/getDistanceForDirection.d.ts +1 -1
- package/lib/typescript/src/utils/getDistanceForDirection.d.ts.map +1 -1
- package/lib/typescript/src/utils/getInvertedMultiplier.d.ts +1 -1
- package/lib/typescript/src/utils/getInvertedMultiplier.d.ts.map +1 -1
- package/lib/typescript/src/utils/getModalRoutesKeys.d.ts +4 -0
- package/lib/typescript/src/utils/getModalRoutesKeys.d.ts.map +1 -0
- package/lib/typescript/src/views/GestureHandlerNative.d.ts +3 -2
- package/lib/typescript/src/views/GestureHandlerNative.d.ts.map +1 -1
- package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
- package/lib/typescript/src/views/Header/HeaderContainer.d.ts +4 -3
- package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
- package/lib/typescript/src/views/Header/HeaderSegment.d.ts +3 -1
- package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
- package/lib/typescript/src/views/Screens.d.ts +4 -3
- package/lib/typescript/src/views/Screens.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/Card.d.ts +6 -5
- package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardContainer.d.ts +3 -6
- package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardSheet.d.ts +1 -1
- package/lib/typescript/src/views/Stack/CardSheet.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardStack.d.ts +4 -5
- package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/StackView.d.ts +9 -80
- package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
- package/package.json +19 -20
- package/src/TransitionConfigs/CardStyleInterpolators.tsx +18 -5
- package/src/TransitionConfigs/HeaderStyleInterpolators.tsx +32 -22
- package/src/TransitionConfigs/TransitionPresets.tsx +13 -4
- package/src/index.tsx +2 -0
- package/src/navigators/createStackNavigator.tsx +49 -14
- package/src/types.tsx +88 -15
- package/src/utils/findLastIndex.tsx +1 -1
- package/src/utils/getDistanceForDirection.tsx +3 -2
- package/src/utils/getInvertedMultiplier.tsx +4 -5
- package/src/utils/getModalRoutesKeys.ts +21 -0
- package/src/utils/useKeyboardManager.tsx +1 -1
- package/src/views/GestureHandlerNative.tsx +1 -1
- package/src/views/Header/Header.tsx +3 -2
- package/src/views/Header/HeaderContainer.tsx +19 -8
- package/src/views/Header/HeaderSegment.tsx +10 -3
- package/src/views/Screens.tsx +2 -1
- package/src/views/Stack/Card.tsx +82 -63
- package/src/views/Stack/CardContainer.tsx +20 -11
- package/src/views/Stack/CardSheet.tsx +25 -1
- package/src/views/Stack/CardStack.tsx +278 -193
- package/src/views/Stack/StackView.tsx +25 -28
- package/lib/commonjs/views/ModalStatusBarManager.js +0 -44
- package/lib/commonjs/views/ModalStatusBarManager.js.map +0 -1
- package/lib/module/views/ModalStatusBarManager.js +0 -36
- package/lib/module/views/ModalStatusBarManager.js.map +0 -1
- package/lib/typescript/src/views/ModalStatusBarManager.d.ts +0 -11
- package/lib/typescript/src/views/ModalStatusBarManager.d.ts.map +0 -1
- package/src/views/ModalStatusBarManager.tsx +0 -45
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
SafeAreaProviderCompat,
|
|
5
5
|
} from '@react-navigation/elements';
|
|
6
6
|
import type {
|
|
7
|
+
LocaleDirection,
|
|
7
8
|
ParamListBase,
|
|
8
9
|
Route,
|
|
9
10
|
StackNavigationState,
|
|
10
11
|
} from '@react-navigation/native';
|
|
11
|
-
import Color from 'color';
|
|
12
12
|
import * as React from 'react';
|
|
13
13
|
import {
|
|
14
14
|
Animated,
|
|
15
|
-
LayoutChangeEvent,
|
|
15
|
+
type LayoutChangeEvent,
|
|
16
16
|
Platform,
|
|
17
17
|
StyleSheet,
|
|
18
18
|
} from 'react-native';
|
|
@@ -23,23 +23,32 @@ import {
|
|
|
23
23
|
forNoAnimation as forNoAnimationCard,
|
|
24
24
|
} from '../../TransitionConfigs/CardStyleInterpolators';
|
|
25
25
|
import {
|
|
26
|
+
BottomSheetAndroid,
|
|
26
27
|
DefaultTransition,
|
|
28
|
+
FadeFromBottomAndroid,
|
|
27
29
|
ModalFadeTransition,
|
|
30
|
+
ModalSlideFromBottomIOS,
|
|
28
31
|
ModalTransition,
|
|
32
|
+
RevealFromBottomAndroid,
|
|
33
|
+
ScaleFromCenterAndroid,
|
|
34
|
+
SlideFromLeftIOS,
|
|
35
|
+
SlideFromRightIOS,
|
|
29
36
|
} from '../../TransitionConfigs/TransitionPresets';
|
|
30
37
|
import type {
|
|
31
38
|
Layout,
|
|
32
39
|
Scene,
|
|
40
|
+
StackAnimationName,
|
|
41
|
+
StackCardStyleInterpolator,
|
|
33
42
|
StackDescriptor,
|
|
34
43
|
StackDescriptorMap,
|
|
35
44
|
StackHeaderMode,
|
|
36
|
-
|
|
45
|
+
TransitionPreset,
|
|
37
46
|
} from '../../types';
|
|
38
47
|
import { findLastIndex } from '../../utils/findLastIndex';
|
|
39
48
|
import { getDistanceForDirection } from '../../utils/getDistanceForDirection';
|
|
49
|
+
import { getModalRouteKeys } from '../../utils/getModalRoutesKeys';
|
|
40
50
|
import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
|
|
41
51
|
import { MaybeScreen, MaybeScreenContainer } from '../Screens';
|
|
42
|
-
import { getIsModalPresentation } from './Card';
|
|
43
52
|
import { CardContainer } from './CardContainer';
|
|
44
53
|
|
|
45
54
|
type GestureValues = {
|
|
@@ -47,9 +56,13 @@ type GestureValues = {
|
|
|
47
56
|
};
|
|
48
57
|
|
|
49
58
|
type Props = {
|
|
59
|
+
// eslint-disable-next-line react/no-unused-prop-types
|
|
60
|
+
direction: LocaleDirection;
|
|
50
61
|
insets: EdgeInsets;
|
|
51
62
|
state: StackNavigationState<ParamListBase>;
|
|
52
63
|
descriptors: StackDescriptorMap;
|
|
64
|
+
// eslint-disable-next-line react/no-unused-prop-types
|
|
65
|
+
preloadedDescriptors: StackDescriptorMap;
|
|
53
66
|
routes: Route<string>[];
|
|
54
67
|
// eslint-disable-next-line react/no-unused-prop-types
|
|
55
68
|
openingRouteKeys: string[];
|
|
@@ -60,7 +73,6 @@ type Props = {
|
|
|
60
73
|
route: Route<string>;
|
|
61
74
|
}) => Route<string> | undefined;
|
|
62
75
|
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
|
63
|
-
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
|
64
76
|
isParentHeaderShown: boolean;
|
|
65
77
|
isParentModal: boolean;
|
|
66
78
|
onTransitionStart: (
|
|
@@ -83,6 +95,21 @@ type State = {
|
|
|
83
95
|
headerHeights: Record<string, number>;
|
|
84
96
|
};
|
|
85
97
|
|
|
98
|
+
const NAMED_TRANSITIONS_PRESETS = {
|
|
99
|
+
default: DefaultTransition,
|
|
100
|
+
fade: ModalFadeTransition,
|
|
101
|
+
fade_from_bottom: FadeFromBottomAndroid,
|
|
102
|
+
none: DefaultTransition,
|
|
103
|
+
reveal_from_bottom: RevealFromBottomAndroid,
|
|
104
|
+
scale_from_center: ScaleFromCenterAndroid,
|
|
105
|
+
slide_from_left: SlideFromLeftIOS,
|
|
106
|
+
slide_from_right: SlideFromRightIOS,
|
|
107
|
+
slide_from_bottom: Platform.select({
|
|
108
|
+
ios: ModalSlideFromBottomIOS,
|
|
109
|
+
default: BottomSheetAndroid,
|
|
110
|
+
}),
|
|
111
|
+
} as const satisfies Record<StackAnimationName, TransitionPreset>;
|
|
112
|
+
|
|
86
113
|
const EPSILON = 1e-5;
|
|
87
114
|
|
|
88
115
|
const STATE_INACTIVE = 0;
|
|
@@ -111,6 +138,16 @@ const getInterpolationIndex = (scenes: Scene[], index: number) => {
|
|
|
111
138
|
return interpolationIndex;
|
|
112
139
|
};
|
|
113
140
|
|
|
141
|
+
const getIsModalPresentation = (
|
|
142
|
+
cardStyleInterpolator: StackCardStyleInterpolator
|
|
143
|
+
) => {
|
|
144
|
+
return (
|
|
145
|
+
cardStyleInterpolator === forModalPresentationIOS ||
|
|
146
|
+
// Handle custom modal presentation interpolators as well
|
|
147
|
+
cardStyleInterpolator.name === 'forModalPresentationIOS'
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
114
151
|
const getIsModal = (
|
|
115
152
|
scene: Scene,
|
|
116
153
|
interpolationIndex: number,
|
|
@@ -162,22 +199,34 @@ const getHeaderHeights = (
|
|
|
162
199
|
|
|
163
200
|
const getDistanceFromOptions = (
|
|
164
201
|
layout: Layout,
|
|
165
|
-
descriptor
|
|
202
|
+
descriptor: StackDescriptor | undefined,
|
|
203
|
+
isRTL: boolean
|
|
166
204
|
) => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
205
|
+
if (descriptor?.options.gestureDirection) {
|
|
206
|
+
return getDistanceForDirection(
|
|
207
|
+
layout,
|
|
208
|
+
descriptor?.options.gestureDirection,
|
|
209
|
+
isRTL
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const defaultGestureDirection =
|
|
214
|
+
descriptor?.options.presentation === 'modal'
|
|
170
215
|
? ModalTransition.gestureDirection
|
|
171
|
-
: DefaultTransition.gestureDirection
|
|
172
|
-
|
|
216
|
+
: DefaultTransition.gestureDirection;
|
|
217
|
+
|
|
218
|
+
const gestureDirection = descriptor?.options.animation
|
|
219
|
+
? NAMED_TRANSITIONS_PRESETS[descriptor?.options.animation]?.gestureDirection
|
|
220
|
+
: defaultGestureDirection;
|
|
173
221
|
|
|
174
|
-
return getDistanceForDirection(layout, gestureDirection);
|
|
222
|
+
return getDistanceForDirection(layout, gestureDirection, isRTL);
|
|
175
223
|
};
|
|
176
224
|
|
|
177
225
|
const getProgressFromGesture = (
|
|
178
226
|
gesture: Animated.Value,
|
|
179
227
|
layout: Layout,
|
|
180
|
-
descriptor
|
|
228
|
+
descriptor: StackDescriptor | undefined,
|
|
229
|
+
isRTL: boolean
|
|
181
230
|
) => {
|
|
182
231
|
const distance = getDistanceFromOptions(
|
|
183
232
|
{
|
|
@@ -186,7 +235,8 @@ const getProgressFromGesture = (
|
|
|
186
235
|
width: Math.max(1, layout.width),
|
|
187
236
|
height: Math.max(1, layout.height),
|
|
188
237
|
},
|
|
189
|
-
descriptor
|
|
238
|
+
descriptor,
|
|
239
|
+
isRTL
|
|
190
240
|
);
|
|
191
241
|
|
|
192
242
|
if (distance > 0) {
|
|
@@ -214,158 +264,202 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
214
264
|
return null;
|
|
215
265
|
}
|
|
216
266
|
|
|
217
|
-
const gestures =
|
|
218
|
-
|
|
219
|
-
|
|
267
|
+
const gestures = [
|
|
268
|
+
...props.routes,
|
|
269
|
+
...props.state.preloadedRoutes,
|
|
270
|
+
].reduce<GestureValues>((acc, curr) => {
|
|
271
|
+
const descriptor =
|
|
272
|
+
props.descriptors[curr.key] || props.preloadedDescriptors[curr.key];
|
|
273
|
+
const { animation } = descriptor?.options || {};
|
|
220
274
|
|
|
221
275
|
acc[curr.key] =
|
|
222
276
|
state.gestures[curr.key] ||
|
|
223
277
|
new Animated.Value(
|
|
224
|
-
props.openingRouteKeys.includes(curr.key) &&
|
|
225
|
-
|
|
226
|
-
? getDistanceFromOptions(
|
|
278
|
+
(props.openingRouteKeys.includes(curr.key) && animation !== 'none') ||
|
|
279
|
+
props.state.preloadedRoutes.includes(curr)
|
|
280
|
+
? getDistanceFromOptions(
|
|
281
|
+
state.layout,
|
|
282
|
+
descriptor,
|
|
283
|
+
props.direction === 'rtl'
|
|
284
|
+
)
|
|
227
285
|
: 0
|
|
228
286
|
);
|
|
229
287
|
|
|
230
288
|
return acc;
|
|
231
289
|
}, {});
|
|
232
290
|
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const previousGesture = previousRoute
|
|
241
|
-
? gestures[previousRoute.key]
|
|
242
|
-
: undefined;
|
|
243
|
-
const nextGesture = nextRoute ? gestures[nextRoute.key] : undefined;
|
|
244
|
-
|
|
245
|
-
const descriptor =
|
|
246
|
-
props.descriptors[route.key] ||
|
|
247
|
-
state.descriptors[route.key] ||
|
|
248
|
-
(oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR);
|
|
249
|
-
|
|
250
|
-
const nextDescriptor =
|
|
251
|
-
props.descriptors[nextRoute?.key] || state.descriptors[nextRoute?.key];
|
|
252
|
-
|
|
253
|
-
const previousDescriptor =
|
|
254
|
-
props.descriptors[previousRoute?.key] ||
|
|
255
|
-
state.descriptors[previousRoute?.key];
|
|
256
|
-
|
|
257
|
-
// When a screen is not the last, it should use next screen's transition config
|
|
258
|
-
// Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
|
|
259
|
-
// For example combining a slide and a modal transition would look wrong otherwise
|
|
260
|
-
// With this approach, combining different transition styles in the same navigator mostly looks right
|
|
261
|
-
// This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
|
|
262
|
-
// but majority of the transitions look alright
|
|
263
|
-
const optionsForTransitionConfig =
|
|
264
|
-
index !== self.length - 1 &&
|
|
265
|
-
nextDescriptor &&
|
|
266
|
-
nextDescriptor.options.presentation !== 'transparentModal'
|
|
267
|
-
? nextDescriptor.options
|
|
268
|
-
: descriptor.options;
|
|
269
|
-
|
|
270
|
-
let defaultTransitionPreset =
|
|
271
|
-
optionsForTransitionConfig.presentation === 'modal'
|
|
272
|
-
? ModalTransition
|
|
273
|
-
: optionsForTransitionConfig.presentation === 'transparentModal'
|
|
274
|
-
? ModalFadeTransition
|
|
275
|
-
: DefaultTransition;
|
|
291
|
+
const modalRouteKeys = getModalRouteKeys(
|
|
292
|
+
[...props.routes, ...props.state.preloadedRoutes],
|
|
293
|
+
{
|
|
294
|
+
...props.descriptors,
|
|
295
|
+
...props.preloadedDescriptors,
|
|
296
|
+
}
|
|
297
|
+
);
|
|
276
298
|
|
|
277
|
-
|
|
278
|
-
|
|
299
|
+
const scenes = [...props.routes, ...props.state.preloadedRoutes].map(
|
|
300
|
+
(route, index, self) => {
|
|
301
|
+
// For preloaded screens, we don't care about the previous and the next screen
|
|
302
|
+
const isPreloaded = props.state.preloadedRoutes.includes(route);
|
|
303
|
+
const previousRoute = isPreloaded ? undefined : self[index - 1];
|
|
304
|
+
const nextRoute = isPreloaded ? undefined : self[index + 1];
|
|
305
|
+
|
|
306
|
+
const oldScene = state.scenes[index];
|
|
307
|
+
|
|
308
|
+
const currentGesture = gestures[route.key];
|
|
309
|
+
const previousGesture = previousRoute
|
|
310
|
+
? gestures[previousRoute.key]
|
|
311
|
+
: undefined;
|
|
312
|
+
const nextGesture = nextRoute ? gestures[nextRoute.key] : undefined;
|
|
313
|
+
|
|
314
|
+
const descriptor =
|
|
315
|
+
(isPreloaded ? props.preloadedDescriptors : props.descriptors)[
|
|
316
|
+
route.key
|
|
317
|
+
] ||
|
|
318
|
+
state.descriptors[route.key] ||
|
|
319
|
+
(oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR);
|
|
320
|
+
|
|
321
|
+
const nextDescriptor =
|
|
322
|
+
nextRoute &&
|
|
323
|
+
(props.descriptors[nextRoute?.key] ||
|
|
324
|
+
state.descriptors[nextRoute?.key]);
|
|
325
|
+
|
|
326
|
+
const previousDescriptor =
|
|
327
|
+
previousRoute &&
|
|
328
|
+
(props.descriptors[previousRoute?.key] ||
|
|
329
|
+
state.descriptors[previousRoute?.key]);
|
|
330
|
+
|
|
331
|
+
// When a screen is not the last, it should use next screen's transition config
|
|
332
|
+
// Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
|
|
333
|
+
// For example combining a slide and a modal transition would look wrong otherwise
|
|
334
|
+
// With this approach, combining different transition styles in the same navigator mostly looks right
|
|
335
|
+
// This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
|
|
336
|
+
// but the majority of the transitions look alright
|
|
337
|
+
const optionsForTransitionConfig =
|
|
338
|
+
index !== self.length - 1 &&
|
|
339
|
+
nextDescriptor &&
|
|
340
|
+
nextDescriptor.options.presentation !== 'transparentModal'
|
|
341
|
+
? nextDescriptor.options
|
|
342
|
+
: descriptor.options;
|
|
343
|
+
|
|
344
|
+
// Assume modal if there are already modal screens in the stack
|
|
345
|
+
// or current screen is a modal when no presentation is specified
|
|
346
|
+
const isModal = modalRouteKeys.includes(route.key);
|
|
347
|
+
|
|
348
|
+
// Disable screen transition animation by default on web, windows and macos to match the native behavior
|
|
349
|
+
const excludedPlatforms =
|
|
350
|
+
Platform.OS !== 'web' &&
|
|
279
351
|
Platform.OS !== 'windows' &&
|
|
280
|
-
Platform.OS !== 'macos'
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
|
|
352
|
+
Platform.OS !== 'macos';
|
|
353
|
+
|
|
354
|
+
const animation =
|
|
355
|
+
optionsForTransitionConfig.animation ??
|
|
356
|
+
(excludedPlatforms ? 'default' : 'none');
|
|
357
|
+
const isAnimationEnabled = animation !== 'none';
|
|
358
|
+
|
|
359
|
+
const transitionPreset =
|
|
360
|
+
animation !== 'default'
|
|
361
|
+
? NAMED_TRANSITIONS_PRESETS[animation]
|
|
362
|
+
: isModal || optionsForTransitionConfig.presentation === 'modal'
|
|
363
|
+
? ModalTransition
|
|
364
|
+
: optionsForTransitionConfig.presentation === 'transparentModal'
|
|
365
|
+
? ModalFadeTransition
|
|
366
|
+
: DefaultTransition;
|
|
367
|
+
|
|
368
|
+
const {
|
|
369
|
+
gestureEnabled = Platform.OS === 'ios' && isAnimationEnabled,
|
|
370
|
+
gestureDirection = transitionPreset.gestureDirection,
|
|
371
|
+
transitionSpec = transitionPreset.transitionSpec,
|
|
372
|
+
cardStyleInterpolator = isAnimationEnabled
|
|
373
|
+
? transitionPreset.cardStyleInterpolator
|
|
374
|
+
: forNoAnimationCard,
|
|
375
|
+
headerStyleInterpolator = transitionPreset.headerStyleInterpolator,
|
|
376
|
+
cardOverlayEnabled = (Platform.OS !== 'ios' &&
|
|
377
|
+
optionsForTransitionConfig.presentation !== 'transparentModal') ||
|
|
378
|
+
getIsModalPresentation(cardStyleInterpolator),
|
|
379
|
+
} = optionsForTransitionConfig;
|
|
380
|
+
|
|
381
|
+
const headerMode: StackHeaderMode =
|
|
382
|
+
descriptor.options.headerMode ??
|
|
383
|
+
(!(
|
|
384
|
+
optionsForTransitionConfig.presentation === 'modal' ||
|
|
385
|
+
optionsForTransitionConfig.presentation === 'transparentModal' ||
|
|
386
|
+
nextDescriptor?.options.presentation === 'modal' ||
|
|
387
|
+
nextDescriptor?.options.presentation === 'transparentModal' ||
|
|
388
|
+
getIsModalPresentation(cardStyleInterpolator)
|
|
389
|
+
) &&
|
|
390
|
+
Platform.OS === 'ios' &&
|
|
391
|
+
descriptor.options.header === undefined
|
|
392
|
+
? 'float'
|
|
393
|
+
: 'screen');
|
|
394
|
+
|
|
395
|
+
const isRTL = props.direction === 'rtl';
|
|
396
|
+
|
|
397
|
+
const scene = {
|
|
398
|
+
route,
|
|
399
|
+
descriptor: {
|
|
400
|
+
...descriptor,
|
|
401
|
+
options: {
|
|
402
|
+
...descriptor.options,
|
|
403
|
+
animation,
|
|
404
|
+
cardOverlayEnabled,
|
|
405
|
+
cardStyleInterpolator,
|
|
406
|
+
gestureDirection,
|
|
407
|
+
gestureEnabled,
|
|
408
|
+
headerStyleInterpolator,
|
|
409
|
+
transitionSpec,
|
|
410
|
+
headerMode,
|
|
411
|
+
},
|
|
321
412
|
},
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
413
|
+
progress: {
|
|
414
|
+
current: getProgressFromGesture(
|
|
415
|
+
currentGesture,
|
|
416
|
+
state.layout,
|
|
417
|
+
descriptor,
|
|
418
|
+
isRTL
|
|
419
|
+
),
|
|
420
|
+
next:
|
|
421
|
+
nextGesture &&
|
|
422
|
+
nextDescriptor?.options.presentation !== 'transparentModal'
|
|
423
|
+
? getProgressFromGesture(
|
|
424
|
+
nextGesture,
|
|
425
|
+
state.layout,
|
|
426
|
+
nextDescriptor,
|
|
427
|
+
isRTL
|
|
428
|
+
)
|
|
429
|
+
: undefined,
|
|
430
|
+
previous: previousGesture
|
|
332
431
|
? getProgressFromGesture(
|
|
333
|
-
|
|
432
|
+
previousGesture,
|
|
334
433
|
state.layout,
|
|
335
|
-
|
|
434
|
+
previousDescriptor,
|
|
435
|
+
isRTL
|
|
336
436
|
)
|
|
337
437
|
: undefined,
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
438
|
+
},
|
|
439
|
+
__memo: [
|
|
440
|
+
state.layout,
|
|
441
|
+
descriptor,
|
|
442
|
+
nextDescriptor,
|
|
443
|
+
previousDescriptor,
|
|
444
|
+
currentGesture,
|
|
445
|
+
nextGesture,
|
|
446
|
+
previousGesture,
|
|
447
|
+
],
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
if (
|
|
451
|
+
oldScene &&
|
|
452
|
+
scene.__memo.every((it, i) => {
|
|
453
|
+
// @ts-expect-error: we haven't added __memo to the annotation to prevent usage elsewhere
|
|
454
|
+
return oldScene.__memo[i] === it;
|
|
455
|
+
})
|
|
456
|
+
) {
|
|
457
|
+
return oldScene;
|
|
458
|
+
}
|
|
356
459
|
|
|
357
|
-
|
|
358
|
-
oldScene &&
|
|
359
|
-
scene.__memo.every((it, i) => {
|
|
360
|
-
// @ts-expect-error: we haven't added __memo to the annotation to prevent usage elsewhere
|
|
361
|
-
return oldScene.__memo[i] === it;
|
|
362
|
-
})
|
|
363
|
-
) {
|
|
364
|
-
return oldScene;
|
|
460
|
+
return scene;
|
|
365
461
|
}
|
|
366
|
-
|
|
367
|
-
return scene;
|
|
368
|
-
});
|
|
462
|
+
);
|
|
369
463
|
|
|
370
464
|
return {
|
|
371
465
|
routes: props.routes,
|
|
@@ -480,7 +574,6 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
480
574
|
onOpenRoute,
|
|
481
575
|
onCloseRoute,
|
|
482
576
|
renderHeader,
|
|
483
|
-
renderScene,
|
|
484
577
|
isParentHeaderShown,
|
|
485
578
|
isParentModal,
|
|
486
579
|
onTransitionStart,
|
|
@@ -522,16 +615,16 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
522
615
|
detachPreviousScreen = options.presentation === 'transparentModal'
|
|
523
616
|
? false
|
|
524
617
|
: getIsModalPresentation(options.cardStyleInterpolator)
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
618
|
+
? i !==
|
|
619
|
+
findLastIndex(scenes, (scene) => {
|
|
620
|
+
const { cardStyleInterpolator } = scene.descriptor.options;
|
|
621
|
+
|
|
622
|
+
return (
|
|
623
|
+
cardStyleInterpolator === forModalPresentationIOS ||
|
|
624
|
+
cardStyleInterpolator?.name === 'forModalPresentationIOS'
|
|
625
|
+
);
|
|
626
|
+
})
|
|
627
|
+
: true,
|
|
535
628
|
} = options;
|
|
536
629
|
|
|
537
630
|
if (detachPreviousScreen === false) {
|
|
@@ -575,10 +668,23 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
575
668
|
style={styles.container}
|
|
576
669
|
onLayout={this.handleLayout}
|
|
577
670
|
>
|
|
578
|
-
{routes.map((route, index
|
|
671
|
+
{[...routes, ...state.preloadedRoutes].map((route, index) => {
|
|
579
672
|
const focused = focusedRoute.key === route.key;
|
|
580
673
|
const gesture = gestures[route.key];
|
|
581
674
|
const scene = scenes[index];
|
|
675
|
+
// It is possible that for a short period the route appears in both arrays.
|
|
676
|
+
// Particularly, if the screen is removed with `retain`, then it needs a moment to execute the animation.
|
|
677
|
+
// However, due to the router action, it immediately populates the `preloadedRoutes` array.
|
|
678
|
+
// Practically, the logic below takes care that it is rendered only once.
|
|
679
|
+
const isPreloaded =
|
|
680
|
+
state.preloadedRoutes.includes(route) && !routes.includes(route);
|
|
681
|
+
if (
|
|
682
|
+
state.preloadedRoutes.includes(route) &&
|
|
683
|
+
routes.includes(route) &&
|
|
684
|
+
index >= routes.length
|
|
685
|
+
) {
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
582
688
|
|
|
583
689
|
// For the screens that shouldn't be active, the value is 0
|
|
584
690
|
// For those that should be active, but are not the top screen, the value is 1
|
|
@@ -590,17 +696,17 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
590
696
|
| 1
|
|
591
697
|
| 2 = 1;
|
|
592
698
|
|
|
593
|
-
if (index <
|
|
699
|
+
if (index < routes.length - activeScreensLimit - 1 || isPreloaded) {
|
|
594
700
|
// screen should be inactive because it is too deep in the stack
|
|
595
701
|
isScreenActive = STATE_INACTIVE;
|
|
596
702
|
} else {
|
|
597
|
-
const sceneForActivity = scenes[
|
|
703
|
+
const sceneForActivity = scenes[routes.length - 1];
|
|
598
704
|
const outputValue =
|
|
599
|
-
index ===
|
|
705
|
+
index === routes.length - 1
|
|
600
706
|
? STATE_ON_TOP // the screen is on top after the transition
|
|
601
|
-
: index >=
|
|
602
|
-
|
|
603
|
-
|
|
707
|
+
: index >= routes.length - activeScreensLimit
|
|
708
|
+
? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
|
|
709
|
+
: STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
|
|
604
710
|
isScreenActive = sceneForActivity
|
|
605
711
|
? sceneForActivity.progress.current.interpolate({
|
|
606
712
|
inputRange: [0, 1 - EPSILON, 1],
|
|
@@ -613,9 +719,8 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
613
719
|
const {
|
|
614
720
|
headerShown = true,
|
|
615
721
|
headerTransparent,
|
|
616
|
-
headerStyle,
|
|
617
|
-
headerTintColor,
|
|
618
722
|
freezeOnBlur,
|
|
723
|
+
autoHideHomeIndicator,
|
|
619
724
|
} = scene.descriptor.options;
|
|
620
725
|
|
|
621
726
|
const safeAreaInsetTop = insets.top;
|
|
@@ -626,26 +731,6 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
626
731
|
const headerHeight =
|
|
627
732
|
headerShown !== false ? headerHeights[route.key] : 0;
|
|
628
733
|
|
|
629
|
-
let headerDarkContent: boolean | undefined;
|
|
630
|
-
|
|
631
|
-
if (headerShown) {
|
|
632
|
-
if (typeof headerTintColor === 'string') {
|
|
633
|
-
headerDarkContent = Color(headerTintColor).isDark();
|
|
634
|
-
} else {
|
|
635
|
-
const flattenedHeaderStyle = StyleSheet.flatten(headerStyle);
|
|
636
|
-
|
|
637
|
-
if (
|
|
638
|
-
flattenedHeaderStyle &&
|
|
639
|
-
'backgroundColor' in flattenedHeaderStyle &&
|
|
640
|
-
typeof flattenedHeaderStyle.backgroundColor === 'string'
|
|
641
|
-
) {
|
|
642
|
-
headerDarkContent = !Color(
|
|
643
|
-
flattenedHeaderStyle.backgroundColor
|
|
644
|
-
).isDark();
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
734
|
// Start from current card and count backwards the number of cards with same interpolation
|
|
650
735
|
const interpolationIndex = getInterpolationIndex(scenes, index);
|
|
651
736
|
const isModal = getIsModal(
|
|
@@ -665,17 +750,18 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
665
750
|
return (
|
|
666
751
|
<MaybeScreen
|
|
667
752
|
key={route.key}
|
|
668
|
-
style={StyleSheet.absoluteFill}
|
|
753
|
+
style={[StyleSheet.absoluteFill]}
|
|
669
754
|
enabled={detachInactiveScreens}
|
|
670
755
|
active={isScreenActive}
|
|
671
756
|
freezeOnBlur={freezeOnBlur}
|
|
757
|
+
homeIndicatorHidden={autoHideHomeIndicator}
|
|
672
758
|
pointerEvents="box-none"
|
|
673
759
|
>
|
|
674
760
|
<CardContainer
|
|
675
761
|
index={index}
|
|
676
762
|
interpolationIndex={interpolationIndex}
|
|
677
763
|
modal={isModal}
|
|
678
|
-
active={index ===
|
|
764
|
+
active={index === routes.length - 1}
|
|
679
765
|
focused={focused}
|
|
680
766
|
closing={closingRouteKeys.includes(route.key)}
|
|
681
767
|
layout={layout}
|
|
@@ -693,18 +779,17 @@ export class CardStack extends React.Component<Props, State> {
|
|
|
693
779
|
onHeaderHeightChange={this.handleHeaderLayout}
|
|
694
780
|
getPreviousScene={this.getPreviousScene}
|
|
695
781
|
getFocusedRoute={this.getFocusedRoute}
|
|
696
|
-
headerDarkContent={headerDarkContent}
|
|
697
782
|
hasAbsoluteFloatHeader={
|
|
698
783
|
isFloatHeaderAbsolute && !headerTransparent
|
|
699
784
|
}
|
|
700
785
|
renderHeader={renderHeader}
|
|
701
|
-
renderScene={renderScene}
|
|
702
786
|
onOpenRoute={onOpenRoute}
|
|
703
787
|
onCloseRoute={onCloseRoute}
|
|
704
788
|
onTransitionStart={onTransitionStart}
|
|
705
789
|
onTransitionEnd={onTransitionEnd}
|
|
706
790
|
isNextScreenTransparent={isNextScreenTransparent}
|
|
707
791
|
detachCurrentScreen={detachCurrentScreen}
|
|
792
|
+
preloaded={isPreloaded}
|
|
708
793
|
/>
|
|
709
794
|
</MaybeScreen>
|
|
710
795
|
);
|
|
@@ -723,8 +808,8 @@ const styles = StyleSheet.create({
|
|
|
723
808
|
absolute: {
|
|
724
809
|
position: 'absolute',
|
|
725
810
|
top: 0,
|
|
726
|
-
|
|
727
|
-
|
|
811
|
+
start: 0,
|
|
812
|
+
end: 0,
|
|
728
813
|
},
|
|
729
814
|
floating: {
|
|
730
815
|
zIndex: 1,
|