@react-navigation/native-stack 7.8.6 → 8.0.0-alpha.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 (37) hide show
  1. package/lib/module/index.js +1 -1
  2. package/lib/module/index.js.map +1 -1
  3. package/lib/module/navigators/createNativeStackNavigator.js +7 -6
  4. package/lib/module/navigators/createNativeStackNavigator.js.map +1 -1
  5. package/lib/module/views/NativeStackView.js +4 -4
  6. package/lib/module/views/NativeStackView.js.map +1 -1
  7. package/lib/module/views/NativeStackView.native.js +159 -200
  8. package/lib/module/views/NativeStackView.native.js.map +1 -1
  9. package/lib/module/views/useHeaderConfigProps.js +44 -24
  10. package/lib/module/views/useHeaderConfigProps.js.map +1 -1
  11. package/lib/typescript/src/index.d.ts +1 -1
  12. package/lib/typescript/src/index.d.ts.map +1 -1
  13. package/lib/typescript/src/navigators/createNativeStackNavigator.d.ts +10 -6
  14. package/lib/typescript/src/navigators/createNativeStackNavigator.d.ts.map +1 -1
  15. package/lib/typescript/src/types.d.ts +72 -67
  16. package/lib/typescript/src/types.d.ts.map +1 -1
  17. package/lib/typescript/src/views/NativeStackView.d.ts.map +1 -1
  18. package/lib/typescript/src/views/NativeStackView.native.d.ts.map +1 -1
  19. package/lib/typescript/src/views/useHeaderConfigProps.d.ts +1 -1
  20. package/lib/typescript/src/views/useHeaderConfigProps.d.ts.map +1 -1
  21. package/package.json +15 -17
  22. package/src/index.tsx +4 -1
  23. package/src/navigators/createNativeStackNavigator.tsx +48 -25
  24. package/src/types.tsx +72 -72
  25. package/src/views/NativeStackView.native.tsx +191 -253
  26. package/src/views/NativeStackView.tsx +6 -9
  27. package/src/views/useHeaderConfigProps.tsx +32 -30
  28. package/lib/module/views/FontProcessor.js +0 -6
  29. package/lib/module/views/FontProcessor.js.map +0 -1
  30. package/lib/module/views/FontProcessor.native.js +0 -12
  31. package/lib/module/views/FontProcessor.native.js.map +0 -1
  32. package/lib/typescript/src/views/FontProcessor.d.ts +0 -2
  33. package/lib/typescript/src/views/FontProcessor.d.ts.map +0 -1
  34. package/lib/typescript/src/views/FontProcessor.native.d.ts +0 -2
  35. package/lib/typescript/src/views/FontProcessor.native.d.ts.map +0 -1
  36. package/src/views/FontProcessor.native.tsx +0 -12
  37. package/src/views/FontProcessor.tsx +0 -5
@@ -4,12 +4,11 @@ import {
4
4
  HeaderBackContext,
5
5
  HeaderHeightContext,
6
6
  HeaderShownContext,
7
- SafeAreaProviderCompat,
8
7
  useFrameSize,
9
8
  } from '@react-navigation/elements';
9
+ import { SafeAreaProviderCompat } from '@react-navigation/elements/internal';
10
10
  import {
11
- NavigationContext,
12
- NavigationRouteContext,
11
+ NavigationProvider,
13
12
  type ParamListBase,
14
13
  type RouteProp,
15
14
  StackActions,
@@ -21,7 +20,6 @@ import * as React from 'react';
21
20
  import {
22
21
  Animated,
23
22
  Platform,
24
- StatusBar,
25
23
  StyleSheet,
26
24
  useAnimatedValue,
27
25
  View,
@@ -79,7 +77,6 @@ const SceneView = ({
79
77
  shouldFreeze,
80
78
  descriptor,
81
79
  previousDescriptor,
82
- nextDescriptor,
83
80
  isPresentationModal,
84
81
  isPreloaded,
85
82
  onWillDisappear,
@@ -94,19 +91,15 @@ const SceneView = ({
94
91
  }: SceneViewProps) => {
95
92
  const { route, navigation, options, render } = descriptor;
96
93
 
97
- let {
98
- animation,
99
- animationMatchesGesture,
100
- presentation = isPresentationModal ? 'modal' : 'card',
101
- fullScreenGestureEnabled,
102
- } = options;
103
-
104
94
  const {
95
+ animation,
105
96
  animationDuration,
97
+ animationMatchesGesture,
106
98
  animationTypeForReplace = 'push',
99
+ fullScreenGestureEnabled,
107
100
  fullScreenGestureShadowEnabled = true,
108
101
  gestureEnabled,
109
- gestureDirection = presentation === 'card' ? 'horizontal' : 'vertical',
102
+ gestureDirection,
110
103
  gestureResponseDistance,
111
104
  header,
112
105
  headerBackButtonMenuEnabled,
@@ -115,8 +108,6 @@ const SceneView = ({
115
108
  headerTransparent,
116
109
  autoHideHomeIndicator,
117
110
  keyboardHandlingEnabled,
118
- navigationBarColor,
119
- navigationBarTranslucent,
120
111
  navigationBarHidden,
121
112
  orientation,
122
113
  sheetAllowedDetents = [1.0],
@@ -129,38 +120,13 @@ const SceneView = ({
129
120
  statusBarAnimation,
130
121
  statusBarHidden,
131
122
  statusBarStyle,
132
- statusBarTranslucent,
133
- statusBarBackgroundColor,
134
123
  unstable_sheetFooter,
135
124
  scrollEdgeEffects,
136
125
  freezeOnBlur,
137
126
  contentStyle,
138
127
  } = options;
139
128
 
140
- if (gestureDirection === 'vertical' && Platform.OS === 'ios') {
141
- // for `vertical` direction to work, we need to set `fullScreenGestureEnabled` to `true`
142
- // so the screen can be dismissed from any point on screen.
143
- // `animationMatchesGesture` needs to be set to `true` so the `animation` set by user can be used,
144
- // otherwise `simple_push` will be used.
145
- // Also, the default animation for this direction seems to be `slide_from_bottom`.
146
- if (fullScreenGestureEnabled === undefined) {
147
- fullScreenGestureEnabled = true;
148
- }
149
-
150
- if (animationMatchesGesture === undefined) {
151
- animationMatchesGesture = true;
152
- }
153
-
154
- if (animation === undefined) {
155
- animation = 'slide_from_bottom';
156
- }
157
- }
158
-
159
- // workaround for rn-screens where gestureDirection has to be set on both
160
- // current and previous screen - software-mansion/react-native-screens/pull/1509
161
- const nextGestureDirection = nextDescriptor?.options.gestureDirection;
162
- const gestureDirectionOverride =
163
- nextGestureDirection != null ? nextGestureDirection : gestureDirection;
129
+ let { presentation = isPresentationModal ? 'modal' : 'card' } = options;
164
130
 
165
131
  if (index === 0) {
166
132
  // first screen should always be treated as `card`, it resolves problems with no header animation
@@ -199,7 +165,11 @@ const SceneView = ({
199
165
  // So our `getDefaultHeaderHeight` doesn't return the correct value
200
166
  // So we hardcode the value here for now until screens is updated
201
167
  android: ANDROID_DEFAULT_HEADER_HEIGHT + topInset,
202
- default: getDefaultHeaderHeight(frame, isModal, topInset),
168
+ default: getDefaultHeaderHeight({
169
+ landscape: frame.width > frame.height,
170
+ modalPresentation: isModal,
171
+ topInset,
172
+ }),
203
173
  })
204
174
  );
205
175
 
@@ -216,38 +186,7 @@ const SceneView = ({
216
186
 
217
187
  const hasCustomHeader = header != null;
218
188
 
219
- let headerHeightCorrectionOffset = 0;
220
-
221
- if (Platform.OS === 'android' && !hasCustomHeader) {
222
- const statusBarHeight = StatusBar.currentHeight ?? 0;
223
-
224
- // FIXME: On Android, the native header height is not correctly calculated
225
- // It includes status bar height even if statusbar is not translucent
226
- // And the statusbar value itself doesn't match the actual status bar height
227
- // So we subtract the bogus status bar height and add the actual top inset
228
- headerHeightCorrectionOffset = -statusBarHeight + topInset;
229
- }
230
-
231
- const rawAnimatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
232
- const animatedHeaderHeight = React.useMemo(
233
- () =>
234
- Animated.add<number>(
235
- rawAnimatedHeaderHeight,
236
- headerHeightCorrectionOffset
237
- ),
238
- [headerHeightCorrectionOffset, rawAnimatedHeaderHeight]
239
- );
240
-
241
- // During the very first render topInset is > 0 when running
242
- // in non edge-to-edge mode on Android, while on every consecutive render
243
- // topInset === 0, causing header content to jump, as we add padding on the first frame,
244
- // just to remove it in next one. To prevent this, when statusBarTranslucent is set,
245
- // we apply additional padding in header only if its true.
246
- // For more details see: https://github.com/react-navigation/react-navigation/pull/12014
247
- const headerTopInsetEnabled =
248
- typeof statusBarTranslucent === 'boolean'
249
- ? statusBarTranslucent
250
- : topInset !== 0;
189
+ const headerTopInsetEnabled = topInset !== 0;
251
190
 
252
191
  const canGoBack = previousDescriptor != null || parentHeaderBack != null;
253
192
  const backTitle = previousDescriptor
@@ -267,6 +206,8 @@ const SceneView = ({
267
206
 
268
207
  const isRemovePrevented = preventedRoutes[route.key]?.preventRemove;
269
208
 
209
+ const animatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
210
+
270
211
  const headerConfig = useHeaderConfigProps({
271
212
  ...options,
272
213
  route,
@@ -281,195 +222,192 @@ const SceneView = ({
281
222
  headerHeight,
282
223
  headerShown: header !== undefined ? false : headerShown,
283
224
  headerTopInsetEnabled,
284
- headerTransparent,
285
225
  headerBack,
286
226
  });
287
227
 
288
- return (
289
- <NavigationContext.Provider value={navigation}>
290
- <NavigationRouteContext.Provider value={route}>
291
- <ScreenStackItem
292
- key={route.key}
293
- screenId={route.key}
294
- activityState={isPreloaded ? 0 : 2}
295
- style={StyleSheet.absoluteFill}
296
- aria-hidden={!focused}
297
- customAnimationOnSwipe={animationMatchesGesture}
298
- fullScreenSwipeEnabled={fullScreenGestureEnabled}
299
- fullScreenSwipeShadowEnabled={fullScreenGestureShadowEnabled}
300
- freezeOnBlur={freezeOnBlur}
301
- gestureEnabled={
302
- Platform.OS === 'android'
303
- ? // This prop enables handling of system back gestures on Android
304
- // Since we handle them in JS side, we disable this
305
- false
306
- : gestureEnabled
307
- }
308
- homeIndicatorHidden={autoHideHomeIndicator}
309
- hideKeyboardOnSwipe={keyboardHandlingEnabled}
310
- navigationBarColor={navigationBarColor}
311
- navigationBarTranslucent={navigationBarTranslucent}
312
- navigationBarHidden={navigationBarHidden}
313
- replaceAnimation={animationTypeForReplace}
314
- stackPresentation={presentation === 'card' ? 'push' : presentation}
315
- stackAnimation={animation}
316
- screenOrientation={orientation}
317
- sheetAllowedDetents={sheetAllowedDetents}
318
- sheetLargestUndimmedDetentIndex={sheetLargestUndimmedDetentIndex}
319
- sheetGrabberVisible={sheetGrabberVisible}
320
- sheetInitialDetentIndex={sheetInitialDetentIndex}
321
- sheetCornerRadius={sheetCornerRadius}
322
- sheetElevation={sheetElevation}
323
- sheetExpandsWhenScrolledToEdge={sheetExpandsWhenScrolledToEdge}
324
- statusBarAnimation={statusBarAnimation}
325
- statusBarHidden={statusBarHidden}
326
- statusBarStyle={statusBarStyle}
327
- statusBarColor={statusBarBackgroundColor}
328
- statusBarTranslucent={statusBarTranslucent}
329
- swipeDirection={gestureDirectionOverride}
330
- transitionDuration={animationDuration}
331
- onWillAppear={onWillAppear}
332
- onWillDisappear={onWillDisappear}
333
- onAppear={onAppear}
334
- onDisappear={onDisappear}
335
- onDismissed={onDismissed}
336
- onGestureCancel={onGestureCancel}
337
- onSheetDetentChanged={onSheetDetentChanged}
338
- gestureResponseDistance={gestureResponseDistance}
339
- nativeBackButtonDismissalEnabled={false} // on Android
340
- onHeaderBackButtonClicked={onHeaderBackButtonClicked}
341
- preventNativeDismiss={isRemovePrevented} // on iOS
342
- scrollEdgeEffects={{
343
- bottom: scrollEdgeEffects?.bottom ?? 'automatic',
344
- top: scrollEdgeEffects?.top ?? 'automatic',
345
- left: scrollEdgeEffects?.left ?? 'automatic',
346
- right: scrollEdgeEffects?.right ?? 'automatic',
347
- }}
348
- onNativeDismissCancelled={onNativeDismissCancelled}
349
- // Unfortunately, because of the bug that exists on Fabric, where native event drivers
350
- // for Animated objects are being created after the first notifications about the header height
351
- // from the native side, `onHeaderHeightChange` event does not notify
352
- // `animatedHeaderHeight` about initial values on appearing screens at the moment.
353
- onHeaderHeightChange={Animated.event(
354
- [
355
- {
356
- nativeEvent: {
357
- headerHeight: rawAnimatedHeaderHeight,
358
- },
359
- },
360
- ],
361
- {
362
- useNativeDriver,
363
- listener: (e) => {
364
- if (hasCustomHeader) {
365
- // If we have a custom header, don't use native header height
366
- return;
367
- }
368
-
228
+ const onHeaderHeightChange = hasCustomHeader
229
+ ? // If we have a custom header, don't use native header height
230
+ undefined
231
+ : // On Fabric, there's a bug where native event drivers for Animated objects
232
+ // are created after the first notifications about the header height
233
+ // from the native side, `onHeaderHeightChange` event does not notify
234
+ // `animatedHeaderHeight` about initial values on appearing screens at the moment.
235
+ Animated.event(
236
+ [
237
+ {
238
+ nativeEvent: {
239
+ headerHeight: animatedHeaderHeight,
240
+ },
241
+ },
242
+ ],
243
+ {
244
+ useNativeDriver,
245
+ listener: (e) => {
246
+ if (
247
+ e.nativeEvent &&
248
+ typeof e.nativeEvent === 'object' &&
249
+ 'headerHeight' in e.nativeEvent &&
250
+ typeof e.nativeEvent.headerHeight === 'number'
251
+ ) {
252
+ const headerHeight = e.nativeEvent.headerHeight;
253
+
254
+ // Only debounce if header has large title or search bar
255
+ // As it's the only case where the header height can change frequently
256
+ const doesHeaderAnimate =
257
+ Platform.OS === 'ios' &&
258
+ (options.headerLargeTitleEnabled ||
259
+ options.headerSearchBarOptions);
260
+
261
+ if (doesHeaderAnimate) {
262
+ setHeaderHeightDebounced(headerHeight);
263
+ } else {
369
264
  if (
370
265
  Platform.OS === 'android' &&
371
- (headerBackground != null || headerTransparent)
266
+ headerHeight !== 0 &&
267
+ headerHeight <= ANDROID_DEFAULT_HEADER_HEIGHT
372
268
  ) {
373
- // FIXME: On Android, we get 0 if the header is translucent
374
- // So we set a default height in that case
375
- setHeaderHeight(ANDROID_DEFAULT_HEADER_HEIGHT + topInset);
376
- return;
269
+ // FIXME: On Android, events may get delivered out-of-order
270
+ // https://github.com/facebook/react-native/issues/54636
271
+ // We seem to get header height without status bar height first,
272
+ // and then the correct height with status bar height included
273
+ // But due to out-of-order delivery, we may get the correct height first
274
+ // and then the one without status bar height
275
+ // This is hack to include status bar height if it's not already included
276
+ // It only works because header height doesn't change dynamically on Android
277
+ setHeaderHeight(headerHeight + insets.top);
278
+ } else {
279
+ setHeaderHeight(headerHeight);
377
280
  }
281
+ }
282
+ }
283
+ },
284
+ }
285
+ );
378
286
 
379
- if (
380
- e.nativeEvent &&
381
- typeof e.nativeEvent === 'object' &&
382
- 'headerHeight' in e.nativeEvent &&
383
- typeof e.nativeEvent.headerHeight === 'number'
384
- ) {
385
- const headerHeight =
386
- e.nativeEvent.headerHeight + headerHeightCorrectionOffset;
387
-
388
- // Only debounce if header has large title or search bar
389
- // As it's the only case where the header height can change frequently
390
- const doesHeaderAnimate =
391
- Platform.OS === 'ios' &&
392
- (options.headerLargeTitleEnabled ||
393
- options.headerLargeTitle ||
394
- options.headerSearchBarOptions);
395
-
396
- if (doesHeaderAnimate) {
397
- setHeaderHeightDebounced(headerHeight);
398
- } else {
399
- setHeaderHeight(headerHeight);
400
- }
401
- }
402
- },
287
+ return (
288
+ <NavigationProvider navigation={navigation} route={route}>
289
+ <ScreenStackItem
290
+ key={route.key}
291
+ screenId={route.key}
292
+ activityState={isPreloaded ? 0 : 2}
293
+ style={StyleSheet.absoluteFill}
294
+ aria-hidden={!focused}
295
+ customAnimationOnSwipe={animationMatchesGesture}
296
+ fullScreenSwipeEnabled={fullScreenGestureEnabled}
297
+ fullScreenSwipeShadowEnabled={fullScreenGestureShadowEnabled}
298
+ freezeOnBlur={freezeOnBlur}
299
+ gestureEnabled={
300
+ Platform.OS === 'android'
301
+ ? // This prop enables handling of system back gestures on Android
302
+ // Since we handle them in JS side, we disable this
303
+ false
304
+ : gestureEnabled
305
+ }
306
+ homeIndicatorHidden={autoHideHomeIndicator}
307
+ hideKeyboardOnSwipe={keyboardHandlingEnabled}
308
+ navigationBarHidden={navigationBarHidden}
309
+ replaceAnimation={animationTypeForReplace}
310
+ stackPresentation={presentation === 'card' ? 'push' : presentation}
311
+ stackAnimation={animation}
312
+ screenOrientation={orientation}
313
+ sheetAllowedDetents={sheetAllowedDetents}
314
+ sheetLargestUndimmedDetentIndex={sheetLargestUndimmedDetentIndex}
315
+ sheetGrabberVisible={sheetGrabberVisible}
316
+ sheetInitialDetentIndex={sheetInitialDetentIndex}
317
+ sheetCornerRadius={sheetCornerRadius}
318
+ sheetElevation={sheetElevation}
319
+ sheetExpandsWhenScrolledToEdge={sheetExpandsWhenScrolledToEdge}
320
+ statusBarAnimation={statusBarAnimation}
321
+ statusBarHidden={statusBarHidden}
322
+ statusBarStyle={statusBarStyle}
323
+ swipeDirection={gestureDirection}
324
+ transitionDuration={animationDuration}
325
+ onWillAppear={onWillAppear}
326
+ onWillDisappear={onWillDisappear}
327
+ onAppear={onAppear}
328
+ onDisappear={onDisappear}
329
+ onDismissed={onDismissed}
330
+ onGestureCancel={onGestureCancel}
331
+ onSheetDetentChanged={onSheetDetentChanged}
332
+ gestureResponseDistance={gestureResponseDistance}
333
+ nativeBackButtonDismissalEnabled={false} // on Android
334
+ onHeaderBackButtonClicked={onHeaderBackButtonClicked}
335
+ preventNativeDismiss={isRemovePrevented} // on iOS
336
+ scrollEdgeEffects={{
337
+ bottom: scrollEdgeEffects?.bottom ?? 'automatic',
338
+ top: scrollEdgeEffects?.top ?? 'automatic',
339
+ left: scrollEdgeEffects?.left ?? 'automatic',
340
+ right: scrollEdgeEffects?.right ?? 'automatic',
341
+ }}
342
+ onNativeDismissCancelled={onNativeDismissCancelled}
343
+ onHeaderHeightChange={onHeaderHeightChange}
344
+ contentStyle={[
345
+ presentation !== 'transparentModal' &&
346
+ presentation !== 'containedTransparentModal' && {
347
+ backgroundColor: colors.background,
348
+ },
349
+ contentStyle,
350
+ ]}
351
+ headerConfig={headerConfig}
352
+ unstable_sheetFooter={unstable_sheetFooter}
353
+ // When ts-expect-error is added, it affects all the props below it
354
+ // So we keep any props that need it at the end
355
+ // Otherwise invalid props may not be caught by TypeScript
356
+ shouldFreeze={shouldFreeze}
357
+ >
358
+ <AnimatedHeaderHeightContext.Provider value={animatedHeaderHeight}>
359
+ <HeaderHeightContext.Provider
360
+ value={
361
+ headerShown !== false ? headerHeight : (parentHeaderHeight ?? 0)
403
362
  }
404
- )}
405
- contentStyle={[
406
- presentation !== 'transparentModal' &&
407
- presentation !== 'containedTransparentModal' && {
408
- backgroundColor: colors.background,
409
- },
410
- contentStyle,
411
- ]}
412
- headerConfig={headerConfig}
413
- unstable_sheetFooter={unstable_sheetFooter}
414
- // When ts-expect-error is added, it affects all the props below it
415
- // So we keep any props that need it at the end
416
- // Otherwise invalid props may not be caught by TypeScript
417
- shouldFreeze={shouldFreeze}
418
- >
419
- <AnimatedHeaderHeightContext.Provider value={animatedHeaderHeight}>
420
- <HeaderHeightContext.Provider
421
- value={
422
- headerShown !== false ? headerHeight : (parentHeaderHeight ?? 0)
423
- }
424
- >
425
- {headerBackground != null ? (
426
- /**
427
- * To show a custom header background, we render it at the top of the screen below the header
428
- * The header also needs to be positioned absolutely (with `translucent` style)
429
- */
430
- <View
431
- style={[
432
- styles.background,
433
- headerTransparent ? styles.translucent : null,
434
- { height: headerHeight },
435
- ]}
436
- >
437
- {headerBackground()}
438
- </View>
439
- ) : null}
440
- {header != null && headerShown !== false ? (
441
- <View
442
- onLayout={(e) => {
443
- const headerHeight = e.nativeEvent.layout.height;
444
-
445
- setHeaderHeight(headerHeight);
446
- rawAnimatedHeaderHeight.setValue(headerHeight);
447
- }}
448
- style={[
449
- styles.header,
450
- headerTransparent ? styles.absolute : null,
451
- ]}
452
- >
453
- {header({
454
- back: headerBack,
455
- options,
456
- route,
457
- navigation,
458
- })}
459
- </View>
460
- ) : null}
461
- <HeaderShownContext.Provider
462
- value={isParentHeaderShown || headerShown !== false}
363
+ >
364
+ {headerBackground != null ? (
365
+ /**
366
+ * To show a custom header background, we render it at the top of the screen below the header
367
+ * The header also needs to be positioned absolutely (with `translucent` style)
368
+ */
369
+ <View
370
+ style={[
371
+ styles.background,
372
+ headerTransparent ? styles.translucent : null,
373
+ { height: headerHeight },
374
+ ]}
463
375
  >
464
- <HeaderBackContext.Provider value={headerBack}>
465
- {render()}
466
- </HeaderBackContext.Provider>
467
- </HeaderShownContext.Provider>
468
- </HeaderHeightContext.Provider>
469
- </AnimatedHeaderHeightContext.Provider>
470
- </ScreenStackItem>
471
- </NavigationRouteContext.Provider>
472
- </NavigationContext.Provider>
376
+ {headerBackground()}
377
+ </View>
378
+ ) : null}
379
+ {header != null && headerShown !== false ? (
380
+ <View
381
+ onLayout={(e) => {
382
+ const headerHeight = e.nativeEvent.layout.height;
383
+
384
+ animatedHeaderHeight.setValue(headerHeight);
385
+ setHeaderHeight(headerHeight);
386
+ }}
387
+ style={[
388
+ styles.header,
389
+ headerTransparent ? styles.absolute : null,
390
+ ]}
391
+ >
392
+ {header({
393
+ back: headerBack,
394
+ options,
395
+ route,
396
+ navigation,
397
+ })}
398
+ </View>
399
+ ) : null}
400
+ <HeaderShownContext.Provider
401
+ value={isParentHeaderShown || headerShown !== false}
402
+ >
403
+ <HeaderBackContext.Provider value={headerBack}>
404
+ {render()}
405
+ </HeaderBackContext.Provider>
406
+ </HeaderShownContext.Provider>
407
+ </HeaderHeightContext.Provider>
408
+ </AnimatedHeaderHeightContext.Provider>
409
+ </ScreenStackItem>
410
+ </NavigationProvider>
473
411
  );
474
412
  };
475
413
 
@@ -3,10 +3,12 @@ import {
3
3
  Header,
4
4
  HeaderBackButton,
5
5
  HeaderBackContext,
6
- SafeAreaProviderCompat,
7
- Screen,
8
6
  useHeaderHeight,
9
7
  } from '@react-navigation/elements';
8
+ import {
9
+ SafeAreaProviderCompat,
10
+ Screen,
11
+ } from '@react-navigation/elements/internal';
10
12
  import {
11
13
  type ParamListBase,
12
14
  type RouteProp,
@@ -81,7 +83,6 @@ export function NativeStackView({ state, descriptors, describe }: Props) {
81
83
  header,
82
84
  headerShown,
83
85
  headerBackIcon,
84
- headerBackImageSource,
85
86
  headerLeft,
86
87
  headerTransparent,
87
88
  headerBackTitle,
@@ -131,14 +132,10 @@ export function NativeStackView({ state, descriptors, describe }: Props) {
131
132
  label={headerBackTitle ?? label}
132
133
  tintColor={tintColor}
133
134
  backImage={
134
- headerBackIcon !== undefined ||
135
- headerBackImageSource !== undefined
135
+ headerBackIcon !== undefined
136
136
  ? () => (
137
137
  <Image
138
- source={
139
- headerBackIcon?.source ??
140
- headerBackImageSource
141
- }
138
+ source={headerBackIcon.source}
142
139
  resizeMode="contain"
143
140
  tintColor={tintColor}
144
141
  style={styles.backImage}