@react-navigation/core 7.0.0-rc.13 → 7.0.0-rc.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/BaseNavigationContainer.js +1 -1
- package/lib/commonjs/BaseNavigationContainer.js.map +1 -1
- package/lib/commonjs/getPathFromState.js +10 -3
- package/lib/commonjs/getPathFromState.js.map +1 -1
- package/lib/commonjs/getStateFromPath.js +82 -45
- package/lib/commonjs/getStateFromPath.js.map +1 -1
- package/lib/module/BaseNavigationContainer.js +1 -1
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/getPathFromState.js +10 -3
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getStateFromPath.js +82 -45
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/typescript/commonjs/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/commonjs/tsconfig.build.tsbuildinfo +1 -1
- package/lib/typescript/module/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/module/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/module/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/BaseNavigationContainer.tsx +1 -1
- package/src/getPathFromState.tsx +20 -4
- package/src/getStateFromPath.tsx +124 -63
package/src/getPathFromState.tsx
CHANGED
|
@@ -37,6 +37,25 @@ const getActiveRoute = (state: State): { name: string; params?: object } => {
|
|
|
37
37
|
return route;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
const cachedNormalizedConfigs = new WeakMap<
|
|
41
|
+
PathConfigMap<{}>,
|
|
42
|
+
Record<string, ConfigItem>
|
|
43
|
+
>();
|
|
44
|
+
|
|
45
|
+
const getNormalizedConfigs = (options?: Options<{}>) => {
|
|
46
|
+
if (!options?.screens) return {};
|
|
47
|
+
|
|
48
|
+
const cached = cachedNormalizedConfigs.get(options?.screens);
|
|
49
|
+
|
|
50
|
+
if (cached) return cached;
|
|
51
|
+
|
|
52
|
+
const normalizedConfigs = createNormalizedConfigs(options.screens);
|
|
53
|
+
|
|
54
|
+
cachedNormalizedConfigs.set(options.screens, normalizedConfigs);
|
|
55
|
+
|
|
56
|
+
return normalizedConfigs;
|
|
57
|
+
};
|
|
58
|
+
|
|
40
59
|
/**
|
|
41
60
|
* Utility to serialize a navigation state object to a path string.
|
|
42
61
|
*
|
|
@@ -80,10 +99,7 @@ export function getPathFromState<ParamList extends {}>(
|
|
|
80
99
|
validatePathConfig(options);
|
|
81
100
|
}
|
|
82
101
|
|
|
83
|
-
|
|
84
|
-
const configs: Record<string, ConfigItem> = options?.screens
|
|
85
|
-
? createNormalizedConfigs(options?.screens)
|
|
86
|
-
: {};
|
|
102
|
+
const configs = getNormalizedConfigs(options);
|
|
87
103
|
|
|
88
104
|
let path = '/';
|
|
89
105
|
let current: State | undefined = state;
|
package/src/getStateFromPath.tsx
CHANGED
|
@@ -42,6 +42,12 @@ type ParsedRoute = {
|
|
|
42
42
|
params?: Record<string, any> | undefined;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
type ConfigResources = {
|
|
46
|
+
initialRoutes: InitialRouteConfig[];
|
|
47
|
+
configs: RouteConfig[];
|
|
48
|
+
configWithRegexes: RouteConfig[];
|
|
49
|
+
};
|
|
50
|
+
|
|
45
51
|
/**
|
|
46
52
|
* Utility to parse a path string to initial state object accepted by the container.
|
|
47
53
|
* This is useful for deep linking when we need to handle the incoming URL.
|
|
@@ -67,18 +73,8 @@ export function getStateFromPath<ParamList extends {}>(
|
|
|
67
73
|
path: string,
|
|
68
74
|
options?: Options<ParamList>
|
|
69
75
|
): ResultState | undefined {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const initialRoutes: InitialRouteConfig[] = [];
|
|
75
|
-
|
|
76
|
-
if (options?.initialRouteName) {
|
|
77
|
-
initialRoutes.push({
|
|
78
|
-
initialRouteName: options.initialRouteName,
|
|
79
|
-
parentScreens: [],
|
|
80
|
-
});
|
|
81
|
-
}
|
|
76
|
+
const { initialRoutes, configs, configWithRegexes } =
|
|
77
|
+
getConfigResources(options);
|
|
82
78
|
|
|
83
79
|
const screens = options?.screens;
|
|
84
80
|
|
|
@@ -122,8 +118,114 @@ export function getStateFromPath<ParamList extends {}>(
|
|
|
122
118
|
return undefined;
|
|
123
119
|
}
|
|
124
120
|
|
|
121
|
+
if (remaining === '/') {
|
|
122
|
+
// We need to add special handling of empty path so navigation to empty path also works
|
|
123
|
+
// When handling empty path, we should only look at the root level config
|
|
124
|
+
const match = configs.find(
|
|
125
|
+
(config) =>
|
|
126
|
+
config.path === '' &&
|
|
127
|
+
config.routeNames.every(
|
|
128
|
+
// Make sure that none of the parent configs have a non-empty path defined
|
|
129
|
+
(name) => !configs.find((c) => c.screen === name)?.path
|
|
130
|
+
)
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
if (match) {
|
|
134
|
+
return createNestedStateObject(
|
|
135
|
+
path,
|
|
136
|
+
match.routeNames.map((name) => ({ name })),
|
|
137
|
+
initialRoutes,
|
|
138
|
+
configs
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let result: PartialState<NavigationState> | undefined;
|
|
146
|
+
let current: PartialState<NavigationState> | undefined;
|
|
147
|
+
|
|
148
|
+
// We match the whole path against the regex instead of segments
|
|
149
|
+
// This makes sure matches such as wildcard will catch any unmatched routes, even if nested
|
|
150
|
+
const { routes, remainingPath } = matchAgainstConfigs(
|
|
151
|
+
remaining,
|
|
152
|
+
configWithRegexes
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
if (routes !== undefined) {
|
|
156
|
+
// This will always be empty if full path matched
|
|
157
|
+
current = createNestedStateObject(path, routes, initialRoutes, configs);
|
|
158
|
+
remaining = remainingPath;
|
|
159
|
+
result = current;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (current == null || result == null) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Reference to the last used config resources. This is used to avoid recomputing the config resources when the options are the same.
|
|
171
|
+
*/
|
|
172
|
+
const cachedConfigResources = new WeakMap<Options<{}>, ConfigResources>();
|
|
173
|
+
|
|
174
|
+
function getConfigResources<ParamList extends {}>(
|
|
175
|
+
options: Options<ParamList> | undefined
|
|
176
|
+
) {
|
|
177
|
+
if (!options) return prepareConfigResources();
|
|
178
|
+
|
|
179
|
+
const cached = cachedConfigResources.get(options);
|
|
180
|
+
|
|
181
|
+
if (cached) return cached;
|
|
182
|
+
|
|
183
|
+
const resources = prepareConfigResources(options);
|
|
184
|
+
|
|
185
|
+
cachedConfigResources.set(options, resources);
|
|
186
|
+
|
|
187
|
+
return resources;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function prepareConfigResources(options?: Options<{}>) {
|
|
191
|
+
if (options) {
|
|
192
|
+
validatePathConfig(options);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const initialRoutes = getInitialRoutes(options);
|
|
196
|
+
|
|
197
|
+
const configs = getNormalizedConfigs(initialRoutes, options?.screens);
|
|
198
|
+
|
|
199
|
+
checkForDuplicatedConfigs(configs);
|
|
200
|
+
|
|
201
|
+
const configWithRegexes = getConfigsWithRegexes(configs);
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
initialRoutes,
|
|
205
|
+
configs,
|
|
206
|
+
configWithRegexes,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getInitialRoutes(options?: Options<{}>) {
|
|
211
|
+
const initialRoutes: InitialRouteConfig[] = [];
|
|
212
|
+
|
|
213
|
+
if (options?.initialRouteName) {
|
|
214
|
+
initialRoutes.push({
|
|
215
|
+
initialRouteName: options.initialRouteName,
|
|
216
|
+
parentScreens: [],
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return initialRoutes;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function getNormalizedConfigs(
|
|
224
|
+
initialRoutes: InitialRouteConfig[],
|
|
225
|
+
screens: PathConfigMap<object> = {}
|
|
226
|
+
) {
|
|
125
227
|
// Create a normalized configs array which will be easier to use
|
|
126
|
-
|
|
228
|
+
return ([] as RouteConfig[])
|
|
127
229
|
.concat(
|
|
128
230
|
...Object.keys(screens).map((key) =>
|
|
129
231
|
createNormalizedConfigs(
|
|
@@ -185,7 +287,9 @@ export function getStateFromPath<ParamList extends {}>(
|
|
|
185
287
|
}
|
|
186
288
|
return bParts.length - aParts.length;
|
|
187
289
|
});
|
|
290
|
+
}
|
|
188
291
|
|
|
292
|
+
function checkForDuplicatedConfigs(configs: RouteConfig[]) {
|
|
189
293
|
// Check for duplicate patterns in the config
|
|
190
294
|
configs.reduce<Record<string, RouteConfig>>((acc, config) => {
|
|
191
295
|
if (acc[config.pattern]) {
|
|
@@ -214,57 +318,14 @@ export function getStateFromPath<ParamList extends {}>(
|
|
|
214
318
|
[config.pattern]: config,
|
|
215
319
|
});
|
|
216
320
|
}, {});
|
|
321
|
+
}
|
|
217
322
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
config.routeNames.every(
|
|
225
|
-
// Make sure that none of the parent configs have a non-empty path defined
|
|
226
|
-
(name) => !configs.find((c) => c.screen === name)?.path
|
|
227
|
-
)
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
if (match) {
|
|
231
|
-
return createNestedStateObject(
|
|
232
|
-
path,
|
|
233
|
-
match.routeNames.map((name) => ({ name })),
|
|
234
|
-
initialRoutes,
|
|
235
|
-
configs
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return undefined;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let result: PartialState<NavigationState> | undefined;
|
|
243
|
-
let current: PartialState<NavigationState> | undefined;
|
|
244
|
-
|
|
245
|
-
// We match the whole path against the regex instead of segments
|
|
246
|
-
// This makes sure matches such as wildcard will catch any unmatched routes, even if nested
|
|
247
|
-
const { routes, remainingPath } = matchAgainstConfigs(
|
|
248
|
-
remaining,
|
|
249
|
-
configs.map((c) => ({
|
|
250
|
-
...c,
|
|
251
|
-
// Add `$` to the regex to make sure it matches till end of the path and not just beginning
|
|
252
|
-
regex: c.regex ? new RegExp(c.regex.source + '$') : undefined,
|
|
253
|
-
}))
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
if (routes !== undefined) {
|
|
257
|
-
// This will always be empty if full path matched
|
|
258
|
-
current = createNestedStateObject(path, routes, initialRoutes, configs);
|
|
259
|
-
remaining = remainingPath;
|
|
260
|
-
result = current;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (current == null || result == null) {
|
|
264
|
-
return undefined;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return result;
|
|
323
|
+
function getConfigsWithRegexes(configs: RouteConfig[]) {
|
|
324
|
+
return configs.map((c) => ({
|
|
325
|
+
...c,
|
|
326
|
+
// Add `$` to the regex to make sure it matches till end of the path and not just beginning
|
|
327
|
+
regex: c.regex ? new RegExp(c.regex.source + '$') : undefined,
|
|
328
|
+
}));
|
|
268
329
|
}
|
|
269
330
|
|
|
270
331
|
const joinPaths = (...paths: string[]): string =>
|