@react-navigation/native-stack 7.0.0-alpha.8 → 7.0.0-rc.0

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 (76) 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 -58
  25. package/lib/commonjs/views/NativeStackView.js.map +1 -1
  26. package/lib/commonjs/views/NativeStackView.native.js +145 -58
  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 -58
  47. package/lib/module/views/NativeStackView.js.map +1 -1
  48. package/lib/module/views/NativeStackView.native.js +144 -57
  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 +95 -9
  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 +0 -1
  63. package/lib/typescript/src/views/HeaderConfig.d.ts.map +1 -1
  64. package/lib/typescript/src/views/NativeStackView.d.ts.map +1 -1
  65. package/lib/typescript/src/views/NativeStackView.native.d.ts +1 -1
  66. package/lib/typescript/src/views/NativeStackView.native.d.ts.map +1 -1
  67. package/package.json +15 -15
  68. package/src/index.tsx +1 -0
  69. package/src/navigators/createNativeStackNavigator.tsx +30 -6
  70. package/src/types.tsx +100 -6
  71. package/src/utils/debounce.tsx +14 -0
  72. package/src/utils/getModalRoutesKeys.ts +21 -0
  73. package/src/utils/useAnimatedHeaderHeight.tsx +1 -1
  74. package/src/views/HeaderConfig.tsx +12 -5
  75. package/src/views/NativeStackView.native.tsx +207 -98
  76. package/src/views/NativeStackView.tsx +119 -123
@@ -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';
@@ -104,7 +107,12 @@ const MaybeNestedStack = ({
104
107
  if (isHeaderInModal) {
105
108
  return (
106
109
  <ScreenStack style={styles.container}>
107
- <Screen enabled style={StyleSheet.absoluteFill}>
110
+ <Screen
111
+ enabled
112
+ isNativeStack
113
+ hasLargeHeader={options.headerLargeTitle ?? false}
114
+ style={StyleSheet.absoluteFill}
115
+ >
108
116
  {content}
109
117
  <HeaderConfig
110
118
  {...options}
@@ -127,12 +135,15 @@ type SceneViewProps = {
127
135
  descriptor: NativeStackDescriptor;
128
136
  previousDescriptor?: NativeStackDescriptor;
129
137
  nextDescriptor?: NativeStackDescriptor;
138
+ isPresentationModal?: boolean;
130
139
  onWillDisappear: () => void;
140
+ onWillAppear: () => void;
131
141
  onAppear: () => void;
132
142
  onDisappear: () => void;
133
143
  onDismissed: ScreenProps['onDismissed'];
134
144
  onHeaderBackButtonClicked: ScreenProps['onHeaderBackButtonClicked'];
135
145
  onNativeDismissCancelled: ScreenProps['onDismissed'];
146
+ onGestureCancel: ScreenProps['onGestureCancel'];
136
147
  };
137
148
 
138
149
  const SceneView = ({
@@ -141,20 +152,23 @@ const SceneView = ({
141
152
  descriptor,
142
153
  previousDescriptor,
143
154
  nextDescriptor,
155
+ isPresentationModal,
144
156
  onWillDisappear,
157
+ onWillAppear,
145
158
  onAppear,
146
159
  onDisappear,
147
160
  onDismissed,
148
161
  onHeaderBackButtonClicked,
149
162
  onNativeDismissCancelled,
163
+ onGestureCancel,
150
164
  }: SceneViewProps) => {
151
165
  const { route, navigation, options, render } = descriptor;
152
166
 
153
167
  let {
154
168
  animation,
155
169
  animationMatchesGesture,
170
+ presentation = isPresentationModal ? 'modal' : 'card',
156
171
  fullScreenGestureEnabled,
157
- presentation = 'card',
158
172
  } = options;
159
173
 
160
174
  const {
@@ -162,15 +176,23 @@ const SceneView = ({
162
176
  animationTypeForReplace = 'push',
163
177
  gestureEnabled,
164
178
  gestureDirection = presentation === 'card' ? 'horizontal' : 'vertical',
179
+ gestureResponseDistance,
165
180
  header,
166
181
  headerBackButtonMenuEnabled,
167
182
  headerShown,
168
183
  headerBackground,
169
184
  headerTransparent,
170
185
  autoHideHomeIndicator,
186
+ keyboardHandlingEnabled,
171
187
  navigationBarColor,
188
+ navigationBarTranslucent,
172
189
  navigationBarHidden,
173
190
  orientation,
191
+ sheetAllowedDetents = 'large',
192
+ sheetLargestUndimmedDetent = 'all',
193
+ sheetGrabberVisible = false,
194
+ sheetCornerRadius = -1.0,
195
+ sheetExpandsWhenScrolledToEdge = true,
174
196
  statusBarAnimation,
175
197
  statusBarHidden,
176
198
  statusBarStyle,
@@ -231,25 +253,59 @@ const SceneView = ({
231
253
  ? 0
232
254
  : insets.top;
233
255
 
234
- // On models with Dynamic Island the status bar height is smaller than the safe area top inset.
235
- const hasDynamicIsland = Platform.OS === 'ios' && topInset > 50;
236
- const statusBarHeight = hasDynamicIsland ? topInset - 5 : topInset;
237
-
238
256
  const { preventedRoutes } = usePreventRemoveContext();
239
257
 
240
- const defaultHeaderHeight = getDefaultHeaderHeight(
241
- frame,
242
- isModal,
243
- statusBarHeight
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
+ []
244
273
  );
245
274
 
246
- const [customHeaderHeight, setCustomHeaderHeight] =
247
- React.useState(defaultHeaderHeight);
275
+ const hasCustomHeader = header !== undefined;
276
+
277
+ let headerHeightCorrectionOffset = 0;
248
278
 
249
- const animatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
279
+ if (isAndroid && !hasCustomHeader) {
280
+ const statusBarHeight = StatusBar.currentHeight ?? 0;
250
281
 
251
- const headerTopInsetEnabled = topInset !== 0;
252
- const headerHeight = header ? customHeaderHeight : 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
+ }
288
+
289
+ const rawAnimatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
290
+ const animatedHeaderHeight = React.useMemo(
291
+ () =>
292
+ Animated.add<number>(
293
+ rawAnimatedHeaderHeight,
294
+ headerHeightCorrectionOffset
295
+ ),
296
+ [headerHeightCorrectionOffset, rawAnimatedHeaderHeight]
297
+ );
298
+
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;
253
309
 
254
310
  const backTitle = previousDescriptor
255
311
  ? getHeaderTitle(previousDescriptor.options, previousDescriptor.route.name)
@@ -270,7 +326,9 @@ const SceneView = ({
270
326
  <Screen
271
327
  key={route.key}
272
328
  enabled
329
+ isNativeStack
273
330
  style={StyleSheet.absoluteFill}
331
+ hasLargeHeader={options.headerLargeTitle ?? false}
274
332
  customAnimationOnSwipe={animationMatchesGesture}
275
333
  fullScreenSwipeEnabled={fullScreenGestureEnabled}
276
334
  gestureEnabled={
@@ -281,12 +339,20 @@ const SceneView = ({
281
339
  : gestureEnabled
282
340
  }
283
341
  homeIndicatorHidden={autoHideHomeIndicator}
342
+ hideKeyboardOnSwipe={keyboardHandlingEnabled}
284
343
  navigationBarColor={navigationBarColor}
344
+ // @ts-expect-error prop supported from react-native-screens 3.32.0 onwards
345
+ navigationBarTranslucent={navigationBarTranslucent}
285
346
  navigationBarHidden={navigationBarHidden}
286
347
  replaceAnimation={animationTypeForReplace}
287
348
  stackPresentation={presentation === 'card' ? 'push' : presentation}
288
349
  stackAnimation={animation}
289
350
  screenOrientation={orientation}
351
+ sheetAllowedDetents={sheetAllowedDetents}
352
+ sheetLargestUndimmedDetent={sheetLargestUndimmedDetent}
353
+ sheetGrabberVisible={sheetGrabberVisible}
354
+ sheetCornerRadius={sheetCornerRadius}
355
+ sheetExpandsWhenScrolledToEdge={sheetExpandsWhenScrolledToEdge}
290
356
  statusBarAnimation={statusBarAnimation}
291
357
  statusBarHidden={statusBarHidden}
292
358
  statusBarStyle={statusBarStyle}
@@ -294,16 +360,17 @@ const SceneView = ({
294
360
  statusBarTranslucent={statusBarTranslucent}
295
361
  swipeDirection={gestureDirectionOverride}
296
362
  transitionDuration={animationDuration}
363
+ onWillAppear={onWillAppear}
297
364
  onWillDisappear={onWillDisappear}
298
365
  onAppear={onAppear}
299
366
  onDisappear={onDisappear}
300
367
  onDismissed={onDismissed}
301
- isNativeStack
368
+ onGestureCancel={onGestureCancel}
369
+ gestureResponseDistance={gestureResponseDistance}
302
370
  nativeBackButtonDismissalEnabled={false} // on Android
303
371
  onHeaderBackButtonClicked={onHeaderBackButtonClicked}
304
372
  preventNativeDismiss={isRemovePrevented} // on iOS
305
373
  onNativeDismissCancelled={onNativeDismissCancelled}
306
- // @ts-expect-error this prop is available since rn-screens 3.26
307
374
  // Unfortunately, because of the bug that exists on Fabric, where native event drivers
308
375
  // for Animated objects are being created after the first notifications about the header height
309
376
  // from the native side, `onHeaderHeightChange` event does not notify
@@ -312,11 +379,36 @@ const SceneView = ({
312
379
  [
313
380
  {
314
381
  nativeEvent: {
315
- headerHeight: animatedHeaderHeight,
382
+ headerHeight: rawAnimatedHeaderHeight,
316
383
  },
317
384
  },
318
385
  ],
319
- { 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
+ }
320
412
  )}
321
413
  // this prop is available since rn-screens 3.16
322
414
  freezeOnBlur={freezeOnBlur}
@@ -368,7 +460,10 @@ const SceneView = ({
368
460
  {header !== undefined && headerShown !== false ? (
369
461
  <View
370
462
  onLayout={(e) => {
371
- setCustomHeaderHeight(e.nativeEvent.layout.height);
463
+ const headerHeight = e.nativeEvent.layout.height;
464
+
465
+ setHeaderHeight(headerHeight);
466
+ rawAnimatedHeaderHeight.setValue(headerHeight);
372
467
  }}
373
468
  style={headerTransparent ? styles.absolute : null}
374
469
  >
@@ -425,86 +520,100 @@ type Props = {
425
520
  descriptors: NativeStackDescriptorMap;
426
521
  };
427
522
 
428
- function NativeStackViewInner({ state, navigation, descriptors }: Props) {
523
+ export function NativeStackView({ state, navigation, descriptors }: Props) {
429
524
  const { setNextDismissedKey } = useDismissedRouteError(state);
430
525
 
526
+ const { colors } = useTheme();
527
+
431
528
  useInvalidPreventRemoveError(descriptors);
432
529
 
433
- return (
434
- <ScreenStack style={styles.container}>
435
- {state.routes.map((route, index) => {
436
- const descriptor = descriptors[route.key];
437
- const isFocused = state.index === index;
438
- const previousKey = state.routes[index - 1]?.key;
439
- const nextKey = state.routes[index + 1]?.key;
440
- const previousDescriptor = previousKey
441
- ? descriptors[previousKey]
442
- : undefined;
443
- const nextDescriptor = nextKey ? descriptors[nextKey] : undefined;
444
-
445
- return (
446
- <SceneView
447
- key={route.key}
448
- index={index}
449
- focused={isFocused}
450
- descriptor={descriptor}
451
- previousDescriptor={previousDescriptor}
452
- nextDescriptor={nextDescriptor}
453
- onWillDisappear={() => {
454
- navigation.emit({
455
- type: 'transitionStart',
456
- data: { closing: true },
457
- target: route.key,
458
- });
459
- }}
460
- onAppear={() => {
461
- navigation.emit({
462
- type: 'transitionEnd',
463
- data: { closing: false },
464
- target: route.key,
465
- });
466
- }}
467
- onDisappear={() => {
468
- navigation.emit({
469
- type: 'transitionEnd',
470
- data: { closing: true },
471
- target: route.key,
472
- });
473
- }}
474
- onDismissed={(event) => {
475
- navigation.dispatch({
476
- ...StackActions.pop(event.nativeEvent.dismissCount),
477
- source: route.key,
478
- target: state.key,
479
- });
480
-
481
- setNextDismissedKey(route.key);
482
- }}
483
- onHeaderBackButtonClicked={() => {
484
- navigation.dispatch({
485
- ...StackActions.pop(),
486
- source: route.key,
487
- target: state.key,
488
- });
489
- }}
490
- onNativeDismissCancelled={(event) => {
491
- navigation.dispatch({
492
- ...StackActions.pop(event.nativeEvent.dismissCount),
493
- source: route.key,
494
- target: state.key,
495
- });
496
- }}
497
- />
498
- );
499
- })}
500
- </ScreenStack>
501
- );
502
- }
530
+ const modalRouteKeys = getModalRouteKeys(state.routes, descriptors);
503
531
 
504
- export function NativeStackView(props: Props) {
505
532
  return (
506
- <SafeAreaProviderCompat>
507
- <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>
508
617
  </SafeAreaProviderCompat>
509
618
  );
510
619
  }
@@ -520,14 +629,14 @@ const styles = StyleSheet.create({
520
629
  absolute: {
521
630
  position: 'absolute',
522
631
  top: 0,
523
- left: 0,
524
- right: 0,
632
+ start: 0,
633
+ end: 0,
525
634
  },
526
635
  translucent: {
527
636
  position: 'absolute',
528
637
  top: 0,
529
- left: 0,
530
- right: 0,
638
+ start: 0,
639
+ end: 0,
531
640
  zIndex: 1,
532
641
  elevation: 1,
533
642
  },