@react-navigation/core 7.0.0-rc.12 → 7.0.0-rc.14
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 +5 -1
- package/lib/commonjs/getPathFromState.js.map +1 -1
- package/lib/commonjs/getStateFromPath.js +80 -45
- package/lib/commonjs/getStateFromPath.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/module/BaseNavigationContainer.js +1 -1
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/getPathFromState.js +5 -1
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getStateFromPath.js +80 -45
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/types.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/src/types.d.ts +21 -14
- package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/useDescriptors.d.ts +18 -18
- package/lib/typescript/commonjs/src/useNavigationBuilder.d.ts +28 -28
- package/lib/typescript/commonjs/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/useNavigationCache.d.ts +9 -9
- package/lib/typescript/commonjs/src/useNavigationHelpers.d.ts +9 -9
- 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/src/types.d.ts +21 -14
- package/lib/typescript/module/src/types.d.ts.map +1 -1
- package/lib/typescript/module/src/useDescriptors.d.ts +18 -18
- package/lib/typescript/module/src/useNavigationBuilder.d.ts +28 -28
- package/lib/typescript/module/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/module/src/useNavigationCache.d.ts +9 -9
- package/lib/typescript/module/src/useNavigationHelpers.d.ts +9 -9
- package/lib/typescript/module/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/BaseNavigationContainer.tsx +1 -1
- package/src/getPathFromState.tsx +12 -3
- package/src/getStateFromPath.tsx +121 -63
- package/src/types.tsx +33 -46
- package/src/useNavigationBuilder.tsx +1 -1
package/src/getPathFromState.tsx
CHANGED
|
@@ -37,6 +37,11 @@ const getActiveRoute = (state: State): { name: string; params?: object } => {
|
|
|
37
37
|
return route;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
let cachedNormalizedConfigs: [
|
|
41
|
+
PathConfigMap<{}> | undefined,
|
|
42
|
+
Record<string, ConfigItem>,
|
|
43
|
+
] = [undefined, {}];
|
|
44
|
+
|
|
40
45
|
/**
|
|
41
46
|
* Utility to serialize a navigation state object to a path string.
|
|
42
47
|
*
|
|
@@ -81,9 +86,13 @@ export function getPathFromState<ParamList extends {}>(
|
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
// Create a normalized configs object which will be easier to use
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
if (cachedNormalizedConfigs[0] !== options?.screens) {
|
|
90
|
+
cachedNormalizedConfigs = [
|
|
91
|
+
options?.screens,
|
|
92
|
+
options?.screens ? createNormalizedConfigs(options.screens) : {},
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
const configs: Record<string, ConfigItem> = cachedNormalizedConfigs[1];
|
|
87
96
|
|
|
88
97
|
let path = '/';
|
|
89
98
|
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,111 @@ 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
|
+
let cachedConfigResources: [Options<{}> | undefined, ConfigResources] = [
|
|
173
|
+
undefined,
|
|
174
|
+
prepareConfigResources(),
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
function getConfigResources<ParamList extends {}>(
|
|
178
|
+
options: Options<ParamList> | undefined
|
|
179
|
+
) {
|
|
180
|
+
if (cachedConfigResources[0] !== options) {
|
|
181
|
+
cachedConfigResources = [options, prepareConfigResources(options)];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return cachedConfigResources[1];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function prepareConfigResources(options?: Options<{}>) {
|
|
188
|
+
if (options) {
|
|
189
|
+
validatePathConfig(options);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const initialRoutes = getInitialRoutes(options);
|
|
193
|
+
|
|
194
|
+
const configs = getNormalizedConfigs(initialRoutes, options?.screens);
|
|
195
|
+
|
|
196
|
+
checkForDuplicatedConfigs(configs);
|
|
197
|
+
|
|
198
|
+
const configWithRegexes = getConfigsWithRegexes(configs);
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
initialRoutes,
|
|
202
|
+
configs,
|
|
203
|
+
configWithRegexes,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function getInitialRoutes(options?: Options<{}>) {
|
|
208
|
+
const initialRoutes: InitialRouteConfig[] = [];
|
|
209
|
+
|
|
210
|
+
if (options?.initialRouteName) {
|
|
211
|
+
initialRoutes.push({
|
|
212
|
+
initialRouteName: options.initialRouteName,
|
|
213
|
+
parentScreens: [],
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return initialRoutes;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function getNormalizedConfigs(
|
|
221
|
+
initialRoutes: InitialRouteConfig[],
|
|
222
|
+
screens: PathConfigMap<object> = {}
|
|
223
|
+
) {
|
|
125
224
|
// Create a normalized configs array which will be easier to use
|
|
126
|
-
|
|
225
|
+
return ([] as RouteConfig[])
|
|
127
226
|
.concat(
|
|
128
227
|
...Object.keys(screens).map((key) =>
|
|
129
228
|
createNormalizedConfigs(
|
|
@@ -185,7 +284,9 @@ export function getStateFromPath<ParamList extends {}>(
|
|
|
185
284
|
}
|
|
186
285
|
return bParts.length - aParts.length;
|
|
187
286
|
});
|
|
287
|
+
}
|
|
188
288
|
|
|
289
|
+
function checkForDuplicatedConfigs(configs: RouteConfig[]) {
|
|
189
290
|
// Check for duplicate patterns in the config
|
|
190
291
|
configs.reduce<Record<string, RouteConfig>>((acc, config) => {
|
|
191
292
|
if (acc[config.pattern]) {
|
|
@@ -214,57 +315,14 @@ export function getStateFromPath<ParamList extends {}>(
|
|
|
214
315
|
[config.pattern]: config,
|
|
215
316
|
});
|
|
216
317
|
}, {});
|
|
318
|
+
}
|
|
217
319
|
|
|
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;
|
|
320
|
+
function getConfigsWithRegexes(configs: RouteConfig[]) {
|
|
321
|
+
return configs.map((c) => ({
|
|
322
|
+
...c,
|
|
323
|
+
// Add `$` to the regex to make sure it matches till end of the path and not just beginning
|
|
324
|
+
regex: c.regex ? new RegExp(c.regex.source + '$') : undefined,
|
|
325
|
+
}));
|
|
268
326
|
}
|
|
269
327
|
|
|
270
328
|
const joinPaths = (...paths: string[]): string =>
|
package/src/types.tsx
CHANGED
|
@@ -22,6 +22,21 @@ declare global {
|
|
|
22
22
|
|
|
23
23
|
type Keyof<T extends {}> = Extract<keyof T, string>;
|
|
24
24
|
|
|
25
|
+
type ScreenParamsPair<
|
|
26
|
+
ParamList extends ParamListBase,
|
|
27
|
+
RouteName extends keyof ParamList,
|
|
28
|
+
> = {
|
|
29
|
+
// First we use a mapped type to get an union of screen & params pairs
|
|
30
|
+
// Then we pick the pair which matches the RouteName
|
|
31
|
+
// Mapped type is used instead of just ParamList[RouteName]
|
|
32
|
+
// Otherwise it'll result in union of all params leading to incorrect types
|
|
33
|
+
[Screen in keyof ParamList]: undefined extends ParamList[Screen] // Params are either undefined or a union with undefined
|
|
34
|
+
?
|
|
35
|
+
| [screen: Screen] // if the params are optional, we don't have to provide it
|
|
36
|
+
| [screen: Screen, params: ParamList[Screen]]
|
|
37
|
+
: [screen: Screen, params: ParamList[Screen]];
|
|
38
|
+
}[RouteName];
|
|
39
|
+
|
|
25
40
|
export type DefaultNavigatorOptions<
|
|
26
41
|
ParamList extends ParamListBase,
|
|
27
42
|
NavigatorID extends string | undefined,
|
|
@@ -239,18 +254,7 @@ type NavigationHelpersCommon<
|
|
|
239
254
|
* @param [params] Params object for the route.
|
|
240
255
|
*/
|
|
241
256
|
navigate<RouteName extends keyof ParamList>(
|
|
242
|
-
...args:
|
|
243
|
-
// This is to avoid getting a union of all the params from `ParamList[RouteName]`,
|
|
244
|
-
// which will get our types all mixed up if a union RouteName is passed in.
|
|
245
|
-
RouteName extends unknown
|
|
246
|
-
? // This condition checks if the params are optional,
|
|
247
|
-
// which means it's either undefined or a union with undefined
|
|
248
|
-
undefined extends ParamList[RouteName]
|
|
249
|
-
?
|
|
250
|
-
| [screen: RouteName] // if the params are optional, we don't have to provide it
|
|
251
|
-
| [screen: RouteName, params: ParamList[RouteName]]
|
|
252
|
-
: [screen: RouteName, params: ParamList[RouteName]]
|
|
253
|
-
: never
|
|
257
|
+
...args: ScreenParamsPair<ParamList, RouteName>
|
|
254
258
|
): void;
|
|
255
259
|
|
|
256
260
|
/**
|
|
@@ -259,14 +263,14 @@ type NavigationHelpersCommon<
|
|
|
259
263
|
* @param route Object with `name` for the route to navigate to, and a `params` object.
|
|
260
264
|
*/
|
|
261
265
|
navigate<RouteName extends keyof ParamList>(
|
|
262
|
-
options:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
266
|
+
options: {
|
|
267
|
+
[Screen in keyof ParamList]: {
|
|
268
|
+
name: Screen;
|
|
269
|
+
params: ParamList[Screen];
|
|
270
|
+
path?: string;
|
|
271
|
+
merge?: boolean;
|
|
272
|
+
};
|
|
273
|
+
}[RouteName]
|
|
270
274
|
): void;
|
|
271
275
|
|
|
272
276
|
/**
|
|
@@ -278,18 +282,7 @@ type NavigationHelpersCommon<
|
|
|
278
282
|
* @param [params] Params object for the route.
|
|
279
283
|
*/
|
|
280
284
|
navigateDeprecated<RouteName extends keyof ParamList>(
|
|
281
|
-
...args:
|
|
282
|
-
// This is to avoid getting a union of all the params from `ParamList[RouteName]`,
|
|
283
|
-
// which will get our types all mixed up if a union RouteName is passed in.
|
|
284
|
-
RouteName extends unknown
|
|
285
|
-
? // This condition checks if the params are optional,
|
|
286
|
-
// which means it's either undefined or a union with undefined
|
|
287
|
-
undefined extends ParamList[RouteName]
|
|
288
|
-
?
|
|
289
|
-
| [screen: RouteName] // if the params are optional, we don't have to provide it
|
|
290
|
-
| [screen: RouteName, params: ParamList[RouteName]]
|
|
291
|
-
: [screen: RouteName, params: ParamList[RouteName]]
|
|
292
|
-
: never
|
|
285
|
+
...args: ScreenParamsPair<ParamList, RouteName>
|
|
293
286
|
): void;
|
|
294
287
|
|
|
295
288
|
/**
|
|
@@ -300,13 +293,13 @@ type NavigationHelpersCommon<
|
|
|
300
293
|
* @param route Object with `name` for the route to navigate to, and a `params` object.
|
|
301
294
|
*/
|
|
302
295
|
navigateDeprecated<RouteName extends keyof ParamList>(
|
|
303
|
-
options:
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
296
|
+
options: {
|
|
297
|
+
[Screen in keyof ParamList]: {
|
|
298
|
+
name: Screen;
|
|
299
|
+
params: ParamList[Screen];
|
|
300
|
+
merge?: boolean;
|
|
301
|
+
};
|
|
302
|
+
}[RouteName]
|
|
310
303
|
): void;
|
|
311
304
|
|
|
312
305
|
/**
|
|
@@ -316,13 +309,7 @@ type NavigationHelpersCommon<
|
|
|
316
309
|
* @param [params] Params object for the route.
|
|
317
310
|
*/
|
|
318
311
|
preload<RouteName extends keyof ParamList>(
|
|
319
|
-
...args: RouteName
|
|
320
|
-
? undefined extends ParamList[RouteName]
|
|
321
|
-
?
|
|
322
|
-
| [screen: RouteName]
|
|
323
|
-
| [screen: RouteName, params: ParamList[RouteName]]
|
|
324
|
-
: [screen: RouteName, params: ParamList[RouteName]]
|
|
325
|
-
: never
|
|
312
|
+
...args: ScreenParamsPair<ParamList, RouteName>
|
|
326
313
|
): void;
|
|
327
314
|
|
|
328
315
|
/**
|
|
@@ -249,7 +249,7 @@ const getRouteConfigsFromChildren = <
|
|
|
249
249
|
export function useNavigationBuilder<
|
|
250
250
|
State extends NavigationState,
|
|
251
251
|
RouterOptions extends DefaultRouterOptions,
|
|
252
|
-
ActionHelpers extends Record<string, () => void>,
|
|
252
|
+
ActionHelpers extends Record<string, (...args: any) => void>,
|
|
253
253
|
ScreenOptions extends {},
|
|
254
254
|
EventMap extends Record<string, any>,
|
|
255
255
|
>(
|