@react-navigation/native-stack 7.0.0-alpha.9 → 7.0.0-rc.1

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 (75) hide show
  1. package/lib/commonjs/index.js.map +1 -1
  2. package/lib/commonjs/navigators/createNativeStackNavigator.js +19 -16
  3. package/lib/commonjs/navigators/createNativeStackNavigator.js.map +1 -1
  4. package/lib/commonjs/types.js.map +1 -1
  5. package/lib/commonjs/utils/debounce.js +16 -0
  6. package/lib/commonjs/utils/debounce.js.map +1 -0
  7. package/lib/commonjs/utils/getModalRoutesKeys.js +17 -0
  8. package/lib/commonjs/utils/getModalRoutesKeys.js.map +1 -0
  9. package/lib/commonjs/utils/useAnimatedHeaderHeight.js +1 -1
  10. package/lib/commonjs/utils/useAnimatedHeaderHeight.js.map +1 -1
  11. package/lib/commonjs/utils/useDismissedRouteError.js +1 -1
  12. package/lib/commonjs/utils/useDismissedRouteError.js.map +1 -1
  13. package/lib/commonjs/utils/useInvalidPreventRemoveError.js +1 -1
  14. package/lib/commonjs/utils/useInvalidPreventRemoveError.js.map +1 -1
  15. package/lib/commonjs/views/DebugContainer.js +1 -1
  16. package/lib/commonjs/views/DebugContainer.js.map +1 -1
  17. package/lib/commonjs/views/DebugContainer.native.js +3 -3
  18. package/lib/commonjs/views/DebugContainer.native.js.map +1 -1
  19. package/lib/commonjs/views/FontProcessor.js.map +1 -1
  20. package/lib/commonjs/views/FontProcessor.native.js +1 -1
  21. package/lib/commonjs/views/FontProcessor.native.js.map +1 -1
  22. package/lib/commonjs/views/HeaderConfig.js +41 -39
  23. package/lib/commonjs/views/HeaderConfig.js.map +1 -1
  24. package/lib/commonjs/views/NativeStackView.js +47 -57
  25. package/lib/commonjs/views/NativeStackView.js.map +1 -1
  26. package/lib/commonjs/views/NativeStackView.native.js +110 -54
  27. package/lib/commonjs/views/NativeStackView.native.js.map +1 -1
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/navigators/createNativeStackNavigator.js +17 -14
  30. package/lib/module/navigators/createNativeStackNavigator.js.map +1 -1
  31. package/lib/module/types.js.map +1 -1
  32. package/lib/module/utils/debounce.js +10 -0
  33. package/lib/module/utils/debounce.js.map +1 -0
  34. package/lib/module/utils/getModalRoutesKeys.js +10 -0
  35. package/lib/module/utils/getModalRoutesKeys.js.map +1 -0
  36. package/lib/module/utils/useAnimatedHeaderHeight.js.map +1 -1
  37. package/lib/module/utils/useDismissedRouteError.js.map +1 -1
  38. package/lib/module/utils/useInvalidPreventRemoveError.js.map +1 -1
  39. package/lib/module/views/DebugContainer.js.map +1 -1
  40. package/lib/module/views/DebugContainer.native.js +1 -1
  41. package/lib/module/views/DebugContainer.native.js.map +1 -1
  42. package/lib/module/views/FontProcessor.js.map +1 -1
  43. package/lib/module/views/FontProcessor.native.js.map +1 -1
  44. package/lib/module/views/HeaderConfig.js +40 -38
  45. package/lib/module/views/HeaderConfig.js.map +1 -1
  46. package/lib/module/views/NativeStackView.js +47 -57
  47. package/lib/module/views/NativeStackView.js.map +1 -1
  48. package/lib/module/views/NativeStackView.native.js +109 -53
  49. package/lib/module/views/NativeStackView.native.js.map +1 -1
  50. package/lib/typescript/src/index.d.ts +1 -1
  51. package/lib/typescript/src/index.d.ts.map +1 -1
  52. package/lib/typescript/src/navigators/createNativeStackNavigator.d.ts +13 -8
  53. package/lib/typescript/src/navigators/createNativeStackNavigator.d.ts.map +1 -1
  54. package/lib/typescript/src/types.d.ts +16 -4
  55. package/lib/typescript/src/types.d.ts.map +1 -1
  56. package/lib/typescript/src/utils/debounce.d.ts +2 -0
  57. package/lib/typescript/src/utils/debounce.d.ts.map +1 -0
  58. package/lib/typescript/src/utils/getModalRoutesKeys.d.ts +4 -0
  59. package/lib/typescript/src/utils/getModalRoutesKeys.d.ts.map +1 -0
  60. package/lib/typescript/src/utils/useAnimatedHeaderHeight.d.ts +2 -2
  61. package/lib/typescript/src/utils/useAnimatedHeaderHeight.d.ts.map +1 -1
  62. package/lib/typescript/src/views/HeaderConfig.d.ts.map +1 -1
  63. package/lib/typescript/src/views/NativeStackView.d.ts.map +1 -1
  64. package/lib/typescript/src/views/NativeStackView.native.d.ts +1 -1
  65. package/lib/typescript/src/views/NativeStackView.native.d.ts.map +1 -1
  66. package/package.json +13 -13
  67. package/src/index.tsx +1 -0
  68. package/src/navigators/createNativeStackNavigator.tsx +30 -6
  69. package/src/types.tsx +23 -2
  70. package/src/utils/debounce.tsx +14 -0
  71. package/src/utils/getModalRoutesKeys.ts +21 -0
  72. package/src/utils/useAnimatedHeaderHeight.tsx +1 -1
  73. package/src/views/HeaderConfig.tsx +12 -5
  74. package/src/views/NativeStackView.native.tsx +180 -101
  75. package/src/views/NativeStackView.tsx +141 -144
@@ -1,12 +1,15 @@
1
1
  import {
2
2
  createNavigatorFactory,
3
3
  type EventArg,
4
+ type NavigatorTypeBagBase,
4
5
  type ParamListBase,
5
6
  type StackActionHelpers,
6
7
  StackActions,
7
8
  type StackNavigationState,
8
9
  StackRouter,
9
10
  type StackRouterOptions,
11
+ type StaticConfig,
12
+ type TypedNavigator,
10
13
  useNavigationBuilder,
11
14
  } from '@react-navigation/native';
12
15
  import * as React from 'react';
@@ -14,6 +17,7 @@ import * as React from 'react';
14
17
  import type {
15
18
  NativeStackNavigationEventMap,
16
19
  NativeStackNavigationOptions,
20
+ NativeStackNavigationProp,
17
21
  NativeStackNavigatorProps,
18
22
  } from '../types';
19
23
  import { NativeStackView } from '../views/NativeStackView';
@@ -26,6 +30,7 @@ function NativeStackNavigator({
26
30
  screenListeners,
27
31
  screenOptions,
28
32
  screenLayout,
33
+ UNSTABLE_getStateForRouteNamesChange,
29
34
  ...rest
30
35
  }: NativeStackNavigatorProps) {
31
36
  const { state, descriptors, navigation, NavigationContent } =
@@ -43,6 +48,7 @@ function NativeStackNavigator({
43
48
  screenListeners,
44
49
  screenOptions,
45
50
  screenLayout,
51
+ UNSTABLE_getStateForRouteNamesChange,
46
52
  });
47
53
 
48
54
  React.useEffect(
@@ -83,9 +89,27 @@ function NativeStackNavigator({
83
89
  );
84
90
  }
85
91
 
86
- export const createNativeStackNavigator = createNavigatorFactory<
87
- StackNavigationState<ParamListBase>,
88
- NativeStackNavigationOptions,
89
- NativeStackNavigationEventMap,
90
- typeof NativeStackNavigator
91
- >(NativeStackNavigator);
92
+ export function createNativeStackNavigator<
93
+ ParamList extends ParamListBase,
94
+ NavigatorID extends string | undefined = undefined,
95
+ TypeBag extends NavigatorTypeBagBase = {
96
+ ParamList: ParamList;
97
+ NavigatorID: NavigatorID;
98
+ State: StackNavigationState<ParamList>;
99
+ ScreenOptions: NativeStackNavigationOptions;
100
+ EventMap: NativeStackNavigationEventMap;
101
+ NavigationList: {
102
+ [RouteName in keyof ParamList]: NativeStackNavigationProp<
103
+ ParamList,
104
+ RouteName,
105
+ NavigatorID
106
+ >;
107
+ };
108
+ Navigator: typeof NativeStackNavigator;
109
+ },
110
+ Config extends StaticConfig<TypeBag> | undefined =
111
+ | StaticConfig<TypeBag>
112
+ | undefined,
113
+ >(config?: Config): TypedNavigator<TypeBag, Config> {
114
+ return createNavigatorFactory(NativeStackNavigator)(config);
115
+ }
package/src/types.tsx CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  StackActionHelpers,
10
10
  StackNavigationState,
11
11
  StackRouterOptions,
12
+ Theme,
12
13
  } from '@react-navigation/native';
13
14
  import type {
14
15
  ImageSourcePropType,
@@ -61,6 +62,14 @@ export type NativeStackScreenProps<
61
62
  route: RouteProp<ParamList, RouteName>;
62
63
  };
63
64
 
65
+ export type NativeStackOptionsArgs<
66
+ ParamList extends ParamListBase,
67
+ RouteName extends keyof ParamList = keyof ParamList,
68
+ NavigatorID extends string | undefined = undefined,
69
+ > = NativeStackScreenProps<ParamList, RouteName, NavigatorID> & {
70
+ theme: Theme;
71
+ };
72
+
64
73
  export type NativeStackNavigationHelpers = NavigationHelpers<
65
74
  ParamListBase,
66
75
  NativeStackNavigationEventMap
@@ -114,6 +123,10 @@ export type NativeStackHeaderLeftProps = NativeStackHeaderRightProps & {
114
123
  * By default, this is only shown on iOS.
115
124
  */
116
125
  label?: string;
126
+ /**
127
+ * The `href` to use for the anchor tag on web
128
+ */
129
+ href?: string;
117
130
  };
118
131
 
119
132
  export type NativeStackNavigationOptions = {
@@ -319,7 +332,7 @@ export type NativeStackNavigationOptions = {
319
332
  *
320
333
  * Only supported on iOS and Android.
321
334
  */
322
- headerSearchBarOptions?: SearchBarProps;
335
+ headerSearchBarOptions?: Omit<SearchBarProps, 'ref'>;
323
336
  /**
324
337
  * Boolean indicating whether to show the menu on longPress of iOS >= 14 back button. Defaults to `true`.
325
338
  * Requires `react-native-screens` version >=3.3.0.
@@ -347,6 +360,12 @@ export type NativeStackNavigationOptions = {
347
360
  * @platform android
348
361
  */
349
362
  navigationBarColor?: string;
363
+ /**
364
+ * Boolean indicating whether the content should be visible behind the navigation bar. Defaults to `false`.
365
+ *
366
+ * @platform android
367
+ */
368
+ navigationBarTranslucent?: boolean;
350
369
  /**
351
370
  * Sets the visibility of the navigation bar. Defaults to `false`.
352
371
  *
@@ -571,9 +590,11 @@ export type NativeStackNavigationOptions = {
571
590
 
572
591
  export type NativeStackNavigatorProps = DefaultNavigatorOptions<
573
592
  ParamListBase,
593
+ string | undefined,
574
594
  StackNavigationState<ParamListBase>,
575
595
  NativeStackNavigationOptions,
576
- NativeStackNavigationEventMap
596
+ NativeStackNavigationEventMap,
597
+ NativeStackNavigationProp<ParamListBase>
577
598
  > &
578
599
  StackRouterOptions &
579
600
  NativeStackNavigationConfig;
@@ -0,0 +1,14 @@
1
+ export function debounce<T extends (...args: any[]) => void>(
2
+ func: T,
3
+ duration: number
4
+ ): T {
5
+ let timeout: NodeJS.Timeout;
6
+
7
+ return function (this: unknown, ...args) {
8
+ clearTimeout(timeout);
9
+
10
+ timeout = setTimeout(() => {
11
+ func.apply(this, args);
12
+ }, duration);
13
+ } as T;
14
+ }
@@ -0,0 +1,21 @@
1
+ import type { Route } from '@react-navigation/native';
2
+
3
+ import type { NativeStackDescriptorMap } from '../types';
4
+
5
+ export const getModalRouteKeys = (
6
+ routes: Route<string>[],
7
+ descriptors: NativeStackDescriptorMap
8
+ ) =>
9
+ routes.reduce<string[]>((acc, route) => {
10
+ const { presentation } = descriptors[route.key]?.options ?? {};
11
+
12
+ if (
13
+ (acc.length && !presentation) ||
14
+ presentation === 'modal' ||
15
+ presentation === 'transparentModal'
16
+ ) {
17
+ acc.push(route.key);
18
+ }
19
+
20
+ return acc;
21
+ }, []);
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import type { Animated } from 'react-native';
3
3
 
4
4
  export const AnimatedHeaderHeightContext = React.createContext<
5
- Animated.Value | undefined
5
+ Animated.AnimatedInterpolation<number> | undefined
6
6
  >(undefined);
7
7
 
8
8
  export function useAnimatedHeaderHeight() {
@@ -58,16 +58,16 @@ export function HeaderConfig({
58
58
  headerTintColor ?? (Platform.OS === 'ios' ? colors.primary : colors.text);
59
59
 
60
60
  const headerBackTitleStyleFlattened =
61
- StyleSheet.flatten([headerBackTitleStyle, fonts.regular]) || {};
61
+ StyleSheet.flatten([fonts.regular, headerBackTitleStyle]) || {};
62
62
  const headerLargeTitleStyleFlattened =
63
63
  StyleSheet.flatten([
64
- headerLargeTitleStyle,
65
64
  Platform.select({ ios: fonts.heavy, default: fonts.medium }),
65
+ headerLargeTitleStyle,
66
66
  ]) || {};
67
67
  const headerTitleStyleFlattened =
68
68
  StyleSheet.flatten([
69
- headerTitleStyle,
70
69
  Platform.select({ ios: fonts.bold, default: fonts.medium }),
70
+ headerTitleStyle,
71
71
  ]) || {};
72
72
  const headerStyleFlattened = StyleSheet.flatten(headerStyle) || {};
73
73
  const headerLargeStyleFlattened = StyleSheet.flatten(headerLargeStyle) || {};
@@ -130,6 +130,8 @@ export function HeaderConfig({
130
130
  tintColor,
131
131
  canGoBack,
132
132
  label: headerBackTitle,
133
+ // `href` is only applicable to web
134
+ href: undefined,
133
135
  });
134
136
  const headerRightElement = headerRight?.({
135
137
  tintColor,
@@ -179,7 +181,12 @@ export function HeaderConfig({
179
181
  <ScreenStackHeaderConfig
180
182
  backButtonInCustomView={backButtonInCustomView}
181
183
  backgroundColor={headerBackgroundColor}
182
- backTitle={headerBackTitleVisible ? headerBackTitle : ' '}
184
+ backTitle={
185
+ headerBackTitleVisible
186
+ ? headerBackTitle
187
+ : ' ' /* For backward compatibility with react-native-screens versions <3.21.0, where `backTitleVisible` is not available */
188
+ }
189
+ backTitleVisible={headerBackTitleVisible}
183
190
  backTitleFontFamily={backTitleFontFamily}
184
191
  backTitleFontSize={backTitleFontSize}
185
192
  blurEffect={headerBlurEffect}
@@ -204,7 +211,7 @@ export function HeaderConfig({
204
211
  titleColor={titleColor}
205
212
  titleFontFamily={titleFontFamily}
206
213
  titleFontSize={titleFontSize}
207
- titleFontWeight={titleFontWeight}
214
+ titleFontWeight={String(titleFontWeight)}
208
215
  topInsetEnabled={headerTopInsetEnabled}
209
216
  translucent={
210
217
  // This defaults to `true`, so we can't pass `undefined`
@@ -20,6 +20,7 @@ import * as React from 'react';
20
20
  import {
21
21
  Animated,
22
22
  Platform,
23
+ StatusBar,
23
24
  StyleSheet,
24
25
  useAnimatedValue,
25
26
  View,
@@ -42,6 +43,8 @@ import type {
42
43
  NativeStackNavigationHelpers,
43
44
  NativeStackNavigationOptions,
44
45
  } from '../types';
46
+ import { debounce } from '../utils/debounce';
47
+ import { getModalRouteKeys } from '../utils/getModalRoutesKeys';
45
48
  import { AnimatedHeaderHeightContext } from '../utils/useAnimatedHeaderHeight';
46
49
  import { useDismissedRouteError } from '../utils/useDismissedRouteError';
47
50
  import { useInvalidPreventRemoveError } from '../utils/useInvalidPreventRemoveError';
@@ -132,6 +135,7 @@ type SceneViewProps = {
132
135
  descriptor: NativeStackDescriptor;
133
136
  previousDescriptor?: NativeStackDescriptor;
134
137
  nextDescriptor?: NativeStackDescriptor;
138
+ isPresentationModal?: boolean;
135
139
  onWillDisappear: () => void;
136
140
  onWillAppear: () => void;
137
141
  onAppear: () => void;
@@ -148,6 +152,7 @@ const SceneView = ({
148
152
  descriptor,
149
153
  previousDescriptor,
150
154
  nextDescriptor,
155
+ isPresentationModal,
151
156
  onWillDisappear,
152
157
  onWillAppear,
153
158
  onAppear,
@@ -162,8 +167,8 @@ const SceneView = ({
162
167
  let {
163
168
  animation,
164
169
  animationMatchesGesture,
170
+ presentation = isPresentationModal ? 'modal' : 'card',
165
171
  fullScreenGestureEnabled,
166
- presentation = 'card',
167
172
  } = options;
168
173
 
169
174
  const {
@@ -180,6 +185,7 @@ const SceneView = ({
180
185
  autoHideHomeIndicator,
181
186
  keyboardHandlingEnabled,
182
187
  navigationBarColor,
188
+ navigationBarTranslucent,
183
189
  navigationBarHidden,
184
190
  orientation,
185
191
  sheetAllowedDetents = 'large',
@@ -249,15 +255,57 @@ const SceneView = ({
249
255
 
250
256
  const { preventedRoutes } = usePreventRemoveContext();
251
257
 
252
- const defaultHeaderHeight = getDefaultHeaderHeight(frame, isModal, topInset);
258
+ const defaultHeaderHeight = Platform.select({
259
+ // FIXME: Currently screens isn't using Material 3
260
+ // So our `getDefaultHeaderHeight` doesn't return the correct value
261
+ // So we hardcode the value here for now until screens is updated
262
+ android: 56 + topInset,
263
+ default: getDefaultHeaderHeight(frame, isModal, topInset),
264
+ });
265
+
266
+ const [headerHeight, setHeaderHeight] = React.useState(defaultHeaderHeight);
267
+
268
+ // eslint-disable-next-line react-hooks/exhaustive-deps
269
+ const setHeaderHeightDebounced = React.useCallback(
270
+ // Debounce the header height updates to avoid excessive re-renders
271
+ debounce(setHeaderHeight, 100),
272
+ []
273
+ );
274
+
275
+ const hasCustomHeader = header !== undefined;
276
+
277
+ let headerHeightCorrectionOffset = 0;
278
+
279
+ if (isAndroid && !hasCustomHeader) {
280
+ const statusBarHeight = StatusBar.currentHeight ?? 0;
253
281
 
254
- const [customHeaderHeight, setCustomHeaderHeight] =
255
- React.useState(defaultHeaderHeight);
282
+ // FIXME: On Android, the native header height is not correctly calculated
283
+ // It includes status bar height even if statusbar is not translucent
284
+ // And the statusbar value itself doesn't match the actual status bar height
285
+ // So we subtract the bogus status bar height and add the actual top inset
286
+ headerHeightCorrectionOffset = -statusBarHeight + topInset;
287
+ }
256
288
 
257
- const animatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
289
+ const rawAnimatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
290
+ const animatedHeaderHeight = React.useMemo(
291
+ () =>
292
+ Animated.add<number>(
293
+ rawAnimatedHeaderHeight,
294
+ headerHeightCorrectionOffset
295
+ ),
296
+ [headerHeightCorrectionOffset, rawAnimatedHeaderHeight]
297
+ );
258
298
 
259
- const headerTopInsetEnabled = topInset !== 0;
260
- const headerHeight = header ? customHeaderHeight : defaultHeaderHeight;
299
+ // During the very first render topInset is > 0 when running
300
+ // in non edge-to-edge mode on Android, while on every consecutive render
301
+ // topInset === 0, causing header content to jump, as we add padding on the first frame,
302
+ // just to remove it in next one. To prevent this, when statusBarTranslucent is set,
303
+ // we apply additional padding in header only if its true.
304
+ // For more details see: https://github.com/react-navigation/react-navigation/pull/12014
305
+ const headerTopInsetEnabled =
306
+ typeof statusBarTranslucent === 'boolean'
307
+ ? statusBarTranslucent
308
+ : topInset !== 0;
261
309
 
262
310
  const backTitle = previousDescriptor
263
311
  ? getHeaderTitle(previousDescriptor.options, previousDescriptor.route.name)
@@ -293,6 +341,8 @@ const SceneView = ({
293
341
  homeIndicatorHidden={autoHideHomeIndicator}
294
342
  hideKeyboardOnSwipe={keyboardHandlingEnabled}
295
343
  navigationBarColor={navigationBarColor}
344
+ // @ts-expect-error prop supported from react-native-screens 3.32.0 onwards
345
+ navigationBarTranslucent={navigationBarTranslucent}
296
346
  navigationBarHidden={navigationBarHidden}
297
347
  replaceAnimation={animationTypeForReplace}
298
348
  stackPresentation={presentation === 'card' ? 'push' : presentation}
@@ -329,11 +379,36 @@ const SceneView = ({
329
379
  [
330
380
  {
331
381
  nativeEvent: {
332
- headerHeight: animatedHeaderHeight,
382
+ headerHeight: rawAnimatedHeaderHeight,
333
383
  },
334
384
  },
335
385
  ],
336
- { useNativeDriver: true }
386
+ {
387
+ useNativeDriver: true,
388
+ listener: (e) => {
389
+ if (
390
+ e.nativeEvent &&
391
+ typeof e.nativeEvent === 'object' &&
392
+ 'headerHeight' in e.nativeEvent &&
393
+ typeof e.nativeEvent.headerHeight === 'number'
394
+ ) {
395
+ const headerHeight =
396
+ e.nativeEvent.headerHeight + headerHeightCorrectionOffset;
397
+
398
+ // Only debounce if header has large title or search bar
399
+ // As it's the only case where the header height can change frequently
400
+ const doesHeaderAnimate =
401
+ Platform.OS === 'ios' &&
402
+ (options.headerLargeTitle || options.headerSearchBarOptions);
403
+
404
+ if (doesHeaderAnimate) {
405
+ setHeaderHeightDebounced(headerHeight);
406
+ } else {
407
+ setHeaderHeight(headerHeight);
408
+ }
409
+ }
410
+ },
411
+ }
337
412
  )}
338
413
  // this prop is available since rn-screens 3.16
339
414
  freezeOnBlur={freezeOnBlur}
@@ -385,7 +460,10 @@ const SceneView = ({
385
460
  {header !== undefined && headerShown !== false ? (
386
461
  <View
387
462
  onLayout={(e) => {
388
- setCustomHeaderHeight(e.nativeEvent.layout.height);
463
+ const headerHeight = e.nativeEvent.layout.height;
464
+
465
+ setHeaderHeight(headerHeight);
466
+ rawAnimatedHeaderHeight.setValue(headerHeight);
389
467
  }}
390
468
  style={headerTransparent ? styles.absolute : null}
391
469
  >
@@ -442,99 +520,100 @@ type Props = {
442
520
  descriptors: NativeStackDescriptorMap;
443
521
  };
444
522
 
445
- function NativeStackViewInner({ state, navigation, descriptors }: Props) {
523
+ export function NativeStackView({ state, navigation, descriptors }: Props) {
446
524
  const { setNextDismissedKey } = useDismissedRouteError(state);
447
525
 
526
+ const { colors } = useTheme();
527
+
448
528
  useInvalidPreventRemoveError(descriptors);
449
529
 
450
- return (
451
- <ScreenStack style={styles.container}>
452
- {state.routes.map((route, index) => {
453
- const descriptor = descriptors[route.key];
454
- const isFocused = state.index === index;
455
- const previousKey = state.routes[index - 1]?.key;
456
- const nextKey = state.routes[index + 1]?.key;
457
- const previousDescriptor = previousKey
458
- ? descriptors[previousKey]
459
- : undefined;
460
- const nextDescriptor = nextKey ? descriptors[nextKey] : undefined;
461
-
462
- return (
463
- <SceneView
464
- key={route.key}
465
- index={index}
466
- focused={isFocused}
467
- descriptor={descriptor}
468
- previousDescriptor={previousDescriptor}
469
- nextDescriptor={nextDescriptor}
470
- onWillDisappear={() => {
471
- navigation.emit({
472
- type: 'transitionStart',
473
- data: { closing: true },
474
- target: route.key,
475
- });
476
- }}
477
- onWillAppear={() => {
478
- navigation.emit({
479
- type: 'transitionStart',
480
- data: { closing: false },
481
- target: route.key,
482
- });
483
- }}
484
- onAppear={() => {
485
- navigation.emit({
486
- type: 'transitionEnd',
487
- data: { closing: false },
488
- target: route.key,
489
- });
490
- }}
491
- onDisappear={() => {
492
- navigation.emit({
493
- type: 'transitionEnd',
494
- data: { closing: true },
495
- target: route.key,
496
- });
497
- }}
498
- onDismissed={(event) => {
499
- navigation.dispatch({
500
- ...StackActions.pop(event.nativeEvent.dismissCount),
501
- source: route.key,
502
- target: state.key,
503
- });
504
-
505
- setNextDismissedKey(route.key);
506
- }}
507
- onHeaderBackButtonClicked={() => {
508
- navigation.dispatch({
509
- ...StackActions.pop(),
510
- source: route.key,
511
- target: state.key,
512
- });
513
- }}
514
- onNativeDismissCancelled={(event) => {
515
- navigation.dispatch({
516
- ...StackActions.pop(event.nativeEvent.dismissCount),
517
- source: route.key,
518
- target: state.key,
519
- });
520
- }}
521
- onGestureCancel={() => {
522
- navigation.emit({
523
- type: 'gestureCancel',
524
- target: route.key,
525
- });
526
- }}
527
- />
528
- );
529
- })}
530
- </ScreenStack>
531
- );
532
- }
530
+ const modalRouteKeys = getModalRouteKeys(state.routes, descriptors);
533
531
 
534
- export function NativeStackView(props: Props) {
535
532
  return (
536
- <SafeAreaProviderCompat>
537
- <NativeStackViewInner {...props} />
533
+ <SafeAreaProviderCompat style={{ backgroundColor: colors.background }}>
534
+ <ScreenStack style={styles.container}>
535
+ {state.routes.map((route, index) => {
536
+ const descriptor = descriptors[route.key];
537
+ const isFocused = state.index === index;
538
+ const previousKey = state.routes[index - 1]?.key;
539
+ const nextKey = state.routes[index + 1]?.key;
540
+ const previousDescriptor = previousKey
541
+ ? descriptors[previousKey]
542
+ : undefined;
543
+ const nextDescriptor = nextKey ? descriptors[nextKey] : undefined;
544
+
545
+ const isModal = modalRouteKeys.includes(route.key);
546
+
547
+ return (
548
+ <SceneView
549
+ key={route.key}
550
+ index={index}
551
+ focused={isFocused}
552
+ descriptor={descriptor}
553
+ previousDescriptor={previousDescriptor}
554
+ nextDescriptor={nextDescriptor}
555
+ isPresentationModal={isModal}
556
+ onWillDisappear={() => {
557
+ navigation.emit({
558
+ type: 'transitionStart',
559
+ data: { closing: true },
560
+ target: route.key,
561
+ });
562
+ }}
563
+ onWillAppear={() => {
564
+ navigation.emit({
565
+ type: 'transitionStart',
566
+ data: { closing: false },
567
+ target: route.key,
568
+ });
569
+ }}
570
+ onAppear={() => {
571
+ navigation.emit({
572
+ type: 'transitionEnd',
573
+ data: { closing: false },
574
+ target: route.key,
575
+ });
576
+ }}
577
+ onDisappear={() => {
578
+ navigation.emit({
579
+ type: 'transitionEnd',
580
+ data: { closing: true },
581
+ target: route.key,
582
+ });
583
+ }}
584
+ onDismissed={(event) => {
585
+ navigation.dispatch({
586
+ ...StackActions.pop(event.nativeEvent.dismissCount),
587
+ source: route.key,
588
+ target: state.key,
589
+ });
590
+
591
+ setNextDismissedKey(route.key);
592
+ }}
593
+ onHeaderBackButtonClicked={() => {
594
+ navigation.dispatch({
595
+ ...StackActions.pop(),
596
+ source: route.key,
597
+ target: state.key,
598
+ });
599
+ }}
600
+ onNativeDismissCancelled={(event) => {
601
+ navigation.dispatch({
602
+ ...StackActions.pop(event.nativeEvent.dismissCount),
603
+ source: route.key,
604
+ target: state.key,
605
+ });
606
+ }}
607
+ onGestureCancel={() => {
608
+ navigation.emit({
609
+ type: 'gestureCancel',
610
+ target: route.key,
611
+ });
612
+ }}
613
+ />
614
+ );
615
+ })}
616
+ </ScreenStack>
538
617
  </SafeAreaProviderCompat>
539
618
  );
540
619
  }
@@ -550,14 +629,14 @@ const styles = StyleSheet.create({
550
629
  absolute: {
551
630
  position: 'absolute',
552
631
  top: 0,
553
- left: 0,
554
- right: 0,
632
+ start: 0,
633
+ end: 0,
555
634
  },
556
635
  translucent: {
557
636
  position: 'absolute',
558
637
  top: 0,
559
- left: 0,
560
- right: 0,
638
+ start: 0,
639
+ end: 0,
561
640
  zIndex: 1,
562
641
  elevation: 1,
563
642
  },