@react-navigation/core 8.0.0-alpha.0 → 8.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/module/BaseNavigationContainer.js +14 -7
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/ConsumedParamsContext.js +5 -0
- package/lib/module/ConsumedParamsContext.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +1 -0
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +8 -4
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationMetaContext.js +15 -0
- package/lib/module/NavigationMetaContext.js.map +1 -0
- package/lib/module/NavigationProvider.js +14 -3
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +3 -3
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +46 -56
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +30 -4
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/createNavigatorFactory.js +22 -1
- package/lib/module/createNavigatorFactory.js.map +1 -1
- package/lib/module/getPathFromState.js +25 -3
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getStateFromPath.js +158 -73
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +24 -0
- package/lib/module/getStateFromRouteParams.js.map +1 -0
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/theming/useTheme.js +1 -1
- package/lib/module/theming/useTheme.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useCurrentRender.js +1 -1
- package/lib/module/useCurrentRender.js.map +1 -1
- package/lib/module/useDescriptors.js +12 -43
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useFocusEvents.js +1 -1
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
- package/lib/module/useIsFocused.js +7 -12
- package/lib/module/useIsFocused.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +92 -42
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +14 -56
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +1 -1
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationIndependentTree.js +1 -1
- package/lib/module/useNavigationIndependentTree.js.map +1 -1
- package/lib/module/useNavigationState.js +4 -2
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +1 -1
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetState.js +2 -2
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +2 -2
- package/lib/module/useOnPreventRemove.js.map +1 -1
- package/lib/module/useOnRouteFocus.js +1 -1
- package/lib/module/useOnRouteFocus.js.map +1 -1
- package/lib/module/useOptionsGetters.js +2 -2
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +1 -1
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +1 -1
- package/lib/module/useRegisterNavigator.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +1 -1
- package/lib/module/useScheduleUpdate.js.map +1 -1
- package/lib/module/useStateForPath.js +1 -1
- package/lib/module/useStateForPath.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/ConsumedParamsContext.d.ts +8 -0
- package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
- package/lib/typescript/src/NavigationBuilderContext.d.ts +11 -5
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationMetaContext.d.ts +12 -0
- package/lib/typescript/src/NavigationMetaContext.d.ts.map +1 -0
- package/lib/typescript/src/NavigationProvider.d.ts +4 -4
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationStateContext.d.ts +3 -3
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/StaticContainer.d.ts +1 -1
- package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts +33 -19
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
- package/lib/typescript/src/findFocusedRoute.d.ts +3 -3
- package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts +3 -3
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPathFromState.d.ts +2 -2
- package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +3 -3
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
- package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +144 -82
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +12 -25
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useIsFocused.d.ts +3 -0
- package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +20 -29
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +2 -42
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +18 -16
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnAction.d.ts +6 -6
- package/lib/typescript/src/useOnAction.d.ts.map +1 -1
- package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
- package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts +2 -2
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +35 -3
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/package.json +20 -18
- package/src/BaseNavigationContainer.tsx +332 -326
- package/src/ConsumedParamsContext.tsx +10 -0
- package/src/NavigationBuilderContext.tsx +14 -8
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +8 -5
- package/src/NavigationMetaContext.tsx +14 -0
- package/src/NavigationProvider.tsx +17 -3
- package/src/NavigationStateContext.tsx +5 -6
- package/src/PreventRemoveProvider.tsx +3 -3
- package/src/SceneView.tsx +58 -56
- package/src/StaticNavigation.tsx +100 -30
- package/src/createNavigatorFactory.tsx +35 -4
- package/src/findFocusedRoute.tsx +3 -3
- package/src/getActionFromState.tsx +7 -7
- package/src/getPathFromState.tsx +53 -9
- package/src/getStateFromPath.tsx +255 -97
- package/src/getStateFromRouteParams.tsx +60 -0
- package/src/index.tsx +2 -1
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +330 -187
- package/src/useCurrentRender.tsx +1 -1
- package/src/useDescriptors.tsx +13 -48
- package/src/useFocusEvents.tsx +1 -1
- package/src/useFocusedListenersChildrenAdapter.tsx +1 -1
- package/src/useIsFocused.tsx +14 -21
- package/src/useNavigation.tsx +2 -2
- package/src/useNavigationBuilder.tsx +138 -53
- package/src/useNavigationCache.tsx +12 -73
- package/src/useNavigationHelpers.tsx +1 -1
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +6 -4
- package/src/useOnAction.tsx +8 -8
- package/src/useOnGetState.tsx +2 -2
- package/src/useOnPreventRemove.tsx +2 -2
- package/src/useOnRouteFocus.tsx +10 -12
- package/src/useOptionsGetters.tsx +2 -2
- package/src/usePreventRemoveContext.tsx +1 -1
- package/src/useRegisterNavigator.tsx +1 -1
- package/src/useScheduleUpdate.tsx +1 -3
- package/src/useStateForPath.tsx +1 -1
- package/src/utilities.tsx +72 -4
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type ConsumedParamsContextValue = {
|
|
4
|
+
isConsumed: (params: object) => boolean;
|
|
5
|
+
setConsumed: (params: object) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const ConsumedParamsContext = React.createContext<
|
|
9
|
+
ConsumedParamsContextValue | undefined
|
|
10
|
+
>(undefined);
|
|
@@ -52,20 +52,26 @@ export type ChildBeforeRemoveListener = (action: NavigationAction) => boolean;
|
|
|
52
52
|
* Context which holds the required helpers needed to build nested navigators.
|
|
53
53
|
*/
|
|
54
54
|
export const NavigationBuilderContext = React.createContext<{
|
|
55
|
-
onAction?:
|
|
56
|
-
action: NavigationAction,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
onRouteFocus?: (key: string) => void;
|
|
55
|
+
onAction?:
|
|
56
|
+
| ((action: NavigationAction, visitedNavigators?: Set<string>) => boolean)
|
|
57
|
+
| undefined;
|
|
58
|
+
addListener?: AddListener | undefined;
|
|
59
|
+
addKeyedListener?: AddKeyedListener | undefined;
|
|
60
|
+
onRouteFocus?: ((key: string) => void) | undefined;
|
|
62
61
|
onDispatchAction: (action: NavigationAction, noop: boolean) => void;
|
|
62
|
+
onEmitEvent: (event: {
|
|
63
|
+
type: string;
|
|
64
|
+
defaultPrevented: boolean | undefined;
|
|
65
|
+
target: string | undefined;
|
|
66
|
+
data: unknown;
|
|
67
|
+
}) => void;
|
|
63
68
|
onOptionsChange: (options: object) => void;
|
|
64
69
|
scheduleUpdate: (callback: () => void) => void;
|
|
65
70
|
flushUpdates: () => void;
|
|
66
|
-
stackRef?: React.MutableRefObject<string | undefined
|
|
71
|
+
stackRef?: React.MutableRefObject<string | undefined> | undefined;
|
|
67
72
|
}>({
|
|
68
73
|
onDispatchAction: () => undefined,
|
|
74
|
+
onEmitEvent: () => undefined,
|
|
69
75
|
onOptionsChange: () => undefined,
|
|
70
76
|
scheduleUpdate: () => {
|
|
71
77
|
throw new Error("Couldn't find a context for scheduling updates.");
|
|
@@ -3,11 +3,11 @@ import * as React from 'react';
|
|
|
3
3
|
export type FocusedRouteState = {
|
|
4
4
|
routes: [
|
|
5
5
|
{
|
|
6
|
-
key?: string;
|
|
6
|
+
key?: string | undefined;
|
|
7
7
|
name: string;
|
|
8
|
-
params?: object;
|
|
9
|
-
path?: string;
|
|
10
|
-
state?: FocusedRouteState;
|
|
8
|
+
params?: object | undefined;
|
|
9
|
+
path?: string | undefined;
|
|
10
|
+
state?: FocusedRouteState | undefined;
|
|
11
11
|
},
|
|
12
12
|
];
|
|
13
13
|
};
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
NavigationRouteContext,
|
|
8
8
|
NavigationRouteNameContext,
|
|
9
9
|
} from './NavigationProvider';
|
|
10
|
+
import { IsFocusedContext } from './useIsFocused';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Component to make the child navigation container independent of parent containers.
|
|
@@ -21,11 +22,13 @@ export function NavigationIndependentTree({
|
|
|
21
22
|
<NamedRouteContextListContext.Provider value={undefined}>
|
|
22
23
|
<NavigationRouteContext.Provider value={undefined}>
|
|
23
24
|
<NavigationContext.Provider value={undefined}>
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
{
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
<IsFocusedContext.Provider value={undefined}>
|
|
26
|
+
<NavigationRouteNameContext.Provider value={undefined}>
|
|
27
|
+
<NavigationIndependentTreeContext.Provider value={true}>
|
|
28
|
+
{children}
|
|
29
|
+
</NavigationIndependentTreeContext.Provider>
|
|
30
|
+
</NavigationRouteNameContext.Provider>
|
|
31
|
+
</IsFocusedContext.Provider>
|
|
29
32
|
</NavigationContext.Provider>
|
|
30
33
|
</NavigationRouteContext.Provider>
|
|
31
34
|
</NamedRouteContextListContext.Provider>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context with additional metadata to pass to child navigator in a screen.
|
|
5
|
+
* For example, child native stack to know it's inside native tabs.
|
|
6
|
+
* So it doesn't implement features such as `popToTop` that are handled by native tabs.
|
|
7
|
+
*
|
|
8
|
+
* Consumers should not make any assumptions about the shape of the object.
|
|
9
|
+
* It can be different depending on the navigator and may change without notice.
|
|
10
|
+
* This is not intended to be used by application code.
|
|
11
|
+
*/
|
|
12
|
+
export const NavigationMetaContext = React.createContext<object | undefined>(
|
|
13
|
+
undefined
|
|
14
|
+
);
|
|
@@ -2,6 +2,7 @@ import type { ParamListBase, Route } from '@react-navigation/routers';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
import type { NavigationProp } from './types';
|
|
5
|
+
import { FocusedRouteKeyContext, IsFocusedContext } from './useIsFocused';
|
|
5
6
|
import { useLazyValue } from './useLazyValue';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -48,14 +49,27 @@ export function NavigationProvider({ route, navigation, children }: Props) {
|
|
|
48
49
|
[NamedRouteContext, parents, route.name]
|
|
49
50
|
);
|
|
50
51
|
|
|
52
|
+
const parentIsFocused = React.use(IsFocusedContext);
|
|
53
|
+
const focusedRouteKey = React.use(FocusedRouteKeyContext);
|
|
54
|
+
|
|
55
|
+
// Mark route as focused only if:
|
|
56
|
+
// - It doesn't have a parent navigator
|
|
57
|
+
// - Parent navigator is focused
|
|
58
|
+
const isFocused =
|
|
59
|
+
parentIsFocused == null || parentIsFocused
|
|
60
|
+
? focusedRouteKey === route.key
|
|
61
|
+
: false;
|
|
62
|
+
|
|
51
63
|
return (
|
|
52
64
|
<NamedRouteContextListContext.Provider value={NamedRouteContextList}>
|
|
53
65
|
<NamedRouteContext.Provider value={route}>
|
|
54
66
|
<NavigationRouteContext.Provider value={route}>
|
|
55
67
|
<NavigationContext.Provider value={navigation}>
|
|
56
|
-
<
|
|
57
|
-
{
|
|
58
|
-
|
|
68
|
+
<IsFocusedContext.Provider value={isFocused}>
|
|
69
|
+
<NavigationRouteNameContext.Provider value={route.name}>
|
|
70
|
+
{children}
|
|
71
|
+
</NavigationRouteNameContext.Provider>
|
|
72
|
+
</IsFocusedContext.Provider>
|
|
59
73
|
</NavigationContext.Provider>
|
|
60
74
|
</NavigationRouteContext.Provider>
|
|
61
75
|
</NamedRouteContext.Provider>
|
|
@@ -5,8 +5,8 @@ const MISSING_CONTEXT_ERROR =
|
|
|
5
5
|
"Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started for setup instructions.";
|
|
6
6
|
|
|
7
7
|
export const NavigationStateContext = React.createContext<{
|
|
8
|
-
isDefault?: true;
|
|
9
|
-
state?: NavigationState | PartialState<NavigationState
|
|
8
|
+
isDefault?: true | undefined;
|
|
9
|
+
state?: NavigationState | PartialState<NavigationState> | undefined;
|
|
10
10
|
getKey: () => string | undefined;
|
|
11
11
|
setKey: (key: string) => void;
|
|
12
12
|
getState: () => NavigationState | PartialState<NavigationState> | undefined;
|
|
@@ -14,10 +14,9 @@ export const NavigationStateContext = React.createContext<{
|
|
|
14
14
|
state: NavigationState | PartialState<NavigationState> | undefined
|
|
15
15
|
) => void;
|
|
16
16
|
getIsInitial: () => boolean;
|
|
17
|
-
addOptionsGetter?:
|
|
18
|
-
key: string,
|
|
19
|
-
|
|
20
|
-
) => void;
|
|
17
|
+
addOptionsGetter?:
|
|
18
|
+
| ((key: string, getter: () => object | undefined | null) => void)
|
|
19
|
+
| undefined;
|
|
21
20
|
}>({
|
|
22
21
|
isDefault: true,
|
|
23
22
|
|
|
@@ -50,10 +50,10 @@ export function PreventRemoveProvider({ children }: Props) {
|
|
|
50
50
|
const [preventedRoutesMap, setPreventedRoutesMap] =
|
|
51
51
|
React.useState<PreventedRoutesMap>(() => new Map());
|
|
52
52
|
|
|
53
|
-
const navigation = React.
|
|
54
|
-
const route = React.
|
|
53
|
+
const navigation = React.use(NavigationHelpersContext);
|
|
54
|
+
const route = React.use(NavigationRouteContext);
|
|
55
55
|
|
|
56
|
-
const preventRemoveContextValue = React.
|
|
56
|
+
const preventRemoveContextValue = React.use(PreventRemoveContext);
|
|
57
57
|
// take `setPreventRemove` from parent context - if exist it means we're in a nested context
|
|
58
58
|
const setParentPrevented = preventRemoveContextValue?.setPreventRemove;
|
|
59
59
|
|
package/src/SceneView.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from '@react-navigation/routers';
|
|
7
7
|
import * as React from 'react';
|
|
8
8
|
|
|
9
|
+
import { ConsumedParamsContext } from './ConsumedParamsContext';
|
|
9
10
|
import { EnsureSingleNavigator } from './EnsureSingleNavigator';
|
|
10
11
|
import { isArrayEqual } from './isArrayEqual';
|
|
11
12
|
import {
|
|
@@ -70,46 +71,16 @@ export function SceneView<
|
|
|
70
71
|
const state = getState();
|
|
71
72
|
|
|
72
73
|
const routes = state.routes.map((r) => {
|
|
73
|
-
if (r.key
|
|
74
|
-
return
|
|
74
|
+
if (r.key === route.key && r.state !== child) {
|
|
75
|
+
return {
|
|
76
|
+
...r,
|
|
77
|
+
state: child,
|
|
78
|
+
};
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// Before updating the state, cleanup any nested screen and state
|
|
80
|
-
// This will avoid the navigator trying to handle them again
|
|
81
|
-
if (
|
|
82
|
-
nextRoute.params &&
|
|
83
|
-
(('state' in nextRoute.params &&
|
|
84
|
-
typeof nextRoute.params.state === 'object' &&
|
|
85
|
-
nextRoute.params.state !== null) ||
|
|
86
|
-
('screen' in nextRoute.params &&
|
|
87
|
-
typeof nextRoute.params.screen === 'string'))
|
|
88
|
-
) {
|
|
89
|
-
// @ts-expect-error: we don't have correct type for params
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
91
|
-
const { state, screen, params, initial, ...rest } = nextRoute.params;
|
|
92
|
-
|
|
93
|
-
if (Object.keys(rest).length) {
|
|
94
|
-
return { ...nextRoute, params: rest };
|
|
95
|
-
} else {
|
|
96
|
-
const {
|
|
97
|
-
// We destructure the params to omit them
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
99
|
-
params,
|
|
100
|
-
...restRoute
|
|
101
|
-
} = nextRoute;
|
|
102
|
-
|
|
103
|
-
return restRoute;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return nextRoute;
|
|
81
|
+
return r;
|
|
108
82
|
});
|
|
109
83
|
|
|
110
|
-
// Make sure not to update state if routes haven't changed
|
|
111
|
-
// Otherwise this will result in params cleanup as well
|
|
112
|
-
// We only want to cleanup params when state changes - after they are used
|
|
113
84
|
if (!isArrayEqual(state.routes, routes)) {
|
|
114
85
|
setState({
|
|
115
86
|
...state,
|
|
@@ -134,10 +105,39 @@ export function SceneView<
|
|
|
134
105
|
|
|
135
106
|
const getIsInitial = React.useCallback(() => isInitialRef.current, []);
|
|
136
107
|
|
|
137
|
-
const
|
|
138
|
-
|
|
108
|
+
const [consumedParams, setConsumedParams] = React.useState<WeakMap<
|
|
109
|
+
object,
|
|
110
|
+
true
|
|
111
|
+
> | null>(null);
|
|
112
|
+
|
|
113
|
+
const consumedParamsContext = React.useMemo(
|
|
114
|
+
() => ({
|
|
115
|
+
isConsumed: (params: object) => {
|
|
116
|
+
if (consumedParams) {
|
|
117
|
+
return consumedParams.has(params);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return false;
|
|
121
|
+
},
|
|
122
|
+
setConsumed: (params: object) => {
|
|
123
|
+
setConsumedParams((prev) => {
|
|
124
|
+
if (prev && prev.has(params)) {
|
|
125
|
+
return prev;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const map = new WeakMap<object, true>();
|
|
129
|
+
|
|
130
|
+
map.set(params, true);
|
|
131
|
+
|
|
132
|
+
return map;
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
}),
|
|
136
|
+
[consumedParams]
|
|
139
137
|
);
|
|
140
138
|
|
|
139
|
+
const parentFocusedRouteState = React.use(NavigationFocusedRouteStateContext);
|
|
140
|
+
|
|
141
141
|
const focusedRouteState = React.useMemo(() => {
|
|
142
142
|
const state: FocusedRouteState = {
|
|
143
143
|
routes: [
|
|
@@ -205,23 +205,25 @@ export function SceneView<
|
|
|
205
205
|
: screen.component;
|
|
206
206
|
|
|
207
207
|
return (
|
|
208
|
-
<
|
|
209
|
-
<
|
|
210
|
-
<
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
screen.children
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
208
|
+
<ConsumedParamsContext.Provider value={consumedParamsContext}>
|
|
209
|
+
<NavigationStateContext.Provider value={context}>
|
|
210
|
+
<NavigationFocusedRouteStateContext.Provider value={focusedRouteState}>
|
|
211
|
+
<EnsureSingleNavigator>
|
|
212
|
+
<StaticContainer
|
|
213
|
+
name={screen.name}
|
|
214
|
+
render={ScreenComponent || screen.children}
|
|
215
|
+
navigation={navigation}
|
|
216
|
+
route={route}
|
|
217
|
+
>
|
|
218
|
+
{ScreenComponent !== undefined ? (
|
|
219
|
+
<ScreenComponent navigation={navigation} route={route} />
|
|
220
|
+
) : screen.children !== undefined ? (
|
|
221
|
+
screen.children({ navigation, route })
|
|
222
|
+
) : null}
|
|
223
|
+
</StaticContainer>
|
|
224
|
+
</EnsureSingleNavigator>
|
|
225
|
+
</NavigationFocusedRouteStateContext.Provider>
|
|
226
|
+
</NavigationStateContext.Provider>
|
|
227
|
+
</ConsumedParamsContext.Provider>
|
|
226
228
|
);
|
|
227
229
|
}
|
package/src/StaticNavigation.tsx
CHANGED
|
@@ -28,6 +28,7 @@ import type {
|
|
|
28
28
|
InferParse,
|
|
29
29
|
InferPath,
|
|
30
30
|
KeysOf,
|
|
31
|
+
StandardSchemaV1,
|
|
31
32
|
UnionToIntersection,
|
|
32
33
|
ValidPathPattern,
|
|
33
34
|
} from './utilities';
|
|
@@ -42,13 +43,32 @@ type ParamsForScreenComponent<T> = T extends (...args: any[]) => any
|
|
|
42
43
|
? Params
|
|
43
44
|
: undefined;
|
|
44
45
|
|
|
46
|
+
// If every nested route's params include `undefined`, the nested navigator
|
|
47
|
+
// itself can be omitted. Otherwise, require `NavigatorScreenParams`.
|
|
48
|
+
type ParamsForNestedNavigator<
|
|
49
|
+
T extends {
|
|
50
|
+
config: StaticConfig<NavigatorTypeBagBase>;
|
|
51
|
+
},
|
|
52
|
+
ParamList extends {} = StaticParamList<T>,
|
|
53
|
+
> = {
|
|
54
|
+
// Exclude routes with optional params so the resulting union only contains route names with required params.
|
|
55
|
+
// If there are no routes with required params, the resulting union will be `never`.
|
|
56
|
+
[RouteName in keyof ParamList]-?: undefined extends ParamList[RouteName]
|
|
57
|
+
? never
|
|
58
|
+
: RouteName;
|
|
59
|
+
}[keyof ParamList] extends never
|
|
60
|
+
? NavigatorScreenParams<ParamList> | undefined
|
|
61
|
+
: NavigatorScreenParams<ParamList>;
|
|
62
|
+
|
|
45
63
|
type ParamsForScreen<T> =
|
|
46
64
|
// Nested navigator in screen property
|
|
47
|
-
T extends {
|
|
48
|
-
|
|
65
|
+
T extends {
|
|
66
|
+
screen: { config: StaticConfig<NavigatorTypeBagBase> };
|
|
67
|
+
}
|
|
68
|
+
? ParamsForNestedNavigator<T['screen']>
|
|
49
69
|
: // Direct nested navigator
|
|
50
|
-
T extends
|
|
51
|
-
?
|
|
70
|
+
T extends { config: StaticConfig<NavigatorTypeBagBase> }
|
|
71
|
+
? ParamsForNestedNavigator<T>
|
|
52
72
|
: T extends {
|
|
53
73
|
screen: React.ComponentType<any>;
|
|
54
74
|
}
|
|
@@ -75,7 +95,7 @@ type ParamsForConfig<Linking, Screen> = undefined extends Linking
|
|
|
75
95
|
: // Only infer params from linking if it's a pattern (i.e., contains ':')
|
|
76
96
|
// This avoids inferring non-literals like 'string'
|
|
77
97
|
Linking extends ValidPathPattern | { path: ValidPathPattern }
|
|
78
|
-
? Screen extends
|
|
98
|
+
? Screen extends { config: StaticConfig<NavigatorTypeBagBase> }
|
|
79
99
|
? FlatType<ParamsForLinking<Linking>> & ParamsForScreen<Screen>
|
|
80
100
|
: // Don't combine if `undefined`, otherwise it'll result in `never`
|
|
81
101
|
undefined extends ParamsForScreen<Screen>
|
|
@@ -147,7 +167,7 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
147
167
|
*/
|
|
148
168
|
exact?: boolean;
|
|
149
169
|
/**
|
|
150
|
-
* An object mapping the param name to a function
|
|
170
|
+
* An object mapping the param name to a parser function or a Standard Schema.
|
|
151
171
|
*
|
|
152
172
|
* @example
|
|
153
173
|
* ```js
|
|
@@ -157,7 +177,11 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
157
177
|
* }
|
|
158
178
|
* ```
|
|
159
179
|
*/
|
|
160
|
-
parse?: Record<
|
|
180
|
+
parse?: Record<
|
|
181
|
+
string,
|
|
182
|
+
| ((value: string) => unknown)
|
|
183
|
+
| StandardSchemaV1<string | string[] | null | undefined, unknown>
|
|
184
|
+
>;
|
|
161
185
|
/**
|
|
162
186
|
* An object mapping the param name to a function which converts the param value to a string.
|
|
163
187
|
* By default, all params are converted to strings using `String(value)`.
|
|
@@ -184,7 +208,7 @@ export type StaticScreenConfigLinking =
|
|
|
184
208
|
|
|
185
209
|
export type StaticScreenConfigScreen =
|
|
186
210
|
| React.ComponentType<any>
|
|
187
|
-
| StaticNavigation<any
|
|
211
|
+
| StaticNavigation<any>;
|
|
188
212
|
|
|
189
213
|
export type StaticScreenConfig<
|
|
190
214
|
Linking extends StaticScreenConfigLinking,
|
|
@@ -328,15 +352,18 @@ type StaticConfigScreens<
|
|
|
328
352
|
> = {
|
|
329
353
|
[RouteName in keyof ParamList]:
|
|
330
354
|
| React.ComponentType<any>
|
|
331
|
-
| StaticNavigation<any
|
|
355
|
+
| StaticNavigation<any>
|
|
332
356
|
| StaticScreenConfig<
|
|
333
357
|
| {
|
|
334
358
|
path: string;
|
|
335
|
-
parse?: Record<
|
|
359
|
+
parse?: Record<
|
|
360
|
+
string,
|
|
361
|
+
((value: string) => any) | StandardSchemaV1<any, any>
|
|
362
|
+
>;
|
|
336
363
|
}
|
|
337
364
|
| string
|
|
338
365
|
| undefined,
|
|
339
|
-
StaticNavigation<any
|
|
366
|
+
StaticNavigation<any> | React.ComponentType<any>,
|
|
340
367
|
State,
|
|
341
368
|
ScreenOptions,
|
|
342
369
|
EventMap,
|
|
@@ -503,11 +530,9 @@ export type StaticParamList<
|
|
|
503
530
|
ParamListForGroups<T['config']['groups']>
|
|
504
531
|
>;
|
|
505
532
|
|
|
506
|
-
export type StaticNavigation<
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
Screen: React.ComponentType<ScreenProps>;
|
|
510
|
-
config: StaticConfig<NavigatorTypeBagBase>;
|
|
533
|
+
export type StaticNavigation<NavigatorTypeBag extends NavigatorTypeBagBase> = {
|
|
534
|
+
config: StaticConfig<NavigatorTypeBag>;
|
|
535
|
+
getComponent: () => React.ComponentType<{}>;
|
|
511
536
|
};
|
|
512
537
|
|
|
513
538
|
const MemoizedScreen = React.memo(
|
|
@@ -542,16 +567,13 @@ const getItemsFromScreens = (
|
|
|
542
567
|
component = screen;
|
|
543
568
|
} else if ('config' in screen) {
|
|
544
569
|
isNavigator = true;
|
|
545
|
-
component =
|
|
546
|
-
screen,
|
|
547
|
-
`${name}Navigator`
|
|
548
|
-
);
|
|
570
|
+
component = screen.getComponent();
|
|
549
571
|
}
|
|
550
572
|
} else if (isValidElementType(item)) {
|
|
551
573
|
component = item;
|
|
552
574
|
} else if ('config' in item) {
|
|
553
575
|
isNavigator = true;
|
|
554
|
-
component =
|
|
576
|
+
component = item.getComponent();
|
|
555
577
|
}
|
|
556
578
|
|
|
557
579
|
if (component == null) {
|
|
@@ -589,10 +611,17 @@ const getItemsFromScreens = (
|
|
|
589
611
|
* @param displayName Name of the component to be displayed in React DevTools.
|
|
590
612
|
* @returns A component which renders the navigator.
|
|
591
613
|
*/
|
|
592
|
-
export function
|
|
593
|
-
|
|
614
|
+
export function createComponentForStaticConfig<
|
|
615
|
+
T extends {
|
|
616
|
+
Navigator: React.ComponentType<any>;
|
|
617
|
+
Group: React.ComponentType<any>;
|
|
618
|
+
Screen: React.ComponentType<any>;
|
|
619
|
+
config: StaticConfig<NavigatorTypeBagBase>;
|
|
620
|
+
},
|
|
621
|
+
>(
|
|
622
|
+
tree: T,
|
|
594
623
|
displayName: string
|
|
595
|
-
): React.ComponentType<
|
|
624
|
+
): React.ComponentType<Omit<React.ComponentProps<T['Navigator']>, 'children'>> {
|
|
596
625
|
const { Navigator, Group, Screen, config } = tree;
|
|
597
626
|
const { screens, groups, ...rest } = config;
|
|
598
627
|
|
|
@@ -637,10 +666,51 @@ export function createComponentForStaticNavigation(
|
|
|
637
666
|
}
|
|
638
667
|
}
|
|
639
668
|
|
|
640
|
-
|
|
669
|
+
if (items.length === 0) {
|
|
670
|
+
throw new Error(
|
|
671
|
+
"Couldn't find any screens in the 'screens' or 'groups' property. Make sure to define at least one screen in the configuration."
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const NavigatorComponent = ({ children: _, ...props }: typeof rest) => {
|
|
641
676
|
const children = items.map((item) => item());
|
|
642
677
|
|
|
643
|
-
|
|
678
|
+
const screenOptions =
|
|
679
|
+
typeof props.screenOptions === 'function' ||
|
|
680
|
+
typeof rest.screenOptions === 'function'
|
|
681
|
+
? (options: unknown) => ({
|
|
682
|
+
...(typeof rest.screenOptions === 'function'
|
|
683
|
+
? rest.screenOptions(options)
|
|
684
|
+
: rest.screenOptions),
|
|
685
|
+
...(typeof props.screenOptions === 'function'
|
|
686
|
+
? props.screenOptions(options)
|
|
687
|
+
: props.screenOptions),
|
|
688
|
+
})
|
|
689
|
+
: { ...rest.screenOptions, ...props.screenOptions };
|
|
690
|
+
|
|
691
|
+
const screenListeners =
|
|
692
|
+
typeof props.screenListeners === 'function' ||
|
|
693
|
+
typeof rest.screenListeners === 'function'
|
|
694
|
+
? (options: unknown) => ({
|
|
695
|
+
...(typeof rest.screenListeners === 'function'
|
|
696
|
+
? rest.screenListeners(options)
|
|
697
|
+
: rest.screenListeners),
|
|
698
|
+
...(typeof props.screenListeners === 'function'
|
|
699
|
+
? props.screenListeners(options)
|
|
700
|
+
: props.screenListeners),
|
|
701
|
+
})
|
|
702
|
+
: { ...rest.screenListeners, ...props.screenListeners };
|
|
703
|
+
|
|
704
|
+
return (
|
|
705
|
+
<Navigator
|
|
706
|
+
{...rest}
|
|
707
|
+
{...props}
|
|
708
|
+
screenOptions={screenOptions}
|
|
709
|
+
screenListeners={screenListeners}
|
|
710
|
+
>
|
|
711
|
+
{children}
|
|
712
|
+
</Navigator>
|
|
713
|
+
);
|
|
644
714
|
};
|
|
645
715
|
|
|
646
716
|
NavigatorComponent.displayName = displayName;
|
|
@@ -696,19 +766,19 @@ type TreeForPathConfig = {
|
|
|
696
766
|
* };
|
|
697
767
|
* ```
|
|
698
768
|
*/
|
|
699
|
-
export function createPathConfigForStaticNavigation(
|
|
769
|
+
export function createPathConfigForStaticNavigation<ParamList extends {}>(
|
|
700
770
|
tree: TreeForPathConfig,
|
|
701
771
|
options?: {
|
|
702
|
-
initialRouteName?: string;
|
|
772
|
+
initialRouteName?: string | undefined;
|
|
703
773
|
},
|
|
704
774
|
auto?: boolean
|
|
705
|
-
): PathConfigMap<
|
|
775
|
+
): PathConfigMap<ParamList> | undefined {
|
|
706
776
|
let initialScreenHasPath: boolean = false;
|
|
707
777
|
let initialScreenConfig: PathConfig<{}> | undefined;
|
|
708
778
|
|
|
709
779
|
const createPathConfigForTree = (
|
|
710
780
|
t: TreeForPathConfig,
|
|
711
|
-
o: { initialRouteName?: string } | undefined,
|
|
781
|
+
o: { initialRouteName?: string | undefined } | undefined,
|
|
712
782
|
// If a screen is a leaf node, but inside a screen with path,
|
|
713
783
|
// It should not be used for initial detection
|
|
714
784
|
skipInitialDetection: boolean
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { Group } from './Group';
|
|
4
4
|
import { Screen } from './Screen';
|
|
5
|
+
import { createComponentForStaticConfig } from './StaticNavigation';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Higher order component to create a `Navigator` and `Screen` pair.
|
|
@@ -11,13 +12,43 @@ import { Screen } from './Screen';
|
|
|
11
12
|
* @returns Factory method to create a `Navigator` and `Screen` pair.
|
|
12
13
|
*/
|
|
13
14
|
export function createNavigatorFactory(Navigator: React.ComponentType<any>) {
|
|
15
|
+
const displayName = Navigator.displayName ?? Navigator.name ?? 'Navigator';
|
|
16
|
+
|
|
14
17
|
function createNavigator(config?: any): any {
|
|
15
18
|
if (config != null) {
|
|
19
|
+
const NavigatorComponent = createComponentForStaticConfig(
|
|
20
|
+
{
|
|
21
|
+
Navigator,
|
|
22
|
+
Screen,
|
|
23
|
+
Group,
|
|
24
|
+
config,
|
|
25
|
+
},
|
|
26
|
+
displayName
|
|
27
|
+
);
|
|
28
|
+
|
|
16
29
|
return {
|
|
17
|
-
Navigator,
|
|
18
|
-
Screen,
|
|
19
|
-
Group,
|
|
20
30
|
config,
|
|
31
|
+
with(
|
|
32
|
+
DecoratorComponent: React.ComponentType<{
|
|
33
|
+
Navigator: React.ComponentType<any>;
|
|
34
|
+
}>
|
|
35
|
+
) {
|
|
36
|
+
const WithComponent = () => {
|
|
37
|
+
return React.createElement(DecoratorComponent, {
|
|
38
|
+
Navigator: NavigatorComponent,
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
WithComponent.displayName = `${displayName}With`;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
config,
|
|
46
|
+
getComponent: () => WithComponent,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
getComponent() {
|
|
50
|
+
return NavigatorComponent;
|
|
51
|
+
},
|
|
21
52
|
};
|
|
22
53
|
}
|
|
23
54
|
|
package/src/findFocusedRoute.tsx
CHANGED
|
@@ -2,10 +2,10 @@ import type { InitialState } from '@react-navigation/routers';
|
|
|
2
2
|
|
|
3
3
|
type Result =
|
|
4
4
|
| {
|
|
5
|
-
key?: string;
|
|
5
|
+
key?: string | undefined;
|
|
6
6
|
name: string;
|
|
7
|
-
params?: object;
|
|
8
|
-
path?: string;
|
|
7
|
+
params?: object | undefined;
|
|
8
|
+
path?: string | undefined;
|
|
9
9
|
}
|
|
10
10
|
| undefined;
|
|
11
11
|
|