@react-navigation/core 8.0.0-alpha.3 → 8.0.0-alpha.31
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 +38 -19
- 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/DataLoading.js +127 -0
- package/lib/module/DataLoading.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +1 -0
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +20 -8
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +22 -11
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationStateContext.js +3 -0
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/PreventRemoveContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +37 -27
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +10 -41
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +179 -50
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/StaticTreeContext.js +5 -0
- package/lib/module/StaticTreeContext.js.map +1 -0
- package/lib/module/checkSerializable.js +18 -13
- package/lib/module/checkSerializable.js.map +1 -1
- package/lib/module/createNavigationContainerRef.js +6 -8
- package/lib/module/createNavigationContainerRef.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 +45 -20
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getPathFromState.js +171 -90
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +20 -4
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +487 -217
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +23 -0
- package/lib/module/getStateFromRouteParams.js.map +1 -0
- package/lib/module/index.js +5 -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 +35 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +21 -11
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useEventEmitter.js +48 -33
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useFocusEvents.js +12 -4
- 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/useKeyedChildListeners.js +4 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useLazyValue.js.map +1 -1
- package/lib/module/useNavigation.js +2 -15
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +204 -131
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +22 -17
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +28 -10
- 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 +125 -45
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +37 -7
- 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 +39 -30
- 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 +10 -5
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +10 -3
- 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 +2 -0
- package/lib/module/useRoute.js.map +1 -1
- package/lib/module/useRouteCache.js +17 -11
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +9 -9
- 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/useSyncState.js +32 -9
- package/lib/module/useSyncState.js.map +1 -1
- package/lib/module/validatePathConfig.js +50 -36
- 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 +3 -0
- package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
- package/lib/typescript/src/DataLoading.d.ts +21 -0
- package/lib/typescript/src/DataLoading.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 +9 -8
- 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 +12 -13
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationStateContext.d.ts +4 -3
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
- package/lib/typescript/src/PreventRemoveContext.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 +4 -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 +189 -109
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
- package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
- package/lib/typescript/src/checkSerializable.d.ts +8 -4
- 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 +23 -5
- package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
- package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
- 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 +4 -7
- 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 +36 -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 +260 -159
- 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 +10 -9
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts +2 -2
- 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/useLazyValue.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts +4 -2
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +23 -30
- 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 -27
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +17 -3
- 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 +5 -9
- 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/usePreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/useRoute.d.ts +7 -3
- package/lib/typescript/src/useRoute.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts +5 -5
- package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
- package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
- 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/useSyncState.d.ts +1 -0
- package/lib/typescript/src/useSyncState.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +74 -37
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +23 -22
- package/src/BaseNavigationContainer.tsx +362 -334
- package/src/ConsumedParamsContext.tsx +5 -0
- package/src/DataLoading.tsx +203 -0
- package/src/NavigationBuilderContext.tsx +14 -9
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +23 -12
- package/src/NavigationProvider.tsx +26 -15
- package/src/NavigationStateContext.tsx +9 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +51 -46
- package/src/SceneView.tsx +11 -39
- package/src/StaticNavigation.tsx +659 -307
- package/src/StaticTreeContext.tsx +7 -0
- package/src/checkSerializable.tsx +35 -19
- package/src/createNavigationContainerRef.tsx +12 -9
- package/src/createNavigatorFactory.tsx +92 -8
- package/src/findFocusedRoute.tsx +16 -16
- package/src/getActionFromState.tsx +87 -51
- package/src/getPathFromState.tsx +254 -128
- package/src/getPatternParts.tsx +25 -4
- package/src/getStateFromPath.tsx +821 -331
- package/src/getStateFromRouteParams.tsx +59 -0
- package/src/index.tsx +55 -5
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +798 -373
- package/src/useDescriptors.tsx +31 -14
- package/src/useEventEmitter.tsx +52 -38
- package/src/useFocusEvents.tsx +15 -7
- package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
- package/src/useIsFocused.tsx +14 -21
- package/src/useKeyedChildListeners.tsx +4 -2
- package/src/useLazyValue.tsx +2 -2
- package/src/useNavigation.tsx +7 -24
- package/src/useNavigationBuilder.tsx +314 -186
- package/src/useNavigationCache.tsx +32 -25
- package/src/useNavigationHelpers.tsx +27 -10
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +168 -69
- package/src/useOnAction.tsx +61 -13
- package/src/useOnGetState.tsx +5 -3
- package/src/useOnPreventRemove.tsx +75 -42
- package/src/useOnRouteFocus.tsx +10 -12
- package/src/useOptionsGetters.tsx +11 -5
- package/src/usePreventRemove.tsx +12 -3
- package/src/usePreventRemoveContext.tsx +1 -1
- package/src/useRegisterNavigator.tsx +2 -2
- package/src/useRoute.tsx +20 -6
- package/src/useRouteCache.tsx +22 -16
- package/src/useScheduleUpdate.tsx +9 -10
- package/src/useStateForPath.tsx +1 -1
- package/src/useSyncState.tsx +35 -9
- package/src/utilities.tsx +144 -31
- package/src/validatePathConfig.tsx +86 -57
- 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
|
@@ -6,12 +6,19 @@ import type {
|
|
|
6
6
|
import * as React from 'react';
|
|
7
7
|
import { isValidElementType } from 'react-is';
|
|
8
8
|
|
|
9
|
+
import {
|
|
10
|
+
combinePatternParts,
|
|
11
|
+
getPatternParts,
|
|
12
|
+
type PatternPart,
|
|
13
|
+
} from './getPatternParts';
|
|
14
|
+
import { StaticTreeContext } from './StaticTreeContext';
|
|
9
15
|
import type {
|
|
10
|
-
DefaultNavigatorOptions,
|
|
11
16
|
EventMapBase,
|
|
12
17
|
NavigationListBase,
|
|
18
|
+
NavigatorProps,
|
|
13
19
|
NavigatorScreenParams,
|
|
14
20
|
NavigatorTypeBagBase,
|
|
21
|
+
NavigatorTypeBagFor,
|
|
15
22
|
PathConfig,
|
|
16
23
|
PathConfigMap,
|
|
17
24
|
RouteGroupConfig,
|
|
@@ -21,68 +28,107 @@ import type {
|
|
|
21
28
|
import { useRoute } from './useRoute';
|
|
22
29
|
import type {
|
|
23
30
|
AnyToUnknown,
|
|
24
|
-
ExtractParamStrings,
|
|
25
|
-
ExtractParamsType,
|
|
26
31
|
FlatType,
|
|
27
32
|
HasArguments,
|
|
28
|
-
|
|
29
|
-
InferPath,
|
|
33
|
+
InferParamsFromLinking,
|
|
30
34
|
KeysOf,
|
|
35
|
+
NoExcessCallbackReturn,
|
|
36
|
+
NoExcessObject,
|
|
37
|
+
NoExcessValue,
|
|
38
|
+
NotUndefinedObject,
|
|
39
|
+
StandardSchemaV1,
|
|
31
40
|
UnionToIntersection,
|
|
32
41
|
ValidPathPattern,
|
|
33
42
|
} from './utilities';
|
|
34
43
|
|
|
35
|
-
type
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
type ScreenComponentParams<T> = [T] extends [
|
|
45
|
+
React.ComponentType<{ route: { params: infer Params } }>,
|
|
46
|
+
]
|
|
47
|
+
? Params
|
|
48
|
+
: undefined;
|
|
49
|
+
|
|
50
|
+
type ParamsForScreenComponent<T> = [T] extends [(...args: any[]) => any]
|
|
51
|
+
? // Don't infer params from a parameterless function component
|
|
52
|
+
// It'd infer `unknown` - but we want `undefined` if no params are accepted
|
|
53
|
+
HasArguments<T> extends true
|
|
54
|
+
? ScreenComponentParams<T>
|
|
40
55
|
: undefined
|
|
41
|
-
: T
|
|
42
|
-
|
|
56
|
+
: ScreenComponentParams<T>;
|
|
57
|
+
|
|
58
|
+
// If the initial route's params include `undefined`, the nested navigator itself can be optional.
|
|
59
|
+
// If no initial route is specified, check if every nested route's params include `undefined`.
|
|
60
|
+
// Otherwise the nested navigator needs to be required.
|
|
61
|
+
type ParamsForNestedNavigator<
|
|
62
|
+
T extends { config: any },
|
|
63
|
+
ParamList extends {} = StaticParamList<T>,
|
|
64
|
+
Params = NavigatorScreenParams<ParamList>,
|
|
65
|
+
RouteNames extends keyof ParamList = T['config'] extends {
|
|
66
|
+
initialRouteName: infer RouteName extends keyof ParamList;
|
|
67
|
+
}
|
|
68
|
+
? RouteName
|
|
69
|
+
: keyof ParamList,
|
|
70
|
+
> = {
|
|
71
|
+
[RouteName in RouteNames]-?: undefined extends ParamList[RouteName]
|
|
72
|
+
? never
|
|
73
|
+
: RouteName;
|
|
74
|
+
}[RouteNames] extends never
|
|
75
|
+
? Params | undefined
|
|
76
|
+
: Params;
|
|
77
|
+
|
|
78
|
+
// If the screens were constructed from a `Record<K, V>`,
|
|
79
|
+
// the screen value (`T`) may be a union.
|
|
80
|
+
// A naked `T extends ...` conditional would distribute over every screen in the union,
|
|
81
|
+
// creating a large params union per route.
|
|
82
|
+
// Wrapping `T` in a tuple checks the union as a whole instead of distributing,
|
|
83
|
+
// https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
|
|
84
|
+
type ParamsForScreen<T> = [T] extends [{ config: any }]
|
|
85
|
+
? ParamsForNestedNavigator<T>
|
|
86
|
+
: [T] extends [React.ComponentType<any>]
|
|
87
|
+
? ParamsForScreenComponent<T>
|
|
43
88
|
: undefined;
|
|
44
89
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
InferParse<Linking>
|
|
62
|
-
>
|
|
63
|
-
: Linking extends string
|
|
64
|
-
? ExtractParamsType<ExtractParamStrings<Linking>, undefined>
|
|
65
|
-
: undefined;
|
|
90
|
+
// Unlike `ParamsForScreen`, we want to distribute for `Record<string, Component | StaticNavigation>`
|
|
91
|
+
// This creates union like:
|
|
92
|
+
// `C extends C ? ParamsForScreen<C> : never) | (S extends S ? ParamsForScreen<S> : never)`
|
|
93
|
+
// `= ParamsForScreen<C> | ParamsForScreen<S>`
|
|
94
|
+
type ParamsForScreenEntry<T> = T extends T ? ParamsForScreen<T> : never;
|
|
95
|
+
|
|
96
|
+
// Only infer params from linking if it's a pattern (i.e., contains ':')
|
|
97
|
+
// or if parse is present, which can also define query params.
|
|
98
|
+
// This avoids inferring non-literals like 'string' without parse.
|
|
99
|
+
type ShouldInferFromLinking<Linking> = Linking extends {
|
|
100
|
+
parse: Record<string, unknown>;
|
|
101
|
+
}
|
|
102
|
+
? true
|
|
103
|
+
: Linking extends ValidPathPattern | { path: ValidPathPattern }
|
|
104
|
+
? true
|
|
105
|
+
: false;
|
|
66
106
|
|
|
67
107
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* -
|
|
71
|
-
*
|
|
108
|
+
* Params type derived from both linking and screen.
|
|
109
|
+
*
|
|
110
|
+
* - Linking has no extractable params (no ':' in path, no `parse`): returns
|
|
111
|
+
* screen params alone.
|
|
112
|
+
* - Linking has params + screen is a nested navigator: intersects path params
|
|
113
|
+
* with the navigator's screen params.
|
|
114
|
+
* - Linking has params + screen is a component without route params: returns
|
|
115
|
+
* path params alone (avoids `LP & undefined = never`).
|
|
116
|
+
* - Linking has params + screen has route params: intersects them.
|
|
72
117
|
*/
|
|
73
|
-
type ParamsForConfig<Linking, Screen
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
type ParamsForConfig<Linking, Screen, Params = ParamsForScreen<Screen>> =
|
|
119
|
+
ShouldInferFromLinking<Linking> extends true
|
|
120
|
+
? [Screen] extends [{ config: any }]
|
|
121
|
+
? undefined extends Params
|
|
122
|
+
? FlatType<InferParamsFromLinking<Linking>> & Params
|
|
123
|
+
: // Optional linking params make the whole route params type optional when intersected.
|
|
124
|
+
// e.g. `({...} | undefined) & NavigatorScreenParams<{...}>` adds `| undefined` to the whole type.
|
|
125
|
+
// But if nested navigator had required params, it should still be required.
|
|
126
|
+
// So we remove `| undefined` from linking params before intersecting with nested navigator params.
|
|
127
|
+
FlatType<NotUndefinedObject<InferParamsFromLinking<Linking>>> & Params
|
|
128
|
+
: undefined extends Params
|
|
129
|
+
? FlatType<InferParamsFromLinking<Linking>>
|
|
130
|
+
: FlatType<InferParamsFromLinking<Linking> & Params>
|
|
131
|
+
: Params;
|
|
86
132
|
|
|
87
133
|
type ParamListForScreens<Screens> = {
|
|
88
134
|
[Key in KeysOf<Screens>]: Screens[Key] extends StaticScreenConfig<
|
|
@@ -91,21 +137,16 @@ type ParamListForScreens<Screens> = {
|
|
|
91
137
|
any,
|
|
92
138
|
any,
|
|
93
139
|
any,
|
|
140
|
+
any,
|
|
141
|
+
any,
|
|
142
|
+
any,
|
|
94
143
|
any
|
|
95
144
|
>
|
|
96
145
|
? ParamsForConfig<Linking, Screen>
|
|
97
|
-
:
|
|
146
|
+
: ParamsForScreenEntry<Screens[Key]>;
|
|
98
147
|
};
|
|
99
148
|
|
|
100
|
-
type ParamListForGroups<
|
|
101
|
-
Groups extends
|
|
102
|
-
| Readonly<{
|
|
103
|
-
[key: string]: {
|
|
104
|
-
screens: {};
|
|
105
|
-
};
|
|
106
|
-
}>
|
|
107
|
-
| undefined,
|
|
108
|
-
> = Groups extends {
|
|
149
|
+
type ParamListForGroups<Groups> = Groups extends {
|
|
109
150
|
[key: string]: {
|
|
110
151
|
screens: infer Screens;
|
|
111
152
|
};
|
|
@@ -113,26 +154,22 @@ type ParamListForGroups<
|
|
|
113
154
|
? ParamListForScreens<UnionToIntersection<Screens>>
|
|
114
155
|
: {};
|
|
115
156
|
|
|
116
|
-
type
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
>
|
|
134
|
-
>
|
|
135
|
-
>;
|
|
157
|
+
type StaticRouteBase = Readonly<Omit<Route<string>, 'params'>>;
|
|
158
|
+
|
|
159
|
+
type StaticRoute<Params, P = AnyToUnknown<Params>> = StaticRouteBase &
|
|
160
|
+
(undefined extends Params
|
|
161
|
+
? {
|
|
162
|
+
/**
|
|
163
|
+
* Params for this route
|
|
164
|
+
*/
|
|
165
|
+
readonly params?: P extends object ? Readonly<P> : P;
|
|
166
|
+
}
|
|
167
|
+
: {
|
|
168
|
+
/**
|
|
169
|
+
* Params for this route
|
|
170
|
+
*/
|
|
171
|
+
readonly params: Readonly<P>;
|
|
172
|
+
});
|
|
136
173
|
|
|
137
174
|
type StaticScreenConfigLinkingAlias = {
|
|
138
175
|
/**
|
|
@@ -147,7 +184,7 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
147
184
|
*/
|
|
148
185
|
exact?: boolean;
|
|
149
186
|
/**
|
|
150
|
-
* An object mapping the param name to a function
|
|
187
|
+
* An object mapping the param name to a parser function or a Standard Schema.
|
|
151
188
|
*
|
|
152
189
|
* @example
|
|
153
190
|
* ```js
|
|
@@ -157,10 +194,14 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
157
194
|
* }
|
|
158
195
|
* ```
|
|
159
196
|
*/
|
|
160
|
-
parse?: Record<
|
|
197
|
+
parse?: Record<
|
|
198
|
+
string,
|
|
199
|
+
| ((value: string) => unknown)
|
|
200
|
+
| StandardSchemaV1<string | string[] | null | undefined, unknown>
|
|
201
|
+
>;
|
|
161
202
|
/**
|
|
162
203
|
* An object mapping the param name to a function which converts the param value to a string.
|
|
163
|
-
* By default,
|
|
204
|
+
* By default, arrays and null are preserved for query params, and other values are converted using `String(value)`.
|
|
164
205
|
*
|
|
165
206
|
* @example
|
|
166
207
|
* ```js
|
|
@@ -170,31 +211,60 @@ type StaticScreenConfigLinkingAlias = {
|
|
|
170
211
|
* ```
|
|
171
212
|
*/
|
|
172
213
|
stringify?: Record<string, (value: unknown) => string>;
|
|
214
|
+
/**
|
|
215
|
+
* Whether this path can resolve to multiple routes.
|
|
216
|
+
* Both routes should specify `shared: true` for this to work.
|
|
217
|
+
*
|
|
218
|
+
* When automatic path generation is enabled,
|
|
219
|
+
* screens using the same path pattern and the same screen component
|
|
220
|
+
* or navigator will be automatically marked as shared.
|
|
221
|
+
* Explicitly specifying the option overrides the automatic detection.
|
|
222
|
+
*
|
|
223
|
+
* This is useful when same screen used in multiple navigators,
|
|
224
|
+
* e.g. tabs with stacks containing profile screen in each stack.
|
|
225
|
+
*
|
|
226
|
+
* The path defined first will be the canonical path.
|
|
227
|
+
*/
|
|
228
|
+
shared?: boolean;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
type StaticScreenConfigLinkingExtras = {
|
|
232
|
+
/**
|
|
233
|
+
* Additional path alias that will be matched to the same screen.
|
|
234
|
+
*/
|
|
235
|
+
alias?: (string | StaticScreenConfigLinkingAlias)[];
|
|
236
|
+
/**
|
|
237
|
+
* Name of the initial route to use for the nested navigator when the path matches.
|
|
238
|
+
*/
|
|
239
|
+
initialRouteName?: string | undefined;
|
|
240
|
+
/**
|
|
241
|
+
* Path configuration for child screens in the nested navigator.
|
|
242
|
+
* Only supported when the screen renders a navigator with dynamic API.
|
|
243
|
+
*/
|
|
244
|
+
screens?: PathConfigMap<ParamListBase> | undefined;
|
|
173
245
|
};
|
|
174
246
|
|
|
175
247
|
export type StaticScreenConfigLinking =
|
|
176
248
|
| string
|
|
177
|
-
| (StaticScreenConfigLinkingAlias &
|
|
178
|
-
|
|
179
|
-
* Additional path alias that will be matched to the same screen.
|
|
180
|
-
*/
|
|
181
|
-
alias?: (string | StaticScreenConfigLinkingAlias)[];
|
|
182
|
-
})
|
|
249
|
+
| (StaticScreenConfigLinkingAlias & StaticScreenConfigLinkingExtras)
|
|
250
|
+
| null
|
|
183
251
|
| undefined;
|
|
184
252
|
|
|
185
253
|
export type StaticScreenConfigScreen =
|
|
186
254
|
| React.ComponentType<any>
|
|
187
|
-
| StaticNavigation<any
|
|
188
|
-
|
|
189
|
-
export
|
|
190
|
-
Linking extends StaticScreenConfigLinking,
|
|
191
|
-
Screen,
|
|
192
|
-
State extends NavigationState,
|
|
193
|
-
ScreenOptions extends {},
|
|
194
|
-
EventMap extends EventMapBase,
|
|
195
|
-
Navigation,
|
|
196
|
-
Params = ParamsForConfig<Linking, Screen>,
|
|
197
|
-
|
|
255
|
+
| StaticNavigation<any>;
|
|
256
|
+
|
|
257
|
+
export interface StaticScreenConfig<
|
|
258
|
+
out Linking extends StaticScreenConfigLinking,
|
|
259
|
+
out Screen,
|
|
260
|
+
in out State extends NavigationState,
|
|
261
|
+
in out ScreenOptions extends {},
|
|
262
|
+
in out EventMap extends EventMapBase,
|
|
263
|
+
in out Navigation,
|
|
264
|
+
in out Params = ParamsForConfig<Linking, Screen>,
|
|
265
|
+
in out ProvidedOptions extends {} = {},
|
|
266
|
+
in out ProvidedListeners extends {} = {},
|
|
267
|
+
> {
|
|
198
268
|
/**
|
|
199
269
|
* Static navigation config or Component to render for the screen.
|
|
200
270
|
*/
|
|
@@ -228,10 +298,10 @@ export type StaticScreenConfig<
|
|
|
228
298
|
options?:
|
|
229
299
|
| ScreenOptions
|
|
230
300
|
| ((props: {
|
|
231
|
-
route:
|
|
301
|
+
route: StaticRoute<Params>;
|
|
232
302
|
navigation: Navigation;
|
|
233
303
|
theme: Theme;
|
|
234
|
-
}) => ScreenOptions);
|
|
304
|
+
}) => NoExcessCallbackReturn<ProvidedOptions, ScreenOptions>);
|
|
235
305
|
|
|
236
306
|
/**
|
|
237
307
|
* Event listeners for this screen.
|
|
@@ -248,9 +318,12 @@ export type StaticScreenConfig<
|
|
|
248
318
|
listeners?:
|
|
249
319
|
| ScreenListeners<State, EventMap>
|
|
250
320
|
| ((props: {
|
|
251
|
-
route:
|
|
321
|
+
route: StaticRoute<Params>;
|
|
252
322
|
navigation: Navigation;
|
|
253
|
-
}) =>
|
|
323
|
+
}) => NoExcessCallbackReturn<
|
|
324
|
+
ProvidedListeners,
|
|
325
|
+
ScreenListeners<State, EventMap>
|
|
326
|
+
>);
|
|
254
327
|
|
|
255
328
|
/**
|
|
256
329
|
* Layout for this screen.
|
|
@@ -268,7 +341,7 @@ export type StaticScreenConfig<
|
|
|
268
341
|
*
|
|
269
342
|
*/
|
|
270
343
|
layout?: (props: {
|
|
271
|
-
route:
|
|
344
|
+
route: StaticRoute<Params>;
|
|
272
345
|
options: ScreenOptions;
|
|
273
346
|
navigation: Navigation;
|
|
274
347
|
theme: Theme;
|
|
@@ -295,7 +368,9 @@ export type StaticScreenConfig<
|
|
|
295
368
|
* getId: ({ params }) => params?.userId,
|
|
296
369
|
* ```
|
|
297
370
|
*/
|
|
298
|
-
getId?: (props: {
|
|
371
|
+
getId?: (props: {
|
|
372
|
+
params: AnyToUnknown<Params extends object ? Readonly<Params> : Params>;
|
|
373
|
+
}) => string | undefined;
|
|
299
374
|
|
|
300
375
|
/**
|
|
301
376
|
* Linking config for the screen.
|
|
@@ -317,31 +392,75 @@ export type StaticScreenConfig<
|
|
|
317
392
|
* Optional key for this screen.
|
|
318
393
|
*/
|
|
319
394
|
navigationKey?: string;
|
|
320
|
-
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Loader function to start loading data when the screen is navigated to.
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* ```js
|
|
401
|
+
* UNSTABLE_loader: ({ params }) => loadProfile(params.id),
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
UNSTABLE_loader?: (options: {
|
|
405
|
+
name: string;
|
|
406
|
+
params: AnyToUnknown<Params>;
|
|
407
|
+
}) => Promise<void>;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export type StaticScreenFactory<in out Bag extends NavigatorTypeBagBase> = <
|
|
411
|
+
const Linking extends StaticScreenConfigLinking,
|
|
412
|
+
const Screen extends StaticScreenConfigScreen,
|
|
413
|
+
ProvidedOptions extends {} = {},
|
|
414
|
+
ProvidedListeners extends {} = {},
|
|
415
|
+
>(
|
|
416
|
+
config: StaticScreenConfig<
|
|
417
|
+
Linking,
|
|
418
|
+
Screen,
|
|
419
|
+
Bag['State'],
|
|
420
|
+
Bag['ScreenOptions'],
|
|
421
|
+
Bag['EventMap'],
|
|
422
|
+
Bag['NavigationList'][keyof Bag['ParamList']],
|
|
423
|
+
ParamsForConfig<Linking, Screen>,
|
|
424
|
+
ProvidedOptions,
|
|
425
|
+
ProvidedListeners
|
|
426
|
+
>
|
|
427
|
+
) => StaticScreenConfig<
|
|
428
|
+
Linking,
|
|
429
|
+
Screen,
|
|
430
|
+
Bag['State'],
|
|
431
|
+
Bag['ScreenOptions'],
|
|
432
|
+
Bag['EventMap'],
|
|
433
|
+
Bag['NavigationList'][keyof Bag['ParamList']]
|
|
434
|
+
>;
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Helper to create a typed `createXScreen` for static configuration.
|
|
438
|
+
*/
|
|
439
|
+
export function createScreenFactory<
|
|
440
|
+
TypeBag extends NavigatorTypeBagBase,
|
|
441
|
+
>(): StaticScreenFactory<NavigatorTypeBagFor<TypeBag, ParamListBase>> {
|
|
442
|
+
return ((config: unknown) => config) as never;
|
|
443
|
+
}
|
|
321
444
|
|
|
322
445
|
type StaticConfigScreens<
|
|
323
|
-
ParamList extends ParamListBase,
|
|
324
|
-
State extends NavigationState,
|
|
325
|
-
ScreenOptions extends {},
|
|
326
|
-
EventMap extends EventMapBase,
|
|
327
|
-
NavigationList extends NavigationListBase<ParamList>,
|
|
446
|
+
in out ParamList extends ParamListBase,
|
|
447
|
+
in out State extends NavigationState,
|
|
448
|
+
in out ScreenOptions extends {},
|
|
449
|
+
in out EventMap extends EventMapBase,
|
|
450
|
+
in out NavigationList extends NavigationListBase<ParamList>,
|
|
328
451
|
> = {
|
|
329
452
|
[RouteName in keyof ParamList]:
|
|
330
|
-
|
|
|
331
|
-
| StaticNavigation<any, any, any>
|
|
453
|
+
| StaticScreenConfigScreen
|
|
332
454
|
| StaticScreenConfig<
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
parse?: Record<string, (value: string) => any>;
|
|
336
|
-
}
|
|
337
|
-
| string
|
|
338
|
-
| undefined,
|
|
339
|
-
StaticNavigation<any, any, any> | React.ComponentType<any>,
|
|
455
|
+
StaticScreenConfigLinking,
|
|
456
|
+
StaticScreenConfigScreen,
|
|
340
457
|
State,
|
|
341
458
|
ScreenOptions,
|
|
342
459
|
EventMap,
|
|
343
460
|
NavigationList[RouteName],
|
|
344
|
-
any
|
|
461
|
+
any,
|
|
462
|
+
{},
|
|
463
|
+
{}
|
|
345
464
|
>;
|
|
346
465
|
};
|
|
347
466
|
|
|
@@ -360,27 +479,6 @@ type StaticConfigGroup<
|
|
|
360
479
|
* This can be useful for conditional rendering of group of screens.
|
|
361
480
|
*/
|
|
362
481
|
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
482
|
/**
|
|
385
483
|
* Static navigation config or Component to render for the screen.
|
|
386
484
|
*/
|
|
@@ -393,101 +491,160 @@ type StaticConfigGroup<
|
|
|
393
491
|
>;
|
|
394
492
|
};
|
|
395
493
|
|
|
396
|
-
|
|
397
|
-
|
|
494
|
+
type StaticConfigScreensForBag<Bag extends NavigatorTypeBagBase> =
|
|
495
|
+
StaticConfigScreens<
|
|
398
496
|
Bag['ParamList'],
|
|
399
497
|
Bag['State'],
|
|
400
498
|
Bag['ScreenOptions'],
|
|
401
499
|
Bag['EventMap'],
|
|
402
|
-
Bag['NavigationList']
|
|
403
|
-
Bag['Navigator']
|
|
500
|
+
Bag['NavigationList']
|
|
404
501
|
>;
|
|
405
502
|
|
|
406
|
-
type
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
ParamList,
|
|
426
|
-
State,
|
|
427
|
-
ScreenOptions,
|
|
428
|
-
EventMap,
|
|
429
|
-
NavigationList[keyof ParamList]
|
|
430
|
-
>,
|
|
503
|
+
type StaticConfigGroupsForBag<Bag extends NavigatorTypeBagBase> = {
|
|
504
|
+
[key: string]: StaticConfigGroup<
|
|
505
|
+
Bag['ParamList'],
|
|
506
|
+
Bag['State'],
|
|
507
|
+
Bag['ScreenOptions'],
|
|
508
|
+
Bag['EventMap'],
|
|
509
|
+
Bag['NavigationList']
|
|
510
|
+
>;
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
type StaticConfigCommon<Bag extends NavigatorTypeBagBase> = Omit<
|
|
514
|
+
NavigatorProps<
|
|
515
|
+
Bag['ParamList'],
|
|
516
|
+
Bag['State'],
|
|
517
|
+
Bag['ScreenOptions'],
|
|
518
|
+
Bag['EventMap'],
|
|
519
|
+
Bag['NavigationList'][keyof Bag['ParamList']],
|
|
520
|
+
Bag['Navigator']
|
|
521
|
+
>,
|
|
431
522
|
'screens' | 'children'
|
|
432
|
-
|
|
523
|
+
>;
|
|
524
|
+
|
|
525
|
+
export type StaticConfigBase<
|
|
526
|
+
Bag extends NavigatorTypeBagBase,
|
|
527
|
+
Screens = StaticConfigScreensForBag<Bag>,
|
|
528
|
+
Groups = StaticConfigGroupsForBag<Bag>,
|
|
529
|
+
> = StaticConfigCommon<Bag> & {
|
|
530
|
+
/**
|
|
531
|
+
* Screens to render in the navigator and their configuration.
|
|
532
|
+
*/
|
|
533
|
+
screens?: Screens;
|
|
534
|
+
/**
|
|
535
|
+
* Groups of screens to render in the navigator and their configuration.
|
|
536
|
+
*/
|
|
537
|
+
groups?: Groups;
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
export type StaticConfig<
|
|
541
|
+
Bag extends NavigatorTypeBagBase,
|
|
542
|
+
Screens = StaticConfigScreensForBag<Bag>,
|
|
543
|
+
Groups = StaticConfigGroupsForBag<Bag>,
|
|
544
|
+
> = StaticConfigCommon<Bag> &
|
|
433
545
|
(
|
|
434
546
|
| {
|
|
435
547
|
/**
|
|
436
548
|
* Screens to render in the navigator and their configuration.
|
|
437
549
|
*/
|
|
438
|
-
screens:
|
|
439
|
-
ParamList,
|
|
440
|
-
State,
|
|
441
|
-
ScreenOptions,
|
|
442
|
-
EventMap,
|
|
443
|
-
NavigationList
|
|
444
|
-
>;
|
|
550
|
+
screens: Screens;
|
|
445
551
|
/**
|
|
446
552
|
* Groups of screens to render in the navigator and their configuration.
|
|
447
553
|
*/
|
|
448
|
-
groups?:
|
|
449
|
-
[key: string]: StaticConfigGroup<
|
|
450
|
-
ParamList,
|
|
451
|
-
State,
|
|
452
|
-
ScreenOptions,
|
|
453
|
-
EventMap,
|
|
454
|
-
NavigationList
|
|
455
|
-
>;
|
|
456
|
-
};
|
|
554
|
+
groups?: Groups;
|
|
457
555
|
}
|
|
458
556
|
| {
|
|
459
557
|
/**
|
|
460
558
|
* Screens to render in the navigator and their configuration.
|
|
461
559
|
*/
|
|
462
|
-
screens?:
|
|
463
|
-
ParamList,
|
|
464
|
-
State,
|
|
465
|
-
ScreenOptions,
|
|
466
|
-
EventMap,
|
|
467
|
-
NavigationList
|
|
468
|
-
>;
|
|
560
|
+
screens?: Screens;
|
|
469
561
|
/**
|
|
470
562
|
* Groups of screens to render in the navigator and their configuration.
|
|
471
563
|
*/
|
|
472
|
-
groups:
|
|
473
|
-
[key: string]: StaticConfigGroup<
|
|
474
|
-
ParamList,
|
|
475
|
-
State,
|
|
476
|
-
ScreenOptions,
|
|
477
|
-
EventMap,
|
|
478
|
-
NavigationList
|
|
479
|
-
>;
|
|
480
|
-
};
|
|
564
|
+
groups: Groups;
|
|
481
565
|
}
|
|
482
566
|
);
|
|
483
567
|
|
|
568
|
+
type NoExcessScreen<
|
|
569
|
+
Screen,
|
|
570
|
+
ScreenOptions extends {},
|
|
571
|
+
Listeners extends {},
|
|
572
|
+
> = (Screen extends { screen: unknown; options: unknown }
|
|
573
|
+
? { options: NoExcessValue<Screen['options'], ScreenOptions> }
|
|
574
|
+
: unknown) &
|
|
575
|
+
(Screen extends { screen: unknown; listeners: unknown }
|
|
576
|
+
? { listeners: NoExcessValue<Screen['listeners'], Listeners> }
|
|
577
|
+
: unknown);
|
|
578
|
+
|
|
579
|
+
type NoExcessScreens<
|
|
580
|
+
Screens,
|
|
581
|
+
ScreenOptions extends {},
|
|
582
|
+
Listeners extends {},
|
|
583
|
+
> = {
|
|
584
|
+
[RouteName in keyof Screens]: NoExcessScreen<
|
|
585
|
+
Screens[RouteName],
|
|
586
|
+
ScreenOptions,
|
|
587
|
+
Listeners
|
|
588
|
+
>;
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
type NoExcessGroups<
|
|
592
|
+
Groups,
|
|
593
|
+
Bag extends NavigatorTypeBagBase,
|
|
594
|
+
ScreenOptions extends {},
|
|
595
|
+
Listeners extends {},
|
|
596
|
+
> = {
|
|
597
|
+
[GroupName in keyof Groups]: NoExcessObject<
|
|
598
|
+
Groups[GroupName],
|
|
599
|
+
StaticConfigGroup<
|
|
600
|
+
ParamListBase,
|
|
601
|
+
NavigationState,
|
|
602
|
+
{},
|
|
603
|
+
EventMapBase,
|
|
604
|
+
NavigationListBase<ParamListBase>
|
|
605
|
+
>
|
|
606
|
+
> &
|
|
607
|
+
NoExcessStaticConfig<Groups[GroupName], Bag, ScreenOptions, Listeners>;
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// Each property is probed with `Config extends { key: infer X }` and the results are intersected.
|
|
611
|
+
// These conditionals stay deferred while the config is inferred, so they don't interfere with the inference.
|
|
612
|
+
// Indexed access (`Config['screens']`) or a mapped type over the whole config breaks the param list inference.
|
|
613
|
+
export type NoExcessStaticConfig<
|
|
614
|
+
Config,
|
|
615
|
+
Bag extends NavigatorTypeBagBase,
|
|
616
|
+
ScreenOptions extends {} = Bag['ScreenOptions'],
|
|
617
|
+
Listeners extends {} = ScreenListeners<Bag['State'], Bag['EventMap']>,
|
|
618
|
+
> = (Config extends { screenOptions: infer ProvidedOptions }
|
|
619
|
+
? {
|
|
620
|
+
screenOptions: NoExcessValue<ProvidedOptions, ScreenOptions>;
|
|
621
|
+
}
|
|
622
|
+
: unknown) &
|
|
623
|
+
(Config extends { screenListeners: infer ProvidedListeners }
|
|
624
|
+
? {
|
|
625
|
+
screenListeners: NoExcessValue<ProvidedListeners, Listeners>;
|
|
626
|
+
}
|
|
627
|
+
: unknown) &
|
|
628
|
+
(Config extends { screens: infer Screens }
|
|
629
|
+
? {
|
|
630
|
+
screens: NoExcessScreens<Screens, ScreenOptions, Listeners>;
|
|
631
|
+
}
|
|
632
|
+
: unknown) &
|
|
633
|
+
(Config extends { groups: infer Groups }
|
|
634
|
+
? {
|
|
635
|
+
groups: NoExcessGroups<Groups, Bag, ScreenOptions, Listeners>;
|
|
636
|
+
}
|
|
637
|
+
: unknown);
|
|
638
|
+
|
|
484
639
|
/**
|
|
485
640
|
* Props for a screen component which is rendered by a static navigator.
|
|
486
641
|
* Takes the route params as a generic argument.
|
|
487
642
|
*/
|
|
488
|
-
export type StaticScreenProps<
|
|
643
|
+
export type StaticScreenProps<
|
|
644
|
+
in out T extends Record<string, unknown> | undefined,
|
|
645
|
+
> = {
|
|
489
646
|
route: {
|
|
490
|
-
params: T;
|
|
647
|
+
readonly params: T;
|
|
491
648
|
};
|
|
492
649
|
};
|
|
493
650
|
|
|
@@ -503,11 +660,11 @@ export type StaticParamList<
|
|
|
503
660
|
ParamListForGroups<T['config']['groups']>
|
|
504
661
|
>;
|
|
505
662
|
|
|
506
|
-
export type StaticNavigation<
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
663
|
+
export type StaticNavigation<
|
|
664
|
+
in out NavigatorTypeBag extends NavigatorTypeBagBase,
|
|
665
|
+
> = {
|
|
666
|
+
config: StaticConfigBase<NavigatorTypeBag>;
|
|
667
|
+
getComponent: () => React.ComponentType<{}>;
|
|
511
668
|
};
|
|
512
669
|
|
|
513
670
|
const MemoizedScreen = React.memo(
|
|
@@ -542,16 +699,13 @@ const getItemsFromScreens = (
|
|
|
542
699
|
component = screen;
|
|
543
700
|
} else if ('config' in screen) {
|
|
544
701
|
isNavigator = true;
|
|
545
|
-
component =
|
|
546
|
-
screen,
|
|
547
|
-
`${name}Navigator`
|
|
548
|
-
);
|
|
702
|
+
component = screen.getComponent();
|
|
549
703
|
}
|
|
550
704
|
} else if (isValidElementType(item)) {
|
|
551
705
|
component = item;
|
|
552
706
|
} else if ('config' in item) {
|
|
553
707
|
isNavigator = true;
|
|
554
|
-
component =
|
|
708
|
+
component = item.getComponent();
|
|
555
709
|
}
|
|
556
710
|
|
|
557
711
|
if (component == null) {
|
|
@@ -589,10 +743,17 @@ const getItemsFromScreens = (
|
|
|
589
743
|
* @param displayName Name of the component to be displayed in React DevTools.
|
|
590
744
|
* @returns A component which renders the navigator.
|
|
591
745
|
*/
|
|
592
|
-
export function
|
|
593
|
-
|
|
746
|
+
export function createComponentForStaticConfig<
|
|
747
|
+
T extends {
|
|
748
|
+
Navigator: React.ComponentType<any>;
|
|
749
|
+
Group: React.ComponentType<any>;
|
|
750
|
+
Screen: React.ComponentType<any>;
|
|
751
|
+
config: StaticConfig<NavigatorTypeBagBase>;
|
|
752
|
+
},
|
|
753
|
+
>(
|
|
754
|
+
tree: T,
|
|
594
755
|
displayName: string
|
|
595
|
-
): React.ComponentType<
|
|
756
|
+
): React.ComponentType<Omit<React.ComponentProps<T['Navigator']>, 'children'>> {
|
|
596
757
|
const { Navigator, Group, Screen, config } = tree;
|
|
597
758
|
const { screens, groups, ...rest } = config;
|
|
598
759
|
|
|
@@ -637,10 +798,53 @@ export function createComponentForStaticNavigation(
|
|
|
637
798
|
}
|
|
638
799
|
}
|
|
639
800
|
|
|
640
|
-
|
|
801
|
+
if (items.length === 0) {
|
|
802
|
+
throw new Error(
|
|
803
|
+
"Couldn't find any screens in the 'screens' or 'groups' property. Make sure to define at least one screen in the configuration."
|
|
804
|
+
);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
const NavigatorComponent = ({ children: _, ...props }: typeof rest) => {
|
|
641
808
|
const children = items.map((item) => item());
|
|
642
809
|
|
|
643
|
-
|
|
810
|
+
const screenOptions =
|
|
811
|
+
typeof props.screenOptions === 'function' ||
|
|
812
|
+
typeof rest.screenOptions === 'function'
|
|
813
|
+
? (options: unknown) => ({
|
|
814
|
+
...(typeof rest.screenOptions === 'function'
|
|
815
|
+
? rest.screenOptions(options)
|
|
816
|
+
: rest.screenOptions),
|
|
817
|
+
...(typeof props.screenOptions === 'function'
|
|
818
|
+
? props.screenOptions(options)
|
|
819
|
+
: props.screenOptions),
|
|
820
|
+
})
|
|
821
|
+
: { ...rest.screenOptions, ...props.screenOptions };
|
|
822
|
+
|
|
823
|
+
const screenListeners =
|
|
824
|
+
typeof props.screenListeners === 'function' ||
|
|
825
|
+
typeof rest.screenListeners === 'function'
|
|
826
|
+
? (options: unknown) => ({
|
|
827
|
+
...(typeof rest.screenListeners === 'function'
|
|
828
|
+
? rest.screenListeners(options)
|
|
829
|
+
: rest.screenListeners),
|
|
830
|
+
...(typeof props.screenListeners === 'function'
|
|
831
|
+
? props.screenListeners(options)
|
|
832
|
+
: props.screenListeners),
|
|
833
|
+
})
|
|
834
|
+
: { ...rest.screenListeners, ...props.screenListeners };
|
|
835
|
+
|
|
836
|
+
return (
|
|
837
|
+
<StaticTreeContext.Provider value={tree}>
|
|
838
|
+
<Navigator
|
|
839
|
+
{...rest}
|
|
840
|
+
{...props}
|
|
841
|
+
screenOptions={screenOptions}
|
|
842
|
+
screenListeners={screenListeners}
|
|
843
|
+
>
|
|
844
|
+
{children}
|
|
845
|
+
</Navigator>
|
|
846
|
+
</StaticTreeContext.Provider>
|
|
847
|
+
);
|
|
644
848
|
};
|
|
645
849
|
|
|
646
850
|
NavigatorComponent.displayName = displayName;
|
|
@@ -648,33 +852,111 @@ export function createComponentForStaticNavigation(
|
|
|
648
852
|
return NavigatorComponent;
|
|
649
853
|
}
|
|
650
854
|
|
|
651
|
-
type
|
|
652
|
-
|
|
653
|
-
|
|
855
|
+
export type TreeForPathConfig = {
|
|
856
|
+
config: ConfigForPathConfig;
|
|
857
|
+
};
|
|
654
858
|
|
|
655
|
-
type
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
859
|
+
type ConfigForPathConfig = {
|
|
860
|
+
initialRouteName?: string;
|
|
861
|
+
screens?: Record<string, ScreenForPathConfig>;
|
|
862
|
+
groups?: Record<string, { screens: Record<string, ScreenForPathConfig> }>;
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
type LinkingForPathConfig =
|
|
866
|
+
| string
|
|
867
|
+
| (Partial<StaticScreenConfigLinkingAlias> & StaticScreenConfigLinkingExtras)
|
|
868
|
+
| null
|
|
869
|
+
| undefined;
|
|
870
|
+
|
|
871
|
+
type ScreenValueForPathConfig = React.ComponentType<{}> | TreeForPathConfig;
|
|
872
|
+
|
|
873
|
+
type ScreenForPathConfig =
|
|
874
|
+
| ScreenValueForPathConfig
|
|
875
|
+
| {
|
|
876
|
+
screen: ScreenValueForPathConfig;
|
|
877
|
+
initialParams?: object;
|
|
878
|
+
linking?: LinkingForPathConfig;
|
|
879
|
+
UNSTABLE_loader?: unknown;
|
|
676
880
|
};
|
|
881
|
+
|
|
882
|
+
type PathConfigMapForStaticNavigation = Record<
|
|
883
|
+
string,
|
|
884
|
+
string | PathConfigForStaticNavigation | undefined
|
|
885
|
+
>;
|
|
886
|
+
|
|
887
|
+
type PathConfigForStaticNavigation = Omit<
|
|
888
|
+
PathConfig<ParamListBase>,
|
|
889
|
+
'screens'
|
|
890
|
+
> & {
|
|
891
|
+
initialRouteName?: string | undefined;
|
|
892
|
+
screens?: PathConfigMapForStaticNavigation | undefined;
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
// Mark screens that resolve to the same pattern and same component or navigator
|
|
896
|
+
const markSharedPathConfigs = (
|
|
897
|
+
screens: PathConfigMapForStaticNavigation,
|
|
898
|
+
sources: WeakMap<PathConfigForStaticNavigation, ScreenValueForPathConfig>,
|
|
899
|
+
blocked: WeakSet<PathConfigForStaticNavigation>
|
|
900
|
+
) => {
|
|
901
|
+
const candidates = new Map<string, PathConfigForStaticNavigation[]>();
|
|
902
|
+
|
|
903
|
+
const collect = (
|
|
904
|
+
screens: PathConfigMapForStaticNavigation,
|
|
905
|
+
parentParts: PatternPart[],
|
|
906
|
+
disabled: boolean
|
|
907
|
+
) => {
|
|
908
|
+
for (const config of Object.values(screens)) {
|
|
909
|
+
if (config == null || typeof config === 'string') {
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
const parts =
|
|
914
|
+
typeof config.path === 'string'
|
|
915
|
+
? combinePatternParts(
|
|
916
|
+
parentParts,
|
|
917
|
+
getPatternParts(config.path),
|
|
918
|
+
config.exact
|
|
919
|
+
)
|
|
920
|
+
: parentParts;
|
|
921
|
+
|
|
922
|
+
if (sources.has(config) && typeof config.path === 'string') {
|
|
923
|
+
if (disabled) {
|
|
924
|
+
blocked.add(config);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
const pattern = parts.map((part) => part.segment).join('/');
|
|
928
|
+
const entries = candidates.get(pattern) ?? [];
|
|
929
|
+
|
|
930
|
+
entries.push(config);
|
|
931
|
+
candidates.set(pattern, entries);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (config.screens) {
|
|
935
|
+
collect(config.screens, parts, disabled || config.shared === false);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
677
938
|
};
|
|
939
|
+
|
|
940
|
+
collect(screens, [], false);
|
|
941
|
+
|
|
942
|
+
for (const entries of candidates.values()) {
|
|
943
|
+
for (const entry of entries) {
|
|
944
|
+
const source = sources.get(entry);
|
|
945
|
+
|
|
946
|
+
if (
|
|
947
|
+
entry.shared === undefined &&
|
|
948
|
+
!blocked.has(entry) &&
|
|
949
|
+
entries.some(
|
|
950
|
+
(candidate) =>
|
|
951
|
+
candidate !== entry &&
|
|
952
|
+
!blocked.has(candidate) &&
|
|
953
|
+
sources.get(candidate) === source
|
|
954
|
+
)
|
|
955
|
+
) {
|
|
956
|
+
entry.shared = true;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
678
960
|
};
|
|
679
961
|
|
|
680
962
|
/**
|
|
@@ -696,32 +978,49 @@ type TreeForPathConfig = {
|
|
|
696
978
|
* };
|
|
697
979
|
* ```
|
|
698
980
|
*/
|
|
699
|
-
export function createPathConfigForStaticNavigation(
|
|
981
|
+
export function createPathConfigForStaticNavigation<ParamList extends {}>(
|
|
700
982
|
tree: TreeForPathConfig,
|
|
701
983
|
options?: {
|
|
702
|
-
initialRouteName?: string;
|
|
984
|
+
initialRouteName?: string | undefined;
|
|
703
985
|
},
|
|
704
986
|
auto?: boolean
|
|
705
|
-
): PathConfigMap<
|
|
987
|
+
): PathConfigMap<ParamList> | undefined {
|
|
706
988
|
let initialScreenHasPath: boolean = false;
|
|
707
989
|
let initialScreenConfig: PathConfig<{}> | undefined;
|
|
990
|
+
let hasEmptyPath = false;
|
|
991
|
+
|
|
992
|
+
const blocked = new WeakSet<PathConfigForStaticNavigation>();
|
|
993
|
+
const sources = new WeakMap<
|
|
994
|
+
PathConfigForStaticNavigation,
|
|
995
|
+
ScreenValueForPathConfig
|
|
996
|
+
>();
|
|
708
997
|
|
|
709
998
|
const createPathConfigForTree = (
|
|
710
999
|
t: TreeForPathConfig,
|
|
711
|
-
o: { initialRouteName?: string } | undefined,
|
|
1000
|
+
o: { initialRouteName?: string | undefined } | undefined,
|
|
712
1001
|
// If a screen is a leaf node, but inside a screen with path,
|
|
713
1002
|
// It should not be used for initial detection
|
|
714
|
-
skipInitialDetection: boolean
|
|
1003
|
+
skipInitialDetection: boolean,
|
|
1004
|
+
allowAutoEmptyPath: boolean
|
|
715
1005
|
) => {
|
|
1006
|
+
const initialRouteName = o?.initialRouteName ?? t.config.initialRouteName;
|
|
1007
|
+
|
|
1008
|
+
if (initialRouteName != null) {
|
|
1009
|
+
const routeNames = new Set(Object.keys(t.config.screens ?? {}));
|
|
1010
|
+
|
|
1011
|
+
for (const group of Object.values(t.config.groups ?? {})) {
|
|
1012
|
+
Object.keys(group.screens).forEach((name) => routeNames.add(name));
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
if (!routeNames.has(initialRouteName)) {
|
|
1016
|
+
throw new Error(
|
|
1017
|
+
`Couldn't find a screen named '${initialRouteName}' to use as 'initialRouteName'.`
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
716
1022
|
const createPathConfigForScreens = (
|
|
717
|
-
screens:
|
|
718
|
-
ParamListBase,
|
|
719
|
-
NavigationState,
|
|
720
|
-
{},
|
|
721
|
-
EventMapBase,
|
|
722
|
-
Record<string, unknown>
|
|
723
|
-
>,
|
|
724
|
-
groupLinking: LinkingForGroup | undefined,
|
|
1023
|
+
screens: Record<string, ScreenForPathConfig>,
|
|
725
1024
|
initialRouteName: string | undefined
|
|
726
1025
|
) => {
|
|
727
1026
|
return Object.fromEntries(
|
|
@@ -740,95 +1039,144 @@ export function createPathConfigForStaticNavigation(
|
|
|
740
1039
|
return 0;
|
|
741
1040
|
})
|
|
742
1041
|
.map(([key, item]) => {
|
|
743
|
-
const screenConfig:
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
if ('linking' in item) {
|
|
1042
|
+
const screenConfig: PathConfigForStaticNavigation = {};
|
|
1043
|
+
|
|
1044
|
+
sources.set(
|
|
1045
|
+
screenConfig,
|
|
1046
|
+
typeof item === 'object' && 'screen' in item ? item.screen : item
|
|
1047
|
+
);
|
|
1048
|
+
|
|
1049
|
+
const normalizePath = (path: string) =>
|
|
1050
|
+
path.replace(/^\/+|\/+$/g, '');
|
|
1051
|
+
|
|
1052
|
+
if ('linking' in item && item.linking !== undefined) {
|
|
756
1053
|
if (typeof item.linking === 'string') {
|
|
757
1054
|
screenConfig.path = item.linking;
|
|
758
|
-
} else
|
|
759
|
-
|
|
1055
|
+
} else if (
|
|
1056
|
+
item.linking != null &&
|
|
1057
|
+
typeof item.linking === 'object'
|
|
1058
|
+
) {
|
|
1059
|
+
Object.assign(screenConfig, { ...item.linking });
|
|
760
1060
|
}
|
|
761
1061
|
}
|
|
762
1062
|
|
|
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
|
-
}
|
|
1063
|
+
if (screenConfig.exact && screenConfig.path == null) {
|
|
1064
|
+
throw new Error(
|
|
1065
|
+
"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: ''`."
|
|
1066
|
+
);
|
|
777
1067
|
}
|
|
778
1068
|
|
|
779
1069
|
if (typeof screenConfig.path === 'string') {
|
|
780
1070
|
screenConfig.path = normalizePath(screenConfig.path);
|
|
781
1071
|
}
|
|
782
1072
|
|
|
1073
|
+
if (screenConfig.alias != null) {
|
|
1074
|
+
screenConfig.alias = screenConfig.alias.map((alias) => {
|
|
1075
|
+
if (typeof alias === 'string') {
|
|
1076
|
+
return normalizePath(alias);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
return {
|
|
1080
|
+
...alias,
|
|
1081
|
+
path: normalizePath(alias.path),
|
|
1082
|
+
};
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
|
|
783
1086
|
let screens;
|
|
784
1087
|
|
|
1088
|
+
const hasExplicitScreens =
|
|
1089
|
+
'screens' in screenConfig && screenConfig.screens != null;
|
|
1090
|
+
const hasDisabledLinking =
|
|
1091
|
+
'linking' in item && item.linking === null;
|
|
1092
|
+
const childOptions =
|
|
1093
|
+
'initialRouteName' in screenConfig &&
|
|
1094
|
+
typeof screenConfig.initialRouteName === 'string'
|
|
1095
|
+
? { initialRouteName: screenConfig.initialRouteName }
|
|
1096
|
+
: undefined;
|
|
1097
|
+
|
|
1098
|
+
if (
|
|
1099
|
+
hasExplicitScreens &&
|
|
1100
|
+
childOptions != null &&
|
|
1101
|
+
!Object.keys(screenConfig.screens ?? {}).includes(
|
|
1102
|
+
childOptions.initialRouteName
|
|
1103
|
+
)
|
|
1104
|
+
) {
|
|
1105
|
+
throw new Error(
|
|
1106
|
+
`Couldn't find a screen named '${childOptions.initialRouteName}' to use as 'initialRouteName'.`
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
785
1110
|
const skipInitialDetectionInChild =
|
|
786
1111
|
skipInitialDetection ||
|
|
787
1112
|
(screenConfig.path != null && screenConfig.path !== '');
|
|
1113
|
+
const allowAutoEmptyPathInChild =
|
|
1114
|
+
allowAutoEmptyPath &&
|
|
1115
|
+
(initialRouteName == null || key === initialRouteName);
|
|
788
1116
|
|
|
789
|
-
if (
|
|
1117
|
+
if (
|
|
1118
|
+
!hasExplicitScreens &&
|
|
1119
|
+
!hasDisabledLinking &&
|
|
1120
|
+
'config' in item
|
|
1121
|
+
) {
|
|
790
1122
|
screens = createPathConfigForTree(
|
|
791
1123
|
item,
|
|
792
|
-
|
|
793
|
-
skipInitialDetectionInChild
|
|
1124
|
+
childOptions,
|
|
1125
|
+
skipInitialDetectionInChild,
|
|
1126
|
+
allowAutoEmptyPathInChild
|
|
794
1127
|
);
|
|
795
1128
|
} else if (
|
|
1129
|
+
!hasExplicitScreens &&
|
|
1130
|
+
!hasDisabledLinking &&
|
|
796
1131
|
'screen' in item &&
|
|
797
1132
|
'config' in item.screen &&
|
|
798
1133
|
(item.screen.config.screens || item.screen.config.groups)
|
|
799
1134
|
) {
|
|
800
1135
|
screens = createPathConfigForTree(
|
|
801
1136
|
item.screen,
|
|
802
|
-
|
|
803
|
-
skipInitialDetectionInChild
|
|
1137
|
+
childOptions,
|
|
1138
|
+
skipInitialDetectionInChild,
|
|
1139
|
+
allowAutoEmptyPathInChild
|
|
804
1140
|
);
|
|
805
1141
|
}
|
|
806
1142
|
|
|
807
1143
|
if (screens) {
|
|
808
|
-
// @ts-expect-error - we can't type this properly
|
|
809
1144
|
screenConfig.screens = screens;
|
|
810
1145
|
}
|
|
811
1146
|
|
|
812
1147
|
if (
|
|
813
1148
|
auto &&
|
|
814
1149
|
!('screens' in screenConfig && screenConfig.screens) &&
|
|
815
|
-
// Skip generating path for screens that specify linking config as `
|
|
816
|
-
!
|
|
1150
|
+
// Skip generating path for screens that specify linking config as `null` explicitly
|
|
1151
|
+
!hasDisabledLinking
|
|
817
1152
|
) {
|
|
818
1153
|
if (screenConfig.path != null) {
|
|
819
1154
|
if (!skipInitialDetection) {
|
|
820
|
-
if (
|
|
821
|
-
initialScreenHasPath = true;
|
|
822
|
-
} else if (screenConfig.path === '') {
|
|
1155
|
+
if (screenConfig.path === '') {
|
|
823
1156
|
// We encounter a leaf screen with empty path,
|
|
824
1157
|
// Clear the initial screen config as it's not needed anymore
|
|
825
1158
|
initialScreenConfig = undefined;
|
|
1159
|
+
hasEmptyPath = true;
|
|
1160
|
+
|
|
1161
|
+
if (allowAutoEmptyPath && key === initialRouteName) {
|
|
1162
|
+
initialScreenHasPath = true;
|
|
1163
|
+
}
|
|
1164
|
+
} else if (
|
|
1165
|
+
allowAutoEmptyPath &&
|
|
1166
|
+
key === initialRouteName &&
|
|
1167
|
+
// Keep an already discovered fallback unless the initial route
|
|
1168
|
+
// explicitly uses an empty path.
|
|
1169
|
+
initialScreenConfig == null
|
|
1170
|
+
) {
|
|
1171
|
+
initialScreenHasPath = true;
|
|
826
1172
|
}
|
|
827
1173
|
}
|
|
828
1174
|
} else {
|
|
829
1175
|
if (
|
|
830
|
-
!groupPath &&
|
|
831
1176
|
!skipInitialDetection &&
|
|
1177
|
+
allowAutoEmptyPath &&
|
|
1178
|
+
(initialRouteName == null || key === initialRouteName) &&
|
|
1179
|
+
!hasEmptyPath &&
|
|
832
1180
|
initialScreenConfig == null
|
|
833
1181
|
) {
|
|
834
1182
|
initialScreenConfig = screenConfig;
|
|
@@ -836,8 +1184,8 @@ export function createPathConfigForStaticNavigation(
|
|
|
836
1184
|
|
|
837
1185
|
screenConfig.path = normalizePath(
|
|
838
1186
|
key
|
|
839
|
-
.replace(/([A-Z]
|
|
840
|
-
.replace(
|
|
1187
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
1188
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
|
|
841
1189
|
.toLowerCase()
|
|
842
1190
|
);
|
|
843
1191
|
}
|
|
@@ -849,7 +1197,7 @@ export function createPathConfigForStaticNavigation(
|
|
|
849
1197
|
);
|
|
850
1198
|
};
|
|
851
1199
|
|
|
852
|
-
const screens = {};
|
|
1200
|
+
const screens: PathConfigMapForStaticNavigation = {};
|
|
853
1201
|
|
|
854
1202
|
// Loop through the config to find screens and groups
|
|
855
1203
|
// So we add the screens and groups in the same order as they are defined
|
|
@@ -859,7 +1207,6 @@ export function createPathConfigForStaticNavigation(
|
|
|
859
1207
|
screens,
|
|
860
1208
|
createPathConfigForScreens(
|
|
861
1209
|
t.config.screens,
|
|
862
|
-
undefined,
|
|
863
1210
|
o?.initialRouteName ?? t.config.initialRouteName
|
|
864
1211
|
)
|
|
865
1212
|
);
|
|
@@ -871,7 +1218,6 @@ export function createPathConfigForStaticNavigation(
|
|
|
871
1218
|
screens,
|
|
872
1219
|
createPathConfigForScreens(
|
|
873
1220
|
group.screens,
|
|
874
|
-
group.linking,
|
|
875
1221
|
o?.initialRouteName ?? t.config.initialRouteName
|
|
876
1222
|
)
|
|
877
1223
|
);
|
|
@@ -886,11 +1232,17 @@ export function createPathConfigForStaticNavigation(
|
|
|
886
1232
|
return screens;
|
|
887
1233
|
};
|
|
888
1234
|
|
|
889
|
-
const screens = createPathConfigForTree(tree, options, false);
|
|
1235
|
+
const screens = createPathConfigForTree(tree, options, false, true);
|
|
890
1236
|
|
|
891
1237
|
if (auto && initialScreenConfig && !initialScreenHasPath) {
|
|
892
1238
|
initialScreenConfig.path = '';
|
|
893
1239
|
}
|
|
894
1240
|
|
|
895
|
-
|
|
1241
|
+
if (!screens) {
|
|
1242
|
+
return undefined;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
markSharedPathConfigs(screens, sources, blocked);
|
|
1246
|
+
|
|
1247
|
+
return screens as PathConfigMap<ParamList>;
|
|
896
1248
|
}
|