@react-navigation/native-stack 7.20.0 → 7.21.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.
- package/README.md +1 -1
- package/lib/module/utils/useAnimatedHeaderHeight.js.map +1 -1
- package/lib/module/views/NativeStackView.js +100 -77
- package/lib/module/views/NativeStackView.js.map +1 -1
- package/lib/module/views/NativeStackView.native.js +101 -95
- package/lib/module/views/NativeStackView.native.js.map +1 -1
- package/lib/module/views/useHeaderConfigProps.js +26 -15
- package/lib/module/views/useHeaderConfigProps.js.map +1 -1
- package/lib/typescript/src/types.d.ts +40 -5
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/useAnimatedHeaderHeight.d.ts.map +1 -1
- package/lib/typescript/src/views/NativeStackView.d.ts.map +1 -1
- package/lib/typescript/src/views/NativeStackView.native.d.ts.map +1 -1
- package/lib/typescript/src/views/useHeaderConfigProps.d.ts +1 -1
- package/lib/typescript/src/views/useHeaderConfigProps.d.ts.map +1 -1
- package/package.json +15 -15
- package/src/types.tsx +44 -7
- package/src/utils/useAnimatedHeaderHeight.tsx +5 -3
- package/src/views/NativeStackView.native.tsx +114 -108
- package/src/views/NativeStackView.tsx +149 -113
- package/src/views/useHeaderConfigProps.tsx +41 -28
- package/lib/module/views/FontProcessor.js +0 -6
- package/lib/module/views/FontProcessor.js.map +0 -1
- package/lib/module/views/FontProcessor.native.js +0 -12
- package/lib/module/views/FontProcessor.native.js.map +0 -1
- package/lib/typescript/src/views/FontProcessor.d.ts +0 -2
- package/lib/typescript/src/views/FontProcessor.d.ts.map +0 -1
- package/lib/typescript/src/views/FontProcessor.native.d.ts +0 -2
- package/lib/typescript/src/views/FontProcessor.native.d.ts.map +0 -1
- package/src/views/FontProcessor.native.tsx +0 -12
- package/src/views/FontProcessor.tsx +0 -5
|
@@ -37,6 +37,7 @@ import type {
|
|
|
37
37
|
NativeStackDescriptor,
|
|
38
38
|
NativeStackDescriptorMap,
|
|
39
39
|
NativeStackNavigationHelpers,
|
|
40
|
+
NativeStackNavigationOptions,
|
|
40
41
|
} from '../types';
|
|
41
42
|
import { debounce } from '../utils/debounce';
|
|
42
43
|
import { getModalRouteKeys } from '../utils/getModalRoutesKeys';
|
|
@@ -57,43 +58,119 @@ type SceneViewProps = {
|
|
|
57
58
|
shouldFreeze: boolean;
|
|
58
59
|
descriptor: NativeStackDescriptor;
|
|
59
60
|
previousDescriptor?: NativeStackDescriptor;
|
|
60
|
-
|
|
61
|
+
nextGestureDirection?: NativeStackNavigationOptions['gestureDirection'];
|
|
61
62
|
isPresentationModal?: boolean;
|
|
62
63
|
isPreloaded?: boolean;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
onHeaderBackButtonClicked: ScreenProps['onHeaderBackButtonClicked'];
|
|
69
|
-
onNativeDismissCancelled: ScreenProps['onDismissed'];
|
|
70
|
-
onGestureCancel: ScreenProps['onGestureCancel'];
|
|
71
|
-
onSheetDetentChanged: ScreenProps['onSheetDetentChanged'];
|
|
64
|
+
stateKey: string;
|
|
65
|
+
emit: NativeStackNavigationHelpers['emit'];
|
|
66
|
+
dispatch: NativeStackNavigationHelpers['dispatch'];
|
|
67
|
+
getState: NativeStackNavigationHelpers['getState'];
|
|
68
|
+
setNextDismissedKey: (key: string) => void;
|
|
72
69
|
};
|
|
73
70
|
|
|
74
71
|
const useNativeDriver = Platform.OS !== 'web';
|
|
75
72
|
|
|
76
|
-
const SceneView = ({
|
|
73
|
+
const SceneView = React.memo(function SceneView({
|
|
77
74
|
index,
|
|
78
75
|
focused,
|
|
79
76
|
shouldFreeze,
|
|
80
77
|
descriptor,
|
|
81
78
|
previousDescriptor,
|
|
82
|
-
|
|
79
|
+
nextGestureDirection,
|
|
83
80
|
isPresentationModal,
|
|
84
81
|
isPreloaded,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
onNativeDismissCancelled,
|
|
92
|
-
onGestureCancel,
|
|
93
|
-
onSheetDetentChanged,
|
|
94
|
-
}: SceneViewProps) => {
|
|
82
|
+
stateKey,
|
|
83
|
+
emit,
|
|
84
|
+
dispatch,
|
|
85
|
+
getState,
|
|
86
|
+
setNextDismissedKey,
|
|
87
|
+
}: SceneViewProps) {
|
|
95
88
|
const { route, navigation, options, render } = descriptor;
|
|
96
89
|
|
|
90
|
+
const onWillDisappear = () => {
|
|
91
|
+
emit({
|
|
92
|
+
type: 'transitionStart',
|
|
93
|
+
data: { closing: true },
|
|
94
|
+
target: route.key,
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const onWillAppear = () => {
|
|
99
|
+
emit({
|
|
100
|
+
type: 'transitionStart',
|
|
101
|
+
data: { closing: false },
|
|
102
|
+
target: route.key,
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const onAppear = () => {
|
|
107
|
+
emit({
|
|
108
|
+
type: 'transitionEnd',
|
|
109
|
+
data: { closing: false },
|
|
110
|
+
target: route.key,
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const onDisappear = () => {
|
|
115
|
+
emit({
|
|
116
|
+
type: 'transitionEnd',
|
|
117
|
+
data: { closing: true },
|
|
118
|
+
target: route.key,
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const onDismissed: ScreenProps['onDismissed'] = (event) => {
|
|
123
|
+
const currentState = getState();
|
|
124
|
+
const currentActiveRoutes = currentState.routes.slice(
|
|
125
|
+
0,
|
|
126
|
+
currentState.index + 1
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
if (currentActiveRoutes.some((r) => r.key === route.key)) {
|
|
130
|
+
dispatch({
|
|
131
|
+
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
132
|
+
source: route.key,
|
|
133
|
+
target: currentState.key,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setNextDismissedKey(route.key);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const onHeaderBackButtonClicked = () => {
|
|
141
|
+
dispatch({
|
|
142
|
+
...StackActions.pop(),
|
|
143
|
+
source: route.key,
|
|
144
|
+
target: stateKey,
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const onNativeDismissCancelled: ScreenProps['onDismissed'] = (event) => {
|
|
149
|
+
dispatch({
|
|
150
|
+
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
151
|
+
source: route.key,
|
|
152
|
+
target: stateKey,
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const onGestureCancel = () => {
|
|
157
|
+
emit({
|
|
158
|
+
type: 'gestureCancel',
|
|
159
|
+
target: route.key,
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const onSheetDetentChanged: ScreenProps['onSheetDetentChanged'] = (event) => {
|
|
164
|
+
emit({
|
|
165
|
+
type: 'sheetDetentChange',
|
|
166
|
+
target: route.key,
|
|
167
|
+
data: {
|
|
168
|
+
index: event.nativeEvent.index,
|
|
169
|
+
stable: event.nativeEvent.isStable,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
97
174
|
let {
|
|
98
175
|
animation,
|
|
99
176
|
animationMatchesGesture,
|
|
@@ -161,7 +238,6 @@ const SceneView = ({
|
|
|
161
238
|
|
|
162
239
|
// workaround for rn-screens where gestureDirection has to be set on both
|
|
163
240
|
// current and previous screen - software-mansion/react-native-screens/pull/1509
|
|
164
|
-
const nextGestureDirection = nextDescriptor?.options.gestureDirection;
|
|
165
241
|
const gestureDirectionOverride =
|
|
166
242
|
nextGestureDirection != null ? nextGestureDirection : gestureDirection;
|
|
167
243
|
|
|
@@ -211,7 +287,7 @@ const SceneView = ({
|
|
|
211
287
|
|
|
212
288
|
const [headerHeight, setHeaderHeight] = React.useState(defaultHeaderHeight);
|
|
213
289
|
|
|
214
|
-
// eslint-disable-next-line react
|
|
290
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
215
291
|
const setHeaderHeightDebounced = React.useCallback(
|
|
216
292
|
// Debounce the header height updates to avoid excessive re-renders
|
|
217
293
|
debounce(setHeaderHeight, 100),
|
|
@@ -242,11 +318,7 @@ const SceneView = ({
|
|
|
242
318
|
|
|
243
319
|
const rawAnimatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
|
|
244
320
|
const animatedHeaderHeight = React.useMemo(
|
|
245
|
-
() =>
|
|
246
|
-
Animated.add<number>(
|
|
247
|
-
rawAnimatedHeaderHeight,
|
|
248
|
-
headerHeightCorrectionOffset
|
|
249
|
-
),
|
|
321
|
+
() => Animated.add(rawAnimatedHeaderHeight, headerHeightCorrectionOffset),
|
|
250
322
|
[headerHeightCorrectionOffset, rawAnimatedHeaderHeight]
|
|
251
323
|
);
|
|
252
324
|
|
|
@@ -439,7 +511,7 @@ const SceneView = ({
|
|
|
439
511
|
headerShown !== false ? headerHeight : (parentHeaderHeight ?? 0)
|
|
440
512
|
}
|
|
441
513
|
>
|
|
442
|
-
{headerBackground != null ? (
|
|
514
|
+
{headerShown !== false && headerBackground != null ? (
|
|
443
515
|
/**
|
|
444
516
|
* To show a custom header background, we render it at the top of the screen below the header
|
|
445
517
|
* The header also needs to be positioned absolutely (with `translucent` style)
|
|
@@ -497,7 +569,7 @@ const SceneView = ({
|
|
|
497
569
|
</ScreenStackItem>
|
|
498
570
|
</NavigationProvider>
|
|
499
571
|
);
|
|
500
|
-
};
|
|
572
|
+
});
|
|
501
573
|
|
|
502
574
|
type Props = {
|
|
503
575
|
state: StackNavigationState<ParamListBase>;
|
|
@@ -515,6 +587,7 @@ export function NativeStackView({
|
|
|
515
587
|
descriptors,
|
|
516
588
|
describe,
|
|
517
589
|
}: Props) {
|
|
590
|
+
const { colors } = useTheme();
|
|
518
591
|
const { setNextDismissedKey } = useDismissedRouteError(state);
|
|
519
592
|
|
|
520
593
|
useInvalidPreventRemoveError(descriptors);
|
|
@@ -529,7 +602,10 @@ export function NativeStackView({
|
|
|
529
602
|
|
|
530
603
|
return (
|
|
531
604
|
<SafeAreaProviderCompat>
|
|
532
|
-
<ScreenStack
|
|
605
|
+
<ScreenStack
|
|
606
|
+
style={styles.container}
|
|
607
|
+
nativeContainerStyle={{ backgroundColor: colors.background }}
|
|
608
|
+
>
|
|
533
609
|
{state.routes.concat(state.preloadedRoutes).map((route, index) => {
|
|
534
610
|
const descriptor =
|
|
535
611
|
descriptors[route.key] ?? preloadedDescriptors[route.key];
|
|
@@ -563,84 +639,14 @@ export function NativeStackView({
|
|
|
563
639
|
shouldFreeze={shouldFreeze}
|
|
564
640
|
descriptor={descriptor}
|
|
565
641
|
previousDescriptor={previousDescriptor}
|
|
566
|
-
|
|
642
|
+
nextGestureDirection={nextDescriptor?.options.gestureDirection}
|
|
567
643
|
isPresentationModal={isModal}
|
|
568
644
|
isPreloaded={isPreloaded}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
});
|
|
575
|
-
}}
|
|
576
|
-
onWillAppear={() => {
|
|
577
|
-
navigation.emit({
|
|
578
|
-
type: 'transitionStart',
|
|
579
|
-
data: { closing: false },
|
|
580
|
-
target: route.key,
|
|
581
|
-
});
|
|
582
|
-
}}
|
|
583
|
-
onAppear={() => {
|
|
584
|
-
navigation.emit({
|
|
585
|
-
type: 'transitionEnd',
|
|
586
|
-
data: { closing: false },
|
|
587
|
-
target: route.key,
|
|
588
|
-
});
|
|
589
|
-
}}
|
|
590
|
-
onDisappear={() => {
|
|
591
|
-
navigation.emit({
|
|
592
|
-
type: 'transitionEnd',
|
|
593
|
-
data: { closing: true },
|
|
594
|
-
target: route.key,
|
|
595
|
-
});
|
|
596
|
-
}}
|
|
597
|
-
onDismissed={(event) => {
|
|
598
|
-
const currentState = navigation.getState();
|
|
599
|
-
const currentActiveRoutes = currentState.routes.slice(
|
|
600
|
-
0,
|
|
601
|
-
currentState.index + 1
|
|
602
|
-
);
|
|
603
|
-
|
|
604
|
-
if (currentActiveRoutes.some((r) => r.key === route.key)) {
|
|
605
|
-
navigation.dispatch({
|
|
606
|
-
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
607
|
-
source: route.key,
|
|
608
|
-
target: currentState.key,
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
setNextDismissedKey(route.key);
|
|
613
|
-
}}
|
|
614
|
-
onHeaderBackButtonClicked={() => {
|
|
615
|
-
navigation.dispatch({
|
|
616
|
-
...StackActions.pop(),
|
|
617
|
-
source: route.key,
|
|
618
|
-
target: state.key,
|
|
619
|
-
});
|
|
620
|
-
}}
|
|
621
|
-
onNativeDismissCancelled={(event) => {
|
|
622
|
-
navigation.dispatch({
|
|
623
|
-
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
624
|
-
source: route.key,
|
|
625
|
-
target: state.key,
|
|
626
|
-
});
|
|
627
|
-
}}
|
|
628
|
-
onGestureCancel={() => {
|
|
629
|
-
navigation.emit({
|
|
630
|
-
type: 'gestureCancel',
|
|
631
|
-
target: route.key,
|
|
632
|
-
});
|
|
633
|
-
}}
|
|
634
|
-
onSheetDetentChanged={(event) => {
|
|
635
|
-
navigation.emit({
|
|
636
|
-
type: 'sheetDetentChange',
|
|
637
|
-
target: route.key,
|
|
638
|
-
data: {
|
|
639
|
-
index: event.nativeEvent.index,
|
|
640
|
-
stable: event.nativeEvent.isStable,
|
|
641
|
-
},
|
|
642
|
-
});
|
|
643
|
-
}}
|
|
645
|
+
stateKey={state.key}
|
|
646
|
+
emit={navigation.emit}
|
|
647
|
+
dispatch={navigation.dispatch}
|
|
648
|
+
getState={navigation.getState}
|
|
649
|
+
setNextDismissedKey={setNextDismissedKey}
|
|
644
650
|
/>
|
|
645
651
|
);
|
|
646
652
|
})}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
useHeaderHeight,
|
|
9
9
|
} from '@react-navigation/elements';
|
|
10
10
|
import {
|
|
11
|
+
type NavigationRoute,
|
|
11
12
|
type ParamListBase,
|
|
12
13
|
type RouteProp,
|
|
13
14
|
type StackNavigationState,
|
|
@@ -49,143 +50,178 @@ export function NativeStackView({ state, descriptors, describe }: Props) {
|
|
|
49
50
|
return acc;
|
|
50
51
|
}, {});
|
|
51
52
|
|
|
53
|
+
const activeRoutes = state.routes.slice(0, state.index + 1);
|
|
54
|
+
const lastOpaqueIndex = activeRoutes.findLastIndex((route) => {
|
|
55
|
+
const presentation = descriptors[route.key]?.options.presentation;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
presentation == null || !TRANSPARENT_PRESENTATIONS.includes(presentation)
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
52
62
|
return (
|
|
53
63
|
<SafeAreaProviderCompat>
|
|
54
64
|
{state.routes.concat(state.preloadedRoutes).map((route, i) => {
|
|
55
65
|
const isFocused = state.index === i;
|
|
56
66
|
const previousKey = state.routes[i - 1]?.key;
|
|
57
|
-
const nextKey = state.routes[i + 1]?.key;
|
|
58
67
|
const previousDescriptor = previousKey
|
|
59
68
|
? descriptors[previousKey]
|
|
60
69
|
: undefined;
|
|
61
|
-
const
|
|
62
|
-
const { options, navigation, render } =
|
|
70
|
+
const descriptor =
|
|
63
71
|
descriptors[route.key] ?? preloadedDescriptors[route.key];
|
|
64
72
|
|
|
65
|
-
const
|
|
66
|
-
? {
|
|
67
|
-
title: getHeaderTitle(
|
|
68
|
-
previousDescriptor.options,
|
|
69
|
-
previousDescriptor.route.name
|
|
70
|
-
),
|
|
71
|
-
href: buildHref(
|
|
72
|
-
previousDescriptor.route.name,
|
|
73
|
-
previousDescriptor.route.params
|
|
74
|
-
),
|
|
75
|
-
}
|
|
76
|
-
: parentHeaderBack;
|
|
77
|
-
|
|
78
|
-
const canGoBack = headerBack != null;
|
|
79
|
-
|
|
80
|
-
const {
|
|
81
|
-
header,
|
|
82
|
-
headerShown,
|
|
83
|
-
headerBackIcon,
|
|
84
|
-
headerBackImageSource,
|
|
85
|
-
headerLeft,
|
|
86
|
-
headerTransparent,
|
|
87
|
-
headerBackTitle,
|
|
88
|
-
presentation,
|
|
89
|
-
contentStyle,
|
|
90
|
-
...rest
|
|
91
|
-
} = options;
|
|
92
|
-
|
|
93
|
-
const nextPresentation = nextDescriptor?.options.presentation;
|
|
73
|
+
const isVisible = i >= lastOpaqueIndex && i <= state.index;
|
|
94
74
|
|
|
95
75
|
const isPreloaded =
|
|
96
76
|
preloadedDescriptors[route.key] !== undefined &&
|
|
97
77
|
descriptors[route.key] === undefined;
|
|
98
78
|
|
|
99
79
|
return (
|
|
100
|
-
<
|
|
80
|
+
<SceneView
|
|
101
81
|
key={route.key}
|
|
102
|
-
focused={isFocused}
|
|
103
82
|
route={route}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
options,
|
|
112
|
-
route,
|
|
113
|
-
navigation,
|
|
114
|
-
})
|
|
115
|
-
) : (
|
|
116
|
-
<Header
|
|
117
|
-
{...rest}
|
|
118
|
-
back={headerBack}
|
|
119
|
-
title={getHeaderTitle(options, route.name)}
|
|
120
|
-
headerLeft={
|
|
121
|
-
typeof headerLeft === 'function'
|
|
122
|
-
? ({ label, ...rest }) =>
|
|
123
|
-
headerLeft({
|
|
124
|
-
...rest,
|
|
125
|
-
label: headerBackTitle ?? label,
|
|
126
|
-
})
|
|
127
|
-
: headerLeft === undefined && canGoBack
|
|
128
|
-
? ({ tintColor, label, ...rest }) => (
|
|
129
|
-
<HeaderBackButton
|
|
130
|
-
{...rest}
|
|
131
|
-
label={headerBackTitle ?? label}
|
|
132
|
-
tintColor={tintColor}
|
|
133
|
-
backImage={
|
|
134
|
-
headerBackIcon !== undefined ||
|
|
135
|
-
headerBackImageSource !== undefined
|
|
136
|
-
? () => (
|
|
137
|
-
<Image
|
|
138
|
-
source={
|
|
139
|
-
headerBackIcon?.source ??
|
|
140
|
-
headerBackImageSource
|
|
141
|
-
}
|
|
142
|
-
resizeMode="contain"
|
|
143
|
-
tintColor={tintColor}
|
|
144
|
-
style={styles.backImage}
|
|
145
|
-
/>
|
|
146
|
-
)
|
|
147
|
-
: undefined
|
|
148
|
-
}
|
|
149
|
-
onPress={navigation.goBack}
|
|
150
|
-
/>
|
|
151
|
-
)
|
|
152
|
-
: headerLeft
|
|
153
|
-
}
|
|
154
|
-
headerTransparent={headerTransparent}
|
|
155
|
-
/>
|
|
156
|
-
)
|
|
157
|
-
}
|
|
158
|
-
style={[
|
|
159
|
-
StyleSheet.absoluteFill,
|
|
160
|
-
{
|
|
161
|
-
display:
|
|
162
|
-
(isFocused ||
|
|
163
|
-
(nextPresentation != null &&
|
|
164
|
-
TRANSPARENT_PRESENTATIONS.includes(nextPresentation))) &&
|
|
165
|
-
!isPreloaded
|
|
166
|
-
? 'flex'
|
|
167
|
-
: 'none',
|
|
168
|
-
},
|
|
169
|
-
presentation != null &&
|
|
170
|
-
TRANSPARENT_PRESENTATIONS.includes(presentation)
|
|
171
|
-
? { backgroundColor: 'transparent' }
|
|
172
|
-
: null,
|
|
173
|
-
]}
|
|
174
|
-
>
|
|
175
|
-
<HeaderBackContext.Provider value={headerBack}>
|
|
176
|
-
<AnimatedHeaderHeightProvider>
|
|
177
|
-
<View style={[styles.contentContainer, contentStyle]}>
|
|
178
|
-
{render()}
|
|
179
|
-
</View>
|
|
180
|
-
</AnimatedHeaderHeightProvider>
|
|
181
|
-
</HeaderBackContext.Provider>
|
|
182
|
-
</Screen>
|
|
83
|
+
descriptor={descriptor}
|
|
84
|
+
previousDescriptor={previousDescriptor}
|
|
85
|
+
parentHeaderBack={parentHeaderBack}
|
|
86
|
+
buildHref={buildHref}
|
|
87
|
+
focused={isFocused}
|
|
88
|
+
visible={isVisible && !isPreloaded}
|
|
89
|
+
/>
|
|
183
90
|
);
|
|
184
91
|
})}
|
|
185
92
|
</SafeAreaProviderCompat>
|
|
186
93
|
);
|
|
187
94
|
}
|
|
188
95
|
|
|
96
|
+
type SceneViewProps = {
|
|
97
|
+
route: NavigationRoute<ParamListBase, string>;
|
|
98
|
+
descriptor: NativeStackDescriptor;
|
|
99
|
+
previousDescriptor: NativeStackDescriptor | undefined;
|
|
100
|
+
parentHeaderBack: React.ContextType<typeof HeaderBackContext>;
|
|
101
|
+
buildHref: ReturnType<typeof useLinkBuilder>['buildHref'];
|
|
102
|
+
focused: boolean;
|
|
103
|
+
visible: boolean;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const SceneView = React.memo(function SceneView({
|
|
107
|
+
route,
|
|
108
|
+
descriptor,
|
|
109
|
+
previousDescriptor,
|
|
110
|
+
parentHeaderBack,
|
|
111
|
+
buildHref,
|
|
112
|
+
focused,
|
|
113
|
+
visible,
|
|
114
|
+
}: SceneViewProps) {
|
|
115
|
+
const { options, navigation, render } = descriptor;
|
|
116
|
+
|
|
117
|
+
const headerBack = previousDescriptor
|
|
118
|
+
? {
|
|
119
|
+
title: getHeaderTitle(
|
|
120
|
+
previousDescriptor.options,
|
|
121
|
+
previousDescriptor.route.name
|
|
122
|
+
),
|
|
123
|
+
href: buildHref(
|
|
124
|
+
previousDescriptor.route.name,
|
|
125
|
+
previousDescriptor.route.params
|
|
126
|
+
),
|
|
127
|
+
}
|
|
128
|
+
: parentHeaderBack;
|
|
129
|
+
|
|
130
|
+
const canGoBack = headerBack != null;
|
|
131
|
+
|
|
132
|
+
const {
|
|
133
|
+
header,
|
|
134
|
+
headerShown,
|
|
135
|
+
headerBackIcon,
|
|
136
|
+
headerBackImageSource,
|
|
137
|
+
headerLeft,
|
|
138
|
+
headerTransparent,
|
|
139
|
+
headerBackTitle,
|
|
140
|
+
presentation,
|
|
141
|
+
contentStyle,
|
|
142
|
+
...rest
|
|
143
|
+
} = options;
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<Screen
|
|
147
|
+
key={route.key}
|
|
148
|
+
focused={focused}
|
|
149
|
+
route={route}
|
|
150
|
+
navigation={navigation}
|
|
151
|
+
headerShown={headerShown}
|
|
152
|
+
headerTransparent={headerTransparent}
|
|
153
|
+
header={
|
|
154
|
+
header !== undefined ? (
|
|
155
|
+
header({
|
|
156
|
+
back: headerBack,
|
|
157
|
+
options,
|
|
158
|
+
route,
|
|
159
|
+
navigation,
|
|
160
|
+
})
|
|
161
|
+
) : (
|
|
162
|
+
<Header
|
|
163
|
+
{...rest}
|
|
164
|
+
back={headerBack}
|
|
165
|
+
title={getHeaderTitle(options, route.name)}
|
|
166
|
+
headerLeft={
|
|
167
|
+
typeof headerLeft === 'function'
|
|
168
|
+
? ({ label, ...rest }) =>
|
|
169
|
+
headerLeft({
|
|
170
|
+
...rest,
|
|
171
|
+
label: headerBackTitle ?? label,
|
|
172
|
+
})
|
|
173
|
+
: headerLeft === undefined && canGoBack
|
|
174
|
+
? ({ tintColor, label, ...rest }) => (
|
|
175
|
+
<HeaderBackButton
|
|
176
|
+
{...rest}
|
|
177
|
+
label={headerBackTitle ?? label}
|
|
178
|
+
tintColor={tintColor}
|
|
179
|
+
backImage={
|
|
180
|
+
headerBackIcon !== undefined ||
|
|
181
|
+
headerBackImageSource !== undefined
|
|
182
|
+
? () => (
|
|
183
|
+
<Image
|
|
184
|
+
source={
|
|
185
|
+
headerBackIcon?.source ??
|
|
186
|
+
headerBackImageSource
|
|
187
|
+
}
|
|
188
|
+
resizeMode="contain"
|
|
189
|
+
tintColor={tintColor}
|
|
190
|
+
style={styles.backImage}
|
|
191
|
+
/>
|
|
192
|
+
)
|
|
193
|
+
: undefined
|
|
194
|
+
}
|
|
195
|
+
onPress={navigation.goBack}
|
|
196
|
+
/>
|
|
197
|
+
)
|
|
198
|
+
: headerLeft
|
|
199
|
+
}
|
|
200
|
+
headerTransparent={headerTransparent}
|
|
201
|
+
/>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
style={[
|
|
205
|
+
StyleSheet.absoluteFill,
|
|
206
|
+
{
|
|
207
|
+
display: visible ? 'flex' : 'none',
|
|
208
|
+
},
|
|
209
|
+
presentation != null && TRANSPARENT_PRESENTATIONS.includes(presentation)
|
|
210
|
+
? { backgroundColor: 'transparent' }
|
|
211
|
+
: null,
|
|
212
|
+
]}
|
|
213
|
+
>
|
|
214
|
+
<HeaderBackContext.Provider value={headerBack}>
|
|
215
|
+
<AnimatedHeaderHeightProvider>
|
|
216
|
+
<View style={[styles.contentContainer, contentStyle]}>
|
|
217
|
+
{render()}
|
|
218
|
+
</View>
|
|
219
|
+
</AnimatedHeaderHeightProvider>
|
|
220
|
+
</HeaderBackContext.Provider>
|
|
221
|
+
</Screen>
|
|
222
|
+
);
|
|
223
|
+
});
|
|
224
|
+
|
|
189
225
|
const AnimatedHeaderHeightProvider = ({
|
|
190
226
|
children,
|
|
191
227
|
}: {
|