@react-navigation/core 8.0.0-alpha.2 → 8.0.0-alpha.20
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 +20 -9
- 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/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 +166 -46
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/checkSerializable.js +11 -4
- package/lib/module/checkSerializable.js.map +1 -1
- package/lib/module/createNavigatorFactory.js +27 -5
- package/lib/module/createNavigatorFactory.js.map +1 -1
- package/lib/module/findFocusedRoute.js +7 -4
- package/lib/module/findFocusedRoute.js.map +1 -1
- package/lib/module/getActionFromState.js +40 -14
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getPathFromState.js +48 -11
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +3 -0
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +353 -166
- 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 +3 -4
- 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 +15 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +18 -9
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useEventEmitter.js +43 -31
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useFocusEvents.js +6 -2
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +2 -2
- 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/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +144 -86
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +3 -3
- 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 +6 -4
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +3 -3
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetState.js +6 -3
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +3 -3
- 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 +7 -4
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +1 -1
- package/lib/module/usePreventRemove.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +1 -1
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +2 -2
- package/lib/module/useRegisterNavigator.js.map +1 -1
- package/lib/module/useRoute.js.map +1 -1
- package/lib/module/useRouteCache.js +2 -1
- package/lib/module/useRouteCache.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/module/validatePathConfig.js +2 -1
- package/lib/module/validatePathConfig.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/EnsureSingleNavigator.d.ts +1 -1
- package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
- package/lib/typescript/src/Group.d.ts +1 -1
- package/lib/typescript/src/Group.d.ts.map +1 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts +12 -6
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.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/NavigationHelpersContext.d.ts +1 -1
- package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +10 -10
- 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/PreventRemoveProvider.d.ts +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +3 -2
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/Screen.d.ts +1 -1
- package/lib/typescript/src/Screen.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 +123 -92
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/checkSerializable.d.ts +5 -3
- package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts +17 -5
- 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 +4 -4
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPathFromState.d.ts +3 -3
- package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPatternParts.d.ts +1 -0
- package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +5 -5
- 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 +34 -33
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
- package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
- package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +215 -131
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useChildListeners.d.ts +3 -3
- package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useComponent.d.ts +1 -1
- package/lib/typescript/src/useComponent.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +7 -7
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
- package/lib/typescript/src/useFocusEvents.d.ts +2 -2
- package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.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/useKeyedChildListeners.d.ts +3 -3
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts +5 -3
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +24 -24
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +3 -3
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +19 -19
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +2 -2
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnAction.d.ts +9 -9
- package/lib/typescript/src/useOnAction.d.ts.map +1 -1
- package/lib/typescript/src/useOnGetState.d.ts +1 -1
- package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
- package/lib/typescript/src/useOnPreventRemove.d.ts +3 -3
- package/lib/typescript/src/useOnPreventRemove.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/useOptionsGetters.d.ts +1 -1
- package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts +1 -1
- package/lib/typescript/src/useRoute.d.ts +2 -2
- package/lib/typescript/src/useRoute.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts +4 -4
- package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/lib/typescript/src/useStateForPath.d.ts +1 -1
- package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +45 -5
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +23 -20
- package/src/BaseNavigationContainer.tsx +337 -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/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 +488 -250
- package/src/checkSerializable.tsx +22 -12
- package/src/createNavigatorFactory.tsx +83 -8
- package/src/findFocusedRoute.tsx +13 -8
- package/src/getActionFromState.tsx +68 -39
- package/src/getPathFromState.tsx +91 -27
- package/src/getPatternParts.tsx +8 -0
- package/src/getStateFromPath.tsx +555 -180
- package/src/getStateFromRouteParams.tsx +60 -0
- package/src/index.tsx +47 -5
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +541 -338
- package/src/useDescriptors.tsx +27 -12
- package/src/useEventEmitter.tsx +45 -36
- package/src/useFocusEvents.tsx +8 -2
- package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
- package/src/useIsFocused.tsx +14 -21
- package/src/useNavigation.tsx +8 -4
- package/src/useNavigationBuilder.tsx +220 -132
- package/src/useNavigationCache.tsx +6 -6
- package/src/useNavigationHelpers.tsx +1 -1
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +11 -7
- package/src/useOnAction.tsx +10 -10
- package/src/useOnGetState.tsx +5 -3
- package/src/useOnPreventRemove.tsx +3 -3
- package/src/useOnRouteFocus.tsx +10 -12
- package/src/useOptionsGetters.tsx +7 -4
- package/src/usePreventRemove.tsx +1 -1
- package/src/usePreventRemoveContext.tsx +1 -1
- package/src/useRegisterNavigator.tsx +2 -2
- package/src/useRoute.tsx +4 -2
- package/src/useRouteCache.tsx +2 -1
- package/src/useScheduleUpdate.tsx +1 -3
- package/src/useStateForPath.tsx +1 -1
- package/src/utilities.tsx +101 -5
- package/src/validatePathConfig.tsx +1 -0
- package/lib/module/CurrentRenderContext.js +0 -10
- package/lib/module/CurrentRenderContext.js.map +0 -1
- package/lib/module/useCurrentRender.js +0 -19
- package/lib/module/useCurrentRender.js.map +0 -1
- package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
- package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
- package/lib/typescript/src/useCurrentRender.d.ts +0 -14
- package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
- package/src/CurrentRenderContext.tsx +0 -9
- package/src/useCurrentRender.tsx +0 -31
package/src/StaticNavigation.tsx
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
NavigationState,
|
|
3
|
-
ParamListBase,
|
|
4
|
-
Route,
|
|
5
|
-
} from '@react-navigation/routers';
|
|
1
|
+
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
|
|
6
2
|
import * as React from 'react';
|
|
7
3
|
import { isValidElementType } from 'react-is';
|
|
8
4
|
|
|
5
|
+
import {
|
|
6
|
+
combinePatternParts,
|
|
7
|
+
getPatternParts,
|
|
8
|
+
type PatternPart,
|
|
9
|
+
} from './getPatternParts';
|
|
9
10
|
import type {
|
|
10
11
|
DefaultNavigatorOptions,
|
|
11
12
|
EventMapBase,
|
|
12
13
|
NavigationListBase,
|
|
13
14
|
NavigatorScreenParams,
|
|
14
15
|
NavigatorTypeBagBase,
|
|
16
|
+
NavigatorTypeBagFor,
|
|
15
17
|
PathConfig,
|
|
16
18
|
PathConfigMap,
|
|
17
19
|
RouteGroupConfig,
|
|
@@ -21,68 +23,92 @@ import type {
|
|
|
21
23
|
import { useRoute } from './useRoute';
|
|
22
24
|
import type {
|
|
23
25
|
AnyToUnknown,
|
|
24
|
-
ExtractParamStrings,
|
|
25
|
-
ExtractParamsType,
|
|
26
26
|
FlatType,
|
|
27
27
|
HasArguments,
|
|
28
|
-
|
|
29
|
-
InferPath,
|
|
28
|
+
InferParamsFromLinking,
|
|
30
29
|
KeysOf,
|
|
30
|
+
StandardSchemaV1,
|
|
31
31
|
UnionToIntersection,
|
|
32
32
|
ValidPathPattern,
|
|
33
33
|
} from './utilities';
|
|
34
34
|
|
|
35
|
-
type
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
type ScreenComponentParams<T> = [T] extends [
|
|
36
|
+
React.ComponentType<{ route: { params: infer Params } }>,
|
|
37
|
+
]
|
|
38
|
+
? Params
|
|
39
|
+
: undefined;
|
|
40
|
+
|
|
41
|
+
type ParamsForScreenComponent<T> = [T] extends [(...args: any[]) => any]
|
|
42
|
+
? // Don't infer params from a parameterless function component
|
|
43
|
+
// It'd infer `unknown` - but we want `undefined` if no params are accepted
|
|
44
|
+
HasArguments<T> extends true
|
|
45
|
+
? ScreenComponentParams<T>
|
|
40
46
|
: undefined
|
|
41
|
-
: T
|
|
42
|
-
|
|
47
|
+
: ScreenComponentParams<T>;
|
|
48
|
+
|
|
49
|
+
// If every nested route's params include `undefined`, the nested navigator
|
|
50
|
+
// itself can be omitted. Otherwise, require `NavigatorScreenParams`.
|
|
51
|
+
type ParamsForNestedNavigator<
|
|
52
|
+
T extends { config: any },
|
|
53
|
+
ParamList extends {} = StaticParamList<T>,
|
|
54
|
+
Params = NavigatorScreenParams<ParamList>,
|
|
55
|
+
> = {
|
|
56
|
+
// Map each route to `never` when params are optional, or name when params are required
|
|
57
|
+
// If every route has optional params, the resulting union is `never`
|
|
58
|
+
[RouteName in keyof ParamList]-?: undefined extends ParamList[RouteName]
|
|
59
|
+
? never
|
|
60
|
+
: RouteName;
|
|
61
|
+
}[keyof ParamList] extends never
|
|
62
|
+
? Params | undefined
|
|
63
|
+
: Params;
|
|
64
|
+
|
|
65
|
+
// If the screens were constructed from a `Record<K, V>`,
|
|
66
|
+
// the screen value (`T`) may be a union.
|
|
67
|
+
// A naked `T extends ...` conditional would distribute over every screen in the union,
|
|
68
|
+
// creating a large params union per route.
|
|
69
|
+
// Wrapping `T` in a tuple checks the union as a whole instead of distributing,
|
|
70
|
+
// https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
|
|
71
|
+
type ParamsForScreen<T> = [T] extends [{ config: any }]
|
|
72
|
+
? ParamsForNestedNavigator<T>
|
|
73
|
+
: [T] extends [React.ComponentType<any>]
|
|
74
|
+
? ParamsForScreenComponent<T>
|
|
43
75
|
: undefined;
|
|
44
76
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
ExtractParamStrings<InferPath<Linking>>,
|
|
61
|
-
InferParse<Linking>
|
|
62
|
-
>
|
|
63
|
-
: Linking extends string
|
|
64
|
-
? ExtractParamsType<ExtractParamStrings<Linking>, undefined>
|
|
65
|
-
: undefined;
|
|
77
|
+
// Unlike `ParamsForScreen`, we want to distribute for `Record<string, Component | StaticNavigation>`
|
|
78
|
+
// This creates union like:
|
|
79
|
+
// `C extends C ? ParamsForScreen<C> : never) | (S extends S ? ParamsForScreen<S> : never)`
|
|
80
|
+
// `= ParamsForScreen<C> | ParamsForScreen<S>`
|
|
81
|
+
type ParamsForScreenEntry<T> = T extends T ? ParamsForScreen<T> : never;
|
|
82
|
+
|
|
83
|
+
// Only infer params from linking if it's a pattern (i.e., contains ':')
|
|
84
|
+
// or if parse is present for query params.
|
|
85
|
+
// This avoids inferring non-literals like 'string' without parse.
|
|
86
|
+
type ShouldInferFromLinking<Linking> = Linking extends
|
|
87
|
+
| ValidPathPattern
|
|
88
|
+
| { path: ValidPathPattern }
|
|
89
|
+
| { parse: Record<string, unknown> }
|
|
90
|
+
? true
|
|
91
|
+
: false;
|
|
66
92
|
|
|
67
93
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* -
|
|
71
|
-
*
|
|
94
|
+
* Params type derived from both linking and screen.
|
|
95
|
+
*
|
|
96
|
+
* - Linking has no extractable params (no ':' in path, no `parse`): returns
|
|
97
|
+
* screen params alone.
|
|
98
|
+
* - Linking has params + screen is a nested navigator: intersects path params
|
|
99
|
+
* with the navigator's screen params.
|
|
100
|
+
* - Linking has params + screen is a component without route params: returns
|
|
101
|
+
* path params alone (avoids `LP & undefined = never`).
|
|
102
|
+
* - Linking has params + screen has route params: intersects them.
|
|
72
103
|
*/
|
|
73
|
-
type ParamsForConfig<Linking, Screen
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
undefined extends ParamsForScreen<Screen>
|
|
82
|
-
? // Only flatten when not a navigator to keep it legible
|
|
83
|
-
FlatType<ParamsForLinking<Linking>>
|
|
84
|
-
: FlatType<ParamsForLinking<Linking> & ParamsForScreen<Screen>>
|
|
85
|
-
: ParamsForScreen<Screen>;
|
|
104
|
+
type ParamsForConfig<Linking, Screen, Params = ParamsForScreen<Screen>> =
|
|
105
|
+
ShouldInferFromLinking<Linking> extends true
|
|
106
|
+
? [Screen] extends [{ config: any }]
|
|
107
|
+
? FlatType<InferParamsFromLinking<Linking>> & Params
|
|
108
|
+
: undefined extends Params
|
|
109
|
+
? FlatType<InferParamsFromLinking<Linking>>
|
|
110
|
+
: FlatType<InferParamsFromLinking<Linking> & Params>
|
|
111
|
+
: Params;
|
|
86
112
|
|
|
87
113
|
type ParamListForScreens<Screens> = {
|
|
88
114
|
[Key in KeysOf<Screens>]: Screens[Key] extends StaticScreenConfig<
|
|
@@ -91,10 +117,11 @@ type ParamListForScreens<Screens> = {
|
|
|
91
117
|
any,
|
|
92
118
|
any,
|
|
93
119
|
any,
|
|
120
|
+
any,
|
|
94
121
|
any
|
|
95
122
|
>
|
|
96
123
|
? ParamsForConfig<Linking, Screen>
|
|
97
|
-
:
|
|
124
|
+
: ParamsForScreenEntry<Screens[Key]>;
|
|
98
125
|
};
|
|
99
126
|
|
|
100
127
|
type ParamListForGroups<
|
|
@@ -113,25 +140,25 @@ type ParamListForGroups<
|
|
|
113
140
|
? ParamListForScreens<UnionToIntersection<Screens>>
|
|
114
141
|
: {};
|
|
115
142
|
|
|
116
|
-
type RouteType<Params
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
type RouteType<Params, P = AnyToUnknown<Params>> = Readonly<
|
|
144
|
+
{
|
|
145
|
+
key: string;
|
|
146
|
+
name: string;
|
|
147
|
+
path?: string | undefined;
|
|
148
|
+
history?: { type: 'params'; params: object }[] | undefined;
|
|
149
|
+
} & (undefined extends Params
|
|
150
|
+
? {
|
|
151
|
+
/**
|
|
152
|
+
* Params for this route
|
|
153
|
+
*/
|
|
154
|
+
params?: P;
|
|
155
|
+
}
|
|
156
|
+
: {
|
|
157
|
+
/**
|
|
158
|
+
* Params for this route
|
|
159
|
+
*/
|
|
160
|
+
params: P;
|
|
161
|
+
})
|
|
135
162
|
>;
|
|
136
163
|
|
|
137
164
|
type StaticScreenConfigLinkingAlias = {
|
|
@@ -147,7 +174,7 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
147
174
|
*/
|
|
148
175
|
exact?: boolean;
|
|
149
176
|
/**
|
|
150
|
-
* An object mapping the param name to a function
|
|
177
|
+
* An object mapping the param name to a parser function or a Standard Schema.
|
|
151
178
|
*
|
|
152
179
|
* @example
|
|
153
180
|
* ```js
|
|
@@ -157,7 +184,11 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
157
184
|
* }
|
|
158
185
|
* ```
|
|
159
186
|
*/
|
|
160
|
-
parse?: Record<
|
|
187
|
+
parse?: Record<
|
|
188
|
+
string,
|
|
189
|
+
| ((value: string) => unknown)
|
|
190
|
+
| StandardSchemaV1<string | string[] | null | undefined, unknown>
|
|
191
|
+
>;
|
|
161
192
|
/**
|
|
162
193
|
* An object mapping the param name to a function which converts the param value to a string.
|
|
163
194
|
* By default, all params are converted to strings using `String(value)`.
|
|
@@ -170,6 +201,21 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
170
201
|
* ```
|
|
171
202
|
*/
|
|
172
203
|
stringify?: Record<string, (value: unknown) => string>;
|
|
204
|
+
/**
|
|
205
|
+
* Whether this path can resolve to multiple routes.
|
|
206
|
+
* Both routes should specify `shared: true` for this to work.
|
|
207
|
+
*
|
|
208
|
+
* When automatic path generation is enabled,
|
|
209
|
+
* screens using the same path pattern and the same screen component
|
|
210
|
+
* or navigator will be automatically marked as shared.
|
|
211
|
+
* Explicitly specifying the option overrides the automatic detection.
|
|
212
|
+
*
|
|
213
|
+
* This is useful when same screen used in multiple navigators,
|
|
214
|
+
* e.g. tabs with stacks containing profile screen in each stack.
|
|
215
|
+
*
|
|
216
|
+
* The path defined first will be the canonical path.
|
|
217
|
+
*/
|
|
218
|
+
shared?: boolean;
|
|
173
219
|
};
|
|
174
220
|
|
|
175
221
|
export type StaticScreenConfigLinking =
|
|
@@ -179,12 +225,22 @@ export type StaticScreenConfigLinking =
|
|
|
179
225
|
* Additional path alias that will be matched to the same screen.
|
|
180
226
|
*/
|
|
181
227
|
alias?: (string | StaticScreenConfigLinkingAlias)[];
|
|
228
|
+
/**
|
|
229
|
+
* Name of the initial route to use for the nested navigator when the path matches.
|
|
230
|
+
*/
|
|
231
|
+
initialRouteName?: string | undefined;
|
|
232
|
+
/**
|
|
233
|
+
* Path configuration for child screens in the nested navigator.
|
|
234
|
+
* Only supported when the screen renders a navigator with dynamic API.
|
|
235
|
+
*/
|
|
236
|
+
screens?: PathConfigMap<ParamListBase> | undefined;
|
|
182
237
|
})
|
|
238
|
+
| null
|
|
183
239
|
| undefined;
|
|
184
240
|
|
|
185
241
|
export type StaticScreenConfigScreen =
|
|
186
242
|
| React.ComponentType<any>
|
|
187
|
-
| StaticNavigation<any
|
|
243
|
+
| StaticNavigation<any>;
|
|
188
244
|
|
|
189
245
|
export type StaticScreenConfig<
|
|
190
246
|
Linking extends StaticScreenConfigLinking,
|
|
@@ -319,24 +375,48 @@ export type StaticScreenConfig<
|
|
|
319
375
|
navigationKey?: string;
|
|
320
376
|
};
|
|
321
377
|
|
|
378
|
+
export type StaticScreenFactory<in out Bag extends NavigatorTypeBagBase> = <
|
|
379
|
+
const Linking extends StaticScreenConfigLinking,
|
|
380
|
+
const Screen extends StaticScreenConfigScreen,
|
|
381
|
+
>(
|
|
382
|
+
config: StaticScreenConfig<
|
|
383
|
+
Linking,
|
|
384
|
+
Screen,
|
|
385
|
+
Bag['State'],
|
|
386
|
+
Bag['ScreenOptions'],
|
|
387
|
+
Bag['EventMap'],
|
|
388
|
+
Bag['NavigationList'][keyof Bag['ParamList']]
|
|
389
|
+
>
|
|
390
|
+
) => StaticScreenConfig<
|
|
391
|
+
Linking,
|
|
392
|
+
Screen,
|
|
393
|
+
Bag['State'],
|
|
394
|
+
Bag['ScreenOptions'],
|
|
395
|
+
Bag['EventMap'],
|
|
396
|
+
Bag['NavigationList'][keyof Bag['ParamList']]
|
|
397
|
+
>;
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Helper to create a typed `createXScreen` for static configuration.
|
|
401
|
+
*/
|
|
402
|
+
export function createScreenFactory<
|
|
403
|
+
TypeBag extends NavigatorTypeBagBase,
|
|
404
|
+
>(): StaticScreenFactory<NavigatorTypeBagFor<TypeBag, ParamListBase>> {
|
|
405
|
+
return ((config: unknown) => config) as never;
|
|
406
|
+
}
|
|
407
|
+
|
|
322
408
|
type StaticConfigScreens<
|
|
323
|
-
ParamList extends ParamListBase,
|
|
324
|
-
State extends NavigationState,
|
|
325
|
-
ScreenOptions extends {},
|
|
326
|
-
EventMap extends EventMapBase,
|
|
327
|
-
NavigationList extends NavigationListBase<ParamList>,
|
|
409
|
+
in out ParamList extends ParamListBase,
|
|
410
|
+
in out State extends NavigationState,
|
|
411
|
+
in out ScreenOptions extends {},
|
|
412
|
+
in out EventMap extends EventMapBase,
|
|
413
|
+
in out NavigationList extends NavigationListBase<ParamList>,
|
|
328
414
|
> = {
|
|
329
415
|
[RouteName in keyof ParamList]:
|
|
330
|
-
|
|
|
331
|
-
| StaticNavigation<any, any, any>
|
|
416
|
+
| StaticScreenConfigScreen
|
|
332
417
|
| StaticScreenConfig<
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
parse?: Record<string, (value: string) => any>;
|
|
336
|
-
}
|
|
337
|
-
| string
|
|
338
|
-
| undefined,
|
|
339
|
-
StaticNavigation<any, any, any> | React.ComponentType<any>,
|
|
418
|
+
StaticScreenConfigLinking,
|
|
419
|
+
StaticScreenConfigScreen,
|
|
340
420
|
State,
|
|
341
421
|
ScreenOptions,
|
|
342
422
|
EventMap,
|
|
@@ -360,27 +440,6 @@ type StaticConfigGroup<
|
|
|
360
440
|
* This can be useful for conditional rendering of group of screens.
|
|
361
441
|
*/
|
|
362
442
|
if?: () => boolean;
|
|
363
|
-
/**
|
|
364
|
-
* Linking config for the screens in the group.
|
|
365
|
-
* This can be a string to specify the path, or an object following properties:
|
|
366
|
-
* - `path`
|
|
367
|
-
* - `stringify`
|
|
368
|
-
* - `parse`
|
|
369
|
-
*
|
|
370
|
-
* The path specified will be prepended to the paths of the screens in the group.
|
|
371
|
-
* The `parse` and `stringify` properties will be merged.
|
|
372
|
-
*
|
|
373
|
-
* @example
|
|
374
|
-
* ```js
|
|
375
|
-
* linking: {
|
|
376
|
-
* path: 'users/:id',
|
|
377
|
-
* parse: {
|
|
378
|
-
* id: (id) => parseInt(id, 10),
|
|
379
|
-
* }
|
|
380
|
-
* },
|
|
381
|
-
* ```
|
|
382
|
-
*/
|
|
383
|
-
linking?: LinkingForGroup;
|
|
384
443
|
/**
|
|
385
444
|
* Static navigation config or Component to render for the screen.
|
|
386
445
|
*/
|
|
@@ -410,16 +469,26 @@ type StaticConfigInternal<
|
|
|
410
469
|
EventMap extends EventMapBase,
|
|
411
470
|
NavigationList extends NavigationListBase<ParamList>,
|
|
412
471
|
Navigator extends React.ComponentType<any>,
|
|
472
|
+
Screens = StaticConfigScreens<
|
|
473
|
+
ParamList,
|
|
474
|
+
State,
|
|
475
|
+
ScreenOptions,
|
|
476
|
+
EventMap,
|
|
477
|
+
NavigationList
|
|
478
|
+
>,
|
|
479
|
+
Groups = {
|
|
480
|
+
[key: string]: StaticConfigGroup<
|
|
481
|
+
ParamList,
|
|
482
|
+
State,
|
|
483
|
+
ScreenOptions,
|
|
484
|
+
EventMap,
|
|
485
|
+
NavigationList
|
|
486
|
+
>;
|
|
487
|
+
},
|
|
413
488
|
> = Omit<
|
|
414
489
|
Omit<
|
|
415
490
|
React.ComponentProps<Navigator>,
|
|
416
|
-
keyof DefaultNavigatorOptions<
|
|
417
|
-
ParamListBase,
|
|
418
|
-
NavigationState,
|
|
419
|
-
{},
|
|
420
|
-
EventMapBase,
|
|
421
|
-
NavigationList[keyof ParamList]
|
|
422
|
-
>
|
|
491
|
+
keyof DefaultNavigatorOptions<any, any, any, any, any>
|
|
423
492
|
> &
|
|
424
493
|
DefaultNavigatorOptions<
|
|
425
494
|
ParamList,
|
|
@@ -435,49 +504,21 @@ type StaticConfigInternal<
|
|
|
435
504
|
/**
|
|
436
505
|
* Screens to render in the navigator and their configuration.
|
|
437
506
|
*/
|
|
438
|
-
screens:
|
|
439
|
-
ParamList,
|
|
440
|
-
State,
|
|
441
|
-
ScreenOptions,
|
|
442
|
-
EventMap,
|
|
443
|
-
NavigationList
|
|
444
|
-
>;
|
|
507
|
+
screens: Screens;
|
|
445
508
|
/**
|
|
446
509
|
* Groups of screens to render in the navigator and their configuration.
|
|
447
510
|
*/
|
|
448
|
-
groups?:
|
|
449
|
-
[key: string]: StaticConfigGroup<
|
|
450
|
-
ParamList,
|
|
451
|
-
State,
|
|
452
|
-
ScreenOptions,
|
|
453
|
-
EventMap,
|
|
454
|
-
NavigationList
|
|
455
|
-
>;
|
|
456
|
-
};
|
|
511
|
+
groups?: Groups;
|
|
457
512
|
}
|
|
458
513
|
| {
|
|
459
514
|
/**
|
|
460
515
|
* Screens to render in the navigator and their configuration.
|
|
461
516
|
*/
|
|
462
|
-
screens?:
|
|
463
|
-
ParamList,
|
|
464
|
-
State,
|
|
465
|
-
ScreenOptions,
|
|
466
|
-
EventMap,
|
|
467
|
-
NavigationList
|
|
468
|
-
>;
|
|
517
|
+
screens?: Screens;
|
|
469
518
|
/**
|
|
470
519
|
* Groups of screens to render in the navigator and their configuration.
|
|
471
520
|
*/
|
|
472
|
-
groups:
|
|
473
|
-
[key: string]: StaticConfigGroup<
|
|
474
|
-
ParamList,
|
|
475
|
-
State,
|
|
476
|
-
ScreenOptions,
|
|
477
|
-
EventMap,
|
|
478
|
-
NavigationList
|
|
479
|
-
>;
|
|
480
|
-
};
|
|
521
|
+
groups: Groups;
|
|
481
522
|
}
|
|
482
523
|
);
|
|
483
524
|
|
|
@@ -485,7 +526,9 @@ type StaticConfigInternal<
|
|
|
485
526
|
* Props for a screen component which is rendered by a static navigator.
|
|
486
527
|
* Takes the route params as a generic argument.
|
|
487
528
|
*/
|
|
488
|
-
export type StaticScreenProps<
|
|
529
|
+
export type StaticScreenProps<
|
|
530
|
+
in out T extends Record<string, unknown> | undefined,
|
|
531
|
+
> = {
|
|
489
532
|
route: {
|
|
490
533
|
params: T;
|
|
491
534
|
};
|
|
@@ -503,11 +546,11 @@ export type StaticParamList<
|
|
|
503
546
|
ParamListForGroups<T['config']['groups']>
|
|
504
547
|
>;
|
|
505
548
|
|
|
506
|
-
export type StaticNavigation<
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
549
|
+
export type StaticNavigation<
|
|
550
|
+
in out NavigatorTypeBag extends NavigatorTypeBagBase,
|
|
551
|
+
> = {
|
|
552
|
+
config: StaticConfig<NavigatorTypeBag>;
|
|
553
|
+
getComponent: () => React.ComponentType<{}>;
|
|
511
554
|
};
|
|
512
555
|
|
|
513
556
|
const MemoizedScreen = React.memo(
|
|
@@ -542,16 +585,13 @@ const getItemsFromScreens = (
|
|
|
542
585
|
component = screen;
|
|
543
586
|
} else if ('config' in screen) {
|
|
544
587
|
isNavigator = true;
|
|
545
|
-
component =
|
|
546
|
-
screen,
|
|
547
|
-
`${name}Navigator`
|
|
548
|
-
);
|
|
588
|
+
component = screen.getComponent();
|
|
549
589
|
}
|
|
550
590
|
} else if (isValidElementType(item)) {
|
|
551
591
|
component = item;
|
|
552
592
|
} else if ('config' in item) {
|
|
553
593
|
isNavigator = true;
|
|
554
|
-
component =
|
|
594
|
+
component = item.getComponent();
|
|
555
595
|
}
|
|
556
596
|
|
|
557
597
|
if (component == null) {
|
|
@@ -589,10 +629,17 @@ const getItemsFromScreens = (
|
|
|
589
629
|
* @param displayName Name of the component to be displayed in React DevTools.
|
|
590
630
|
* @returns A component which renders the navigator.
|
|
591
631
|
*/
|
|
592
|
-
export function
|
|
593
|
-
|
|
632
|
+
export function createComponentForStaticConfig<
|
|
633
|
+
T extends {
|
|
634
|
+
Navigator: React.ComponentType<any>;
|
|
635
|
+
Group: React.ComponentType<any>;
|
|
636
|
+
Screen: React.ComponentType<any>;
|
|
637
|
+
config: StaticConfig<NavigatorTypeBagBase>;
|
|
638
|
+
},
|
|
639
|
+
>(
|
|
640
|
+
tree: T,
|
|
594
641
|
displayName: string
|
|
595
|
-
): React.ComponentType<
|
|
642
|
+
): React.ComponentType<Omit<React.ComponentProps<T['Navigator']>, 'children'>> {
|
|
596
643
|
const { Navigator, Group, Screen, config } = tree;
|
|
597
644
|
const { screens, groups, ...rest } = config;
|
|
598
645
|
|
|
@@ -637,10 +684,51 @@ export function createComponentForStaticNavigation(
|
|
|
637
684
|
}
|
|
638
685
|
}
|
|
639
686
|
|
|
640
|
-
|
|
687
|
+
if (items.length === 0) {
|
|
688
|
+
throw new Error(
|
|
689
|
+
"Couldn't find any screens in the 'screens' or 'groups' property. Make sure to define at least one screen in the configuration."
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const NavigatorComponent = ({ children: _, ...props }: typeof rest) => {
|
|
641
694
|
const children = items.map((item) => item());
|
|
642
695
|
|
|
643
|
-
|
|
696
|
+
const screenOptions =
|
|
697
|
+
typeof props.screenOptions === 'function' ||
|
|
698
|
+
typeof rest.screenOptions === 'function'
|
|
699
|
+
? (options: unknown) => ({
|
|
700
|
+
...(typeof rest.screenOptions === 'function'
|
|
701
|
+
? rest.screenOptions(options)
|
|
702
|
+
: rest.screenOptions),
|
|
703
|
+
...(typeof props.screenOptions === 'function'
|
|
704
|
+
? props.screenOptions(options)
|
|
705
|
+
: props.screenOptions),
|
|
706
|
+
})
|
|
707
|
+
: { ...rest.screenOptions, ...props.screenOptions };
|
|
708
|
+
|
|
709
|
+
const screenListeners =
|
|
710
|
+
typeof props.screenListeners === 'function' ||
|
|
711
|
+
typeof rest.screenListeners === 'function'
|
|
712
|
+
? (options: unknown) => ({
|
|
713
|
+
...(typeof rest.screenListeners === 'function'
|
|
714
|
+
? rest.screenListeners(options)
|
|
715
|
+
: rest.screenListeners),
|
|
716
|
+
...(typeof props.screenListeners === 'function'
|
|
717
|
+
? props.screenListeners(options)
|
|
718
|
+
: props.screenListeners),
|
|
719
|
+
})
|
|
720
|
+
: { ...rest.screenListeners, ...props.screenListeners };
|
|
721
|
+
|
|
722
|
+
return (
|
|
723
|
+
<Navigator
|
|
724
|
+
{...rest}
|
|
725
|
+
{...props}
|
|
726
|
+
screenOptions={screenOptions}
|
|
727
|
+
screenListeners={screenListeners}
|
|
728
|
+
>
|
|
729
|
+
{children}
|
|
730
|
+
</Navigator>
|
|
731
|
+
);
|
|
644
732
|
};
|
|
645
733
|
|
|
646
734
|
NavigatorComponent.displayName = displayName;
|
|
@@ -648,33 +736,113 @@ export function createComponentForStaticNavigation(
|
|
|
648
736
|
return NavigatorComponent;
|
|
649
737
|
}
|
|
650
738
|
|
|
651
|
-
type LinkingForGroup =
|
|
652
|
-
| Pick<PathConfig<any>, 'path' | 'stringify' | 'parse'>
|
|
653
|
-
| string;
|
|
654
|
-
|
|
655
739
|
type TreeForPathConfig = {
|
|
656
|
-
config:
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
740
|
+
config: ConfigForPathConfig;
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
type ConfigForPathConfig = {
|
|
744
|
+
initialRouteName?: string;
|
|
745
|
+
screens?: Record<string, ScreenForPathConfig>;
|
|
746
|
+
groups?: Record<string, { screens: Record<string, ScreenForPathConfig> }>;
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
type LinkingForPathConfig =
|
|
750
|
+
| string
|
|
751
|
+
| (Partial<StaticScreenConfigLinkingAlias> & {
|
|
752
|
+
alias?: (string | StaticScreenConfigLinkingAlias)[];
|
|
753
|
+
initialRouteName?: string | undefined;
|
|
754
|
+
screens?: PathConfigMap<ParamListBase> | undefined;
|
|
755
|
+
})
|
|
756
|
+
| null
|
|
757
|
+
| undefined;
|
|
758
|
+
|
|
759
|
+
type ScreenValueForPathConfig = React.ComponentType<{}> | TreeForPathConfig;
|
|
760
|
+
|
|
761
|
+
type ScreenForPathConfig =
|
|
762
|
+
| ScreenValueForPathConfig
|
|
763
|
+
| {
|
|
764
|
+
screen: ScreenValueForPathConfig;
|
|
765
|
+
linking?: LinkingForPathConfig;
|
|
676
766
|
};
|
|
767
|
+
|
|
768
|
+
type PathConfigMapForStaticNavigation = Record<
|
|
769
|
+
string,
|
|
770
|
+
string | PathConfigForStaticNavigation | undefined
|
|
771
|
+
>;
|
|
772
|
+
|
|
773
|
+
type PathConfigForStaticNavigation = Omit<
|
|
774
|
+
PathConfig<ParamListBase>,
|
|
775
|
+
'screens'
|
|
776
|
+
> & {
|
|
777
|
+
initialRouteName?: string | undefined;
|
|
778
|
+
screens?: PathConfigMapForStaticNavigation | undefined;
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
// Mark screens that resolve to the same pattern and same component or navigator
|
|
782
|
+
const markSharedPathConfigs = (
|
|
783
|
+
screens: PathConfigMapForStaticNavigation,
|
|
784
|
+
sources: WeakMap<PathConfigForStaticNavigation, ScreenValueForPathConfig>,
|
|
785
|
+
blocked: WeakSet<PathConfigForStaticNavigation>
|
|
786
|
+
) => {
|
|
787
|
+
const candidates = new Map<string, PathConfigForStaticNavigation[]>();
|
|
788
|
+
|
|
789
|
+
const collect = (
|
|
790
|
+
screens: PathConfigMapForStaticNavigation,
|
|
791
|
+
parentParts: PatternPart[],
|
|
792
|
+
disabled: boolean
|
|
793
|
+
) => {
|
|
794
|
+
for (const config of Object.values(screens)) {
|
|
795
|
+
if (config == null || typeof config === 'string') {
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const parts =
|
|
800
|
+
typeof config.path === 'string'
|
|
801
|
+
? combinePatternParts(
|
|
802
|
+
parentParts,
|
|
803
|
+
getPatternParts(config.path),
|
|
804
|
+
config.exact
|
|
805
|
+
)
|
|
806
|
+
: parentParts;
|
|
807
|
+
|
|
808
|
+
if (sources.has(config) && typeof config.path === 'string') {
|
|
809
|
+
if (disabled) {
|
|
810
|
+
blocked.add(config);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const pattern = parts.map((part) => part.segment).join('/');
|
|
814
|
+
const entries = candidates.get(pattern) ?? [];
|
|
815
|
+
|
|
816
|
+
entries.push(config);
|
|
817
|
+
candidates.set(pattern, entries);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
if (config.screens) {
|
|
821
|
+
collect(config.screens, parts, disabled || config.shared === false);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
677
824
|
};
|
|
825
|
+
|
|
826
|
+
collect(screens, [], false);
|
|
827
|
+
|
|
828
|
+
for (const entries of candidates.values()) {
|
|
829
|
+
for (const entry of entries) {
|
|
830
|
+
const source = sources.get(entry);
|
|
831
|
+
|
|
832
|
+
if (
|
|
833
|
+
entry.shared === undefined &&
|
|
834
|
+
!blocked.has(entry) &&
|
|
835
|
+
entries.some(
|
|
836
|
+
(candidate) =>
|
|
837
|
+
candidate !== entry &&
|
|
838
|
+
!blocked.has(candidate) &&
|
|
839
|
+
sources.get(candidate) === source
|
|
840
|
+
)
|
|
841
|
+
) {
|
|
842
|
+
entry.shared = true;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
678
846
|
};
|
|
679
847
|
|
|
680
848
|
/**
|
|
@@ -696,32 +864,49 @@ type TreeForPathConfig = {
|
|
|
696
864
|
* };
|
|
697
865
|
* ```
|
|
698
866
|
*/
|
|
699
|
-
export function createPathConfigForStaticNavigation(
|
|
867
|
+
export function createPathConfigForStaticNavigation<ParamList extends {}>(
|
|
700
868
|
tree: TreeForPathConfig,
|
|
701
869
|
options?: {
|
|
702
|
-
initialRouteName?: string;
|
|
870
|
+
initialRouteName?: string | undefined;
|
|
703
871
|
},
|
|
704
872
|
auto?: boolean
|
|
705
|
-
): PathConfigMap<
|
|
873
|
+
): PathConfigMap<ParamList> | undefined {
|
|
706
874
|
let initialScreenHasPath: boolean = false;
|
|
707
875
|
let initialScreenConfig: PathConfig<{}> | undefined;
|
|
876
|
+
let hasEmptyPath = false;
|
|
877
|
+
|
|
878
|
+
const blocked = new WeakSet<PathConfigForStaticNavigation>();
|
|
879
|
+
const sources = new WeakMap<
|
|
880
|
+
PathConfigForStaticNavigation,
|
|
881
|
+
ScreenValueForPathConfig
|
|
882
|
+
>();
|
|
708
883
|
|
|
709
884
|
const createPathConfigForTree = (
|
|
710
885
|
t: TreeForPathConfig,
|
|
711
|
-
o: { initialRouteName?: string } | undefined,
|
|
886
|
+
o: { initialRouteName?: string | undefined } | undefined,
|
|
712
887
|
// If a screen is a leaf node, but inside a screen with path,
|
|
713
888
|
// It should not be used for initial detection
|
|
714
|
-
skipInitialDetection: boolean
|
|
889
|
+
skipInitialDetection: boolean,
|
|
890
|
+
allowAutoEmptyPath: boolean
|
|
715
891
|
) => {
|
|
892
|
+
const initialRouteName = o?.initialRouteName ?? t.config.initialRouteName;
|
|
893
|
+
|
|
894
|
+
if (initialRouteName != null) {
|
|
895
|
+
const routeNames = new Set(Object.keys(t.config.screens ?? {}));
|
|
896
|
+
|
|
897
|
+
for (const group of Object.values(t.config.groups ?? {})) {
|
|
898
|
+
Object.keys(group.screens).forEach((name) => routeNames.add(name));
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (!routeNames.has(initialRouteName)) {
|
|
902
|
+
throw new Error(
|
|
903
|
+
`Couldn't find a screen named '${initialRouteName}' to use as 'initialRouteName'.`
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
716
908
|
const createPathConfigForScreens = (
|
|
717
|
-
screens:
|
|
718
|
-
ParamListBase,
|
|
719
|
-
NavigationState,
|
|
720
|
-
{},
|
|
721
|
-
EventMapBase,
|
|
722
|
-
Record<string, unknown>
|
|
723
|
-
>,
|
|
724
|
-
groupLinking: LinkingForGroup | undefined,
|
|
909
|
+
screens: Record<string, ScreenForPathConfig>,
|
|
725
910
|
initialRouteName: string | undefined
|
|
726
911
|
) => {
|
|
727
912
|
return Object.fromEntries(
|
|
@@ -740,95 +925,144 @@ export function createPathConfigForStaticNavigation(
|
|
|
740
925
|
return 0;
|
|
741
926
|
})
|
|
742
927
|
.map(([key, item]) => {
|
|
743
|
-
const screenConfig:
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
if ('linking' in item) {
|
|
928
|
+
const screenConfig: PathConfigForStaticNavigation = {};
|
|
929
|
+
|
|
930
|
+
sources.set(
|
|
931
|
+
screenConfig,
|
|
932
|
+
typeof item === 'object' && 'screen' in item ? item.screen : item
|
|
933
|
+
);
|
|
934
|
+
|
|
935
|
+
const normalizePath = (path: string) =>
|
|
936
|
+
path.replace(/^\/+|\/+$/g, '');
|
|
937
|
+
|
|
938
|
+
if ('linking' in item && item.linking !== undefined) {
|
|
756
939
|
if (typeof item.linking === 'string') {
|
|
757
940
|
screenConfig.path = item.linking;
|
|
758
|
-
} else
|
|
759
|
-
|
|
941
|
+
} else if (
|
|
942
|
+
item.linking != null &&
|
|
943
|
+
typeof item.linking === 'object'
|
|
944
|
+
) {
|
|
945
|
+
Object.assign(screenConfig, { ...item.linking });
|
|
760
946
|
}
|
|
761
947
|
}
|
|
762
948
|
|
|
763
|
-
if (
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
...screenConfig.parse,
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
if (groupLinking?.stringify != null) {
|
|
772
|
-
screenConfig.stringify = {
|
|
773
|
-
...groupLinking.stringify,
|
|
774
|
-
...screenConfig.stringify,
|
|
775
|
-
};
|
|
776
|
-
}
|
|
949
|
+
if (screenConfig.exact && screenConfig.path == null) {
|
|
950
|
+
throw new Error(
|
|
951
|
+
"A 'path' needs to be specified when specifying 'exact: true'. If you don't want this screen in the URL, specify it as empty string, e.g. `path: ''`."
|
|
952
|
+
);
|
|
777
953
|
}
|
|
778
954
|
|
|
779
955
|
if (typeof screenConfig.path === 'string') {
|
|
780
956
|
screenConfig.path = normalizePath(screenConfig.path);
|
|
781
957
|
}
|
|
782
958
|
|
|
959
|
+
if (screenConfig.alias != null) {
|
|
960
|
+
screenConfig.alias = screenConfig.alias.map((alias) => {
|
|
961
|
+
if (typeof alias === 'string') {
|
|
962
|
+
return normalizePath(alias);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
return {
|
|
966
|
+
...alias,
|
|
967
|
+
path: normalizePath(alias.path),
|
|
968
|
+
};
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
|
|
783
972
|
let screens;
|
|
784
973
|
|
|
974
|
+
const hasExplicitScreens =
|
|
975
|
+
'screens' in screenConfig && screenConfig.screens != null;
|
|
976
|
+
const hasDisabledLinking =
|
|
977
|
+
'linking' in item && item.linking === null;
|
|
978
|
+
const childOptions =
|
|
979
|
+
'initialRouteName' in screenConfig &&
|
|
980
|
+
typeof screenConfig.initialRouteName === 'string'
|
|
981
|
+
? { initialRouteName: screenConfig.initialRouteName }
|
|
982
|
+
: undefined;
|
|
983
|
+
|
|
984
|
+
if (
|
|
985
|
+
hasExplicitScreens &&
|
|
986
|
+
childOptions != null &&
|
|
987
|
+
!Object.keys(screenConfig.screens ?? {}).includes(
|
|
988
|
+
childOptions.initialRouteName
|
|
989
|
+
)
|
|
990
|
+
) {
|
|
991
|
+
throw new Error(
|
|
992
|
+
`Couldn't find a screen named '${childOptions.initialRouteName}' to use as 'initialRouteName'.`
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
|
|
785
996
|
const skipInitialDetectionInChild =
|
|
786
997
|
skipInitialDetection ||
|
|
787
998
|
(screenConfig.path != null && screenConfig.path !== '');
|
|
999
|
+
const allowAutoEmptyPathInChild =
|
|
1000
|
+
allowAutoEmptyPath &&
|
|
1001
|
+
(initialRouteName == null || key === initialRouteName);
|
|
788
1002
|
|
|
789
|
-
if (
|
|
1003
|
+
if (
|
|
1004
|
+
!hasExplicitScreens &&
|
|
1005
|
+
!hasDisabledLinking &&
|
|
1006
|
+
'config' in item
|
|
1007
|
+
) {
|
|
790
1008
|
screens = createPathConfigForTree(
|
|
791
1009
|
item,
|
|
792
|
-
|
|
793
|
-
skipInitialDetectionInChild
|
|
1010
|
+
childOptions,
|
|
1011
|
+
skipInitialDetectionInChild,
|
|
1012
|
+
allowAutoEmptyPathInChild
|
|
794
1013
|
);
|
|
795
1014
|
} else if (
|
|
1015
|
+
!hasExplicitScreens &&
|
|
1016
|
+
!hasDisabledLinking &&
|
|
796
1017
|
'screen' in item &&
|
|
797
1018
|
'config' in item.screen &&
|
|
798
1019
|
(item.screen.config.screens || item.screen.config.groups)
|
|
799
1020
|
) {
|
|
800
1021
|
screens = createPathConfigForTree(
|
|
801
1022
|
item.screen,
|
|
802
|
-
|
|
803
|
-
skipInitialDetectionInChild
|
|
1023
|
+
childOptions,
|
|
1024
|
+
skipInitialDetectionInChild,
|
|
1025
|
+
allowAutoEmptyPathInChild
|
|
804
1026
|
);
|
|
805
1027
|
}
|
|
806
1028
|
|
|
807
1029
|
if (screens) {
|
|
808
|
-
// @ts-expect-error - we can't type this properly
|
|
809
1030
|
screenConfig.screens = screens;
|
|
810
1031
|
}
|
|
811
1032
|
|
|
812
1033
|
if (
|
|
813
1034
|
auto &&
|
|
814
1035
|
!('screens' in screenConfig && screenConfig.screens) &&
|
|
815
|
-
// Skip generating path for screens that specify linking config as `
|
|
816
|
-
!
|
|
1036
|
+
// Skip generating path for screens that specify linking config as `null` explicitly
|
|
1037
|
+
!hasDisabledLinking
|
|
817
1038
|
) {
|
|
818
1039
|
if (screenConfig.path != null) {
|
|
819
1040
|
if (!skipInitialDetection) {
|
|
820
|
-
if (
|
|
821
|
-
initialScreenHasPath = true;
|
|
822
|
-
} else if (screenConfig.path === '') {
|
|
1041
|
+
if (screenConfig.path === '') {
|
|
823
1042
|
// We encounter a leaf screen with empty path,
|
|
824
1043
|
// Clear the initial screen config as it's not needed anymore
|
|
825
1044
|
initialScreenConfig = undefined;
|
|
1045
|
+
hasEmptyPath = true;
|
|
1046
|
+
|
|
1047
|
+
if (allowAutoEmptyPath && key === initialRouteName) {
|
|
1048
|
+
initialScreenHasPath = true;
|
|
1049
|
+
}
|
|
1050
|
+
} else if (
|
|
1051
|
+
allowAutoEmptyPath &&
|
|
1052
|
+
key === initialRouteName &&
|
|
1053
|
+
// Keep an already discovered fallback unless the initial route
|
|
1054
|
+
// explicitly uses an empty path.
|
|
1055
|
+
initialScreenConfig == null
|
|
1056
|
+
) {
|
|
1057
|
+
initialScreenHasPath = true;
|
|
826
1058
|
}
|
|
827
1059
|
}
|
|
828
1060
|
} else {
|
|
829
1061
|
if (
|
|
830
|
-
!groupPath &&
|
|
831
1062
|
!skipInitialDetection &&
|
|
1063
|
+
allowAutoEmptyPath &&
|
|
1064
|
+
(initialRouteName == null || key === initialRouteName) &&
|
|
1065
|
+
!hasEmptyPath &&
|
|
832
1066
|
initialScreenConfig == null
|
|
833
1067
|
) {
|
|
834
1068
|
initialScreenConfig = screenConfig;
|
|
@@ -849,7 +1083,7 @@ export function createPathConfigForStaticNavigation(
|
|
|
849
1083
|
);
|
|
850
1084
|
};
|
|
851
1085
|
|
|
852
|
-
const screens = {};
|
|
1086
|
+
const screens: PathConfigMapForStaticNavigation = {};
|
|
853
1087
|
|
|
854
1088
|
// Loop through the config to find screens and groups
|
|
855
1089
|
// So we add the screens and groups in the same order as they are defined
|
|
@@ -859,7 +1093,6 @@ export function createPathConfigForStaticNavigation(
|
|
|
859
1093
|
screens,
|
|
860
1094
|
createPathConfigForScreens(
|
|
861
1095
|
t.config.screens,
|
|
862
|
-
undefined,
|
|
863
1096
|
o?.initialRouteName ?? t.config.initialRouteName
|
|
864
1097
|
)
|
|
865
1098
|
);
|
|
@@ -871,7 +1104,6 @@ export function createPathConfigForStaticNavigation(
|
|
|
871
1104
|
screens,
|
|
872
1105
|
createPathConfigForScreens(
|
|
873
1106
|
group.screens,
|
|
874
|
-
group.linking,
|
|
875
1107
|
o?.initialRouteName ?? t.config.initialRouteName
|
|
876
1108
|
)
|
|
877
1109
|
);
|
|
@@ -886,11 +1118,17 @@ export function createPathConfigForStaticNavigation(
|
|
|
886
1118
|
return screens;
|
|
887
1119
|
};
|
|
888
1120
|
|
|
889
|
-
const screens = createPathConfigForTree(tree, options, false);
|
|
1121
|
+
const screens = createPathConfigForTree(tree, options, false, true);
|
|
890
1122
|
|
|
891
1123
|
if (auto && initialScreenConfig && !initialScreenHasPath) {
|
|
892
1124
|
initialScreenConfig.path = '';
|
|
893
1125
|
}
|
|
894
1126
|
|
|
895
|
-
|
|
1127
|
+
if (!screens) {
|
|
1128
|
+
return undefined;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
markSharedPathConfigs(screens, sources, blocked);
|
|
1132
|
+
|
|
1133
|
+
return screens as PathConfigMap<ParamList>;
|
|
896
1134
|
}
|