@react-navigation/core 8.0.0-alpha.4 → 8.0.0-alpha.40
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/README.md +17 -14
- package/lib/module/BaseNavigationContainer.js +168 -87
- 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 +129 -0
- package/lib/module/DataLoading.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +7 -10
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +54 -9
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +36 -11
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationRootContext.js +8 -0
- package/lib/module/NavigationRootContext.js.map +1 -0
- 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 +40 -31
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +12 -42
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +219 -67
- 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/createNavigationContainerRef.js +7 -9
- 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 +204 -94
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +61 -14
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +608 -272
- 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 +7 -6
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +2 -0
- package/lib/module/internal.js.map +1 -0
- package/lib/module/isRecordEqual.js +1 -1
- package/lib/module/isRecordEqual.js.map +1 -1
- package/lib/module/queryString.js +71 -0
- package/lib/module/queryString.js.map +1 -0
- package/lib/module/theming/useTheme.js +1 -1
- package/lib/module/theming/useTheme.js.map +1 -1
- package/lib/module/types.js +35 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +65 -25
- 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/useFocusEffect.js +4 -2
- package/lib/module/useFocusEffect.js.map +1 -1
- package/lib/module/useFocusEvents.js +15 -5
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +3 -3
- package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
- package/lib/module/useIsFocused.js +8 -12
- package/lib/module/useIsFocused.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +5 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useLazyValue.js.map +1 -1
- package/lib/module/useNavigation.js +4 -17
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +244 -147
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +92 -89
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +22 -29
- 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 +158 -46
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +58 -11
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetNavigation.js +26 -0
- package/lib/module/useOnGetNavigation.js.map +1 -0
- package/lib/module/useOnGetState.js +7 -4
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +40 -31
- package/lib/module/useOnPreventRemove.js.map +1 -1
- package/lib/module/useOnRouteFocus.js +2 -2
- package/lib/module/useOnRouteFocus.js.map +1 -1
- package/lib/module/useOptionsGetters.js +34 -24
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +11 -5
- package/lib/module/usePreventRemove.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +2 -2
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +3 -4
- 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 +51 -35
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +12 -10
- 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 +37 -15
- 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 +22 -14
- 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 +21 -18
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationRootContext.d.ts +8 -0
- package/lib/typescript/src/NavigationRootContext.d.ts.map +1 -0
- 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 +5 -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 -111
- 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/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 +5 -2
- 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/internal.d.ts +3 -0
- package/lib/typescript/src/internal.d.ts.map +1 -0
- package/lib/typescript/src/isRecordEqual.d.ts.map +1 -1
- package/lib/typescript/src/queryString.d.ts +5 -0
- package/lib/typescript/src/queryString.d.ts.map +1 -0
- 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 +265 -167
- 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/useDescriptors.d.ts +13 -11
- 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/useFocusEffect.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 +4 -0
- package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts +4 -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 +22 -63
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +6 -5
- 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 +18 -58
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +19 -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/useOnGetNavigation.d.ts +12 -0
- package/lib/typescript/src/useOnGetNavigation.d.ts.map +1 -0
- 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 +2 -4
- 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/useRegisterNavigator.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 +7 -12
- 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 +79 -39
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +26 -22
- package/src/BaseNavigationContainer.tsx +468 -333
- package/src/ConsumedParamsContext.tsx +5 -0
- package/src/DataLoading.tsx +206 -0
- package/src/NavigationBuilderContext.tsx +44 -25
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +60 -12
- package/src/NavigationProvider.tsx +47 -20
- package/src/NavigationRootContext.tsx +11 -0
- package/src/NavigationStateContext.tsx +9 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +55 -56
- package/src/SceneView.tsx +14 -40
- package/src/StaticNavigation.tsx +715 -328
- package/src/StaticTreeContext.tsx +7 -0
- package/src/createNavigationContainerRef.tsx +12 -11
- package/src/createNavigatorFactory.tsx +92 -8
- package/src/findFocusedRoute.tsx +16 -16
- package/src/getActionFromState.tsx +87 -51
- package/src/getPathFromState.tsx +310 -134
- package/src/getPatternParts.tsx +98 -16
- package/src/getStateFromPath.tsx +971 -344
- package/src/getStateFromRouteParams.tsx +59 -0
- package/src/index.tsx +57 -6
- package/src/internal.tsx +2 -0
- package/src/isRecordEqual.tsx +3 -1
- package/src/queryString.ts +109 -0
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +799 -377
- package/src/useDescriptors.tsx +151 -43
- package/src/useEventEmitter.tsx +53 -39
- package/src/useFocusEffect.tsx +5 -2
- package/src/useFocusEvents.tsx +19 -8
- package/src/useFocusedListenersChildrenAdapter.tsx +3 -3
- package/src/useIsFocused.tsx +18 -21
- package/src/useKeyedChildListeners.tsx +5 -2
- package/src/useLazyValue.tsx +2 -2
- package/src/useNavigation.tsx +9 -26
- package/src/useNavigationBuilder.tsx +370 -201
- package/src/useNavigationCache.tsx +148 -123
- package/src/useNavigationHelpers.tsx +27 -37
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +207 -69
- package/src/useOnAction.tsx +92 -18
- package/src/useOnGetNavigation.tsx +30 -0
- package/src/useOnGetState.tsx +8 -4
- package/src/useOnPreventRemove.tsx +78 -43
- package/src/useOnRouteFocus.tsx +11 -15
- package/src/useOptionsGetters.tsx +41 -28
- package/src/usePreventRemove.tsx +13 -5
- package/src/usePreventRemoveContext.tsx +2 -2
- package/src/useRegisterNavigator.tsx +4 -4
- package/src/useRoute.tsx +20 -6
- package/src/useRouteCache.tsx +57 -35
- package/src/useScheduleUpdate.tsx +13 -11
- package/src/useStateForPath.tsx +1 -1
- package/src/useSyncState.tsx +39 -15
- package/src/utilities.tsx +151 -35
- package/src/validatePathConfig.tsx +86 -57
- package/lib/module/CurrentRenderContext.js +0 -10
- package/lib/module/CurrentRenderContext.js.map +0 -1
- package/lib/module/NavigationMetaContext.js +0 -15
- package/lib/module/NavigationMetaContext.js.map +0 -1
- package/lib/module/checkSerializable.js +0 -46
- package/lib/module/checkSerializable.js.map +0 -1
- package/lib/module/useComponent.js +0 -34
- package/lib/module/useComponent.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/NavigationMetaContext.d.ts +0 -12
- package/lib/typescript/src/NavigationMetaContext.d.ts.map +0 -1
- package/lib/typescript/src/checkSerializable.d.ts +0 -10
- package/lib/typescript/src/checkSerializable.d.ts.map +0 -1
- package/lib/typescript/src/useComponent.d.ts +0 -7
- package/lib/typescript/src/useComponent.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/NavigationMetaContext.tsx +0 -14
- package/src/checkSerializable.tsx +0 -74
- package/src/useComponent.tsx +0 -37
- 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
|
+
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,17 +660,13 @@ export type StaticParamList<
|
|
|
503
660
|
ParamListForGroups<T['config']['groups']>
|
|
504
661
|
>;
|
|
505
662
|
|
|
506
|
-
type
|
|
507
|
-
|
|
663
|
+
export type StaticNavigation<
|
|
664
|
+
in out NavigatorTypeBag extends NavigatorTypeBagBase,
|
|
665
|
+
> = {
|
|
666
|
+
config: StaticConfigBase<NavigatorTypeBag>;
|
|
667
|
+
getComponent: () => React.ComponentType<{}>;
|
|
508
668
|
};
|
|
509
669
|
|
|
510
|
-
export type StaticNavigation<NavigatorProps, GroupProps, ScreenProps> =
|
|
511
|
-
StaticNavigationBase & {
|
|
512
|
-
Navigator: React.ComponentType<NavigatorProps>;
|
|
513
|
-
Group: React.ComponentType<GroupProps>;
|
|
514
|
-
Screen: React.ComponentType<ScreenProps>;
|
|
515
|
-
};
|
|
516
|
-
|
|
517
670
|
const MemoizedScreen = React.memo(
|
|
518
671
|
<T extends React.ComponentType<any>>({ component }: { component: T }) => {
|
|
519
672
|
const route = useRoute();
|
|
@@ -525,6 +678,9 @@ const MemoizedScreen = React.memo(
|
|
|
525
678
|
|
|
526
679
|
MemoizedScreen.displayName = 'Memo(Screen)';
|
|
527
680
|
|
|
681
|
+
const hasPropertyGetter = (object: object, property: PropertyKey) =>
|
|
682
|
+
Object.getOwnPropertyDescriptor(object, property)?.get != null;
|
|
683
|
+
|
|
528
684
|
const getItemsFromScreens = (
|
|
529
685
|
Screen: React.ComponentType<any>,
|
|
530
686
|
screens: StaticConfigScreens<any, any, any, any, any>
|
|
@@ -535,41 +691,88 @@ const getItemsFromScreens = (
|
|
|
535
691
|
let useIf: (() => boolean) | undefined;
|
|
536
692
|
|
|
537
693
|
let isNavigator = false;
|
|
694
|
+
let getComponent: (() => React.ComponentType<any>) | undefined;
|
|
538
695
|
|
|
539
696
|
if ('screen' in item) {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
697
|
+
if (hasPropertyGetter(item, 'screen')) {
|
|
698
|
+
const rest: Record<string, unknown> = {};
|
|
699
|
+
|
|
700
|
+
// Iterate over the keys to avoid triggering the getter for 'screen'
|
|
701
|
+
for (const key of Object.keys(item)) {
|
|
702
|
+
if (key === 'screen' || key === 'if') {
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
rest[key] = Reflect.get(item, key);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
useIf = item.if;
|
|
710
|
+
props = rest;
|
|
711
|
+
|
|
712
|
+
getComponent = () => {
|
|
713
|
+
const screen = item.screen;
|
|
714
|
+
|
|
715
|
+
if (isValidElementType(screen)) {
|
|
716
|
+
return screen;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (
|
|
720
|
+
screen != null &&
|
|
721
|
+
typeof screen === 'object' &&
|
|
722
|
+
'config' in screen
|
|
723
|
+
) {
|
|
724
|
+
throw new Error(
|
|
725
|
+
`Got a navigator object for the screen '${name}' instead of a component. A navigator cannot be specified when using a getter.`
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
throw new Error(
|
|
730
|
+
`Got an invalid screen component for the screen '${name}'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.`
|
|
731
|
+
);
|
|
732
|
+
};
|
|
733
|
+
} else {
|
|
734
|
+
const { screen, if: _if, ...rest } = item;
|
|
735
|
+
|
|
736
|
+
useIf = _if;
|
|
737
|
+
props = rest;
|
|
738
|
+
|
|
739
|
+
if (isValidElementType(screen)) {
|
|
740
|
+
component = screen;
|
|
741
|
+
} else if ('config' in screen) {
|
|
742
|
+
isNavigator = true;
|
|
743
|
+
component = screen.getComponent();
|
|
744
|
+
}
|
|
553
745
|
}
|
|
554
746
|
} else if (isValidElementType(item)) {
|
|
555
747
|
component = item;
|
|
556
748
|
} else if ('config' in item) {
|
|
557
749
|
isNavigator = true;
|
|
558
|
-
component =
|
|
750
|
+
component = item.getComponent();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
let children: (() => React.JSX.Element) | undefined;
|
|
754
|
+
|
|
755
|
+
if (getComponent != null) {
|
|
756
|
+
let element: React.JSX.Element | undefined;
|
|
757
|
+
|
|
758
|
+
children = () =>
|
|
759
|
+
(element ??= <MemoizedScreen component={getComponent()} />);
|
|
760
|
+
} else if (component != null) {
|
|
761
|
+
const element = isNavigator ? (
|
|
762
|
+
React.createElement(component, {})
|
|
763
|
+
) : (
|
|
764
|
+
<MemoizedScreen component={component} />
|
|
765
|
+
);
|
|
766
|
+
|
|
767
|
+
children = () => element;
|
|
559
768
|
}
|
|
560
769
|
|
|
561
|
-
if (
|
|
770
|
+
if (children == null) {
|
|
562
771
|
throw new Error(
|
|
563
772
|
`Couldn't find a 'screen' property for the screen '${name}'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.`
|
|
564
773
|
);
|
|
565
774
|
}
|
|
566
775
|
|
|
567
|
-
const element = isNavigator ? (
|
|
568
|
-
React.createElement(component, {})
|
|
569
|
-
) : (
|
|
570
|
-
<MemoizedScreen component={component} />
|
|
571
|
-
);
|
|
572
|
-
|
|
573
776
|
return () => {
|
|
574
777
|
const shouldRender = useIf == null || useIf();
|
|
575
778
|
|
|
@@ -579,7 +782,7 @@ const getItemsFromScreens = (
|
|
|
579
782
|
|
|
580
783
|
return (
|
|
581
784
|
<Screen key={name} name={name} {...props}>
|
|
582
|
-
{
|
|
785
|
+
{children}
|
|
583
786
|
</Screen>
|
|
584
787
|
);
|
|
585
788
|
};
|
|
@@ -593,8 +796,13 @@ const getItemsFromScreens = (
|
|
|
593
796
|
* @param displayName Name of the component to be displayed in React DevTools.
|
|
594
797
|
* @returns A component which renders the navigator.
|
|
595
798
|
*/
|
|
596
|
-
export function
|
|
597
|
-
T extends
|
|
799
|
+
export function createComponentForStaticConfig<
|
|
800
|
+
T extends {
|
|
801
|
+
Navigator: React.ComponentType<any>;
|
|
802
|
+
Group: React.ComponentType<any>;
|
|
803
|
+
Screen: React.ComponentType<any>;
|
|
804
|
+
config: StaticConfig<NavigatorTypeBagBase>;
|
|
805
|
+
},
|
|
598
806
|
>(
|
|
599
807
|
tree: T,
|
|
600
808
|
displayName: string
|
|
@@ -643,6 +851,12 @@ export function createComponentForStaticNavigation<
|
|
|
643
851
|
}
|
|
644
852
|
}
|
|
645
853
|
|
|
854
|
+
if (items.length === 0) {
|
|
855
|
+
throw new Error(
|
|
856
|
+
"Couldn't find any screens in the 'screens' or 'groups' property. Make sure to define at least one screen in the configuration."
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
|
|
646
860
|
const NavigatorComponent = ({ children: _, ...props }: typeof rest) => {
|
|
647
861
|
const children = items.map((item) => item());
|
|
648
862
|
|
|
@@ -659,10 +873,30 @@ export function createComponentForStaticNavigation<
|
|
|
659
873
|
})
|
|
660
874
|
: { ...rest.screenOptions, ...props.screenOptions };
|
|
661
875
|
|
|
876
|
+
const screenListeners =
|
|
877
|
+
typeof props.screenListeners === 'function' ||
|
|
878
|
+
typeof rest.screenListeners === 'function'
|
|
879
|
+
? (options: unknown) => ({
|
|
880
|
+
...(typeof rest.screenListeners === 'function'
|
|
881
|
+
? rest.screenListeners(options)
|
|
882
|
+
: rest.screenListeners),
|
|
883
|
+
...(typeof props.screenListeners === 'function'
|
|
884
|
+
? props.screenListeners(options)
|
|
885
|
+
: props.screenListeners),
|
|
886
|
+
})
|
|
887
|
+
: { ...rest.screenListeners, ...props.screenListeners };
|
|
888
|
+
|
|
662
889
|
return (
|
|
663
|
-
<
|
|
664
|
-
|
|
665
|
-
|
|
890
|
+
<StaticTreeContext.Provider value={tree}>
|
|
891
|
+
<Navigator
|
|
892
|
+
{...rest}
|
|
893
|
+
{...props}
|
|
894
|
+
screenOptions={screenOptions}
|
|
895
|
+
screenListeners={screenListeners}
|
|
896
|
+
>
|
|
897
|
+
{children}
|
|
898
|
+
</Navigator>
|
|
899
|
+
</StaticTreeContext.Provider>
|
|
666
900
|
);
|
|
667
901
|
};
|
|
668
902
|
|
|
@@ -671,33 +905,111 @@ export function createComponentForStaticNavigation<
|
|
|
671
905
|
return NavigatorComponent;
|
|
672
906
|
}
|
|
673
907
|
|
|
674
|
-
type
|
|
675
|
-
|
|
676
|
-
|
|
908
|
+
export type TreeForPathConfig = {
|
|
909
|
+
config: ConfigForPathConfig;
|
|
910
|
+
};
|
|
677
911
|
|
|
678
|
-
type
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
912
|
+
type ConfigForPathConfig = {
|
|
913
|
+
initialRouteName?: string;
|
|
914
|
+
screens?: Record<string, ScreenForPathConfig>;
|
|
915
|
+
groups?: Record<string, { screens: Record<string, ScreenForPathConfig> }>;
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
type LinkingForPathConfig =
|
|
919
|
+
| string
|
|
920
|
+
| (Partial<StaticScreenConfigLinkingAlias> & StaticScreenConfigLinkingExtras)
|
|
921
|
+
| null
|
|
922
|
+
| undefined;
|
|
923
|
+
|
|
924
|
+
type ScreenValueForPathConfig = React.ComponentType<{}> | TreeForPathConfig;
|
|
925
|
+
|
|
926
|
+
type ScreenForPathConfig =
|
|
927
|
+
| ScreenValueForPathConfig
|
|
928
|
+
| {
|
|
929
|
+
screen: ScreenValueForPathConfig;
|
|
930
|
+
initialParams?: object;
|
|
931
|
+
linking?: LinkingForPathConfig;
|
|
932
|
+
UNSTABLE_loader?: unknown;
|
|
699
933
|
};
|
|
934
|
+
|
|
935
|
+
type PathConfigMapForStaticNavigation = Record<
|
|
936
|
+
string,
|
|
937
|
+
string | PathConfigForStaticNavigation | undefined
|
|
938
|
+
>;
|
|
939
|
+
|
|
940
|
+
type PathConfigForStaticNavigation = Omit<
|
|
941
|
+
PathConfig<ParamListBase>,
|
|
942
|
+
'screens'
|
|
943
|
+
> & {
|
|
944
|
+
initialRouteName?: string | undefined;
|
|
945
|
+
screens?: PathConfigMapForStaticNavigation | undefined;
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
// Mark screens that resolve to the same pattern and same component or navigator
|
|
949
|
+
const markSharedPathConfigs = (
|
|
950
|
+
screens: PathConfigMapForStaticNavigation,
|
|
951
|
+
sources: WeakMap<PathConfigForStaticNavigation, ScreenForPathConfig>,
|
|
952
|
+
blocked: WeakSet<PathConfigForStaticNavigation>
|
|
953
|
+
) => {
|
|
954
|
+
const candidates = new Map<string, PathConfigForStaticNavigation[]>();
|
|
955
|
+
|
|
956
|
+
const collect = (
|
|
957
|
+
screens: PathConfigMapForStaticNavigation,
|
|
958
|
+
parentParts: PatternPart[],
|
|
959
|
+
disabled: boolean
|
|
960
|
+
) => {
|
|
961
|
+
for (const config of Object.values(screens)) {
|
|
962
|
+
if (config == null || typeof config === 'string') {
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
const parts =
|
|
967
|
+
typeof config.path === 'string'
|
|
968
|
+
? combinePatternParts(
|
|
969
|
+
parentParts,
|
|
970
|
+
getPatternParts(config.path),
|
|
971
|
+
config.exact
|
|
972
|
+
)
|
|
973
|
+
: parentParts;
|
|
974
|
+
|
|
975
|
+
if (sources.has(config) && typeof config.path === 'string') {
|
|
976
|
+
if (disabled) {
|
|
977
|
+
blocked.add(config);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const pattern = parts.map((part) => part.segment).join('/');
|
|
981
|
+
const entries = candidates.get(pattern) ?? [];
|
|
982
|
+
|
|
983
|
+
entries.push(config);
|
|
984
|
+
candidates.set(pattern, entries);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
if (config.screens) {
|
|
988
|
+
collect(config.screens, parts, disabled || config.shared === false);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
700
991
|
};
|
|
992
|
+
|
|
993
|
+
collect(screens, [], false);
|
|
994
|
+
|
|
995
|
+
for (const entries of candidates.values()) {
|
|
996
|
+
for (const entry of entries) {
|
|
997
|
+
const source = sources.get(entry);
|
|
998
|
+
|
|
999
|
+
if (
|
|
1000
|
+
entry.shared === undefined &&
|
|
1001
|
+
!blocked.has(entry) &&
|
|
1002
|
+
entries.some(
|
|
1003
|
+
(candidate) =>
|
|
1004
|
+
candidate !== entry &&
|
|
1005
|
+
!blocked.has(candidate) &&
|
|
1006
|
+
sources.get(candidate) === source
|
|
1007
|
+
)
|
|
1008
|
+
) {
|
|
1009
|
+
entry.shared = true;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
701
1013
|
};
|
|
702
1014
|
|
|
703
1015
|
/**
|
|
@@ -719,32 +1031,49 @@ type TreeForPathConfig = {
|
|
|
719
1031
|
* };
|
|
720
1032
|
* ```
|
|
721
1033
|
*/
|
|
722
|
-
export function createPathConfigForStaticNavigation(
|
|
1034
|
+
export function createPathConfigForStaticNavigation<ParamList extends {}>(
|
|
723
1035
|
tree: TreeForPathConfig,
|
|
724
1036
|
options?: {
|
|
725
|
-
initialRouteName?: string;
|
|
1037
|
+
initialRouteName?: string | undefined;
|
|
726
1038
|
},
|
|
727
1039
|
auto?: boolean
|
|
728
|
-
): PathConfigMap<
|
|
1040
|
+
): PathConfigMap<ParamList> | undefined {
|
|
729
1041
|
let initialScreenHasPath: boolean = false;
|
|
730
1042
|
let initialScreenConfig: PathConfig<{}> | undefined;
|
|
1043
|
+
let hasEmptyPath = false;
|
|
1044
|
+
|
|
1045
|
+
const blocked = new WeakSet<PathConfigForStaticNavigation>();
|
|
1046
|
+
const sources = new WeakMap<
|
|
1047
|
+
PathConfigForStaticNavigation,
|
|
1048
|
+
ScreenForPathConfig
|
|
1049
|
+
>();
|
|
731
1050
|
|
|
732
1051
|
const createPathConfigForTree = (
|
|
733
1052
|
t: TreeForPathConfig,
|
|
734
|
-
o: { initialRouteName?: string } | undefined,
|
|
1053
|
+
o: { initialRouteName?: string | undefined } | undefined,
|
|
735
1054
|
// If a screen is a leaf node, but inside a screen with path,
|
|
736
1055
|
// It should not be used for initial detection
|
|
737
|
-
skipInitialDetection: boolean
|
|
1056
|
+
skipInitialDetection: boolean,
|
|
1057
|
+
allowAutoEmptyPath: boolean
|
|
738
1058
|
) => {
|
|
1059
|
+
const initialRouteName = o?.initialRouteName ?? t.config.initialRouteName;
|
|
1060
|
+
|
|
1061
|
+
if (initialRouteName != null) {
|
|
1062
|
+
const routeNames = new Set(Object.keys(t.config.screens ?? {}));
|
|
1063
|
+
|
|
1064
|
+
for (const group of Object.values(t.config.groups ?? {})) {
|
|
1065
|
+
Object.keys(group.screens).forEach((name) => routeNames.add(name));
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
if (!routeNames.has(initialRouteName)) {
|
|
1069
|
+
throw new Error(
|
|
1070
|
+
`Couldn't find a screen named '${initialRouteName}' to use as 'initialRouteName'.`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
739
1075
|
const createPathConfigForScreens = (
|
|
740
|
-
screens:
|
|
741
|
-
ParamListBase,
|
|
742
|
-
NavigationState,
|
|
743
|
-
{},
|
|
744
|
-
EventMapBase,
|
|
745
|
-
Record<string, unknown>
|
|
746
|
-
>,
|
|
747
|
-
groupLinking: LinkingForGroup | undefined,
|
|
1076
|
+
screens: Record<string, ScreenForPathConfig>,
|
|
748
1077
|
initialRouteName: string | undefined
|
|
749
1078
|
) => {
|
|
750
1079
|
return Object.fromEntries(
|
|
@@ -763,95 +1092,149 @@ export function createPathConfigForStaticNavigation(
|
|
|
763
1092
|
return 0;
|
|
764
1093
|
})
|
|
765
1094
|
.map(([key, item]) => {
|
|
766
|
-
const screenConfig:
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
1095
|
+
const screenConfig: PathConfigForStaticNavigation = {};
|
|
1096
|
+
|
|
1097
|
+
sources.set(
|
|
1098
|
+
screenConfig,
|
|
1099
|
+
typeof item === 'object' &&
|
|
1100
|
+
'screen' in item &&
|
|
1101
|
+
!hasPropertyGetter(item, 'screen')
|
|
1102
|
+
? item.screen
|
|
1103
|
+
: item
|
|
1104
|
+
);
|
|
1105
|
+
|
|
1106
|
+
const normalizePath = (path: string) =>
|
|
1107
|
+
path.replace(/^\/+|\/+$/g, '');
|
|
1108
|
+
|
|
1109
|
+
if ('linking' in item && item.linking !== undefined) {
|
|
779
1110
|
if (typeof item.linking === 'string') {
|
|
780
1111
|
screenConfig.path = item.linking;
|
|
781
|
-
} else
|
|
782
|
-
|
|
1112
|
+
} else if (
|
|
1113
|
+
item.linking != null &&
|
|
1114
|
+
typeof item.linking === 'object'
|
|
1115
|
+
) {
|
|
1116
|
+
Object.assign(screenConfig, { ...item.linking });
|
|
783
1117
|
}
|
|
784
1118
|
}
|
|
785
1119
|
|
|
786
|
-
if (
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
...screenConfig.parse,
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
if (groupLinking?.stringify != null) {
|
|
795
|
-
screenConfig.stringify = {
|
|
796
|
-
...groupLinking.stringify,
|
|
797
|
-
...screenConfig.stringify,
|
|
798
|
-
};
|
|
799
|
-
}
|
|
1120
|
+
if (screenConfig.exact && screenConfig.path == null) {
|
|
1121
|
+
throw new Error(
|
|
1122
|
+
"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: ''`."
|
|
1123
|
+
);
|
|
800
1124
|
}
|
|
801
1125
|
|
|
802
1126
|
if (typeof screenConfig.path === 'string') {
|
|
803
1127
|
screenConfig.path = normalizePath(screenConfig.path);
|
|
804
1128
|
}
|
|
805
1129
|
|
|
1130
|
+
if (screenConfig.alias != null) {
|
|
1131
|
+
screenConfig.alias = screenConfig.alias.map((alias) => {
|
|
1132
|
+
if (typeof alias === 'string') {
|
|
1133
|
+
return normalizePath(alias);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
return {
|
|
1137
|
+
...alias,
|
|
1138
|
+
path: normalizePath(alias.path),
|
|
1139
|
+
};
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
|
|
806
1143
|
let screens;
|
|
807
1144
|
|
|
1145
|
+
const hasExplicitScreens =
|
|
1146
|
+
'screens' in screenConfig && screenConfig.screens != null;
|
|
1147
|
+
const hasDisabledLinking =
|
|
1148
|
+
'linking' in item && item.linking === null;
|
|
1149
|
+
const childOptions =
|
|
1150
|
+
'initialRouteName' in screenConfig &&
|
|
1151
|
+
typeof screenConfig.initialRouteName === 'string'
|
|
1152
|
+
? { initialRouteName: screenConfig.initialRouteName }
|
|
1153
|
+
: undefined;
|
|
1154
|
+
|
|
1155
|
+
if (
|
|
1156
|
+
hasExplicitScreens &&
|
|
1157
|
+
childOptions != null &&
|
|
1158
|
+
!Object.keys(screenConfig.screens ?? {}).includes(
|
|
1159
|
+
childOptions.initialRouteName
|
|
1160
|
+
)
|
|
1161
|
+
) {
|
|
1162
|
+
throw new Error(
|
|
1163
|
+
`Couldn't find a screen named '${childOptions.initialRouteName}' to use as 'initialRouteName'.`
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
808
1167
|
const skipInitialDetectionInChild =
|
|
809
1168
|
skipInitialDetection ||
|
|
810
1169
|
(screenConfig.path != null && screenConfig.path !== '');
|
|
1170
|
+
const allowAutoEmptyPathInChild =
|
|
1171
|
+
allowAutoEmptyPath &&
|
|
1172
|
+
(initialRouteName == null || key === initialRouteName);
|
|
811
1173
|
|
|
812
|
-
if (
|
|
1174
|
+
if (
|
|
1175
|
+
!hasExplicitScreens &&
|
|
1176
|
+
!hasDisabledLinking &&
|
|
1177
|
+
'config' in item
|
|
1178
|
+
) {
|
|
813
1179
|
screens = createPathConfigForTree(
|
|
814
1180
|
item,
|
|
815
|
-
|
|
816
|
-
skipInitialDetectionInChild
|
|
1181
|
+
childOptions,
|
|
1182
|
+
skipInitialDetectionInChild,
|
|
1183
|
+
allowAutoEmptyPathInChild
|
|
817
1184
|
);
|
|
818
1185
|
} else if (
|
|
1186
|
+
!hasExplicitScreens &&
|
|
1187
|
+
!hasDisabledLinking &&
|
|
819
1188
|
'screen' in item &&
|
|
1189
|
+
!hasPropertyGetter(item, 'screen') &&
|
|
820
1190
|
'config' in item.screen &&
|
|
821
1191
|
(item.screen.config.screens || item.screen.config.groups)
|
|
822
1192
|
) {
|
|
823
1193
|
screens = createPathConfigForTree(
|
|
824
1194
|
item.screen,
|
|
825
|
-
|
|
826
|
-
skipInitialDetectionInChild
|
|
1195
|
+
childOptions,
|
|
1196
|
+
skipInitialDetectionInChild,
|
|
1197
|
+
allowAutoEmptyPathInChild
|
|
827
1198
|
);
|
|
828
1199
|
}
|
|
829
1200
|
|
|
830
1201
|
if (screens) {
|
|
831
|
-
// @ts-expect-error - we can't type this properly
|
|
832
1202
|
screenConfig.screens = screens;
|
|
833
1203
|
}
|
|
834
1204
|
|
|
835
1205
|
if (
|
|
836
1206
|
auto &&
|
|
837
1207
|
!('screens' in screenConfig && screenConfig.screens) &&
|
|
838
|
-
// Skip generating path for screens that specify linking config as `
|
|
839
|
-
!
|
|
1208
|
+
// Skip generating path for screens that specify linking config as `null` explicitly
|
|
1209
|
+
!hasDisabledLinking
|
|
840
1210
|
) {
|
|
841
1211
|
if (screenConfig.path != null) {
|
|
842
1212
|
if (!skipInitialDetection) {
|
|
843
|
-
if (
|
|
844
|
-
initialScreenHasPath = true;
|
|
845
|
-
} else if (screenConfig.path === '') {
|
|
1213
|
+
if (screenConfig.path === '') {
|
|
846
1214
|
// We encounter a leaf screen with empty path,
|
|
847
1215
|
// Clear the initial screen config as it's not needed anymore
|
|
848
1216
|
initialScreenConfig = undefined;
|
|
1217
|
+
hasEmptyPath = true;
|
|
1218
|
+
|
|
1219
|
+
if (allowAutoEmptyPath && key === initialRouteName) {
|
|
1220
|
+
initialScreenHasPath = true;
|
|
1221
|
+
}
|
|
1222
|
+
} else if (
|
|
1223
|
+
allowAutoEmptyPath &&
|
|
1224
|
+
key === initialRouteName &&
|
|
1225
|
+
// Keep an already discovered fallback unless the initial route
|
|
1226
|
+
// explicitly uses an empty path.
|
|
1227
|
+
initialScreenConfig == null
|
|
1228
|
+
) {
|
|
1229
|
+
initialScreenHasPath = true;
|
|
849
1230
|
}
|
|
850
1231
|
}
|
|
851
1232
|
} else {
|
|
852
1233
|
if (
|
|
853
|
-
!groupPath &&
|
|
854
1234
|
!skipInitialDetection &&
|
|
1235
|
+
allowAutoEmptyPath &&
|
|
1236
|
+
(initialRouteName == null || key === initialRouteName) &&
|
|
1237
|
+
!hasEmptyPath &&
|
|
855
1238
|
initialScreenConfig == null
|
|
856
1239
|
) {
|
|
857
1240
|
initialScreenConfig = screenConfig;
|
|
@@ -859,8 +1242,8 @@ export function createPathConfigForStaticNavigation(
|
|
|
859
1242
|
|
|
860
1243
|
screenConfig.path = normalizePath(
|
|
861
1244
|
key
|
|
862
|
-
.replace(/([A-Z]
|
|
863
|
-
.replace(
|
|
1245
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
1246
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
|
|
864
1247
|
.toLowerCase()
|
|
865
1248
|
);
|
|
866
1249
|
}
|
|
@@ -872,7 +1255,7 @@ export function createPathConfigForStaticNavigation(
|
|
|
872
1255
|
);
|
|
873
1256
|
};
|
|
874
1257
|
|
|
875
|
-
const screens = {};
|
|
1258
|
+
const screens: PathConfigMapForStaticNavigation = {};
|
|
876
1259
|
|
|
877
1260
|
// Loop through the config to find screens and groups
|
|
878
1261
|
// So we add the screens and groups in the same order as they are defined
|
|
@@ -882,7 +1265,6 @@ export function createPathConfigForStaticNavigation(
|
|
|
882
1265
|
screens,
|
|
883
1266
|
createPathConfigForScreens(
|
|
884
1267
|
t.config.screens,
|
|
885
|
-
undefined,
|
|
886
1268
|
o?.initialRouteName ?? t.config.initialRouteName
|
|
887
1269
|
)
|
|
888
1270
|
);
|
|
@@ -894,7 +1276,6 @@ export function createPathConfigForStaticNavigation(
|
|
|
894
1276
|
screens,
|
|
895
1277
|
createPathConfigForScreens(
|
|
896
1278
|
group.screens,
|
|
897
|
-
group.linking,
|
|
898
1279
|
o?.initialRouteName ?? t.config.initialRouteName
|
|
899
1280
|
)
|
|
900
1281
|
);
|
|
@@ -909,11 +1290,17 @@ export function createPathConfigForStaticNavigation(
|
|
|
909
1290
|
return screens;
|
|
910
1291
|
};
|
|
911
1292
|
|
|
912
|
-
const screens = createPathConfigForTree(tree, options, false);
|
|
1293
|
+
const screens = createPathConfigForTree(tree, options, false, true);
|
|
913
1294
|
|
|
914
1295
|
if (auto && initialScreenConfig && !initialScreenHasPath) {
|
|
915
1296
|
initialScreenConfig.path = '';
|
|
916
1297
|
}
|
|
917
1298
|
|
|
918
|
-
|
|
1299
|
+
if (!screens) {
|
|
1300
|
+
return undefined;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
markSharedPathConfigs(screens, sources, blocked);
|
|
1304
|
+
|
|
1305
|
+
return screens as PathConfigMap<ParamList>;
|
|
919
1306
|
}
|