@react-navigation/native-stack 7.0.0-rc.3 → 7.0.0-rc.30

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 (142) hide show
  1. package/lib/commonjs/index.js +2 -2
  2. package/lib/commonjs/navigators/createNativeStackNavigator.js +11 -6
  3. package/lib/commonjs/navigators/createNativeStackNavigator.js.map +1 -1
  4. package/lib/commonjs/package.json +1 -0
  5. package/lib/commonjs/utils/debounce.js.map +1 -1
  6. package/lib/commonjs/views/FooterComponent.js +19 -0
  7. package/lib/commonjs/views/FooterComponent.js.map +1 -0
  8. package/lib/commonjs/views/NativeStackView.js +106 -106
  9. package/lib/commonjs/views/NativeStackView.js.map +1 -1
  10. package/lib/commonjs/views/NativeStackView.native.js +221 -219
  11. package/lib/commonjs/views/NativeStackView.native.js.map +1 -1
  12. package/lib/commonjs/views/{HeaderConfig.js → useHeaderConfigProps.js} +84 -43
  13. package/lib/commonjs/views/useHeaderConfigProps.js.map +1 -0
  14. package/lib/module/index.js +4 -2
  15. package/lib/module/index.js.map +1 -1
  16. package/lib/module/navigators/createNativeStackNavigator.js +13 -6
  17. package/lib/module/navigators/createNativeStackNavigator.js.map +1 -1
  18. package/lib/module/package.json +1 -0
  19. package/lib/module/types.js +2 -0
  20. package/lib/module/utils/debounce.js +2 -0
  21. package/lib/module/utils/debounce.js.map +1 -1
  22. package/lib/module/utils/getModalRoutesKeys.js +2 -0
  23. package/lib/module/utils/getModalRoutesKeys.js.map +1 -1
  24. package/lib/module/utils/useAnimatedHeaderHeight.js +2 -0
  25. package/lib/module/utils/useAnimatedHeaderHeight.js.map +1 -1
  26. package/lib/module/utils/useDismissedRouteError.js +2 -0
  27. package/lib/module/utils/useDismissedRouteError.js.map +1 -1
  28. package/lib/module/utils/useInvalidPreventRemoveError.js +2 -0
  29. package/lib/module/utils/useInvalidPreventRemoveError.js.map +1 -1
  30. package/lib/module/views/FontProcessor.js +2 -0
  31. package/lib/module/views/FontProcessor.js.map +1 -1
  32. package/lib/module/views/FontProcessor.native.js +2 -0
  33. package/lib/module/views/FontProcessor.native.js.map +1 -1
  34. package/lib/module/views/FooterComponent.js +14 -0
  35. package/lib/module/views/FooterComponent.js.map +1 -0
  36. package/lib/module/views/NativeStackView.js +110 -108
  37. package/lib/module/views/NativeStackView.js.map +1 -1
  38. package/lib/module/views/NativeStackView.native.js +224 -219
  39. package/lib/module/views/NativeStackView.native.js.map +1 -1
  40. package/lib/module/views/{HeaderConfig.js → useHeaderConfigProps.js} +86 -41
  41. package/lib/module/views/useHeaderConfigProps.js.map +1 -0
  42. package/lib/typescript/commonjs/package.json +1 -0
  43. package/lib/typescript/{src → commonjs/src}/index.d.ts +1 -1
  44. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  45. package/lib/typescript/{src → commonjs/src}/navigators/createNativeStackNavigator.d.ts +3 -4
  46. package/lib/typescript/commonjs/src/navigators/createNativeStackNavigator.d.ts.map +1 -0
  47. package/lib/typescript/{src → commonjs/src}/types.d.ts +112 -34
  48. package/lib/typescript/commonjs/src/types.d.ts.map +1 -0
  49. package/lib/typescript/commonjs/src/utils/debounce.d.ts.map +1 -0
  50. package/lib/typescript/commonjs/src/utils/getModalRoutesKeys.d.ts.map +1 -0
  51. package/lib/typescript/commonjs/src/utils/useAnimatedHeaderHeight.d.ts.map +1 -0
  52. package/lib/typescript/commonjs/src/utils/useDismissedRouteError.d.ts.map +1 -0
  53. package/lib/typescript/commonjs/src/utils/useInvalidPreventRemoveError.d.ts.map +1 -0
  54. package/lib/typescript/commonjs/src/views/FontProcessor.d.ts.map +1 -0
  55. package/lib/typescript/commonjs/src/views/FontProcessor.native.d.ts.map +1 -0
  56. package/lib/typescript/commonjs/src/views/FooterComponent.d.ts +7 -0
  57. package/lib/typescript/commonjs/src/views/FooterComponent.d.ts.map +1 -0
  58. package/lib/typescript/commonjs/src/views/NativeStackView.d.ts +11 -0
  59. package/lib/typescript/commonjs/src/views/NativeStackView.d.ts.map +1 -0
  60. package/lib/typescript/commonjs/src/views/NativeStackView.native.d.ts +11 -0
  61. package/lib/typescript/commonjs/src/views/NativeStackView.native.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/src/views/useHeaderConfigProps.d.ts +41 -0
  63. package/lib/typescript/commonjs/src/views/useHeaderConfigProps.d.ts.map +1 -0
  64. package/lib/typescript/commonjs/tsconfig.build.tsbuildinfo +1 -0
  65. package/lib/typescript/module/package.json +1 -0
  66. package/lib/typescript/module/src/index.d.ts +17 -0
  67. package/lib/typescript/module/src/index.d.ts.map +1 -0
  68. package/lib/typescript/module/src/navigators/createNativeStackNavigator.d.ts +16 -0
  69. package/lib/typescript/module/src/navigators/createNativeStackNavigator.d.ts.map +1 -0
  70. package/lib/typescript/module/src/types.d.ts +623 -0
  71. package/lib/typescript/module/src/types.d.ts.map +1 -0
  72. package/lib/typescript/module/src/utils/debounce.d.ts +2 -0
  73. package/lib/typescript/module/src/utils/debounce.d.ts.map +1 -0
  74. package/lib/typescript/module/src/utils/getModalRoutesKeys.d.ts +4 -0
  75. package/lib/typescript/module/src/utils/getModalRoutesKeys.d.ts.map +1 -0
  76. package/lib/typescript/module/src/utils/useAnimatedHeaderHeight.d.ts +5 -0
  77. package/lib/typescript/module/src/utils/useAnimatedHeaderHeight.d.ts.map +1 -0
  78. package/lib/typescript/module/src/utils/useDismissedRouteError.d.ts +6 -0
  79. package/lib/typescript/module/src/utils/useDismissedRouteError.d.ts.map +1 -0
  80. package/lib/typescript/module/src/utils/useInvalidPreventRemoveError.d.ts +3 -0
  81. package/lib/typescript/module/src/utils/useInvalidPreventRemoveError.d.ts.map +1 -0
  82. package/lib/typescript/module/src/views/FontProcessor.d.ts +2 -0
  83. package/lib/typescript/module/src/views/FontProcessor.d.ts.map +1 -0
  84. package/lib/typescript/module/src/views/FontProcessor.native.d.ts +2 -0
  85. package/lib/typescript/module/src/views/FontProcessor.native.d.ts.map +1 -0
  86. package/lib/typescript/module/src/views/FooterComponent.d.ts +7 -0
  87. package/lib/typescript/module/src/views/FooterComponent.d.ts.map +1 -0
  88. package/lib/typescript/module/src/views/NativeStackView.d.ts +11 -0
  89. package/lib/typescript/module/src/views/NativeStackView.d.ts.map +1 -0
  90. package/lib/typescript/module/src/views/NativeStackView.native.d.ts +11 -0
  91. package/lib/typescript/module/src/views/NativeStackView.native.d.ts.map +1 -0
  92. package/lib/typescript/module/src/views/useHeaderConfigProps.d.ts +41 -0
  93. package/lib/typescript/module/src/views/useHeaderConfigProps.d.ts.map +1 -0
  94. package/lib/typescript/module/tsconfig.build.tsbuildinfo +1 -0
  95. package/package.json +41 -18
  96. package/src/index.tsx +2 -0
  97. package/src/navigators/createNativeStackNavigator.tsx +6 -7
  98. package/src/types.tsx +106 -34
  99. package/src/utils/debounce.tsx +1 -1
  100. package/src/views/FooterComponent.tsx +10 -0
  101. package/src/views/NativeStackView.native.tsx +167 -202
  102. package/src/views/NativeStackView.tsx +62 -50
  103. package/src/views/{HeaderConfig.tsx → useHeaderConfigProps.tsx} +80 -68
  104. package/lib/commonjs/views/DebugContainer.js +0 -19
  105. package/lib/commonjs/views/DebugContainer.js.map +0 -1
  106. package/lib/commonjs/views/DebugContainer.native.js +0 -42
  107. package/lib/commonjs/views/DebugContainer.native.js.map +0 -1
  108. package/lib/commonjs/views/HeaderConfig.js.map +0 -1
  109. package/lib/module/views/DebugContainer.js +0 -11
  110. package/lib/module/views/DebugContainer.js.map +0 -1
  111. package/lib/module/views/DebugContainer.native.js +0 -33
  112. package/lib/module/views/DebugContainer.native.js.map +0 -1
  113. package/lib/module/views/HeaderConfig.js.map +0 -1
  114. package/lib/typescript/src/index.d.ts.map +0 -1
  115. package/lib/typescript/src/navigators/createNativeStackNavigator.d.ts.map +0 -1
  116. package/lib/typescript/src/types.d.ts.map +0 -1
  117. package/lib/typescript/src/utils/debounce.d.ts.map +0 -1
  118. package/lib/typescript/src/utils/getModalRoutesKeys.d.ts.map +0 -1
  119. package/lib/typescript/src/utils/useAnimatedHeaderHeight.d.ts.map +0 -1
  120. package/lib/typescript/src/utils/useDismissedRouteError.d.ts.map +0 -1
  121. package/lib/typescript/src/utils/useInvalidPreventRemoveError.d.ts.map +0 -1
  122. package/lib/typescript/src/views/DebugContainer.d.ts +0 -10
  123. package/lib/typescript/src/views/DebugContainer.d.ts.map +0 -1
  124. package/lib/typescript/src/views/DebugContainer.native.d.ts +0 -15
  125. package/lib/typescript/src/views/DebugContainer.native.d.ts.map +0 -1
  126. package/lib/typescript/src/views/FontProcessor.d.ts.map +0 -1
  127. package/lib/typescript/src/views/FontProcessor.native.d.ts.map +0 -1
  128. package/lib/typescript/src/views/HeaderConfig.d.ts +0 -11
  129. package/lib/typescript/src/views/HeaderConfig.d.ts.map +0 -1
  130. package/lib/typescript/src/views/NativeStackView.d.ts +0 -11
  131. package/lib/typescript/src/views/NativeStackView.d.ts.map +0 -1
  132. package/lib/typescript/src/views/NativeStackView.native.d.ts +0 -11
  133. package/lib/typescript/src/views/NativeStackView.native.d.ts.map +0 -1
  134. package/src/views/DebugContainer.native.tsx +0 -36
  135. package/src/views/DebugContainer.tsx +0 -14
  136. /package/lib/typescript/{src → commonjs/src}/utils/debounce.d.ts +0 -0
  137. /package/lib/typescript/{src → commonjs/src}/utils/getModalRoutesKeys.d.ts +0 -0
  138. /package/lib/typescript/{src → commonjs/src}/utils/useAnimatedHeaderHeight.d.ts +0 -0
  139. /package/lib/typescript/{src → commonjs/src}/utils/useDismissedRouteError.d.ts +0 -0
  140. /package/lib/typescript/{src → commonjs/src}/utils/useInvalidPreventRemoveError.d.ts +0 -0
  141. /package/lib/typescript/{src → commonjs/src}/views/FontProcessor.d.ts +0 -0
  142. /package/lib/typescript/{src → commonjs/src}/views/FontProcessor.native.d.ts +0 -0
@@ -10,7 +10,7 @@ import {
10
10
  NavigationContext,
11
11
  NavigationRouteContext,
12
12
  type ParamListBase,
13
- type Route,
13
+ type RouteProp,
14
14
  StackActions,
15
15
  type StackNavigationState,
16
16
  usePreventRemoveContext,
@@ -30,104 +30,25 @@ import {
30
30
  useSafeAreaInsets,
31
31
  } from 'react-native-safe-area-context';
32
32
  import {
33
- Screen,
34
33
  type ScreenProps,
35
34
  ScreenStack,
36
- type StackPresentationTypes,
35
+ ScreenStackItem,
37
36
  } from 'react-native-screens';
38
- import warnOnce from 'warn-once';
39
37
 
40
38
  import type {
41
39
  NativeStackDescriptor,
42
40
  NativeStackDescriptorMap,
43
41
  NativeStackNavigationHelpers,
44
- NativeStackNavigationOptions,
45
42
  } from '../types';
46
43
  import { debounce } from '../utils/debounce';
47
44
  import { getModalRouteKeys } from '../utils/getModalRoutesKeys';
48
45
  import { AnimatedHeaderHeightContext } from '../utils/useAnimatedHeaderHeight';
49
46
  import { useDismissedRouteError } from '../utils/useDismissedRouteError';
50
47
  import { useInvalidPreventRemoveError } from '../utils/useInvalidPreventRemoveError';
51
- import { DebugContainer } from './DebugContainer';
52
- import { HeaderConfig } from './HeaderConfig';
53
-
54
- const isAndroid = Platform.OS === 'android';
55
-
56
- const MaybeNestedStack = ({
57
- options,
58
- route,
59
- presentation,
60
- headerHeight,
61
- headerTopInsetEnabled,
62
- children,
63
- }: {
64
- options: NativeStackNavigationOptions;
65
- route: Route<string>;
66
- presentation: Exclude<StackPresentationTypes, 'push'> | 'card';
67
- headerHeight: number;
68
- headerTopInsetEnabled: boolean;
69
- children: React.ReactNode;
70
- }) => {
71
- const { colors } = useTheme();
72
- const { header, headerShown = true, contentStyle } = options;
73
-
74
- const isHeaderInModal = isAndroid
75
- ? false
76
- : presentation !== 'card' && headerShown === true && header === undefined;
77
-
78
- const headerShownPreviousRef = React.useRef(headerShown);
79
-
80
- React.useEffect(() => {
81
- warnOnce(
82
- !isAndroid &&
83
- presentation !== 'card' &&
84
- headerShownPreviousRef.current !== headerShown,
85
- `Dynamically changing 'headerShown' in modals will result in remounting the screen and losing all local state. See options for the screen '${route.name}'.`
86
- );
87
-
88
- headerShownPreviousRef.current = headerShown;
89
- }, [headerShown, presentation, route.name]);
90
-
91
- const content = (
92
- <DebugContainer
93
- style={[
94
- styles.container,
95
- presentation !== 'transparentModal' &&
96
- presentation !== 'containedTransparentModal' && {
97
- backgroundColor: colors.background,
98
- },
99
- contentStyle,
100
- ]}
101
- stackPresentation={presentation === 'card' ? 'push' : presentation}
102
- >
103
- {children}
104
- </DebugContainer>
105
- );
48
+ import { FooterComponent } from './FooterComponent';
49
+ import { useHeaderConfigProps } from './useHeaderConfigProps';
106
50
 
107
- if (isHeaderInModal) {
108
- return (
109
- <ScreenStack style={styles.container}>
110
- <Screen
111
- enabled
112
- isNativeStack
113
- hasLargeHeader={options.headerLargeTitle ?? false}
114
- style={StyleSheet.absoluteFill}
115
- >
116
- {content}
117
- <HeaderConfig
118
- {...options}
119
- route={route}
120
- headerHeight={headerHeight}
121
- headerTopInsetEnabled={headerTopInsetEnabled}
122
- canGoBack
123
- />
124
- </Screen>
125
- </ScreenStack>
126
- );
127
- }
128
-
129
- return content;
130
- };
51
+ const ANDROID_DEFAULT_HEADER_HEIGHT = 56;
131
52
 
132
53
  type SceneViewProps = {
133
54
  index: number;
@@ -136,6 +57,7 @@ type SceneViewProps = {
136
57
  previousDescriptor?: NativeStackDescriptor;
137
58
  nextDescriptor?: NativeStackDescriptor;
138
59
  isPresentationModal?: boolean;
60
+ isPreloaded?: boolean;
139
61
  onWillDisappear: () => void;
140
62
  onWillAppear: () => void;
141
63
  onAppear: () => void;
@@ -144,6 +66,7 @@ type SceneViewProps = {
144
66
  onHeaderBackButtonClicked: ScreenProps['onHeaderBackButtonClicked'];
145
67
  onNativeDismissCancelled: ScreenProps['onDismissed'];
146
68
  onGestureCancel: ScreenProps['onGestureCancel'];
69
+ onSheetDetentChanged: ScreenProps['onSheetDetentChanged'];
147
70
  };
148
71
 
149
72
  const SceneView = ({
@@ -153,6 +76,7 @@ const SceneView = ({
153
76
  previousDescriptor,
154
77
  nextDescriptor,
155
78
  isPresentationModal,
79
+ isPreloaded,
156
80
  onWillDisappear,
157
81
  onWillAppear,
158
82
  onAppear,
@@ -161,6 +85,7 @@ const SceneView = ({
161
85
  onHeaderBackButtonClicked,
162
86
  onNativeDismissCancelled,
163
87
  onGestureCancel,
88
+ onSheetDetentChanged,
164
89
  }: SceneViewProps) => {
165
90
  const { route, navigation, options, render } = descriptor;
166
91
 
@@ -174,6 +99,7 @@ const SceneView = ({
174
99
  const {
175
100
  animationDuration,
176
101
  animationTypeForReplace = 'push',
102
+ fullScreenGestureShadowEnabled = false,
177
103
  gestureEnabled,
178
104
  gestureDirection = presentation === 'card' ? 'horizontal' : 'vertical',
179
105
  gestureResponseDistance,
@@ -188,17 +114,21 @@ const SceneView = ({
188
114
  navigationBarTranslucent,
189
115
  navigationBarHidden,
190
116
  orientation,
191
- sheetAllowedDetents = 'large',
192
- sheetLargestUndimmedDetent = 'all',
117
+ sheetAllowedDetents = [1.0],
118
+ sheetLargestUndimmedDetentIndex = -1,
193
119
  sheetGrabberVisible = false,
194
120
  sheetCornerRadius = -1.0,
121
+ sheetElevation = 24,
195
122
  sheetExpandsWhenScrolledToEdge = true,
123
+ sheetInitialDetentIndex = 0,
196
124
  statusBarAnimation,
197
125
  statusBarHidden,
198
126
  statusBarStyle,
199
127
  statusBarTranslucent,
200
128
  statusBarBackgroundColor,
129
+ unstable_sheetFooter = null,
201
130
  freezeOnBlur,
131
+ contentStyle,
202
132
  } = options;
203
133
 
204
134
  if (gestureDirection === 'vertical' && Platform.OS === 'ios') {
@@ -232,6 +162,7 @@ const SceneView = ({
232
162
  presentation = 'card';
233
163
  }
234
164
 
165
+ const { colors } = useTheme();
235
166
  const insets = useSafeAreaInsets();
236
167
  const frame = useSafeAreaFrame();
237
168
 
@@ -259,7 +190,7 @@ const SceneView = ({
259
190
  // FIXME: Currently screens isn't using Material 3
260
191
  // So our `getDefaultHeaderHeight` doesn't return the correct value
261
192
  // So we hardcode the value here for now until screens is updated
262
- android: 56 + topInset,
193
+ android: ANDROID_DEFAULT_HEADER_HEIGHT + topInset,
263
194
  default: getDefaultHeaderHeight(frame, isModal, topInset),
264
195
  });
265
196
 
@@ -276,7 +207,7 @@ const SceneView = ({
276
207
 
277
208
  let headerHeightCorrectionOffset = 0;
278
209
 
279
- if (isAndroid && !hasCustomHeader) {
210
+ if (Platform.OS === 'android' && !hasCustomHeader) {
280
211
  const statusBarHeight = StatusBar.currentHeight ?? 0;
281
212
 
282
213
  // FIXME: On Android, the native header height is not correctly calculated
@@ -307,32 +238,54 @@ const SceneView = ({
307
238
  ? statusBarTranslucent
308
239
  : topInset !== 0;
309
240
 
241
+ const canGoBack = previousDescriptor != null || parentHeaderBack != null;
310
242
  const backTitle = previousDescriptor
311
243
  ? getHeaderTitle(previousDescriptor.options, previousDescriptor.route.name)
312
244
  : parentHeaderBack?.title;
313
245
 
314
- const headerBack = React.useMemo(
315
- () => ({
316
- // No href needed for native
317
- href: undefined,
318
- title: backTitle,
319
- }),
320
- [backTitle]
321
- );
246
+ const headerBack = React.useMemo(() => {
247
+ if (canGoBack) {
248
+ return {
249
+ href: undefined, // No href needed for native
250
+ title: backTitle,
251
+ };
252
+ }
253
+
254
+ return undefined;
255
+ }, [canGoBack, backTitle]);
322
256
 
323
257
  const isRemovePrevented = preventedRoutes[route.key]?.preventRemove;
324
258
 
259
+ const headerConfig = useHeaderConfigProps({
260
+ ...options,
261
+ route,
262
+ canGoBack,
263
+ headerBackButtonMenuEnabled:
264
+ isRemovePrevented !== undefined
265
+ ? !isRemovePrevented
266
+ : headerBackButtonMenuEnabled,
267
+ headerBackTitle:
268
+ options.headerBackTitle !== undefined
269
+ ? options.headerBackTitle
270
+ : undefined,
271
+ headerHeight,
272
+ headerShown: header !== undefined ? false : headerShown,
273
+ headerTopInsetEnabled,
274
+ });
275
+
325
276
  return (
326
- <Screen
277
+ <ScreenStackItem
327
278
  key={route.key}
328
- enabled
329
- isNativeStack
279
+ activityState={isPreloaded ? 0 : 2}
330
280
  style={StyleSheet.absoluteFill}
331
- hasLargeHeader={options.headerLargeTitle ?? false}
281
+ accessibilityElementsHidden={!focused}
282
+ importantForAccessibility={focused ? 'auto' : 'no-hide-descendants'}
332
283
  customAnimationOnSwipe={animationMatchesGesture}
333
284
  fullScreenSwipeEnabled={fullScreenGestureEnabled}
285
+ fullScreenSwipeShadowEnabled={fullScreenGestureShadowEnabled}
286
+ freezeOnBlur={freezeOnBlur}
334
287
  gestureEnabled={
335
- isAndroid
288
+ Platform.OS === 'android'
336
289
  ? // This prop enables handling of system back gestures on Android
337
290
  // Since we handle them in JS side, we disable this
338
291
  false
@@ -341,7 +294,6 @@ const SceneView = ({
341
294
  homeIndicatorHidden={autoHideHomeIndicator}
342
295
  hideKeyboardOnSwipe={keyboardHandlingEnabled}
343
296
  navigationBarColor={navigationBarColor}
344
- // @ts-expect-error prop supported from react-native-screens 3.32.0 onwards
345
297
  navigationBarTranslucent={navigationBarTranslucent}
346
298
  navigationBarHidden={navigationBarHidden}
347
299
  replaceAnimation={animationTypeForReplace}
@@ -349,9 +301,11 @@ const SceneView = ({
349
301
  stackAnimation={animation}
350
302
  screenOrientation={orientation}
351
303
  sheetAllowedDetents={sheetAllowedDetents}
352
- sheetLargestUndimmedDetent={sheetLargestUndimmedDetent}
304
+ sheetLargestUndimmedDetentIndex={sheetLargestUndimmedDetentIndex}
353
305
  sheetGrabberVisible={sheetGrabberVisible}
306
+ sheetInitialDetentIndex={sheetInitialDetentIndex}
354
307
  sheetCornerRadius={sheetCornerRadius}
308
+ sheetElevation={sheetElevation}
355
309
  sheetExpandsWhenScrolledToEdge={sheetExpandsWhenScrolledToEdge}
356
310
  statusBarAnimation={statusBarAnimation}
357
311
  statusBarHidden={statusBarHidden}
@@ -366,6 +320,7 @@ const SceneView = ({
366
320
  onDisappear={onDisappear}
367
321
  onDismissed={onDismissed}
368
322
  onGestureCancel={onGestureCancel}
323
+ onSheetDetentChanged={onSheetDetentChanged}
369
324
  gestureResponseDistance={gestureResponseDistance}
370
325
  nativeBackButtonDismissalEnabled={false} // on Android
371
326
  onHeaderBackButtonClicked={onHeaderBackButtonClicked}
@@ -386,6 +341,16 @@ const SceneView = ({
386
341
  {
387
342
  useNativeDriver: true,
388
343
  listener: (e) => {
344
+ if (
345
+ Platform.OS === 'android' &&
346
+ (options.headerBackground != null || options.headerTransparent)
347
+ ) {
348
+ // FIXME: On Android, we get 0 if the header is translucent
349
+ // So we set a default height in that case
350
+ setHeaderHeight(ANDROID_DEFAULT_HEADER_HEIGHT + topInset);
351
+ return;
352
+ }
353
+
389
354
  if (
390
355
  e.nativeEvent &&
391
356
  typeof e.nativeEvent === 'object' &&
@@ -410,107 +375,77 @@ const SceneView = ({
410
375
  },
411
376
  }
412
377
  )}
413
- // this prop is available since rn-screens 3.16
414
- freezeOnBlur={freezeOnBlur}
378
+ contentStyle={[
379
+ presentation !== 'transparentModal' &&
380
+ presentation !== 'containedTransparentModal' && {
381
+ backgroundColor: colors.background,
382
+ },
383
+ contentStyle,
384
+ ]}
385
+ headerConfig={headerConfig}
386
+ // When ts-expect-error is added, it affects all the props below it
387
+ // So we keep any props that need it at the end
388
+ // Otherwise invalid props may not be caught by TypeScript
415
389
  >
416
390
  <NavigationContext.Provider value={navigation}>
417
391
  <NavigationRouteContext.Provider value={route}>
418
- <HeaderShownContext.Provider
419
- value={isParentHeaderShown || headerShown !== false}
420
- >
421
- <AnimatedHeaderHeightContext.Provider value={animatedHeaderHeight}>
422
- <HeaderHeightContext.Provider
423
- value={
424
- headerShown !== false ? headerHeight : parentHeaderHeight ?? 0
425
- }
426
- >
427
- {headerBackground != null ? (
428
- /**
429
- * To show a custom header background, we render it at the top of the screen below the header
430
- * The header also needs to be positioned absolutely (with `translucent` style)
431
- */
432
- <View
433
- style={[
434
- styles.background,
435
- headerTransparent ? styles.translucent : null,
436
- { height: headerHeight },
437
- ]}
438
- >
439
- {headerBackground()}
440
- </View>
441
- ) : null}
392
+ <AnimatedHeaderHeightContext.Provider value={animatedHeaderHeight}>
393
+ <HeaderHeightContext.Provider
394
+ value={
395
+ headerShown !== false ? headerHeight : parentHeaderHeight ?? 0
396
+ }
397
+ >
398
+ {headerBackground != null ? (
399
+ /**
400
+ * To show a custom header background, we render it at the top of the screen below the header
401
+ * The header also needs to be positioned absolutely (with `translucent` style)
402
+ */
403
+ <View
404
+ style={[
405
+ styles.background,
406
+ headerTransparent ? styles.translucent : null,
407
+ { height: headerHeight },
408
+ ]}
409
+ >
410
+ {headerBackground()}
411
+ </View>
412
+ ) : null}
413
+ {header !== undefined && headerShown !== false ? (
442
414
  <View
443
- accessibilityElementsHidden={!focused}
444
- importantForAccessibility={
445
- focused ? 'auto' : 'no-hide-descendants'
446
- }
447
- style={styles.scene}
415
+ onLayout={(e) => {
416
+ const headerHeight = e.nativeEvent.layout.height;
417
+
418
+ setHeaderHeight(headerHeight);
419
+ rawAnimatedHeaderHeight.setValue(headerHeight);
420
+ }}
421
+ style={[
422
+ styles.header,
423
+ headerTransparent ? styles.absolute : null,
424
+ ]}
448
425
  >
449
- <MaybeNestedStack
450
- options={options}
451
- route={route}
452
- presentation={presentation}
453
- headerHeight={headerHeight}
454
- headerTopInsetEnabled={headerTopInsetEnabled}
455
- >
456
- <HeaderBackContext.Provider value={headerBack}>
457
- {render()}
458
- </HeaderBackContext.Provider>
459
- </MaybeNestedStack>
460
- {header !== undefined && headerShown !== false ? (
461
- <View
462
- onLayout={(e) => {
463
- const headerHeight = e.nativeEvent.layout.height;
464
-
465
- setHeaderHeight(headerHeight);
466
- rawAnimatedHeaderHeight.setValue(headerHeight);
467
- }}
468
- style={headerTransparent ? styles.absolute : null}
469
- >
470
- {header({
471
- back: headerBack,
472
- options,
473
- route,
474
- navigation,
475
- })}
476
- </View>
477
- ) : null}
426
+ {header({
427
+ back: headerBack,
428
+ options,
429
+ route,
430
+ navigation,
431
+ })}
478
432
  </View>
479
- {/**
480
- * `HeaderConfig` needs to be the direct child of `Screen` without any intermediate `View`
481
- * We don't render it conditionally to make it possible to dynamically render a custom `header`
482
- * Otherwise dynamically rendering a custom `header` leaves the native header visible
483
- *
484
- * https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md#screenstackheaderconfig
485
- *
486
- * HeaderConfig must not be first child of a Screen.
487
- * See https://github.com/software-mansion/react-native-screens/pull/1825
488
- * for detailed explanation
489
- */}
490
- <HeaderConfig
491
- {...options}
492
- route={route}
493
- headerBackButtonMenuEnabled={
494
- isRemovePrevented !== undefined
495
- ? !isRemovePrevented
496
- : headerBackButtonMenuEnabled
497
- }
498
- headerShown={header !== undefined ? false : headerShown}
499
- headerHeight={headerHeight}
500
- headerBackTitle={
501
- options.headerBackTitle !== undefined
502
- ? options.headerBackTitle
503
- : undefined
504
- }
505
- headerTopInsetEnabled={headerTopInsetEnabled}
506
- canGoBack={headerBack !== undefined}
507
- />
508
- </HeaderHeightContext.Provider>
509
- </AnimatedHeaderHeightContext.Provider>
510
- </HeaderShownContext.Provider>
433
+ ) : null}
434
+ <HeaderShownContext.Provider
435
+ value={isParentHeaderShown || headerShown !== false}
436
+ >
437
+ <HeaderBackContext.Provider value={headerBack}>
438
+ {render()}
439
+ </HeaderBackContext.Provider>
440
+ </HeaderShownContext.Provider>
441
+ {presentation === 'formSheet' && unstable_sheetFooter && (
442
+ <FooterComponent>{unstable_sheetFooter()}</FooterComponent>
443
+ )}
444
+ </HeaderHeightContext.Provider>
445
+ </AnimatedHeaderHeightContext.Provider>
511
446
  </NavigationRouteContext.Provider>
512
447
  </NavigationContext.Provider>
513
- </Screen>
448
+ </ScreenStackItem>
514
449
  );
515
450
  };
516
451
 
@@ -518,9 +453,18 @@ type Props = {
518
453
  state: StackNavigationState<ParamListBase>;
519
454
  navigation: NativeStackNavigationHelpers;
520
455
  descriptors: NativeStackDescriptorMap;
456
+ describe: (
457
+ route: RouteProp<ParamListBase>,
458
+ placeholder: boolean
459
+ ) => NativeStackDescriptor;
521
460
  };
522
461
 
523
- export function NativeStackView({ state, navigation, descriptors }: Props) {
462
+ export function NativeStackView({
463
+ state,
464
+ navigation,
465
+ descriptors,
466
+ describe,
467
+ }: Props) {
524
468
  const { setNextDismissedKey } = useDismissedRouteError(state);
525
469
 
526
470
  const { colors } = useTheme();
@@ -529,11 +473,18 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
529
473
 
530
474
  const modalRouteKeys = getModalRouteKeys(state.routes, descriptors);
531
475
 
476
+ const preloadedDescriptors =
477
+ state.preloadedRoutes.reduce<NativeStackDescriptorMap>((acc, route) => {
478
+ acc[route.key] = acc[route.key] || describe(route, true);
479
+ return acc;
480
+ }, {});
481
+
532
482
  return (
533
483
  <SafeAreaProviderCompat style={{ backgroundColor: colors.background }}>
534
484
  <ScreenStack style={styles.container}>
535
- {state.routes.map((route, index) => {
536
- const descriptor = descriptors[route.key];
485
+ {state.routes.concat(state.preloadedRoutes).map((route, index) => {
486
+ const descriptor =
487
+ descriptors[route.key] ?? preloadedDescriptors[route.key];
537
488
  const isFocused = state.index === index;
538
489
  const previousKey = state.routes[index - 1]?.key;
539
490
  const nextKey = state.routes[index + 1]?.key;
@@ -544,6 +495,10 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
544
495
 
545
496
  const isModal = modalRouteKeys.includes(route.key);
546
497
 
498
+ const isPreloaded =
499
+ preloadedDescriptors[route.key] !== undefined &&
500
+ descriptors[route.key] === undefined;
501
+
547
502
  return (
548
503
  <SceneView
549
504
  key={route.key}
@@ -553,6 +508,7 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
553
508
  previousDescriptor={previousDescriptor}
554
509
  nextDescriptor={nextDescriptor}
555
510
  isPresentationModal={isModal}
511
+ isPreloaded={isPreloaded}
556
512
  onWillDisappear={() => {
557
513
  navigation.emit({
558
514
  type: 'transitionStart',
@@ -610,6 +566,16 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
610
566
  target: route.key,
611
567
  });
612
568
  }}
569
+ onSheetDetentChanged={(event) => {
570
+ navigation.emit({
571
+ type: 'sheetDetentChange',
572
+ target: route.key,
573
+ data: {
574
+ index: event.nativeEvent.index,
575
+ stable: event.nativeEvent.isStable,
576
+ },
577
+ });
578
+ }}
613
579
  />
614
580
  );
615
581
  })}
@@ -622,9 +588,8 @@ const styles = StyleSheet.create({
622
588
  container: {
623
589
  flex: 1,
624
590
  },
625
- scene: {
626
- flex: 1,
627
- flexDirection: 'column-reverse',
591
+ header: {
592
+ zIndex: 1,
628
593
  },
629
594
  absolute: {
630
595
  position: 'absolute',