@react-navigation/stack 7.0.0-alpha.1 → 7.0.0-alpha.10

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 (160) hide show
  1. package/lib/commonjs/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
  2. package/lib/commonjs/TransitionConfigs/HeaderStyleInterpolators.js +19 -12
  3. package/lib/commonjs/TransitionConfigs/HeaderStyleInterpolators.js.map +1 -1
  4. package/lib/commonjs/TransitionConfigs/TransitionPresets.js +11 -21
  5. package/lib/commonjs/TransitionConfigs/TransitionPresets.js.map +1 -1
  6. package/lib/commonjs/TransitionConfigs/TransitionSpecs.js +7 -14
  7. package/lib/commonjs/TransitionConfigs/TransitionSpecs.js.map +1 -1
  8. package/lib/commonjs/index.js +2 -2
  9. package/lib/commonjs/index.js.map +1 -1
  10. package/lib/commonjs/navigators/createStackNavigator.js +32 -24
  11. package/lib/commonjs/navigators/createStackNavigator.js.map +1 -1
  12. package/lib/commonjs/types.js.map +1 -1
  13. package/lib/commonjs/utils/CardAnimationContext.js +3 -4
  14. package/lib/commonjs/utils/CardAnimationContext.js.map +1 -1
  15. package/lib/commonjs/utils/GestureHandlerRefContext.js +3 -4
  16. package/lib/commonjs/utils/GestureHandlerRefContext.js.map +1 -1
  17. package/lib/commonjs/utils/ModalPresentationContext.js +3 -4
  18. package/lib/commonjs/utils/ModalPresentationContext.js.map +1 -1
  19. package/lib/commonjs/utils/conditional.js.map +1 -1
  20. package/lib/commonjs/utils/debounce.js.map +1 -1
  21. package/lib/commonjs/utils/findLastIndex.js +1 -1
  22. package/lib/commonjs/utils/findLastIndex.js.map +1 -1
  23. package/lib/commonjs/utils/getDistanceForDirection.js +2 -2
  24. package/lib/commonjs/utils/getDistanceForDirection.js.map +1 -1
  25. package/lib/commonjs/utils/getInvertedMultiplier.js +3 -4
  26. package/lib/commonjs/utils/getInvertedMultiplier.js.map +1 -1
  27. package/lib/commonjs/utils/memoize.js.map +1 -1
  28. package/lib/commonjs/utils/useCardAnimation.js +2 -2
  29. package/lib/commonjs/utils/useCardAnimation.js.map +1 -1
  30. package/lib/commonjs/utils/useGestureHandlerRef.js +2 -2
  31. package/lib/commonjs/utils/useGestureHandlerRef.js.map +1 -1
  32. package/lib/commonjs/utils/useKeyboardManager.js +6 -6
  33. package/lib/commonjs/utils/useKeyboardManager.js.map +1 -1
  34. package/lib/commonjs/views/GestureHandler.android.js.map +1 -1
  35. package/lib/commonjs/views/GestureHandler.ios.js.map +1 -1
  36. package/lib/commonjs/views/GestureHandler.js +5 -8
  37. package/lib/commonjs/views/GestureHandler.js.map +1 -1
  38. package/lib/commonjs/views/GestureHandlerNative.js +2 -2
  39. package/lib/commonjs/views/GestureHandlerNative.js.map +1 -1
  40. package/lib/commonjs/views/Header/Header.js +4 -4
  41. package/lib/commonjs/views/Header/Header.js.map +1 -1
  42. package/lib/commonjs/views/Header/HeaderContainer.js +12 -9
  43. package/lib/commonjs/views/Header/HeaderContainer.js.map +1 -1
  44. package/lib/commonjs/views/Header/HeaderSegment.js +11 -3
  45. package/lib/commonjs/views/Header/HeaderSegment.js.map +1 -1
  46. package/lib/commonjs/views/Screens.js +2 -2
  47. package/lib/commonjs/views/Screens.js.map +1 -1
  48. package/lib/commonjs/views/Stack/Card.js +48 -41
  49. package/lib/commonjs/views/Stack/Card.js.map +1 -1
  50. package/lib/commonjs/views/Stack/CardContainer.js +25 -21
  51. package/lib/commonjs/views/Stack/CardContainer.js.map +1 -1
  52. package/lib/commonjs/views/Stack/CardSheet.js +24 -4
  53. package/lib/commonjs/views/Stack/CardSheet.js.map +1 -1
  54. package/lib/commonjs/views/Stack/CardStack.js +58 -60
  55. package/lib/commonjs/views/Stack/CardStack.js.map +1 -1
  56. package/lib/commonjs/views/Stack/StackView.js +26 -30
  57. package/lib/commonjs/views/Stack/StackView.js.map +1 -1
  58. package/lib/module/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
  59. package/lib/module/TransitionConfigs/HeaderStyleInterpolators.js +20 -13
  60. package/lib/module/TransitionConfigs/HeaderStyleInterpolators.js.map +1 -1
  61. package/lib/module/TransitionConfigs/TransitionPresets.js +1 -1
  62. package/lib/module/TransitionConfigs/TransitionPresets.js.map +1 -1
  63. package/lib/module/TransitionConfigs/TransitionSpecs.js.map +1 -1
  64. package/lib/module/index.js.map +1 -1
  65. package/lib/module/navigators/createStackNavigator.js +30 -21
  66. package/lib/module/navigators/createStackNavigator.js.map +1 -1
  67. package/lib/module/types.js.map +1 -1
  68. package/lib/module/utils/CardAnimationContext.js.map +1 -1
  69. package/lib/module/utils/GestureHandlerRefContext.js.map +1 -1
  70. package/lib/module/utils/ModalPresentationContext.js.map +1 -1
  71. package/lib/module/utils/conditional.js.map +1 -1
  72. package/lib/module/utils/debounce.js.map +1 -1
  73. package/lib/module/utils/findLastIndex.js +1 -1
  74. package/lib/module/utils/findLastIndex.js.map +1 -1
  75. package/lib/module/utils/getDistanceForDirection.js +2 -2
  76. package/lib/module/utils/getDistanceForDirection.js.map +1 -1
  77. package/lib/module/utils/getInvertedMultiplier.js +3 -4
  78. package/lib/module/utils/getInvertedMultiplier.js.map +1 -1
  79. package/lib/module/utils/memoize.js.map +1 -1
  80. package/lib/module/utils/useCardAnimation.js.map +1 -1
  81. package/lib/module/utils/useGestureHandlerRef.js.map +1 -1
  82. package/lib/module/utils/useKeyboardManager.js +4 -4
  83. package/lib/module/utils/useKeyboardManager.js.map +1 -1
  84. package/lib/module/views/GestureHandler.android.js.map +1 -1
  85. package/lib/module/views/GestureHandler.ios.js.map +1 -1
  86. package/lib/module/views/GestureHandler.js.map +1 -1
  87. package/lib/module/views/GestureHandlerNative.js.map +1 -1
  88. package/lib/module/views/Header/Header.js +1 -0
  89. package/lib/module/views/Header/Header.js.map +1 -1
  90. package/lib/module/views/Header/HeaderContainer.js +11 -8
  91. package/lib/module/views/Header/HeaderContainer.js.map +1 -1
  92. package/lib/module/views/Header/HeaderSegment.js +9 -1
  93. package/lib/module/views/Header/HeaderSegment.js.map +1 -1
  94. package/lib/module/views/Screens.js.map +1 -1
  95. package/lib/module/views/Stack/Card.js +45 -37
  96. package/lib/module/views/Stack/Card.js.map +1 -1
  97. package/lib/module/views/Stack/CardContainer.js +23 -18
  98. package/lib/module/views/Stack/CardContainer.js.map +1 -1
  99. package/lib/module/views/Stack/CardSheet.js +21 -0
  100. package/lib/module/views/Stack/CardSheet.js.map +1 -1
  101. package/lib/module/views/Stack/CardStack.js +53 -54
  102. package/lib/module/views/Stack/CardStack.js.map +1 -1
  103. package/lib/module/views/Stack/StackView.js +24 -28
  104. package/lib/module/views/Stack/StackView.js.map +1 -1
  105. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts +3 -3
  106. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts.map +1 -1
  107. package/lib/typescript/src/navigators/createStackNavigator.d.ts +4 -4
  108. package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
  109. package/lib/typescript/src/types.d.ts +47 -9
  110. package/lib/typescript/src/types.d.ts.map +1 -1
  111. package/lib/typescript/src/utils/getDistanceForDirection.d.ts +1 -1
  112. package/lib/typescript/src/utils/getDistanceForDirection.d.ts.map +1 -1
  113. package/lib/typescript/src/utils/getInvertedMultiplier.d.ts +1 -1
  114. package/lib/typescript/src/utils/getInvertedMultiplier.d.ts.map +1 -1
  115. package/lib/typescript/src/views/GestureHandlerNative.d.ts +3 -3
  116. package/lib/typescript/src/views/GestureHandlerNative.d.ts.map +1 -1
  117. package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
  118. package/lib/typescript/src/views/Header/HeaderContainer.d.ts +4 -4
  119. package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
  120. package/lib/typescript/src/views/Header/HeaderSegment.d.ts +3 -2
  121. package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
  122. package/lib/typescript/src/views/Screens.d.ts +4 -3
  123. package/lib/typescript/src/views/Screens.d.ts.map +1 -1
  124. package/lib/typescript/src/views/Stack/Card.d.ts +6 -5
  125. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  126. package/lib/typescript/src/views/Stack/CardContainer.d.ts +3 -6
  127. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  128. package/lib/typescript/src/views/Stack/CardSheet.d.ts +1 -1
  129. package/lib/typescript/src/views/Stack/CardSheet.d.ts.map +1 -1
  130. package/lib/typescript/src/views/Stack/CardStack.d.ts +4 -5
  131. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  132. package/lib/typescript/src/views/Stack/StackView.d.ts +9 -80
  133. package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
  134. package/package.json +20 -21
  135. package/src/TransitionConfigs/CardStyleInterpolators.tsx +5 -5
  136. package/src/TransitionConfigs/HeaderStyleInterpolators.tsx +32 -22
  137. package/src/TransitionConfigs/TransitionPresets.tsx +4 -4
  138. package/src/navigators/createStackNavigator.tsx +18 -7
  139. package/src/types.tsx +50 -10
  140. package/src/utils/findLastIndex.tsx +1 -1
  141. package/src/utils/getDistanceForDirection.tsx +3 -2
  142. package/src/utils/getInvertedMultiplier.tsx +4 -5
  143. package/src/utils/useKeyboardManager.tsx +1 -1
  144. package/src/views/GestureHandlerNative.tsx +1 -1
  145. package/src/views/Header/Header.tsx +3 -2
  146. package/src/views/Header/HeaderContainer.tsx +17 -6
  147. package/src/views/Header/HeaderSegment.tsx +12 -4
  148. package/src/views/Screens.tsx +2 -1
  149. package/src/views/Stack/Card.tsx +75 -56
  150. package/src/views/Stack/CardContainer.tsx +18 -9
  151. package/src/views/Stack/CardSheet.tsx +25 -1
  152. package/src/views/Stack/CardStack.tsx +216 -186
  153. package/src/views/Stack/StackView.tsx +24 -27
  154. package/lib/commonjs/views/ModalStatusBarManager.js +0 -44
  155. package/lib/commonjs/views/ModalStatusBarManager.js.map +0 -1
  156. package/lib/module/views/ModalStatusBarManager.js +0 -36
  157. package/lib/module/views/ModalStatusBarManager.js.map +0 -1
  158. package/lib/typescript/src/views/ModalStatusBarManager.d.ts +0 -12
  159. package/lib/typescript/src/views/ModalStatusBarManager.d.ts.map +0 -1
  160. 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';
@@ -30,6 +30,7 @@ import {
30
30
  import type {
31
31
  Layout,
32
32
  Scene,
33
+ StackCardStyleInterpolator,
33
34
  StackDescriptor,
34
35
  StackDescriptorMap,
35
36
  StackHeaderMode,
@@ -39,7 +40,6 @@ import { findLastIndex } from '../../utils/findLastIndex';
39
40
  import { getDistanceForDirection } from '../../utils/getDistanceForDirection';
40
41
  import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
41
42
  import { MaybeScreen, MaybeScreenContainer } from '../Screens';
42
- import { getIsModalPresentation } from './Card';
43
43
  import { CardContainer } from './CardContainer';
44
44
 
45
45
  type GestureValues = {
@@ -47,9 +47,13 @@ type GestureValues = {
47
47
  };
48
48
 
49
49
  type Props = {
50
+ // eslint-disable-next-line react/no-unused-prop-types
51
+ direction: LocaleDirection;
50
52
  insets: EdgeInsets;
51
53
  state: StackNavigationState<ParamListBase>;
52
54
  descriptors: StackDescriptorMap;
55
+ // eslint-disable-next-line react/no-unused-prop-types
56
+ preloadedDescriptors: StackDescriptorMap;
53
57
  routes: Route<string>[];
54
58
  // eslint-disable-next-line react/no-unused-prop-types
55
59
  openingRouteKeys: string[];
@@ -60,7 +64,6 @@ type Props = {
60
64
  route: Route<string>;
61
65
  }) => Route<string> | undefined;
62
66
  renderHeader: (props: HeaderContainerProps) => React.ReactNode;
63
- renderScene: (props: { route: Route<string> }) => React.ReactNode;
64
67
  isParentHeaderShown: boolean;
65
68
  isParentModal: boolean;
66
69
  onTransitionStart: (
@@ -111,6 +114,16 @@ const getInterpolationIndex = (scenes: Scene[], index: number) => {
111
114
  return interpolationIndex;
112
115
  };
113
116
 
117
+ const getIsModalPresentation = (
118
+ cardStyleInterpolator: StackCardStyleInterpolator
119
+ ) => {
120
+ return (
121
+ cardStyleInterpolator === forModalPresentationIOS ||
122
+ // Handle custom modal presentation interpolators as well
123
+ cardStyleInterpolator.name === 'forModalPresentationIOS'
124
+ );
125
+ };
126
+
114
127
  const getIsModal = (
115
128
  scene: Scene,
116
129
  interpolationIndex: number,
@@ -162,7 +175,8 @@ const getHeaderHeights = (
162
175
 
163
176
  const getDistanceFromOptions = (
164
177
  layout: Layout,
165
- descriptor?: StackDescriptor
178
+ descriptor: StackDescriptor | undefined,
179
+ isRTL: boolean
166
180
  ) => {
167
181
  const {
168
182
  presentation,
@@ -171,13 +185,14 @@ const getDistanceFromOptions = (
171
185
  : DefaultTransition.gestureDirection,
172
186
  } = (descriptor?.options || {}) as StackNavigationOptions;
173
187
 
174
- return getDistanceForDirection(layout, gestureDirection);
188
+ return getDistanceForDirection(layout, gestureDirection, isRTL);
175
189
  };
176
190
 
177
191
  const getProgressFromGesture = (
178
192
  gesture: Animated.Value,
179
193
  layout: Layout,
180
- descriptor?: StackDescriptor
194
+ descriptor: StackDescriptor | undefined,
195
+ isRTL: boolean
181
196
  ) => {
182
197
  const distance = getDistanceFromOptions(
183
198
  {
@@ -186,7 +201,8 @@ const getProgressFromGesture = (
186
201
  width: Math.max(1, layout.width),
187
202
  height: Math.max(1, layout.height),
188
203
  },
189
- descriptor
204
+ descriptor,
205
+ isRTL
190
206
  );
191
207
 
192
208
  if (distance > 0) {
@@ -214,158 +230,181 @@ export class CardStack extends React.Component<Props, State> {
214
230
  return null;
215
231
  }
216
232
 
217
- const gestures = props.routes.reduce<GestureValues>((acc, curr) => {
218
- const descriptor = props.descriptors[curr.key];
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];
219
239
  const { animationEnabled } = descriptor?.options || {};
220
240
 
221
241
  acc[curr.key] =
222
242
  state.gestures[curr.key] ||
223
243
  new Animated.Value(
224
- props.openingRouteKeys.includes(curr.key) &&
225
- animationEnabled !== false
226
- ? getDistanceFromOptions(state.layout, descriptor)
244
+ (props.openingRouteKeys.includes(curr.key) &&
245
+ animationEnabled !== false) ||
246
+ props.state.preloadedRoutes.includes(curr)
247
+ ? getDistanceFromOptions(
248
+ state.layout,
249
+ descriptor,
250
+ props.direction === 'rtl'
251
+ )
227
252
  : 0
228
253
  );
229
254
 
230
255
  return acc;
231
256
  }, {});
232
257
 
233
- const scenes = props.routes.map((route, index, self) => {
234
- const previousRoute = self[index - 1];
235
- const nextRoute = self[index + 1];
236
-
237
- const oldScene = state.scenes[index];
238
-
239
- const currentGesture = gestures[route.key];
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;
276
-
277
- const {
278
- animationEnabled = Platform.OS !== 'web' &&
279
- Platform.OS !== 'windows' &&
280
- Platform.OS !== 'macos',
281
- gestureEnabled = Platform.OS === 'ios' && animationEnabled,
282
- gestureDirection = defaultTransitionPreset.gestureDirection,
283
- transitionSpec = defaultTransitionPreset.transitionSpec,
284
- cardStyleInterpolator = animationEnabled === false
285
- ? forNoAnimationCard
286
- : defaultTransitionPreset.cardStyleInterpolator,
287
- headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
288
- cardOverlayEnabled = (Platform.OS !== 'ios' &&
289
- optionsForTransitionConfig.presentation !== 'transparentModal') ||
290
- getIsModalPresentation(cardStyleInterpolator),
291
- } = optionsForTransitionConfig;
292
-
293
- const headerMode: StackHeaderMode =
294
- descriptor.options.headerMode ??
295
- (!(
296
- optionsForTransitionConfig.presentation === 'modal' ||
297
- optionsForTransitionConfig.presentation === 'transparentModal' ||
298
- nextDescriptor?.options.presentation === 'modal' ||
299
- nextDescriptor?.options.presentation === 'transparentModal' ||
300
- getIsModalPresentation(cardStyleInterpolator)
301
- ) &&
302
- Platform.OS === 'ios' &&
303
- descriptor.options.header === undefined
304
- ? 'float'
305
- : 'screen');
306
-
307
- const scene = {
308
- route,
309
- descriptor: {
310
- ...descriptor,
311
- options: {
312
- ...descriptor.options,
313
- animationEnabled,
314
- cardOverlayEnabled,
315
- cardStyleInterpolator,
316
- gestureDirection,
317
- gestureEnabled,
318
- headerStyleInterpolator,
319
- transitionSpec,
320
- headerMode,
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
+ },
321
357
  },
322
- },
323
- progress: {
324
- current: getProgressFromGesture(
325
- currentGesture,
326
- state.layout,
327
- descriptor
328
- ),
329
- next:
330
- nextGesture &&
331
- nextDescriptor?.options.presentation !== 'transparentModal'
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
332
376
  ? getProgressFromGesture(
333
- nextGesture,
377
+ previousGesture,
334
378
  state.layout,
335
- nextDescriptor
379
+ previousDescriptor,
380
+ isRTL
336
381
  )
337
382
  : undefined,
338
- previous: previousGesture
339
- ? getProgressFromGesture(
340
- previousGesture,
341
- state.layout,
342
- previousDescriptor
343
- )
344
- : undefined,
345
- },
346
- __memo: [
347
- state.layout,
348
- descriptor,
349
- nextDescriptor,
350
- previousDescriptor,
351
- currentGesture,
352
- nextGesture,
353
- previousGesture,
354
- ],
355
- };
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
+ }
356
404
 
357
- if (
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;
405
+ return scene;
365
406
  }
366
-
367
- return scene;
368
- });
407
+ );
369
408
 
370
409
  return {
371
410
  routes: props.routes,
@@ -480,7 +519,6 @@ export class CardStack extends React.Component<Props, State> {
480
519
  onOpenRoute,
481
520
  onCloseRoute,
482
521
  renderHeader,
483
- renderScene,
484
522
  isParentHeaderShown,
485
523
  isParentModal,
486
524
  onTransitionStart,
@@ -522,16 +560,16 @@ export class CardStack extends React.Component<Props, State> {
522
560
  detachPreviousScreen = options.presentation === 'transparentModal'
523
561
  ? false
524
562
  : getIsModalPresentation(options.cardStyleInterpolator)
525
- ? i !==
526
- findLastIndex(scenes, (scene) => {
527
- const { cardStyleInterpolator } = scene.descriptor.options;
528
-
529
- return (
530
- cardStyleInterpolator === forModalPresentationIOS ||
531
- cardStyleInterpolator?.name === 'forModalPresentationIOS'
532
- );
533
- })
534
- : true,
563
+ ? i !==
564
+ findLastIndex(scenes, (scene) => {
565
+ const { cardStyleInterpolator } = scene.descriptor.options;
566
+
567
+ return (
568
+ cardStyleInterpolator === forModalPresentationIOS ||
569
+ cardStyleInterpolator?.name === 'forModalPresentationIOS'
570
+ );
571
+ })
572
+ : true,
535
573
  } = options;
536
574
 
537
575
  if (detachPreviousScreen === false) {
@@ -575,10 +613,23 @@ export class CardStack extends React.Component<Props, State> {
575
613
  style={styles.container}
576
614
  onLayout={this.handleLayout}
577
615
  >
578
- {routes.map((route, index, self) => {
616
+ {[...routes, ...state.preloadedRoutes].map((route, index) => {
579
617
  const focused = focusedRoute.key === route.key;
580
618
  const gesture = gestures[route.key];
581
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
+ }
582
633
 
583
634
  // For the screens that shouldn't be active, the value is 0
584
635
  // For those that should be active, but are not the top screen, the value is 1
@@ -590,17 +641,17 @@ export class CardStack extends React.Component<Props, State> {
590
641
  | 1
591
642
  | 2 = 1;
592
643
 
593
- if (index < self.length - activeScreensLimit - 1) {
644
+ if (index < routes.length - activeScreensLimit - 1 || isPreloaded) {
594
645
  // screen should be inactive because it is too deep in the stack
595
646
  isScreenActive = STATE_INACTIVE;
596
647
  } else {
597
- const sceneForActivity = scenes[self.length - 1];
648
+ const sceneForActivity = scenes[routes.length - 1];
598
649
  const outputValue =
599
- index === self.length - 1
650
+ index === routes.length - 1
600
651
  ? STATE_ON_TOP // the screen is on top after the transition
601
- : index >= self.length - activeScreensLimit
602
- ? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
603
- : STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
652
+ : index >= routes.length - activeScreensLimit
653
+ ? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
654
+ : STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
604
655
  isScreenActive = sceneForActivity
605
656
  ? sceneForActivity.progress.current.interpolate({
606
657
  inputRange: [0, 1 - EPSILON, 1],
@@ -613,9 +664,8 @@ export class CardStack extends React.Component<Props, State> {
613
664
  const {
614
665
  headerShown = true,
615
666
  headerTransparent,
616
- headerStyle,
617
- headerTintColor,
618
667
  freezeOnBlur,
668
+ autoHideHomeIndicator,
619
669
  } = scene.descriptor.options;
620
670
 
621
671
  const safeAreaInsetTop = insets.top;
@@ -626,26 +676,6 @@ export class CardStack extends React.Component<Props, State> {
626
676
  const headerHeight =
627
677
  headerShown !== false ? headerHeights[route.key] : 0;
628
678
 
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
679
  // Start from current card and count backwards the number of cards with same interpolation
650
680
  const interpolationIndex = getInterpolationIndex(scenes, index);
651
681
  const isModal = getIsModal(
@@ -665,17 +695,18 @@ export class CardStack extends React.Component<Props, State> {
665
695
  return (
666
696
  <MaybeScreen
667
697
  key={route.key}
668
- style={StyleSheet.absoluteFill}
698
+ style={[StyleSheet.absoluteFill]}
669
699
  enabled={detachInactiveScreens}
670
700
  active={isScreenActive}
671
701
  freezeOnBlur={freezeOnBlur}
702
+ homeIndicatorHidden={autoHideHomeIndicator}
672
703
  pointerEvents="box-none"
673
704
  >
674
705
  <CardContainer
675
706
  index={index}
676
707
  interpolationIndex={interpolationIndex}
677
708
  modal={isModal}
678
- active={index === self.length - 1}
709
+ active={index === routes.length - 1}
679
710
  focused={focused}
680
711
  closing={closingRouteKeys.includes(route.key)}
681
712
  layout={layout}
@@ -693,18 +724,17 @@ export class CardStack extends React.Component<Props, State> {
693
724
  onHeaderHeightChange={this.handleHeaderLayout}
694
725
  getPreviousScene={this.getPreviousScene}
695
726
  getFocusedRoute={this.getFocusedRoute}
696
- headerDarkContent={headerDarkContent}
697
727
  hasAbsoluteFloatHeader={
698
728
  isFloatHeaderAbsolute && !headerTransparent
699
729
  }
700
730
  renderHeader={renderHeader}
701
- renderScene={renderScene}
702
731
  onOpenRoute={onOpenRoute}
703
732
  onCloseRoute={onCloseRoute}
704
733
  onTransitionStart={onTransitionStart}
705
734
  onTransitionEnd={onTransitionEnd}
706
735
  isNextScreenTransparent={isNextScreenTransparent}
707
736
  detachCurrentScreen={detachCurrentScreen}
737
+ preloaded={isPreloaded}
708
738
  />
709
739
  </MaybeScreen>
710
740
  );