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