@react-navigation/core 8.0.0-alpha.4 → 8.0.0-alpha.41
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 +173 -90
- 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 +37 -12
- 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 +29 -57
- 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 +35 -27
- 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 +3 -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 +4 -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 +459 -332
- 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 +59 -21
- package/src/NavigationRootContext.tsx +11 -0
- package/src/NavigationStateContext.tsx +6 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +55 -56
- package/src/SceneView.tsx +31 -57
- 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 +44 -30
- 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/getPathFromState.tsx
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import {
|
|
1
|
+
import type { NavigationState, PartialState } from '@react-navigation/routers';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
combinePatternParts,
|
|
5
|
+
getPatternParts,
|
|
6
|
+
type PatternPart,
|
|
7
|
+
} from './getPatternParts';
|
|
8
|
+
import { getStateFromRouteParams } from './getStateFromRouteParams';
|
|
9
|
+
import * as queryString from './queryString';
|
|
9
10
|
import type { PathConfig, PathConfigMap } from './types';
|
|
10
11
|
import { validatePathConfig } from './validatePathConfig';
|
|
11
12
|
|
|
12
13
|
type Options<ParamList extends {}> = {
|
|
13
|
-
path?: string;
|
|
14
|
-
initialRouteName?: string;
|
|
14
|
+
path?: string | undefined;
|
|
15
|
+
initialRouteName?: string | undefined;
|
|
15
16
|
screens: PathConfigMap<ParamList>;
|
|
16
17
|
};
|
|
17
18
|
|
|
@@ -19,40 +20,87 @@ type State = NavigationState | Omit<PartialState<NavigationState>, 'stale'>;
|
|
|
19
20
|
|
|
20
21
|
type StringifyConfig = Record<string, ((value: unknown) => string) | undefined>;
|
|
21
22
|
|
|
23
|
+
type SerializedParamValue = string | string[] | null;
|
|
24
|
+
|
|
22
25
|
type ConfigItem = {
|
|
23
|
-
parts?: PatternPart[];
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
parts?: PatternPart[] | undefined;
|
|
27
|
+
ownParts: PatternPart[];
|
|
28
|
+
stringify?: StringifyConfig | undefined;
|
|
29
|
+
screens?: Record<string, ConfigItem> | undefined;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const serializeParamValue = (value: unknown): SerializedParamValue =>
|
|
33
|
+
value === null
|
|
34
|
+
? null
|
|
35
|
+
: Array.isArray(value)
|
|
36
|
+
? value.map(String)
|
|
37
|
+
: String(value);
|
|
38
|
+
|
|
39
|
+
const encodePathParam = (value: string) => {
|
|
40
|
+
let result = '';
|
|
41
|
+
|
|
42
|
+
for (const char of value) {
|
|
43
|
+
const charCode = char.charCodeAt(0);
|
|
44
|
+
const safe =
|
|
45
|
+
(charCode >= 65 && charCode <= 90) ||
|
|
46
|
+
(charCode >= 97 && charCode <= 122) ||
|
|
47
|
+
(charCode >= 48 && charCode <= 57) ||
|
|
48
|
+
"-._~!$&'()*+,;=:@".includes(char);
|
|
49
|
+
|
|
50
|
+
result += safe ? char : encodeURIComponent(char);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result;
|
|
26
54
|
};
|
|
27
55
|
|
|
28
|
-
const getActiveRoute = (
|
|
56
|
+
const getActiveRoute = (
|
|
57
|
+
state: State,
|
|
58
|
+
configs: Record<string, ConfigItem> | undefined,
|
|
59
|
+
getRouteState: (
|
|
60
|
+
route: State['routes'][number],
|
|
61
|
+
config: ConfigItem | undefined
|
|
62
|
+
) => State | undefined
|
|
63
|
+
): { name: string; params?: object | undefined } => {
|
|
29
64
|
const route =
|
|
30
65
|
typeof state.index === 'number'
|
|
31
66
|
? state.routes[state.index]
|
|
32
67
|
: state.routes[state.routes.length - 1];
|
|
33
68
|
|
|
34
|
-
if (route
|
|
35
|
-
|
|
69
|
+
if (route == null) {
|
|
70
|
+
throw new Error(`Couldn't find the active route.`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const config = configs?.[route.name];
|
|
74
|
+
const routeState = getRouteState(route, config);
|
|
75
|
+
|
|
76
|
+
if (routeState) {
|
|
77
|
+
return getActiveRoute(routeState, config?.screens, getRouteState);
|
|
36
78
|
}
|
|
37
79
|
|
|
38
80
|
return route;
|
|
39
81
|
};
|
|
40
82
|
|
|
41
83
|
const cachedNormalizedConfigs = new WeakMap<
|
|
42
|
-
|
|
84
|
+
Options<{}>,
|
|
43
85
|
Record<string, ConfigItem>
|
|
44
86
|
>();
|
|
45
87
|
|
|
46
88
|
const getNormalizedConfigs = (options?: Options<{}>) => {
|
|
47
|
-
if (!options
|
|
89
|
+
if (!options) {
|
|
90
|
+
return {};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const cached = cachedNormalizedConfigs.get(options);
|
|
48
94
|
|
|
49
|
-
|
|
95
|
+
if (cached) {
|
|
96
|
+
return cached;
|
|
97
|
+
}
|
|
50
98
|
|
|
51
|
-
|
|
99
|
+
validatePathConfig(options);
|
|
52
100
|
|
|
53
101
|
const normalizedConfigs = createNormalizedConfigs(options.screens);
|
|
54
102
|
|
|
55
|
-
cachedNormalizedConfigs.set(options
|
|
103
|
+
cachedNormalizedConfigs.set(options, normalizedConfigs);
|
|
56
104
|
|
|
57
105
|
return normalizedConfigs;
|
|
58
106
|
};
|
|
@@ -96,105 +144,179 @@ export function getPathFromState<ParamList extends {}>(
|
|
|
96
144
|
);
|
|
97
145
|
}
|
|
98
146
|
|
|
99
|
-
if (options) {
|
|
100
|
-
validatePathConfig(options);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
147
|
const configs = getNormalizedConfigs(options);
|
|
148
|
+
const cachedRouteStates = new Map<object, State | undefined>();
|
|
149
|
+
|
|
150
|
+
const getRouteState = (
|
|
151
|
+
route: State['routes'][number],
|
|
152
|
+
config: ConfigItem | undefined
|
|
153
|
+
) => {
|
|
154
|
+
if (route.state) {
|
|
155
|
+
return route.state;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const hasScreenParams =
|
|
159
|
+
route.params &&
|
|
160
|
+
'screen' in route.params &&
|
|
161
|
+
typeof route.params.screen === 'string' &&
|
|
162
|
+
config?.screens?.[route.params.screen];
|
|
163
|
+
|
|
164
|
+
const hasStateParams =
|
|
165
|
+
route.params && 'state' in route.params && config?.screens;
|
|
166
|
+
|
|
167
|
+
if (
|
|
168
|
+
!route.params ||
|
|
169
|
+
!config?.screens ||
|
|
170
|
+
(!hasScreenParams && !hasStateParams)
|
|
171
|
+
) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!cachedRouteStates.has(route)) {
|
|
176
|
+
cachedRouteStates.set(route, getStateFromRouteParams(route.params));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return cachedRouteStates.get(route);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const focusedRoute = getActiveRoute(state, configs, getRouteState);
|
|
104
183
|
|
|
105
184
|
let path = '/';
|
|
106
185
|
let current: State | undefined = state;
|
|
107
186
|
|
|
108
|
-
const allParams: Record<string, string> = {};
|
|
109
|
-
|
|
110
187
|
while (current) {
|
|
111
|
-
let index = typeof current.index === 'number' ? current.index : 0;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
188
|
+
let index: number = typeof current.index === 'number' ? current.index : 0;
|
|
189
|
+
|
|
190
|
+
const initialRoute: State['routes'][number] | undefined =
|
|
191
|
+
current.routes[index];
|
|
192
|
+
|
|
193
|
+
if (initialRoute == null) {
|
|
194
|
+
throw new Error(`Couldn't find a route at index ${index}.`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let route: State['routes'][number] = initialRoute;
|
|
115
198
|
|
|
116
199
|
let parts: PatternPart[] | undefined;
|
|
117
200
|
|
|
118
|
-
|
|
119
|
-
|
|
201
|
+
// Values for each pattern part object, so the same param name
|
|
202
|
+
// at different nesting levels gets the value from its own level
|
|
203
|
+
const partValues = new Map<PatternPart, SerializedParamValue | undefined>();
|
|
120
204
|
|
|
121
|
-
|
|
205
|
+
let focusedParams: Record<string, SerializedParamValue> | undefined;
|
|
206
|
+
let currentOptions = configs;
|
|
122
207
|
|
|
123
208
|
// Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined
|
|
124
209
|
const nestedRouteNames = [];
|
|
125
210
|
|
|
126
211
|
let hasNext = true;
|
|
127
212
|
|
|
128
|
-
while (
|
|
129
|
-
|
|
213
|
+
while (hasNext) {
|
|
214
|
+
const config = currentOptions[route.name];
|
|
215
|
+
|
|
216
|
+
if (config == null) {
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
parts = config.parts;
|
|
221
|
+
|
|
222
|
+
const ownParts = config.ownParts;
|
|
130
223
|
|
|
131
224
|
nestedRouteNames.push(route.name);
|
|
132
225
|
|
|
133
226
|
if (route.params) {
|
|
134
|
-
const options =
|
|
135
|
-
|
|
136
|
-
const currentParams =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
227
|
+
const options = config;
|
|
228
|
+
const params = route.params as Record<string, unknown>;
|
|
229
|
+
const currentParams: Record<string, SerializedParamValue> = {
|
|
230
|
+
__proto__: null,
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
for (const key in params) {
|
|
234
|
+
const value = params[key];
|
|
235
|
+
|
|
236
|
+
if (value === undefined) {
|
|
237
|
+
let canBeOmitted = false;
|
|
238
|
+
|
|
239
|
+
for (const part of ownParts) {
|
|
240
|
+
if (part.name === key) {
|
|
241
|
+
canBeOmitted = part.optional === true || part.repeat != null;
|
|
242
|
+
break;
|
|
151
243
|
}
|
|
244
|
+
}
|
|
152
245
|
|
|
153
|
-
|
|
246
|
+
if (canBeOmitted) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
154
250
|
|
|
155
|
-
|
|
156
|
-
})
|
|
157
|
-
.filter((entry) => entry != null)
|
|
158
|
-
);
|
|
251
|
+
const stringify = options.stringify?.[key];
|
|
159
252
|
|
|
160
|
-
|
|
161
|
-
|
|
253
|
+
currentParams[key] = stringify
|
|
254
|
+
? stringify(value)
|
|
255
|
+
: serializeParamValue(value);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const claimedParams = new Set<string>();
|
|
259
|
+
|
|
260
|
+
for (const part of ownParts) {
|
|
261
|
+
if (part.name && part.name in currentParams) {
|
|
262
|
+
const value = currentParams[part.name];
|
|
263
|
+
|
|
264
|
+
if (value !== undefined) {
|
|
265
|
+
partValues.set(part, value);
|
|
266
|
+
claimedParams.add(part.name);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
162
269
|
}
|
|
163
270
|
|
|
164
271
|
if (focusedRoute === route) {
|
|
165
272
|
// If this is the focused route, keep the params for later use
|
|
166
273
|
// We save it here since it's been stringified already
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
274
|
+
// Params claimed by the pattern shouldn't be repeated in the query string
|
|
275
|
+
focusedParams = { __proto__: null };
|
|
276
|
+
|
|
277
|
+
for (const key in currentParams) {
|
|
278
|
+
const value = currentParams[key];
|
|
279
|
+
|
|
280
|
+
if (
|
|
281
|
+
!claimedParams.has(key) &&
|
|
282
|
+
value !== undefined &&
|
|
283
|
+
value !== 'undefined'
|
|
284
|
+
) {
|
|
285
|
+
focusedParams[key] = value;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
for (const part of ownParts) {
|
|
292
|
+
if (part.name && !partValues.has(part)) {
|
|
293
|
+
partValues.set(part, undefined);
|
|
180
294
|
}
|
|
181
295
|
}
|
|
182
296
|
|
|
183
297
|
// If there is no `screens` property or no nested state, we return pattern
|
|
184
|
-
|
|
298
|
+
const routeState = getRouteState(route, config);
|
|
299
|
+
|
|
300
|
+
if (!config.screens || routeState == null) {
|
|
185
301
|
hasNext = false;
|
|
186
302
|
} else {
|
|
187
303
|
index =
|
|
188
|
-
typeof
|
|
189
|
-
?
|
|
190
|
-
:
|
|
304
|
+
typeof routeState.index === 'number'
|
|
305
|
+
? routeState.index
|
|
306
|
+
: routeState.routes.length - 1;
|
|
307
|
+
|
|
308
|
+
const nextRoute: State['routes'][number] | undefined =
|
|
309
|
+
routeState.routes[index];
|
|
310
|
+
|
|
311
|
+
if (nextRoute == null) {
|
|
312
|
+
throw new Error(`Couldn't find a route at index ${index}.`);
|
|
313
|
+
}
|
|
191
314
|
|
|
192
|
-
const
|
|
193
|
-
const nestedConfig = currentOptions[route.name].screens;
|
|
315
|
+
const nestedConfig = config.screens;
|
|
194
316
|
|
|
195
317
|
// if there is config for next route name, we go deeper
|
|
196
|
-
if (
|
|
197
|
-
route = nextRoute
|
|
318
|
+
if (nextRoute.name in nestedConfig) {
|
|
319
|
+
route = nextRoute;
|
|
198
320
|
currentOptions = nestedConfig;
|
|
199
321
|
} else {
|
|
200
322
|
// If not, there is no sense in going deeper in config
|
|
@@ -203,70 +325,112 @@ export function getPathFromState<ParamList extends {}>(
|
|
|
203
325
|
}
|
|
204
326
|
}
|
|
205
327
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
328
|
+
const routeState = getRouteState(route, currentOptions[route.name]);
|
|
329
|
+
|
|
330
|
+
if (currentOptions[route.name] != null) {
|
|
331
|
+
if (parts) {
|
|
332
|
+
let index = 0;
|
|
333
|
+
|
|
334
|
+
for (const part of parts) {
|
|
335
|
+
const { segment, name, optional, repeat } = part;
|
|
336
|
+
|
|
337
|
+
if (index > 0) {
|
|
338
|
+
path += '/';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
index++;
|
|
342
|
+
|
|
209
343
|
// We don't know what to show for wildcard patterns
|
|
210
344
|
// Showing the route name seems ok, though whatever we show here will be incorrect
|
|
211
345
|
// Since the page doesn't actually exist
|
|
212
346
|
if (segment === '*') {
|
|
213
|
-
|
|
347
|
+
path += route.name;
|
|
348
|
+
continue;
|
|
214
349
|
}
|
|
215
350
|
|
|
216
351
|
// If the path has a pattern for a param, put the param in the path
|
|
217
|
-
if (
|
|
218
|
-
const value =
|
|
352
|
+
if (name) {
|
|
353
|
+
const value = partValues.get(part);
|
|
219
354
|
|
|
220
355
|
if (value === undefined && optional) {
|
|
221
356
|
// Optional params without value assigned in route.params should be ignored
|
|
222
|
-
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (repeat) {
|
|
361
|
+
if (value === null) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`The path pattern '${segment}' does not allow null for param '${name}'.`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (Array.isArray(value)) {
|
|
368
|
+
throw new Error(
|
|
369
|
+
`The path pattern '${segment}' requires a string for param '${name}'.`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const values =
|
|
374
|
+
value === undefined || value === '' ? [] : value.split('/');
|
|
375
|
+
|
|
376
|
+
if (repeat === 'one-or-more' && values.length === 0) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`The path pattern '${segment}' requires at least one value for param '${name}'.`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (values.some((item) => item.length === 0)) {
|
|
383
|
+
throw new Error(
|
|
384
|
+
`The path pattern '${segment}' does not allow empty values for param '${name}'.`
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (values.length === 0) {
|
|
389
|
+
path = path.replace(/\/$/, '');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
path += values.map(encodePathParam).join('/');
|
|
393
|
+
continue;
|
|
223
394
|
}
|
|
224
395
|
|
|
225
396
|
// Valid characters according to
|
|
226
397
|
// https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 (see pchar definition)
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
/[^A-Za-z0-9\-._~!$&'()*+,;=:@]/g.test(char)
|
|
230
|
-
? encodeURIComponent(char)
|
|
231
|
-
: char
|
|
232
|
-
)
|
|
233
|
-
.join('');
|
|
398
|
+
path += encodePathParam(String(value));
|
|
399
|
+
continue;
|
|
234
400
|
}
|
|
235
401
|
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
|
|
402
|
+
path += encodeURIComponent(segment);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
239
405
|
} else {
|
|
240
406
|
path += encodeURIComponent(route.name);
|
|
241
407
|
}
|
|
242
408
|
|
|
243
409
|
if (!focusedParams && focusedRoute.params) {
|
|
244
|
-
focusedParams =
|
|
245
|
-
Object.entries(focusedRoute.params).map(([key, value]) => [
|
|
246
|
-
key,
|
|
247
|
-
String(value),
|
|
248
|
-
])
|
|
249
|
-
);
|
|
250
|
-
}
|
|
410
|
+
focusedParams = { __proto__: null };
|
|
251
411
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
412
|
+
const params = focusedRoute.params as Record<string, unknown>;
|
|
413
|
+
|
|
414
|
+
for (const key in params) {
|
|
415
|
+
const value = serializeParamValue(params[key]);
|
|
416
|
+
|
|
417
|
+
if (value !== 'undefined') {
|
|
418
|
+
focusedParams[key] = value;
|
|
259
419
|
}
|
|
260
420
|
}
|
|
421
|
+
}
|
|
261
422
|
|
|
262
|
-
|
|
423
|
+
if (routeState) {
|
|
424
|
+
path += '/';
|
|
425
|
+
} else if (focusedParams) {
|
|
426
|
+
const query = queryString.stringify(focusedParams);
|
|
263
427
|
|
|
264
428
|
if (query) {
|
|
265
429
|
path += `?${query}`;
|
|
266
430
|
}
|
|
267
431
|
}
|
|
268
432
|
|
|
269
|
-
current =
|
|
433
|
+
current = routeState;
|
|
270
434
|
}
|
|
271
435
|
|
|
272
436
|
// Include the root path if specified
|
|
@@ -275,8 +439,13 @@ export function getPathFromState<ParamList extends {}>(
|
|
|
275
439
|
}
|
|
276
440
|
|
|
277
441
|
// Remove multiple as well as trailing slashes
|
|
278
|
-
|
|
279
|
-
|
|
442
|
+
if (path.includes('//')) {
|
|
443
|
+
path = path.replace(/\/+/g, '/');
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (path.length > 1 && path.endsWith('/')) {
|
|
447
|
+
path = path.slice(0, -1);
|
|
448
|
+
}
|
|
280
449
|
|
|
281
450
|
// If path doesn't start with a slash, add it
|
|
282
451
|
// This makes sure that history.pushState will update the path correctly instead of appending
|
|
@@ -292,14 +461,16 @@ const createConfigItem = (
|
|
|
292
461
|
parentParts?: PatternPart[]
|
|
293
462
|
): ConfigItem => {
|
|
294
463
|
if (typeof config === 'string') {
|
|
295
|
-
|
|
296
|
-
const parts = getPatternParts(config);
|
|
464
|
+
const ownParts = getPatternParts(config);
|
|
297
465
|
|
|
298
466
|
if (parentParts) {
|
|
299
|
-
return {
|
|
467
|
+
return {
|
|
468
|
+
parts: combinePatternParts(parentParts, ownParts),
|
|
469
|
+
ownParts,
|
|
470
|
+
};
|
|
300
471
|
}
|
|
301
472
|
|
|
302
|
-
return { parts };
|
|
473
|
+
return { parts: ownParts, ownParts };
|
|
303
474
|
}
|
|
304
475
|
|
|
305
476
|
if (config.exact && config.path === undefined) {
|
|
@@ -310,14 +481,12 @@ const createConfigItem = (
|
|
|
310
481
|
|
|
311
482
|
// If an object is specified as the value (e.g. Foo: { ... }),
|
|
312
483
|
// It can have `path` property and `screens` prop which has nested configs
|
|
484
|
+
const ownParts = config.path ? getPatternParts(config.path) : [];
|
|
313
485
|
const parts =
|
|
314
486
|
config.exact !== true
|
|
315
|
-
? [
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
]
|
|
319
|
-
: config.path
|
|
320
|
-
? getPatternParts(config.path)
|
|
487
|
+
? combinePatternParts(parentParts || [], ownParts)
|
|
488
|
+
: ownParts.length
|
|
489
|
+
? ownParts
|
|
321
490
|
: undefined;
|
|
322
491
|
|
|
323
492
|
const screens =
|
|
@@ -327,6 +496,7 @@ const createConfigItem = (
|
|
|
327
496
|
|
|
328
497
|
return {
|
|
329
498
|
parts,
|
|
499
|
+
ownParts,
|
|
330
500
|
stringify: config.stringify,
|
|
331
501
|
screens,
|
|
332
502
|
};
|
|
@@ -335,11 +505,17 @@ const createConfigItem = (
|
|
|
335
505
|
const createNormalizedConfigs = (
|
|
336
506
|
options: PathConfigMap<object>,
|
|
337
507
|
parts?: PatternPart[]
|
|
338
|
-
): Record<string, ConfigItem> =>
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
508
|
+
): Record<string, ConfigItem> => {
|
|
509
|
+
const configs: Record<string, ConfigItem> = {};
|
|
510
|
+
const screens = options as Record<string, PathConfig<{}> | string>;
|
|
511
|
+
|
|
512
|
+
for (const name in screens) {
|
|
513
|
+
const config = screens[name];
|
|
514
|
+
|
|
515
|
+
if (config !== undefined) {
|
|
516
|
+
configs[name] = createConfigItem(config, parts);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return configs;
|
|
521
|
+
};
|