@react-navigation/native-stack 7.0.0-alpha.1 → 7.0.0-alpha.11
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 +25 -16
- package/lib/commonjs/views/NativeStackView.js.map +1 -1
- package/lib/commonjs/views/NativeStackView.native.js +124 -47
- 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 +23 -14
- package/lib/module/views/NativeStackView.js.map +1 -1
- package/lib/module/views/NativeStackView.native.js +123 -46
- 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 +264 -166
- package/src/views/NativeStackView.tsx +131 -123
|
@@ -9,24 +9,30 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
NavigationContext,
|
|
11
11
|
NavigationRouteContext,
|
|
12
|
-
ParamListBase,
|
|
13
|
-
Route,
|
|
12
|
+
type ParamListBase,
|
|
13
|
+
type Route,
|
|
14
14
|
StackActions,
|
|
15
|
-
StackNavigationState,
|
|
15
|
+
type StackNavigationState,
|
|
16
16
|
usePreventRemoveContext,
|
|
17
17
|
useTheme,
|
|
18
18
|
} from '@react-navigation/native';
|
|
19
19
|
import * as React from 'react';
|
|
20
|
-
import {
|
|
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
|
|
346
|
+
<AnimatedHeaderHeightContext.Provider value={animatedHeaderHeight}>
|
|
347
|
+
<HeaderHeightContext.Provider
|
|
348
|
+
value={
|
|
349
|
+
headerShown !== false ? headerHeight : parentHeaderHeight ?? 0
|
|
308
350
|
}
|
|
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'
|
|
323
|
-
}
|
|
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>
|
|
@@ -364,86 +442,95 @@ type Props = {
|
|
|
364
442
|
descriptors: NativeStackDescriptorMap;
|
|
365
443
|
};
|
|
366
444
|
|
|
367
|
-
function
|
|
445
|
+
export function NativeStackView({ state, navigation, descriptors }: Props) {
|
|
368
446
|
const { setNextDismissedKey } = useDismissedRouteError(state);
|
|
369
447
|
|
|
370
|
-
|
|
448
|
+
const { colors } = useTheme();
|
|
371
449
|
|
|
372
|
-
|
|
373
|
-
<ScreenStack style={styles.container}>
|
|
374
|
-
{state.routes.map((route, index) => {
|
|
375
|
-
const descriptor = descriptors[route.key];
|
|
376
|
-
const isFocused = state.index === index;
|
|
377
|
-
const previousKey = state.routes[index - 1]?.key;
|
|
378
|
-
const nextKey = state.routes[index + 1]?.key;
|
|
379
|
-
const previousDescriptor = previousKey
|
|
380
|
-
? descriptors[previousKey]
|
|
381
|
-
: undefined;
|
|
382
|
-
const nextDescriptor = nextKey ? descriptors[nextKey] : undefined;
|
|
383
|
-
|
|
384
|
-
return (
|
|
385
|
-
<SceneView
|
|
386
|
-
key={route.key}
|
|
387
|
-
index={index}
|
|
388
|
-
focused={isFocused}
|
|
389
|
-
descriptor={descriptor}
|
|
390
|
-
previousDescriptor={previousDescriptor}
|
|
391
|
-
nextDescriptor={nextDescriptor}
|
|
392
|
-
onWillDisappear={() => {
|
|
393
|
-
navigation.emit({
|
|
394
|
-
type: 'transitionStart',
|
|
395
|
-
data: { closing: true },
|
|
396
|
-
target: route.key,
|
|
397
|
-
});
|
|
398
|
-
}}
|
|
399
|
-
onAppear={() => {
|
|
400
|
-
navigation.emit({
|
|
401
|
-
type: 'transitionEnd',
|
|
402
|
-
data: { closing: false },
|
|
403
|
-
target: route.key,
|
|
404
|
-
});
|
|
405
|
-
}}
|
|
406
|
-
onDisappear={() => {
|
|
407
|
-
navigation.emit({
|
|
408
|
-
type: 'transitionEnd',
|
|
409
|
-
data: { closing: true },
|
|
410
|
-
target: route.key,
|
|
411
|
-
});
|
|
412
|
-
}}
|
|
413
|
-
onDismissed={(event) => {
|
|
414
|
-
navigation.dispatch({
|
|
415
|
-
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
416
|
-
source: route.key,
|
|
417
|
-
target: state.key,
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
setNextDismissedKey(route.key);
|
|
421
|
-
}}
|
|
422
|
-
onHeaderBackButtonClicked={() => {
|
|
423
|
-
navigation.dispatch({
|
|
424
|
-
...StackActions.pop(),
|
|
425
|
-
source: route.key,
|
|
426
|
-
target: state.key,
|
|
427
|
-
});
|
|
428
|
-
}}
|
|
429
|
-
onNativeDismissCancelled={(event) => {
|
|
430
|
-
navigation.dispatch({
|
|
431
|
-
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
432
|
-
source: route.key,
|
|
433
|
-
target: state.key,
|
|
434
|
-
});
|
|
435
|
-
}}
|
|
436
|
-
/>
|
|
437
|
-
);
|
|
438
|
-
})}
|
|
439
|
-
</ScreenStack>
|
|
440
|
-
);
|
|
441
|
-
}
|
|
450
|
+
useInvalidPreventRemoveError(descriptors);
|
|
442
451
|
|
|
443
|
-
export function NativeStackView(props: Props) {
|
|
444
452
|
return (
|
|
445
|
-
<SafeAreaProviderCompat>
|
|
446
|
-
<
|
|
453
|
+
<SafeAreaProviderCompat style={{ backgroundColor: colors.background }}>
|
|
454
|
+
<ScreenStack style={styles.container}>
|
|
455
|
+
{state.routes.map((route, index) => {
|
|
456
|
+
const descriptor = descriptors[route.key];
|
|
457
|
+
const isFocused = state.index === index;
|
|
458
|
+
const previousKey = state.routes[index - 1]?.key;
|
|
459
|
+
const nextKey = state.routes[index + 1]?.key;
|
|
460
|
+
const previousDescriptor = previousKey
|
|
461
|
+
? descriptors[previousKey]
|
|
462
|
+
: undefined;
|
|
463
|
+
const nextDescriptor = nextKey ? descriptors[nextKey] : undefined;
|
|
464
|
+
|
|
465
|
+
return (
|
|
466
|
+
<SceneView
|
|
467
|
+
key={route.key}
|
|
468
|
+
index={index}
|
|
469
|
+
focused={isFocused}
|
|
470
|
+
descriptor={descriptor}
|
|
471
|
+
previousDescriptor={previousDescriptor}
|
|
472
|
+
nextDescriptor={nextDescriptor}
|
|
473
|
+
onWillDisappear={() => {
|
|
474
|
+
navigation.emit({
|
|
475
|
+
type: 'transitionStart',
|
|
476
|
+
data: { closing: true },
|
|
477
|
+
target: route.key,
|
|
478
|
+
});
|
|
479
|
+
}}
|
|
480
|
+
onWillAppear={() => {
|
|
481
|
+
navigation.emit({
|
|
482
|
+
type: 'transitionStart',
|
|
483
|
+
data: { closing: false },
|
|
484
|
+
target: route.key,
|
|
485
|
+
});
|
|
486
|
+
}}
|
|
487
|
+
onAppear={() => {
|
|
488
|
+
navigation.emit({
|
|
489
|
+
type: 'transitionEnd',
|
|
490
|
+
data: { closing: false },
|
|
491
|
+
target: route.key,
|
|
492
|
+
});
|
|
493
|
+
}}
|
|
494
|
+
onDisappear={() => {
|
|
495
|
+
navigation.emit({
|
|
496
|
+
type: 'transitionEnd',
|
|
497
|
+
data: { closing: true },
|
|
498
|
+
target: route.key,
|
|
499
|
+
});
|
|
500
|
+
}}
|
|
501
|
+
onDismissed={(event) => {
|
|
502
|
+
navigation.dispatch({
|
|
503
|
+
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
504
|
+
source: route.key,
|
|
505
|
+
target: state.key,
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
setNextDismissedKey(route.key);
|
|
509
|
+
}}
|
|
510
|
+
onHeaderBackButtonClicked={() => {
|
|
511
|
+
navigation.dispatch({
|
|
512
|
+
...StackActions.pop(),
|
|
513
|
+
source: route.key,
|
|
514
|
+
target: state.key,
|
|
515
|
+
});
|
|
516
|
+
}}
|
|
517
|
+
onNativeDismissCancelled={(event) => {
|
|
518
|
+
navigation.dispatch({
|
|
519
|
+
...StackActions.pop(event.nativeEvent.dismissCount),
|
|
520
|
+
source: route.key,
|
|
521
|
+
target: state.key,
|
|
522
|
+
});
|
|
523
|
+
}}
|
|
524
|
+
onGestureCancel={() => {
|
|
525
|
+
navigation.emit({
|
|
526
|
+
type: 'gestureCancel',
|
|
527
|
+
target: route.key,
|
|
528
|
+
});
|
|
529
|
+
}}
|
|
530
|
+
/>
|
|
531
|
+
);
|
|
532
|
+
})}
|
|
533
|
+
</ScreenStack>
|
|
447
534
|
</SafeAreaProviderCompat>
|
|
448
535
|
);
|
|
449
536
|
}
|
|
@@ -462,4 +549,15 @@ const styles = StyleSheet.create({
|
|
|
462
549
|
left: 0,
|
|
463
550
|
right: 0,
|
|
464
551
|
},
|
|
552
|
+
translucent: {
|
|
553
|
+
position: 'absolute',
|
|
554
|
+
top: 0,
|
|
555
|
+
left: 0,
|
|
556
|
+
right: 0,
|
|
557
|
+
zIndex: 1,
|
|
558
|
+
elevation: 1,
|
|
559
|
+
},
|
|
560
|
+
background: {
|
|
561
|
+
overflow: 'hidden',
|
|
562
|
+
},
|
|
465
563
|
});
|