@react-navigation/native-stack 7.0.0-rc.26 → 7.0.0-rc.28
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/navigators/createNativeStackNavigator.js +3 -1
- package/lib/commonjs/navigators/createNativeStackNavigator.js.map +1 -1
- package/lib/commonjs/views/DebugContainer.native.js +8 -10
- package/lib/commonjs/views/DebugContainer.native.js.map +1 -1
- package/lib/commonjs/views/FooterComponent.js +19 -0
- package/lib/commonjs/views/FooterComponent.js.map +1 -0
- package/lib/commonjs/views/HeaderConfig.js +24 -14
- package/lib/commonjs/views/HeaderConfig.js.map +1 -1
- package/lib/commonjs/views/NativeStackView.js +10 -7
- package/lib/commonjs/views/NativeStackView.js.map +1 -1
- package/lib/commonjs/views/NativeStackView.native.js +56 -18
- package/lib/commonjs/views/NativeStackView.native.js.map +1 -1
- package/lib/module/navigators/createNativeStackNavigator.js +3 -1
- package/lib/module/navigators/createNativeStackNavigator.js.map +1 -1
- package/lib/module/views/DebugContainer.native.js +9 -11
- package/lib/module/views/DebugContainer.native.js.map +1 -1
- package/lib/module/views/FooterComponent.js +14 -0
- package/lib/module/views/FooterComponent.js.map +1 -0
- package/lib/module/views/HeaderConfig.js +24 -14
- package/lib/module/views/HeaderConfig.js.map +1 -1
- package/lib/module/views/NativeStackView.js +10 -7
- package/lib/module/views/NativeStackView.js.map +1 -1
- package/lib/module/views/NativeStackView.native.js +56 -18
- package/lib/module/views/NativeStackView.native.js.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +1 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/navigators/createNativeStackNavigator.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types.d.ts +80 -18
- package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/views/DebugContainer.d.ts +1 -1
- package/lib/typescript/commonjs/src/views/DebugContainer.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/views/DebugContainer.native.d.ts +1 -1
- package/lib/typescript/commonjs/src/views/DebugContainer.native.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/views/FooterComponent.d.ts +7 -0
- package/lib/typescript/commonjs/src/views/FooterComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/views/HeaderConfig.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/views/NativeStackView.d.ts +4 -3
- package/lib/typescript/commonjs/src/views/NativeStackView.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/views/NativeStackView.native.d.ts +4 -3
- package/lib/typescript/commonjs/src/views/NativeStackView.native.d.ts.map +1 -1
- package/lib/typescript/commonjs/tsconfig.build.tsbuildinfo +1 -1
- package/lib/typescript/module/src/index.d.ts +1 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/navigators/createNativeStackNavigator.d.ts.map +1 -1
- package/lib/typescript/module/src/types.d.ts +80 -18
- package/lib/typescript/module/src/types.d.ts.map +1 -1
- package/lib/typescript/module/src/views/DebugContainer.d.ts +1 -1
- package/lib/typescript/module/src/views/DebugContainer.d.ts.map +1 -1
- package/lib/typescript/module/src/views/DebugContainer.native.d.ts +1 -1
- package/lib/typescript/module/src/views/DebugContainer.native.d.ts.map +1 -1
- package/lib/typescript/module/src/views/FooterComponent.d.ts +7 -0
- package/lib/typescript/module/src/views/FooterComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/views/HeaderConfig.d.ts.map +1 -1
- package/lib/typescript/module/src/views/NativeStackView.d.ts +4 -3
- package/lib/typescript/module/src/views/NativeStackView.d.ts.map +1 -1
- package/lib/typescript/module/src/views/NativeStackView.native.d.ts +4 -3
- package/lib/typescript/module/src/views/NativeStackView.native.d.ts.map +1 -1
- package/lib/typescript/module/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/index.tsx +2 -0
- package/src/navigators/createNativeStackNavigator.tsx +2 -1
- package/src/types.tsx +74 -18
- package/src/views/DebugContainer.native.tsx +13 -6
- package/src/views/DebugContainer.tsx +1 -1
- package/src/views/FooterComponent.tsx +10 -0
- package/src/views/HeaderConfig.tsx +23 -21
- package/src/views/NativeStackView.native.tsx +81 -14
- package/src/views/NativeStackView.tsx +23 -11
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-navigation/native-stack",
|
|
3
3
|
"description": "Native stack navigator using react-native-screens",
|
|
4
|
-
"version": "7.0.0-rc.
|
|
4
|
+
"version": "7.0.0-rc.28",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native-component",
|
|
7
7
|
"react-component",
|
|
@@ -52,27 +52,27 @@
|
|
|
52
52
|
"clean": "del lib"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@react-navigation/elements": "^2.0.0-rc.
|
|
55
|
+
"@react-navigation/elements": "^2.0.0-rc.25",
|
|
56
56
|
"warn-once": "^0.1.1"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@jest/globals": "^29.7.0",
|
|
60
|
-
"@react-navigation/native": "^7.0.0-rc.
|
|
60
|
+
"@react-navigation/native": "^7.0.0-rc.20",
|
|
61
61
|
"@testing-library/react-native": "^12.4.3",
|
|
62
62
|
"@types/react": "~18.2.79",
|
|
63
63
|
"del-cli": "^5.1.0",
|
|
64
64
|
"react": "18.2.0",
|
|
65
65
|
"react-native": "0.74.2",
|
|
66
66
|
"react-native-builder-bob": "^0.29.0",
|
|
67
|
-
"react-native-screens": "
|
|
67
|
+
"react-native-screens": "4.0.0-beta.9",
|
|
68
68
|
"typescript": "^5.5.2"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"@react-navigation/native": "^7.0.0-rc.
|
|
71
|
+
"@react-navigation/native": "^7.0.0-rc.20",
|
|
72
72
|
"react": ">= 18.2.0",
|
|
73
73
|
"react-native": ">= 0.72.0",
|
|
74
74
|
"react-native-safe-area-context": ">= 4.0.0",
|
|
75
|
-
"react-native-screens": ">=
|
|
75
|
+
"react-native-screens": ">= 4.0.0"
|
|
76
76
|
},
|
|
77
77
|
"react-native-builder-bob": {
|
|
78
78
|
"source": "src",
|
|
@@ -99,5 +99,5 @@
|
|
|
99
99
|
]
|
|
100
100
|
]
|
|
101
101
|
},
|
|
102
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "1ad42666923bd76dd9e7dd731ba39cc31dd27317"
|
|
103
103
|
}
|
package/src/index.tsx
CHANGED
|
@@ -17,7 +17,9 @@ export { useAnimatedHeaderHeight } from './utils/useAnimatedHeaderHeight';
|
|
|
17
17
|
* Types
|
|
18
18
|
*/
|
|
19
19
|
export type {
|
|
20
|
+
NativeStackHeaderLeftProps,
|
|
20
21
|
NativeStackHeaderProps,
|
|
22
|
+
NativeStackHeaderRightProps,
|
|
21
23
|
NativeStackNavigationEventMap,
|
|
22
24
|
NativeStackNavigationOptions,
|
|
23
25
|
NativeStackNavigationProp,
|
|
@@ -33,7 +33,7 @@ function NativeStackNavigator({
|
|
|
33
33
|
UNSTABLE_getStateForRouteNamesChange,
|
|
34
34
|
...rest
|
|
35
35
|
}: NativeStackNavigatorProps) {
|
|
36
|
-
const { state, descriptors, navigation, NavigationContent } =
|
|
36
|
+
const { state, describe, descriptors, navigation, NavigationContent } =
|
|
37
37
|
useNavigationBuilder<
|
|
38
38
|
StackNavigationState<ParamListBase>,
|
|
39
39
|
StackRouterOptions,
|
|
@@ -84,6 +84,7 @@ function NativeStackNavigator({
|
|
|
84
84
|
state={state}
|
|
85
85
|
navigation={navigation}
|
|
86
86
|
descriptors={descriptors}
|
|
87
|
+
describe={describe}
|
|
87
88
|
/>
|
|
88
89
|
</NavigationContent>
|
|
89
90
|
);
|
package/src/types.tsx
CHANGED
|
@@ -21,7 +21,6 @@ import type {
|
|
|
21
21
|
ScreenProps,
|
|
22
22
|
ScreenStackHeaderConfigProps,
|
|
23
23
|
SearchBarProps,
|
|
24
|
-
SheetDetentTypes,
|
|
25
24
|
} from 'react-native-screens';
|
|
26
25
|
|
|
27
26
|
export type NativeStackNavigationEventMap = {
|
|
@@ -37,6 +36,15 @@ export type NativeStackNavigationEventMap = {
|
|
|
37
36
|
* Event which fires when a swipe back is canceled on iOS.
|
|
38
37
|
*/
|
|
39
38
|
gestureCancel: { data: undefined };
|
|
39
|
+
/**
|
|
40
|
+
* Event which fires when screen is in sheet presentation & it's detent changes.
|
|
41
|
+
*
|
|
42
|
+
* In payload it caries two fields:
|
|
43
|
+
*
|
|
44
|
+
* * `index` - current detent index in the `sheetAllowedDetents` array,
|
|
45
|
+
* * `stable` - on Android `false` value means that the user is dragging the sheet or it is settling; on iOS it is always `true`.
|
|
46
|
+
*/
|
|
47
|
+
sheetDetentChange: { data: { index: number; stable: boolean } };
|
|
40
48
|
};
|
|
41
49
|
|
|
42
50
|
export type NativeStackNavigationProp<
|
|
@@ -439,6 +447,13 @@ export type NativeStackNavigationOptions = {
|
|
|
439
447
|
* Style object for the scene content.
|
|
440
448
|
*/
|
|
441
449
|
contentStyle?: StyleProp<ViewStyle>;
|
|
450
|
+
/**
|
|
451
|
+
* Style object for the screen native component. This might help to workaround
|
|
452
|
+
* some issues when using `formSheet` presentation.
|
|
453
|
+
*
|
|
454
|
+
* Only `backgroundColor` is accepted.
|
|
455
|
+
*/
|
|
456
|
+
unstable_screenStyle?: ScreenProps['unstable_screenStyle'];
|
|
442
457
|
/**
|
|
443
458
|
* Whether the gesture to dismiss should use animation provided to `animation` prop. Defaults to `false`.
|
|
444
459
|
*
|
|
@@ -497,11 +512,14 @@ export type NativeStackNavigationOptions = {
|
|
|
497
512
|
* Supported values:
|
|
498
513
|
* - "default": use the platform default animation
|
|
499
514
|
* - "fade": fade screen in or out
|
|
515
|
+
* - "fade_from_bottom" – performs a fade from bottom animation
|
|
500
516
|
* - "flip": flip the screen, requires presentation: "modal" (iOS only)
|
|
501
517
|
* - "simple_push": use the platform default animation, but without shadow and native header transition (iOS only)
|
|
502
518
|
* - "slide_from_bottom": slide in the new screen from bottom
|
|
503
519
|
* - "slide_from_right": slide in the new screen from right (Android only, uses default animation on iOS)
|
|
504
520
|
* - "slide_from_left": slide in the new screen from left (Android only, uses default animation on iOS)
|
|
521
|
+
* - "ios_from_right" - iOS like slide in animation. pushes in the new screen from right to left (Android only, resolves to default transition on iOS)
|
|
522
|
+
* - "ios_from_left" - iOS like slide in animation. pushes in the new screen from left to right (Android only, resolves to default transition on iOS)
|
|
505
523
|
* - "none": don't animate the screen
|
|
506
524
|
*
|
|
507
525
|
* Only supported on iOS and Android.
|
|
@@ -532,17 +550,32 @@ export type NativeStackNavigationOptions = {
|
|
|
532
550
|
/**
|
|
533
551
|
* Describes heights where a sheet can rest.
|
|
534
552
|
* Works only when `presentation` is set to `formSheet`.
|
|
535
|
-
* Defaults to `large`.
|
|
536
553
|
*
|
|
537
|
-
*
|
|
554
|
+
* Heights should be described as fraction (a number from `[0, 1]` interval) of screen height / maximum detent height.
|
|
555
|
+
* You can pass an array of ascending values each defining allowed sheet detent. iOS accepts any number of detents,
|
|
556
|
+
* while **Android is limited to three**.
|
|
538
557
|
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
* - `all` - all detent levels will be allowed
|
|
558
|
+
* There is also possibility to specify `fitToContents` literal, which intents to set the sheet height
|
|
559
|
+
* to the height of its contents.
|
|
542
560
|
*
|
|
543
|
-
*
|
|
561
|
+
* Please note that the array **must** be sorted in ascending order. This invariant is verified only in developement mode,
|
|
562
|
+
* where violation results in error.
|
|
563
|
+
*
|
|
564
|
+
* **Android is limited to up 3 values in the array** -- any surplus values, beside first three are ignored.
|
|
565
|
+
*
|
|
566
|
+
* Defaults to `[1.0]`.
|
|
567
|
+
*/
|
|
568
|
+
sheetAllowedDetents?: number[] | 'fitToContents';
|
|
569
|
+
/**
|
|
570
|
+
* Integer value describing elevation of the sheet, impacting shadow on the top edge of the sheet.
|
|
571
|
+
*
|
|
572
|
+
* Not dynamic - changing it after the component is rendered won't have an effect.
|
|
573
|
+
*
|
|
574
|
+
* Defaults to `24`.
|
|
575
|
+
*
|
|
576
|
+
* @platform Android
|
|
544
577
|
*/
|
|
545
|
-
|
|
578
|
+
sheetElevation?: number;
|
|
546
579
|
/**
|
|
547
580
|
* Whether the sheet should expand to larger detent when scrolling.
|
|
548
581
|
* Works only when `presentation` is set to `formSheet`.
|
|
@@ -558,10 +591,20 @@ export type NativeStackNavigationOptions = {
|
|
|
558
591
|
* If set to non-negative value it will try to render sheet with provided radius, else it will apply system default.
|
|
559
592
|
*
|
|
560
593
|
* If left unset system default is used.
|
|
561
|
-
*
|
|
562
|
-
* @platform ios
|
|
563
594
|
*/
|
|
564
595
|
sheetCornerRadius?: number;
|
|
596
|
+
/**
|
|
597
|
+
* Index of the detent the sheet should expand to after being opened.
|
|
598
|
+
* Works only when `stackPresentation` is set to `formSheet`.
|
|
599
|
+
*
|
|
600
|
+
* If the specified index is out of bounds of `sheetAllowedDetents` array, in dev environment more error will be thrown,
|
|
601
|
+
* in production the value will be reset to default value.
|
|
602
|
+
*
|
|
603
|
+
* Additionaly there is `last` value available, when set the sheet will expand initially to last (largest) detent.
|
|
604
|
+
*
|
|
605
|
+
* Defaults to `0` - which represents first detent in the detents array.
|
|
606
|
+
*/
|
|
607
|
+
sheetInitialDetentIndex?: number | 'last';
|
|
565
608
|
/**
|
|
566
609
|
* Boolean indicating whether the sheet shows a grabber at the top.
|
|
567
610
|
* Works only when `presentation` is set to `formSheet`.
|
|
@@ -572,19 +615,19 @@ export type NativeStackNavigationOptions = {
|
|
|
572
615
|
sheetGrabberVisible?: boolean;
|
|
573
616
|
/**
|
|
574
617
|
* The largest sheet detent for which a view underneath won't be dimmed.
|
|
575
|
-
* Works only when `presentation` is
|
|
618
|
+
* Works only when `presentation` is set to `formSheet`.
|
|
576
619
|
*
|
|
577
|
-
*
|
|
620
|
+
* This prop can be set to an number, which indicates index of detent in `sheetAllowedDetents` array for which
|
|
621
|
+
* there won't be a dimming view beneath the sheet.
|
|
578
622
|
*
|
|
579
|
-
*
|
|
580
|
-
* - `medium` - the view underneath will be dimmed only when detent level is `large`
|
|
581
|
-
* - `all` - the view underneath will be dimmed for any detent level
|
|
623
|
+
* Additionaly there are following options available:
|
|
582
624
|
*
|
|
583
|
-
*
|
|
625
|
+
* * `none` - there will be dimming view for all detents levels,
|
|
626
|
+
* * `last` - there won't be a dimming view for any detent level.
|
|
584
627
|
*
|
|
585
|
-
*
|
|
628
|
+
* Defaults to `none`, indicating that the dimming view should be always present.
|
|
586
629
|
*/
|
|
587
|
-
|
|
630
|
+
sheetLargestUndimmedDetentIndex?: number | 'none' | 'last';
|
|
588
631
|
/**
|
|
589
632
|
* The display orientation to use for the screen.
|
|
590
633
|
*
|
|
@@ -609,6 +652,19 @@ export type NativeStackNavigationOptions = {
|
|
|
609
652
|
* Only supported on iOS and Android.
|
|
610
653
|
*/
|
|
611
654
|
freezeOnBlur?: boolean;
|
|
655
|
+
/**
|
|
656
|
+
* Footer component that can be used alongside formSheet stack presentation style.
|
|
657
|
+
*
|
|
658
|
+
* This option is provided, because due to implementation details it might be problematic
|
|
659
|
+
* to implement such layout with JS-only code.
|
|
660
|
+
*
|
|
661
|
+
* Please note that this prop is marked as unstable and might be subject of breaking changes,
|
|
662
|
+
* including removal, in particular when we find solution that will make implementing it with JS
|
|
663
|
+
* straightforward.
|
|
664
|
+
*
|
|
665
|
+
* @platform android
|
|
666
|
+
*/
|
|
667
|
+
unstable_sheetFooter?: () => React.ReactNode;
|
|
612
668
|
};
|
|
613
669
|
|
|
614
670
|
export type NativeStackNavigatorProps = DefaultNavigatorOptions<
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { Platform,
|
|
2
|
+
import { Platform, type ViewProps } from 'react-native';
|
|
3
3
|
// @ts-expect-error Getting private component
|
|
4
4
|
import AppContainer from 'react-native/Libraries/ReactNative/AppContainer';
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
ScreenContentWrapper,
|
|
7
|
+
type StackPresentationTypes,
|
|
8
|
+
} from 'react-native-screens';
|
|
6
9
|
|
|
7
10
|
type ContainerProps = ViewProps & {
|
|
8
11
|
stackPresentation: StackPresentationTypes;
|
|
@@ -15,22 +18,26 @@ type ContainerProps = ViewProps & {
|
|
|
15
18
|
* for detailed explanation.
|
|
16
19
|
*/
|
|
17
20
|
export let DebugContainer = (props: ContainerProps) => {
|
|
18
|
-
return <
|
|
21
|
+
return <ScreenContentWrapper {...props} />;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
if (process.env.NODE_ENV !== 'production') {
|
|
22
25
|
DebugContainer = (props: ContainerProps) => {
|
|
23
26
|
const { stackPresentation, ...rest } = props;
|
|
24
27
|
|
|
25
|
-
if (
|
|
28
|
+
if (
|
|
29
|
+
Platform.OS === 'ios' &&
|
|
30
|
+
stackPresentation !== 'push' &&
|
|
31
|
+
stackPresentation !== 'formSheet'
|
|
32
|
+
) {
|
|
26
33
|
// This is necessary for LogBox
|
|
27
34
|
return (
|
|
28
35
|
<AppContainer>
|
|
29
|
-
<
|
|
36
|
+
<ScreenContentWrapper {...rest} />
|
|
30
37
|
</AppContainer>
|
|
31
38
|
);
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
return <
|
|
41
|
+
return <ScreenContentWrapper {...rest} />;
|
|
35
42
|
};
|
|
36
43
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { View, type ViewProps } from 'react-native';
|
|
3
|
-
import type
|
|
3
|
+
import { type StackPresentationTypes } from 'react-native-screens';
|
|
4
4
|
|
|
5
5
|
type ContainerProps = ViewProps & {
|
|
6
6
|
stackPresentation: StackPresentationTypes;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ScreenFooter } from 'react-native-screens';
|
|
3
|
+
|
|
4
|
+
type FooterProps = {
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function FooterComponent({ children }: FooterProps) {
|
|
9
|
+
return <ScreenFooter collapsable={false}>{children}</ScreenFooter>;
|
|
10
|
+
}
|
|
@@ -164,9 +164,11 @@ export function HeaderConfig({
|
|
|
164
164
|
* - Back button should stay visible when `headerLeft` is specified
|
|
165
165
|
* - If `headerTitle` for Android is specified, so we only need to remove the title and keep the back button
|
|
166
166
|
*/
|
|
167
|
-
const backButtonInCustomView =
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
const backButtonInCustomView =
|
|
168
|
+
headerBackVisible ||
|
|
169
|
+
(Platform.OS === 'android' &&
|
|
170
|
+
headerTitleElement != null &&
|
|
171
|
+
headerLeftElement == null);
|
|
170
172
|
|
|
171
173
|
const translucent =
|
|
172
174
|
headerBackground != null ||
|
|
@@ -188,6 +190,8 @@ export function HeaderConfig({
|
|
|
188
190
|
// Back button menu is not disabled
|
|
189
191
|
headerBackButtonMenuEnabled !== false;
|
|
190
192
|
|
|
193
|
+
const isCenterViewRenderedAndroid = headerTitleAlign === 'center';
|
|
194
|
+
|
|
191
195
|
return (
|
|
192
196
|
<ScreenStackHeaderConfig
|
|
193
197
|
backButtonInCustomView={backButtonInCustomView}
|
|
@@ -250,25 +254,30 @@ export function HeaderConfig({
|
|
|
250
254
|
) : (
|
|
251
255
|
<>
|
|
252
256
|
{headerLeftElement != null || typeof headerTitle === 'function' ? (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
// The style passed to header left, together with title element being wrapped
|
|
258
|
+
// in flex view is reqruied for proper header layout, in particular,
|
|
259
|
+
// for the text truncation to work.
|
|
260
|
+
<ScreenStackHeaderLeftView
|
|
261
|
+
style={!isCenterViewRenderedAndroid ? { flex: 1 } : null}
|
|
262
|
+
>
|
|
263
|
+
{headerLeftElement}
|
|
264
|
+
{headerTitleAlign !== 'center' ? (
|
|
265
|
+
typeof headerTitle === 'function' ? (
|
|
266
|
+
<View style={{ flex: 1 }}>{headerTitleElement}</View>
|
|
267
|
+
) : (
|
|
268
|
+
<View style={{ flex: 1 }}>
|
|
260
269
|
<HeaderTitle
|
|
261
270
|
tintColor={tintColor}
|
|
262
271
|
style={headerTitleStyleSupported}
|
|
263
272
|
>
|
|
264
273
|
{titleText}
|
|
265
274
|
</HeaderTitle>
|
|
266
|
-
|
|
267
|
-
)
|
|
268
|
-
|
|
275
|
+
</View>
|
|
276
|
+
)
|
|
277
|
+
) : null}
|
|
269
278
|
</ScreenStackHeaderLeftView>
|
|
270
279
|
) : null}
|
|
271
|
-
{
|
|
280
|
+
{isCenterViewRenderedAndroid ? (
|
|
272
281
|
<ScreenStackHeaderCenterView>
|
|
273
282
|
{typeof headerTitle === 'function' ? (
|
|
274
283
|
headerTitleElement
|
|
@@ -300,10 +309,3 @@ export function HeaderConfig({
|
|
|
300
309
|
</ScreenStackHeaderConfig>
|
|
301
310
|
);
|
|
302
311
|
}
|
|
303
|
-
|
|
304
|
-
const styles = StyleSheet.create({
|
|
305
|
-
row: {
|
|
306
|
-
flexDirection: 'row',
|
|
307
|
-
alignItems: 'center',
|
|
308
|
-
},
|
|
309
|
-
});
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
NavigationRouteContext,
|
|
12
12
|
type ParamListBase,
|
|
13
13
|
type Route,
|
|
14
|
+
type RouteProp,
|
|
14
15
|
StackActions,
|
|
15
16
|
type StackNavigationState,
|
|
16
17
|
usePreventRemoveContext,
|
|
@@ -49,6 +50,7 @@ import { AnimatedHeaderHeightContext } from '../utils/useAnimatedHeaderHeight';
|
|
|
49
50
|
import { useDismissedRouteError } from '../utils/useDismissedRouteError';
|
|
50
51
|
import { useInvalidPreventRemoveError } from '../utils/useInvalidPreventRemoveError';
|
|
51
52
|
import { DebugContainer } from './DebugContainer';
|
|
53
|
+
import { FooterComponent } from './FooterComponent';
|
|
52
54
|
import { HeaderConfig } from './HeaderConfig';
|
|
53
55
|
|
|
54
56
|
const ANDROID_DEFAULT_HEADER_HEIGHT = 56;
|
|
@@ -60,6 +62,7 @@ const MaybeNestedStack = ({
|
|
|
60
62
|
headerHeight,
|
|
61
63
|
headerTopInsetEnabled,
|
|
62
64
|
children,
|
|
65
|
+
isPreloaded,
|
|
63
66
|
}: {
|
|
64
67
|
options: NativeStackNavigationOptions;
|
|
65
68
|
route: Route<string>;
|
|
@@ -67,9 +70,15 @@ const MaybeNestedStack = ({
|
|
|
67
70
|
headerHeight: number;
|
|
68
71
|
headerTopInsetEnabled: boolean;
|
|
69
72
|
children: React.ReactNode;
|
|
73
|
+
isPreloaded?: boolean;
|
|
70
74
|
}) => {
|
|
71
75
|
const { colors } = useTheme();
|
|
72
|
-
const {
|
|
76
|
+
const {
|
|
77
|
+
header,
|
|
78
|
+
headerShown = true,
|
|
79
|
+
contentStyle,
|
|
80
|
+
unstable_screenStyle = null,
|
|
81
|
+
} = options;
|
|
73
82
|
|
|
74
83
|
const isHeaderInModal =
|
|
75
84
|
Platform.OS === 'android'
|
|
@@ -92,7 +101,11 @@ const MaybeNestedStack = ({
|
|
|
92
101
|
const content = (
|
|
93
102
|
<DebugContainer
|
|
94
103
|
style={[
|
|
95
|
-
|
|
104
|
+
presentation === 'formSheet'
|
|
105
|
+
? Platform.OS === 'ios'
|
|
106
|
+
? styles.absolute
|
|
107
|
+
: null
|
|
108
|
+
: styles.container,
|
|
96
109
|
presentation !== 'transparentModal' &&
|
|
97
110
|
presentation !== 'containedTransparentModal' && {
|
|
98
111
|
backgroundColor: colors.background,
|
|
@@ -112,7 +125,8 @@ const MaybeNestedStack = ({
|
|
|
112
125
|
enabled
|
|
113
126
|
isNativeStack
|
|
114
127
|
hasLargeHeader={options.headerLargeTitle ?? false}
|
|
115
|
-
style={StyleSheet.absoluteFill}
|
|
128
|
+
style={[StyleSheet.absoluteFill, unstable_screenStyle]}
|
|
129
|
+
activityState={isPreloaded ? 0 : 2}
|
|
116
130
|
>
|
|
117
131
|
{content}
|
|
118
132
|
<HeaderConfig
|
|
@@ -137,6 +151,7 @@ type SceneViewProps = {
|
|
|
137
151
|
previousDescriptor?: NativeStackDescriptor;
|
|
138
152
|
nextDescriptor?: NativeStackDescriptor;
|
|
139
153
|
isPresentationModal?: boolean;
|
|
154
|
+
isPreloaded?: boolean;
|
|
140
155
|
onWillDisappear: () => void;
|
|
141
156
|
onWillAppear: () => void;
|
|
142
157
|
onAppear: () => void;
|
|
@@ -145,6 +160,7 @@ type SceneViewProps = {
|
|
|
145
160
|
onHeaderBackButtonClicked: ScreenProps['onHeaderBackButtonClicked'];
|
|
146
161
|
onNativeDismissCancelled: ScreenProps['onDismissed'];
|
|
147
162
|
onGestureCancel: ScreenProps['onGestureCancel'];
|
|
163
|
+
onSheetDetentChanged: ScreenProps['onSheetDetentChanged'];
|
|
148
164
|
};
|
|
149
165
|
|
|
150
166
|
const SceneView = ({
|
|
@@ -154,6 +170,7 @@ const SceneView = ({
|
|
|
154
170
|
previousDescriptor,
|
|
155
171
|
nextDescriptor,
|
|
156
172
|
isPresentationModal,
|
|
173
|
+
isPreloaded,
|
|
157
174
|
onWillDisappear,
|
|
158
175
|
onWillAppear,
|
|
159
176
|
onAppear,
|
|
@@ -162,6 +179,7 @@ const SceneView = ({
|
|
|
162
179
|
onHeaderBackButtonClicked,
|
|
163
180
|
onNativeDismissCancelled,
|
|
164
181
|
onGestureCancel,
|
|
182
|
+
onSheetDetentChanged,
|
|
165
183
|
}: SceneViewProps) => {
|
|
166
184
|
const { route, navigation, options, render } = descriptor;
|
|
167
185
|
|
|
@@ -170,6 +188,7 @@ const SceneView = ({
|
|
|
170
188
|
animationMatchesGesture,
|
|
171
189
|
presentation = isPresentationModal ? 'modal' : 'card',
|
|
172
190
|
fullScreenGestureEnabled,
|
|
191
|
+
unstable_screenStyle = null,
|
|
173
192
|
} = options;
|
|
174
193
|
|
|
175
194
|
const {
|
|
@@ -190,19 +209,30 @@ const SceneView = ({
|
|
|
190
209
|
navigationBarTranslucent,
|
|
191
210
|
navigationBarHidden,
|
|
192
211
|
orientation,
|
|
193
|
-
sheetAllowedDetents =
|
|
194
|
-
|
|
212
|
+
sheetAllowedDetents = [1.0],
|
|
213
|
+
sheetLargestUndimmedDetentIndex = -1,
|
|
195
214
|
sheetGrabberVisible = false,
|
|
196
215
|
sheetCornerRadius = -1.0,
|
|
216
|
+
sheetElevation = 24,
|
|
197
217
|
sheetExpandsWhenScrolledToEdge = true,
|
|
218
|
+
sheetInitialDetentIndex = 0,
|
|
198
219
|
statusBarAnimation,
|
|
199
220
|
statusBarHidden,
|
|
200
221
|
statusBarStyle,
|
|
201
222
|
statusBarTranslucent,
|
|
202
223
|
statusBarBackgroundColor,
|
|
224
|
+
unstable_sheetFooter = null,
|
|
203
225
|
freezeOnBlur,
|
|
204
226
|
} = options;
|
|
205
227
|
|
|
228
|
+
// We want to allow only backgroundColor setting for now.
|
|
229
|
+
// This allows to workaround one issue with truncated
|
|
230
|
+
// content with formSheet presentation.
|
|
231
|
+
unstable_screenStyle =
|
|
232
|
+
unstable_screenStyle && presentation === 'formSheet'
|
|
233
|
+
? { backgroundColor: unstable_screenStyle.backgroundColor }
|
|
234
|
+
: null;
|
|
235
|
+
|
|
206
236
|
if (gestureDirection === 'vertical' && Platform.OS === 'ios') {
|
|
207
237
|
// for `vertical` direction to work, we need to set `fullScreenGestureEnabled` to `true`
|
|
208
238
|
// so the screen can be dismissed from any point on screen.
|
|
@@ -329,12 +359,15 @@ const SceneView = ({
|
|
|
329
359
|
key={route.key}
|
|
330
360
|
enabled
|
|
331
361
|
isNativeStack
|
|
362
|
+
activityState={isPreloaded ? 0 : 2}
|
|
363
|
+
style={[StyleSheet.absoluteFill, unstable_screenStyle]}
|
|
332
364
|
accessibilityElementsHidden={!focused}
|
|
333
365
|
importantForAccessibility={focused ? 'auto' : 'no-hide-descendants'}
|
|
334
|
-
style={StyleSheet.absoluteFill}
|
|
335
366
|
hasLargeHeader={options.headerLargeTitle ?? false}
|
|
336
367
|
customAnimationOnSwipe={animationMatchesGesture}
|
|
337
368
|
fullScreenSwipeEnabled={fullScreenGestureEnabled}
|
|
369
|
+
fullScreenSwipeShadowEnabled={fullScreenGestureShadowEnabled}
|
|
370
|
+
freezeOnBlur={freezeOnBlur}
|
|
338
371
|
gestureEnabled={
|
|
339
372
|
Platform.OS === 'android'
|
|
340
373
|
? // This prop enables handling of system back gestures on Android
|
|
@@ -352,9 +385,11 @@ const SceneView = ({
|
|
|
352
385
|
stackAnimation={animation}
|
|
353
386
|
screenOrientation={orientation}
|
|
354
387
|
sheetAllowedDetents={sheetAllowedDetents}
|
|
355
|
-
|
|
388
|
+
sheetLargestUndimmedDetentIndex={sheetLargestUndimmedDetentIndex}
|
|
356
389
|
sheetGrabberVisible={sheetGrabberVisible}
|
|
390
|
+
sheetInitialDetentIndex={sheetInitialDetentIndex}
|
|
357
391
|
sheetCornerRadius={sheetCornerRadius}
|
|
392
|
+
sheetElevation={sheetElevation}
|
|
358
393
|
sheetExpandsWhenScrolledToEdge={sheetExpandsWhenScrolledToEdge}
|
|
359
394
|
statusBarAnimation={statusBarAnimation}
|
|
360
395
|
statusBarHidden={statusBarHidden}
|
|
@@ -369,6 +404,7 @@ const SceneView = ({
|
|
|
369
404
|
onDisappear={onDisappear}
|
|
370
405
|
onDismissed={onDismissed}
|
|
371
406
|
onGestureCancel={onGestureCancel}
|
|
407
|
+
onSheetDetentChanged={onSheetDetentChanged}
|
|
372
408
|
gestureResponseDistance={gestureResponseDistance}
|
|
373
409
|
nativeBackButtonDismissalEnabled={false} // on Android
|
|
374
410
|
onHeaderBackButtonClicked={onHeaderBackButtonClicked}
|
|
@@ -423,12 +459,9 @@ const SceneView = ({
|
|
|
423
459
|
},
|
|
424
460
|
}
|
|
425
461
|
)}
|
|
426
|
-
freezeOnBlur={freezeOnBlur}
|
|
427
462
|
// When ts-expect-error is added, it affects all the props below it
|
|
428
463
|
// So we keep any props that need it at the end
|
|
429
464
|
// Otherwise invalid props may not be caught by TypeScript
|
|
430
|
-
// @ts-expect-error Props available in newer versions of `react-native-screens`
|
|
431
|
-
fullScreenSwipeShadowEnabled={fullScreenGestureShadowEnabled} // 3.33.0 onwards
|
|
432
465
|
>
|
|
433
466
|
<NavigationContext.Provider value={navigation}>
|
|
434
467
|
<NavigationRouteContext.Provider value={route}>
|
|
@@ -498,7 +531,7 @@ const SceneView = ({
|
|
|
498
531
|
*
|
|
499
532
|
* HeaderConfig must not be first child of a Screen.
|
|
500
533
|
* See https://github.com/software-mansion/react-native-screens/pull/1825
|
|
501
|
-
* for detailed explanation
|
|
534
|
+
* for detailed explanation.
|
|
502
535
|
*/}
|
|
503
536
|
<HeaderConfig
|
|
504
537
|
{...options}
|
|
@@ -518,6 +551,9 @@ const SceneView = ({
|
|
|
518
551
|
headerTopInsetEnabled={headerTopInsetEnabled}
|
|
519
552
|
canGoBack={headerBack !== undefined}
|
|
520
553
|
/>
|
|
554
|
+
{presentation === 'formSheet' && unstable_sheetFooter && (
|
|
555
|
+
<FooterComponent>{unstable_sheetFooter()}</FooterComponent>
|
|
556
|
+
)}
|
|
521
557
|
</HeaderHeightContext.Provider>
|
|
522
558
|
</AnimatedHeaderHeightContext.Provider>
|
|
523
559
|
</NavigationRouteContext.Provider>
|
|
@@ -530,9 +566,18 @@ type Props = {
|
|
|
530
566
|
state: StackNavigationState<ParamListBase>;
|
|
531
567
|
navigation: NativeStackNavigationHelpers;
|
|
532
568
|
descriptors: NativeStackDescriptorMap;
|
|
569
|
+
describe: (
|
|
570
|
+
route: RouteProp<ParamListBase>,
|
|
571
|
+
placeholder: boolean
|
|
572
|
+
) => NativeStackDescriptor;
|
|
533
573
|
};
|
|
534
574
|
|
|
535
|
-
export function NativeStackView({
|
|
575
|
+
export function NativeStackView({
|
|
576
|
+
state,
|
|
577
|
+
navigation,
|
|
578
|
+
descriptors,
|
|
579
|
+
describe,
|
|
580
|
+
}: Props) {
|
|
536
581
|
const { setNextDismissedKey } = useDismissedRouteError(state);
|
|
537
582
|
|
|
538
583
|
const { colors } = useTheme();
|
|
@@ -541,11 +586,18 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
|
|
|
541
586
|
|
|
542
587
|
const modalRouteKeys = getModalRouteKeys(state.routes, descriptors);
|
|
543
588
|
|
|
589
|
+
const preloadedDescriptors =
|
|
590
|
+
state.preloadedRoutes.reduce<NativeStackDescriptorMap>((acc, route) => {
|
|
591
|
+
acc[route.key] = acc[route.key] || describe(route, true);
|
|
592
|
+
return acc;
|
|
593
|
+
}, {});
|
|
594
|
+
|
|
544
595
|
return (
|
|
545
596
|
<SafeAreaProviderCompat style={{ backgroundColor: colors.background }}>
|
|
546
597
|
<ScreenStack style={styles.container}>
|
|
547
|
-
{state.routes.map((route, index) => {
|
|
548
|
-
const descriptor =
|
|
598
|
+
{state.routes.concat(state.preloadedRoutes).map((route, index) => {
|
|
599
|
+
const descriptor =
|
|
600
|
+
descriptors[route.key] ?? preloadedDescriptors[route.key];
|
|
549
601
|
const isFocused = state.index === index;
|
|
550
602
|
const previousKey = state.routes[index - 1]?.key;
|
|
551
603
|
const nextKey = state.routes[index + 1]?.key;
|
|
@@ -556,6 +608,10 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
|
|
|
556
608
|
|
|
557
609
|
const isModal = modalRouteKeys.includes(route.key);
|
|
558
610
|
|
|
611
|
+
const isPreloaded =
|
|
612
|
+
preloadedDescriptors[route.key] !== undefined &&
|
|
613
|
+
descriptors[route.key] === undefined;
|
|
614
|
+
|
|
559
615
|
return (
|
|
560
616
|
<SceneView
|
|
561
617
|
key={route.key}
|
|
@@ -565,6 +621,7 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
|
|
|
565
621
|
previousDescriptor={previousDescriptor}
|
|
566
622
|
nextDescriptor={nextDescriptor}
|
|
567
623
|
isPresentationModal={isModal}
|
|
624
|
+
isPreloaded={isPreloaded}
|
|
568
625
|
onWillDisappear={() => {
|
|
569
626
|
navigation.emit({
|
|
570
627
|
type: 'transitionStart',
|
|
@@ -622,6 +679,16 @@ export function NativeStackView({ state, navigation, descriptors }: Props) {
|
|
|
622
679
|
target: route.key,
|
|
623
680
|
});
|
|
624
681
|
}}
|
|
682
|
+
onSheetDetentChanged={(event) => {
|
|
683
|
+
navigation.emit({
|
|
684
|
+
type: 'sheetDetentChange',
|
|
685
|
+
target: route.key,
|
|
686
|
+
data: {
|
|
687
|
+
index: event.nativeEvent.index,
|
|
688
|
+
stable: event.nativeEvent.isStable,
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
}}
|
|
625
692
|
/>
|
|
626
693
|
);
|
|
627
694
|
})}
|