@react-navigation/native-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.
Files changed (84) hide show
  1. package/lib/commonjs/index.js +7 -0
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/navigators/createNativeStackNavigator.js +29 -25
  4. package/lib/commonjs/navigators/createNativeStackNavigator.js.map +1 -1
  5. package/lib/commonjs/types.js.map +1 -1
  6. package/lib/commonjs/utils/getModalRoutesKeys.js +17 -0
  7. package/lib/commonjs/utils/getModalRoutesKeys.js.map +1 -0
  8. package/lib/commonjs/utils/useAnimatedHeaderHeight.js +19 -0
  9. package/lib/commonjs/utils/useAnimatedHeaderHeight.js.map +1 -0
  10. package/lib/commonjs/utils/useDismissedRouteError.js +3 -4
  11. package/lib/commonjs/utils/useDismissedRouteError.js.map +1 -1
  12. package/lib/commonjs/utils/useInvalidPreventRemoveError.js +4 -5
  13. package/lib/commonjs/utils/useInvalidPreventRemoveError.js.map +1 -1
  14. package/lib/commonjs/views/DebugContainer.js +2 -2
  15. package/lib/commonjs/views/DebugContainer.js.map +1 -1
  16. package/lib/commonjs/views/DebugContainer.native.js +19 -7
  17. package/lib/commonjs/views/DebugContainer.native.js.map +1 -1
  18. package/lib/commonjs/views/FontProcessor.js.map +1 -1
  19. package/lib/commonjs/views/FontProcessor.native.js +2 -4
  20. package/lib/commonjs/views/FontProcessor.native.js.map +1 -1
  21. package/lib/commonjs/views/HeaderConfig.js +18 -29
  22. package/lib/commonjs/views/HeaderConfig.js.map +1 -1
  23. package/lib/commonjs/views/NativeStackView.js +27 -17
  24. package/lib/commonjs/views/NativeStackView.js.map +1 -1
  25. package/lib/commonjs/views/NativeStackView.native.js +131 -49
  26. package/lib/commonjs/views/NativeStackView.native.js.map +1 -1
  27. package/lib/module/index.js +5 -0
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/navigators/createNativeStackNavigator.js +26 -21
  30. package/lib/module/navigators/createNativeStackNavigator.js.map +1 -1
  31. package/lib/module/types.js.map +1 -1
  32. package/lib/module/utils/getModalRoutesKeys.js +10 -0
  33. package/lib/module/utils/getModalRoutesKeys.js.map +1 -0
  34. package/lib/module/utils/useAnimatedHeaderHeight.js +10 -0
  35. package/lib/module/utils/useAnimatedHeaderHeight.js.map +1 -0
  36. package/lib/module/utils/useDismissedRouteError.js +1 -2
  37. package/lib/module/utils/useDismissedRouteError.js.map +1 -1
  38. package/lib/module/utils/useInvalidPreventRemoveError.js +2 -3
  39. package/lib/module/utils/useInvalidPreventRemoveError.js.map +1 -1
  40. package/lib/module/views/DebugContainer.js.map +1 -1
  41. package/lib/module/views/DebugContainer.native.js +18 -4
  42. package/lib/module/views/DebugContainer.native.js.map +1 -1
  43. package/lib/module/views/FontProcessor.js.map +1 -1
  44. package/lib/module/views/FontProcessor.native.js +2 -4
  45. package/lib/module/views/FontProcessor.native.js.map +1 -1
  46. package/lib/module/views/HeaderConfig.js +18 -29
  47. package/lib/module/views/HeaderConfig.js.map +1 -1
  48. package/lib/module/views/NativeStackView.js +25 -15
  49. package/lib/module/views/NativeStackView.js.map +1 -1
  50. package/lib/module/views/NativeStackView.native.js +130 -48
  51. package/lib/module/views/NativeStackView.native.js.map +1 -1
  52. package/lib/typescript/src/index.d.ts +5 -1
  53. package/lib/typescript/src/index.d.ts.map +1 -1
  54. package/lib/typescript/src/navigators/createNativeStackNavigator.d.ts +14 -8
  55. package/lib/typescript/src/navigators/createNativeStackNavigator.d.ts.map +1 -1
  56. package/lib/typescript/src/types.d.ts +97 -12
  57. package/lib/typescript/src/types.d.ts.map +1 -1
  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 +5 -0
  61. package/lib/typescript/src/utils/useAnimatedHeaderHeight.d.ts.map +1 -0
  62. package/lib/typescript/src/views/DebugContainer.d.ts +2 -2
  63. package/lib/typescript/src/views/DebugContainer.d.ts.map +1 -1
  64. package/lib/typescript/src/views/DebugContainer.native.d.ts +7 -2
  65. package/lib/typescript/src/views/DebugContainer.native.d.ts.map +1 -1
  66. package/lib/typescript/src/views/FontProcessor.native.d.ts.map +1 -1
  67. package/lib/typescript/src/views/HeaderConfig.d.ts +2 -2
  68. package/lib/typescript/src/views/HeaderConfig.d.ts.map +1 -1
  69. package/lib/typescript/src/views/NativeStackView.d.ts +3 -2
  70. package/lib/typescript/src/views/NativeStackView.d.ts.map +1 -1
  71. package/lib/typescript/src/views/NativeStackView.native.d.ts +3 -2
  72. package/lib/typescript/src/views/NativeStackView.native.d.ts.map +1 -1
  73. package/package.json +15 -16
  74. package/src/index.tsx +6 -0
  75. package/src/navigators/createNativeStackNavigator.tsx +39 -11
  76. package/src/types.tsx +104 -12
  77. package/src/utils/getModalRoutesKeys.ts +21 -0
  78. package/src/utils/useAnimatedHeaderHeight.tsx +18 -0
  79. package/src/views/DebugContainer.native.tsx +12 -6
  80. package/src/views/DebugContainer.tsx +1 -1
  81. package/src/views/FontProcessor.native.tsx +1 -2
  82. package/src/views/HeaderConfig.tsx +106 -134
  83. package/src/views/NativeStackView.native.tsx +273 -167
  84. package/src/views/NativeStackView.tsx +132 -123
@@ -9,24 +9,30 @@ import {
9
9
  import {
10
10
  NavigationContext,
11
11
  NavigationRouteContext,
12
- ParamListBase,
13
- Route,
12
+ type ParamListBase,
13
+ type Route,
14
14
  StackActions,
15
- StackNavigationState,
15
+ type StackNavigationState,
16
16
  usePreventRemoveContext,
17
17
  useTheme,
18
18
  } from '@react-navigation/native';
19
19
  import * as React from 'react';
20
- import { Platform, StyleSheet, View } from 'react-native';
20
+ import {
21
+ Animated,
22
+ Platform,
23
+ StyleSheet,
24
+ useAnimatedValue,
25
+ View,
26
+ } from 'react-native';
21
27
  import {
22
28
  useSafeAreaFrame,
23
29
  useSafeAreaInsets,
24
30
  } from 'react-native-safe-area-context';
25
- import type { ScreenProps } from 'react-native-screens';
26
31
  import {
27
32
  Screen,
33
+ type ScreenProps,
28
34
  ScreenStack,
29
- StackPresentationTypes,
35
+ type StackPresentationTypes,
30
36
  } from 'react-native-screens';
31
37
  import warnOnce from 'warn-once';
32
38
 
@@ -36,6 +42,8 @@ import type {
36
42
  NativeStackNavigationHelpers,
37
43
  NativeStackNavigationOptions,
38
44
  } from '../types';
45
+ import { getModalRouteKeys } from '../utils/getModalRoutesKeys';
46
+ import { AnimatedHeaderHeightContext } from '../utils/useAnimatedHeaderHeight';
39
47
  import { useDismissedRouteError } from '../utils/useDismissedRouteError';
40
48
  import { useInvalidPreventRemoveError } from '../utils/useInvalidPreventRemoveError';
41
49
  import { DebugContainer } from './DebugContainer';
@@ -97,7 +105,13 @@ const MaybeNestedStack = ({
97
105
  if (isHeaderInModal) {
98
106
  return (
99
107
  <ScreenStack style={styles.container}>
100
- <Screen enabled style={StyleSheet.absoluteFill}>
108
+ <Screen
109
+ enabled
110
+ isNativeStack
111
+ hasLargeHeader={options.headerLargeTitle ?? false}
112
+ style={StyleSheet.absoluteFill}
113
+ >
114
+ {content}
101
115
  <HeaderConfig
102
116
  {...options}
103
117
  route={route}
@@ -105,7 +119,6 @@ const MaybeNestedStack = ({
105
119
  headerTopInsetEnabled={headerTopInsetEnabled}
106
120
  canGoBack
107
121
  />
108
- {content}
109
122
  </Screen>
110
123
  </ScreenStack>
111
124
  );
@@ -120,12 +133,15 @@ type SceneViewProps = {
120
133
  descriptor: NativeStackDescriptor;
121
134
  previousDescriptor?: NativeStackDescriptor;
122
135
  nextDescriptor?: NativeStackDescriptor;
136
+ isPresentationModal?: boolean;
123
137
  onWillDisappear: () => void;
138
+ onWillAppear: () => void;
124
139
  onAppear: () => void;
125
140
  onDisappear: () => void;
126
141
  onDismissed: ScreenProps['onDismissed'];
127
142
  onHeaderBackButtonClicked: ScreenProps['onHeaderBackButtonClicked'];
128
143
  onNativeDismissCancelled: ScreenProps['onDismissed'];
144
+ onGestureCancel: ScreenProps['onGestureCancel'];
129
145
  };
130
146
 
131
147
  const SceneView = ({
@@ -134,54 +150,68 @@ const SceneView = ({
134
150
  descriptor,
135
151
  previousDescriptor,
136
152
  nextDescriptor,
153
+ isPresentationModal,
137
154
  onWillDisappear,
155
+ onWillAppear,
138
156
  onAppear,
139
157
  onDisappear,
140
158
  onDismissed,
141
159
  onHeaderBackButtonClicked,
142
160
  onNativeDismissCancelled,
161
+ onGestureCancel,
143
162
  }: SceneViewProps) => {
144
163
  const { route, navigation, options, render } = descriptor;
164
+
165
+ let {
166
+ animation,
167
+ animationMatchesGesture,
168
+ presentation = isPresentationModal ? 'modal' : 'card',
169
+ fullScreenGestureEnabled,
170
+ } = options;
171
+
145
172
  const {
146
173
  animationDuration,
147
174
  animationTypeForReplace = 'push',
148
175
  gestureEnabled,
176
+ gestureDirection = presentation === 'card' ? 'horizontal' : 'vertical',
177
+ gestureResponseDistance,
149
178
  header,
150
179
  headerBackButtonMenuEnabled,
151
180
  headerShown,
181
+ headerBackground,
152
182
  headerTransparent,
153
183
  autoHideHomeIndicator,
184
+ keyboardHandlingEnabled,
154
185
  navigationBarColor,
155
186
  navigationBarHidden,
156
187
  orientation,
188
+ sheetAllowedDetents = 'large',
189
+ sheetLargestUndimmedDetent = 'all',
190
+ sheetGrabberVisible = false,
191
+ sheetCornerRadius = -1.0,
192
+ sheetExpandsWhenScrolledToEdge = true,
157
193
  statusBarAnimation,
158
194
  statusBarHidden,
159
195
  statusBarStyle,
160
196
  statusBarTranslucent,
161
- statusBarColor,
197
+ statusBarBackgroundColor,
162
198
  freezeOnBlur,
163
199
  } = options;
164
200
 
165
- let {
166
- animation,
167
- customAnimationOnGesture,
168
- fullScreenGestureEnabled,
169
- presentation = 'card',
170
- gestureDirection = presentation === 'card' ? 'horizontal' : 'vertical',
171
- } = options;
172
-
173
201
  if (gestureDirection === 'vertical' && Platform.OS === 'ios') {
174
202
  // for `vertical` direction to work, we need to set `fullScreenGestureEnabled` to `true`
175
203
  // so the screen can be dismissed from any point on screen.
176
- // `customAnimationOnGesture` needs to be set to `true` so the `animation` set by user can be used,
204
+ // `animationMatchesGesture` needs to be set to `true` so the `animation` set by user can be used,
177
205
  // otherwise `simple_push` will be used.
178
206
  // Also, the default animation for this direction seems to be `slide_from_bottom`.
179
207
  if (fullScreenGestureEnabled === undefined) {
180
208
  fullScreenGestureEnabled = true;
181
209
  }
182
- if (customAnimationOnGesture === undefined) {
183
- customAnimationOnGesture = true;
210
+
211
+ if (animationMatchesGesture === undefined) {
212
+ animationMatchesGesture = true;
184
213
  }
214
+
185
215
  if (animation === undefined) {
186
216
  animation = 'slide_from_bottom';
187
217
  }
@@ -227,16 +257,23 @@ const SceneView = ({
227
257
  const [customHeaderHeight, setCustomHeaderHeight] =
228
258
  React.useState(defaultHeaderHeight);
229
259
 
260
+ const animatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
261
+
230
262
  const headerTopInsetEnabled = topInset !== 0;
231
263
  const headerHeight = header ? customHeaderHeight : defaultHeaderHeight;
232
- const headerBack = previousDescriptor
233
- ? {
234
- title: getHeaderTitle(
235
- previousDescriptor.options,
236
- previousDescriptor.route.name
237
- ),
238
- }
239
- : parentHeaderBack;
264
+
265
+ const backTitle = previousDescriptor
266
+ ? getHeaderTitle(previousDescriptor.options, previousDescriptor.route.name)
267
+ : parentHeaderBack?.title;
268
+
269
+ const headerBack = React.useMemo(
270
+ () => ({
271
+ // No href needed for native
272
+ href: undefined,
273
+ title: backTitle,
274
+ }),
275
+ [backTitle]
276
+ );
240
277
 
241
278
  const isRemovePrevented = preventedRoutes[route.key]?.preventRemove;
242
279
 
@@ -244,8 +281,10 @@ const SceneView = ({
244
281
  <Screen
245
282
  key={route.key}
246
283
  enabled
284
+ isNativeStack
247
285
  style={StyleSheet.absoluteFill}
248
- customAnimationOnSwipe={customAnimationOnGesture}
286
+ hasLargeHeader={options.headerLargeTitle ?? false}
287
+ customAnimationOnSwipe={animationMatchesGesture}
249
288
  fullScreenSwipeEnabled={fullScreenGestureEnabled}
250
289
  gestureEnabled={
251
290
  isAndroid
@@ -255,29 +294,50 @@ const SceneView = ({
255
294
  : gestureEnabled
256
295
  }
257
296
  homeIndicatorHidden={autoHideHomeIndicator}
297
+ hideKeyboardOnSwipe={keyboardHandlingEnabled}
258
298
  navigationBarColor={navigationBarColor}
259
299
  navigationBarHidden={navigationBarHidden}
260
300
  replaceAnimation={animationTypeForReplace}
261
301
  stackPresentation={presentation === 'card' ? 'push' : presentation}
262
302
  stackAnimation={animation}
263
303
  screenOrientation={orientation}
304
+ sheetAllowedDetents={sheetAllowedDetents}
305
+ sheetLargestUndimmedDetent={sheetLargestUndimmedDetent}
306
+ sheetGrabberVisible={sheetGrabberVisible}
307
+ sheetCornerRadius={sheetCornerRadius}
308
+ sheetExpandsWhenScrolledToEdge={sheetExpandsWhenScrolledToEdge}
264
309
  statusBarAnimation={statusBarAnimation}
265
310
  statusBarHidden={statusBarHidden}
266
311
  statusBarStyle={statusBarStyle}
267
- statusBarColor={statusBarColor}
312
+ statusBarColor={statusBarBackgroundColor}
268
313
  statusBarTranslucent={statusBarTranslucent}
269
314
  swipeDirection={gestureDirectionOverride}
270
315
  transitionDuration={animationDuration}
316
+ onWillAppear={onWillAppear}
271
317
  onWillDisappear={onWillDisappear}
272
318
  onAppear={onAppear}
273
319
  onDisappear={onDisappear}
274
320
  onDismissed={onDismissed}
275
- isNativeStack
321
+ onGestureCancel={onGestureCancel}
322
+ gestureResponseDistance={gestureResponseDistance}
276
323
  nativeBackButtonDismissalEnabled={false} // on Android
277
324
  onHeaderBackButtonClicked={onHeaderBackButtonClicked}
278
- // @ts-ignore props not exported from rn-screens
279
325
  preventNativeDismiss={isRemovePrevented} // on iOS
280
326
  onNativeDismissCancelled={onNativeDismissCancelled}
327
+ // Unfortunately, because of the bug that exists on Fabric, where native event drivers
328
+ // for Animated objects are being created after the first notifications about the header height
329
+ // from the native side, `onHeaderHeightChange` event does not notify
330
+ // `animatedHeaderHeight` about initial values on appearing screens at the moment.
331
+ onHeaderHeightChange={Animated.event(
332
+ [
333
+ {
334
+ nativeEvent: {
335
+ headerHeight: animatedHeaderHeight,
336
+ },
337
+ },
338
+ ],
339
+ { useNativeDriver: true }
340
+ )}
281
341
  // this prop is available since rn-screens 3.16
282
342
  freezeOnBlur={freezeOnBlur}
283
343
  >
@@ -286,71 +346,92 @@ const SceneView = ({
286
346
  <HeaderShownContext.Provider
287
347
  value={isParentHeaderShown || headerShown !== false}
288
348
  >
289
- <HeaderHeightContext.Provider
290
- value={
291
- headerShown !== false ? headerHeight : parentHeaderHeight ?? 0
292
- }
293
- >
294
- {/**
295
- * `HeaderConfig` needs to be the direct child of `Screen` without any intermediate `View`
296
- * We don't render it conditionally to make it possible to dynamically render a custom `header`
297
- * Otherwise dynamically rendering a custom `header` leaves the native header visible
298
- *
299
- * https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md#screenstackheaderconfig
300
- */}
301
- <HeaderConfig
302
- {...options}
303
- route={route}
304
- headerBackButtonMenuEnabled={
305
- isRemovePrevented !== undefined
306
- ? !isRemovePrevented
307
- : headerBackButtonMenuEnabled
308
- }
309
- headerShown={header !== undefined ? false : headerShown}
310
- headerHeight={headerHeight}
311
- headerBackTitle={
312
- options.headerBackTitle !== undefined
313
- ? options.headerBackTitle
314
- : undefined
315
- }
316
- headerTopInsetEnabled={headerTopInsetEnabled}
317
- canGoBack={headerBack !== undefined}
318
- />
319
- <View
320
- accessibilityElementsHidden={!focused}
321
- importantForAccessibility={
322
- focused ? 'auto' : 'no-hide-descendants'
349
+ <AnimatedHeaderHeightContext.Provider value={animatedHeaderHeight}>
350
+ <HeaderHeightContext.Provider
351
+ value={
352
+ headerShown !== false ? headerHeight : parentHeaderHeight ?? 0
323
353
  }
324
- style={styles.scene}
325
354
  >
326
- <MaybeNestedStack
327
- options={options}
328
- route={route}
329
- presentation={presentation}
330
- headerHeight={headerHeight}
331
- headerTopInsetEnabled={headerTopInsetEnabled}
332
- >
333
- <HeaderBackContext.Provider value={headerBack}>
334
- {render()}
335
- </HeaderBackContext.Provider>
336
- </MaybeNestedStack>
337
- {header !== undefined && headerShown !== false ? (
355
+ {headerBackground != null ? (
356
+ /**
357
+ * To show a custom header background, we render it at the top of the screen below the header
358
+ * The header also needs to be positioned absolutely (with `translucent` style)
359
+ */
338
360
  <View
339
- onLayout={(e) => {
340
- setCustomHeaderHeight(e.nativeEvent.layout.height);
341
- }}
342
- style={headerTransparent ? styles.absolute : null}
361
+ style={[
362
+ styles.background,
363
+ headerTransparent ? styles.translucent : null,
364
+ { height: headerHeight },
365
+ ]}
343
366
  >
344
- {header({
345
- back: headerBack,
346
- options,
347
- route,
348
- navigation,
349
- })}
367
+ {headerBackground()}
350
368
  </View>
351
369
  ) : null}
352
- </View>
353
- </HeaderHeightContext.Provider>
370
+ <View
371
+ accessibilityElementsHidden={!focused}
372
+ importantForAccessibility={
373
+ focused ? 'auto' : 'no-hide-descendants'
374
+ }
375
+ style={styles.scene}
376
+ >
377
+ <MaybeNestedStack
378
+ options={options}
379
+ route={route}
380
+ presentation={presentation}
381
+ headerHeight={headerHeight}
382
+ headerTopInsetEnabled={headerTopInsetEnabled}
383
+ >
384
+ <HeaderBackContext.Provider value={headerBack}>
385
+ {render()}
386
+ </HeaderBackContext.Provider>
387
+ </MaybeNestedStack>
388
+ {header !== undefined && headerShown !== false ? (
389
+ <View
390
+ onLayout={(e) => {
391
+ setCustomHeaderHeight(e.nativeEvent.layout.height);
392
+ }}
393
+ style={headerTransparent ? styles.absolute : null}
394
+ >
395
+ {header({
396
+ back: headerBack,
397
+ options,
398
+ route,
399
+ navigation,
400
+ })}
401
+ </View>
402
+ ) : null}
403
+ </View>
404
+ {/**
405
+ * `HeaderConfig` needs to be the direct child of `Screen` without any intermediate `View`
406
+ * We don't render it conditionally to make it possible to dynamically render a custom `header`
407
+ * Otherwise dynamically rendering a custom `header` leaves the native header visible
408
+ *
409
+ * https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md#screenstackheaderconfig
410
+ *
411
+ * HeaderConfig must not be first child of a Screen.
412
+ * See https://github.com/software-mansion/react-native-screens/pull/1825
413
+ * for detailed explanation
414
+ */}
415
+ <HeaderConfig
416
+ {...options}
417
+ route={route}
418
+ headerBackButtonMenuEnabled={
419
+ isRemovePrevented !== undefined
420
+ ? !isRemovePrevented
421
+ : headerBackButtonMenuEnabled
422
+ }
423
+ headerShown={header !== undefined ? false : headerShown}
424
+ headerHeight={headerHeight}
425
+ headerBackTitle={
426
+ options.headerBackTitle !== undefined
427
+ ? options.headerBackTitle
428
+ : undefined
429
+ }
430
+ headerTopInsetEnabled={headerTopInsetEnabled}
431
+ canGoBack={headerBack !== undefined}
432
+ />
433
+ </HeaderHeightContext.Provider>
434
+ </AnimatedHeaderHeightContext.Provider>
354
435
  </HeaderShownContext.Provider>
355
436
  </NavigationRouteContext.Provider>
356
437
  </NavigationContext.Provider>
@@ -364,86 +445,100 @@ type Props = {
364
445
  descriptors: NativeStackDescriptorMap;
365
446
  };
366
447
 
367
- function NativeStackViewInner({ state, navigation, descriptors }: Props) {
448
+ export function NativeStackView({ state, navigation, descriptors }: Props) {
368
449
  const { setNextDismissedKey } = useDismissedRouteError(state);
369
450
 
451
+ const { colors } = useTheme();
452
+
370
453
  useInvalidPreventRemoveError(descriptors);
371
454
 
372
- return (
373
- <ScreenStack style={styles.container}>
374
- {state.routes.map((route, index) => {
375
- const descriptor = descriptors[route.key];
376
- const isFocused = state.index === index;
377
- const previousKey = state.routes[index - 1]?.key;
378
- const nextKey = state.routes[index + 1]?.key;
379
- const previousDescriptor = previousKey
380
- ? descriptors[previousKey]
381
- : undefined;
382
- const nextDescriptor = nextKey ? descriptors[nextKey] : undefined;
383
-
384
- return (
385
- <SceneView
386
- key={route.key}
387
- index={index}
388
- focused={isFocused}
389
- descriptor={descriptor}
390
- previousDescriptor={previousDescriptor}
391
- nextDescriptor={nextDescriptor}
392
- onWillDisappear={() => {
393
- navigation.emit({
394
- type: 'transitionStart',
395
- data: { closing: true },
396
- target: route.key,
397
- });
398
- }}
399
- onAppear={() => {
400
- navigation.emit({
401
- type: 'transitionEnd',
402
- data: { closing: false },
403
- target: route.key,
404
- });
405
- }}
406
- onDisappear={() => {
407
- navigation.emit({
408
- type: 'transitionEnd',
409
- data: { closing: true },
410
- target: route.key,
411
- });
412
- }}
413
- onDismissed={(event) => {
414
- navigation.dispatch({
415
- ...StackActions.pop(event.nativeEvent.dismissCount),
416
- source: route.key,
417
- target: state.key,
418
- });
419
-
420
- setNextDismissedKey(route.key);
421
- }}
422
- onHeaderBackButtonClicked={() => {
423
- navigation.dispatch({
424
- ...StackActions.pop(),
425
- source: route.key,
426
- target: state.key,
427
- });
428
- }}
429
- onNativeDismissCancelled={(event) => {
430
- navigation.dispatch({
431
- ...StackActions.pop(event.nativeEvent.dismissCount),
432
- source: route.key,
433
- target: state.key,
434
- });
435
- }}
436
- />
437
- );
438
- })}
439
- </ScreenStack>
440
- );
441
- }
455
+ const modalRouteKeys = getModalRouteKeys(state.routes, descriptors);
442
456
 
443
- export function NativeStackView(props: Props) {
444
457
  return (
445
- <SafeAreaProviderCompat>
446
- <NativeStackViewInner {...props} />
458
+ <SafeAreaProviderCompat style={{ backgroundColor: colors.background }}>
459
+ <ScreenStack style={styles.container}>
460
+ {state.routes.map((route, index) => {
461
+ const descriptor = descriptors[route.key];
462
+ const isFocused = state.index === index;
463
+ const previousKey = state.routes[index - 1]?.key;
464
+ const nextKey = state.routes[index + 1]?.key;
465
+ const previousDescriptor = previousKey
466
+ ? descriptors[previousKey]
467
+ : undefined;
468
+ const nextDescriptor = nextKey ? descriptors[nextKey] : undefined;
469
+
470
+ const isModal = modalRouteKeys.includes(route.key);
471
+
472
+ return (
473
+ <SceneView
474
+ key={route.key}
475
+ index={index}
476
+ focused={isFocused}
477
+ descriptor={descriptor}
478
+ previousDescriptor={previousDescriptor}
479
+ nextDescriptor={nextDescriptor}
480
+ isPresentationModal={isModal}
481
+ onWillDisappear={() => {
482
+ navigation.emit({
483
+ type: 'transitionStart',
484
+ data: { closing: true },
485
+ target: route.key,
486
+ });
487
+ }}
488
+ onWillAppear={() => {
489
+ navigation.emit({
490
+ type: 'transitionStart',
491
+ data: { closing: false },
492
+ target: route.key,
493
+ });
494
+ }}
495
+ onAppear={() => {
496
+ navigation.emit({
497
+ type: 'transitionEnd',
498
+ data: { closing: false },
499
+ target: route.key,
500
+ });
501
+ }}
502
+ onDisappear={() => {
503
+ navigation.emit({
504
+ type: 'transitionEnd',
505
+ data: { closing: true },
506
+ target: route.key,
507
+ });
508
+ }}
509
+ onDismissed={(event) => {
510
+ navigation.dispatch({
511
+ ...StackActions.pop(event.nativeEvent.dismissCount),
512
+ source: route.key,
513
+ target: state.key,
514
+ });
515
+
516
+ setNextDismissedKey(route.key);
517
+ }}
518
+ onHeaderBackButtonClicked={() => {
519
+ navigation.dispatch({
520
+ ...StackActions.pop(),
521
+ source: route.key,
522
+ target: state.key,
523
+ });
524
+ }}
525
+ onNativeDismissCancelled={(event) => {
526
+ navigation.dispatch({
527
+ ...StackActions.pop(event.nativeEvent.dismissCount),
528
+ source: route.key,
529
+ target: state.key,
530
+ });
531
+ }}
532
+ onGestureCancel={() => {
533
+ navigation.emit({
534
+ type: 'gestureCancel',
535
+ target: route.key,
536
+ });
537
+ }}
538
+ />
539
+ );
540
+ })}
541
+ </ScreenStack>
447
542
  </SafeAreaProviderCompat>
448
543
  );
449
544
  }
@@ -459,7 +554,18 @@ const styles = StyleSheet.create({
459
554
  absolute: {
460
555
  position: 'absolute',
461
556
  top: 0,
462
- left: 0,
463
- right: 0,
557
+ start: 0,
558
+ end: 0,
559
+ },
560
+ translucent: {
561
+ position: 'absolute',
562
+ top: 0,
563
+ start: 0,
564
+ end: 0,
565
+ zIndex: 1,
566
+ elevation: 1,
567
+ },
568
+ background: {
569
+ overflow: 'hidden',
464
570
  },
465
571
  });