@react-navigation/core 8.0.0-alpha.22 → 8.0.0-alpha.24

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.
Files changed (63) hide show
  1. package/lib/module/NavigationBuilderContext.js.map +1 -1
  2. package/lib/module/StaticNavigation.js +1 -1
  3. package/lib/module/StaticNavigation.js.map +1 -1
  4. package/lib/module/createNavigatorFactory.js.map +1 -1
  5. package/lib/module/getPathFromState.js +87 -57
  6. package/lib/module/getPathFromState.js.map +1 -1
  7. package/lib/module/getStateFromPath.js +77 -46
  8. package/lib/module/getStateFromPath.js.map +1 -1
  9. package/lib/module/index.js.map +1 -1
  10. package/lib/module/types.js +13 -0
  11. package/lib/module/types.js.map +1 -1
  12. package/lib/module/useEventEmitter.js +4 -1
  13. package/lib/module/useEventEmitter.js.map +1 -1
  14. package/lib/module/useNavigationBuilder.js +11 -14
  15. package/lib/module/useNavigationBuilder.js.map +1 -1
  16. package/lib/module/useOnAction.js +4 -1
  17. package/lib/module/useOnAction.js.map +1 -1
  18. package/lib/module/useOnPreventRemove.js +35 -24
  19. package/lib/module/useOnPreventRemove.js.map +1 -1
  20. package/lib/module/useRoute.js.map +1 -1
  21. package/lib/module/validatePathConfig.js +50 -37
  22. package/lib/module/validatePathConfig.js.map +1 -1
  23. package/lib/typescript/src/NavigationBuilderContext.d.ts +2 -2
  24. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  25. package/lib/typescript/src/StaticNavigation.d.ts +3 -3
  26. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  27. package/lib/typescript/src/createNavigatorFactory.d.ts +4 -2
  28. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  29. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  30. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  31. package/lib/typescript/src/index.d.ts +1 -1
  32. package/lib/typescript/src/index.d.ts.map +1 -1
  33. package/lib/typescript/src/types.d.ts +66 -33
  34. package/lib/typescript/src/types.d.ts.map +1 -1
  35. package/lib/typescript/src/useEventEmitter.d.ts +1 -1
  36. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  37. package/lib/typescript/src/useNavigationBuilder.d.ts +0 -7
  38. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  39. package/lib/typescript/src/useNavigationHelpers.d.ts +0 -7
  40. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  41. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  42. package/lib/typescript/src/useOnPreventRemove.d.ts +2 -6
  43. package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
  44. package/lib/typescript/src/useRoute.d.ts +1 -1
  45. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  46. package/lib/typescript/src/utilities.d.ts +4 -38
  47. package/lib/typescript/src/utilities.d.ts.map +1 -1
  48. package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
  49. package/package.json +5 -5
  50. package/src/NavigationBuilderContext.tsx +5 -1
  51. package/src/StaticNavigation.tsx +7 -6
  52. package/src/createNavigatorFactory.tsx +23 -2
  53. package/src/getPathFromState.tsx +97 -66
  54. package/src/getStateFromPath.tsx +168 -142
  55. package/src/index.tsx +1 -0
  56. package/src/types.tsx +257 -54
  57. package/src/useEventEmitter.tsx +6 -1
  58. package/src/useNavigationBuilder.tsx +11 -15
  59. package/src/useOnAction.tsx +6 -2
  60. package/src/useOnPreventRemove.tsx +68 -36
  61. package/src/useRoute.tsx +3 -5
  62. package/src/utilities.tsx +8 -41
  63. package/src/validatePathConfig.tsx +85 -58
@@ -22,6 +22,23 @@ type ConfigItem = {
22
22
  screens?: Record<string, ConfigItem> | undefined;
23
23
  };
24
24
 
25
+ const encodePathParam = (value: string) => {
26
+ let result = '';
27
+
28
+ for (const char of value) {
29
+ const charCode = char.charCodeAt(0);
30
+ const safe =
31
+ (charCode >= 65 && charCode <= 90) ||
32
+ (charCode >= 97 && charCode <= 122) ||
33
+ (charCode >= 48 && charCode <= 57) ||
34
+ "-._~!$&'()*+,;=:@".includes(char);
35
+
36
+ result += safe ? char : encodeURIComponent(char);
37
+ }
38
+
39
+ return result;
40
+ };
41
+
25
42
  const getActiveRoute = (
26
43
  state: State
27
44
  ): { name: string; params?: object | undefined } => {
@@ -190,30 +207,31 @@ export function getPathFromState<ParamList extends {}>(
190
207
 
191
208
  if (route.params) {
192
209
  const options = config;
210
+ const params = route.params as Record<string, unknown>;
211
+ const currentParams: Record<string, string> = {};
212
+
213
+ for (const key in params) {
214
+ const value = params[key];
193
215
 
194
- const currentParams = Object.fromEntries(
195
- Object.entries(route.params)
196
- .map(([key, value]): [string, string] | null => {
197
- if (value === undefined) {
198
- if (options) {
199
- const optional = options.parts?.find(
200
- (part) => part.param === key
201
- )?.optional;
202
-
203
- if (optional) {
204
- return null;
205
- }
206
- } else {
207
- return null;
208
- }
216
+ if (value === undefined) {
217
+ let optional = false;
218
+
219
+ for (const part of options.parts ?? []) {
220
+ if (part.param === key) {
221
+ optional = part.optional === true;
222
+ break;
209
223
  }
224
+ }
210
225
 
211
- const stringify = options?.stringify?.[key] ?? String;
226
+ if (optional) {
227
+ continue;
228
+ }
229
+ }
212
230
 
213
- return [key, stringify(value)];
214
- })
215
- .filter((entry) => entry != null)
216
- );
231
+ const stringify = options.stringify?.[key] ?? String;
232
+
233
+ currentParams[key] = stringify(value);
234
+ }
217
235
 
218
236
  if (parts?.length) {
219
237
  Object.assign(allParams, currentParams);
@@ -222,19 +240,24 @@ export function getPathFromState<ParamList extends {}>(
222
240
  if (focusedRoute === route) {
223
241
  // If this is the focused route, keep the params for later use
224
242
  // We save it here since it's been stringified already
225
- focusedParams = { ...currentParams };
226
-
227
- parts
228
- // eslint-disable-next-line no-loop-func
229
- ?.forEach(({ param }) => {
230
- if (param) {
231
- // Remove the params present in the pattern since we'll only use the rest for query string
232
- if (focusedParams) {
233
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
234
- delete focusedParams[param];
235
- }
243
+ focusedParams = {};
244
+
245
+ for (const key in currentParams) {
246
+ let inPattern = false;
247
+
248
+ for (const part of parts ?? []) {
249
+ if (part.param === key) {
250
+ inPattern = true;
251
+ break;
236
252
  }
237
- });
253
+ }
254
+
255
+ const value = currentParams[key];
256
+
257
+ if (!inPattern && value !== undefined && value !== 'undefined') {
258
+ focusedParams[key] = value;
259
+ }
260
+ }
238
261
  }
239
262
  }
240
263
 
@@ -268,13 +291,22 @@ export function getPathFromState<ParamList extends {}>(
268
291
  }
269
292
 
270
293
  if (currentOptions[route.name] != null) {
271
- path += parts
272
- ?.map(({ segment, param, optional }) => {
294
+ if (parts) {
295
+ let index = 0;
296
+
297
+ for (const { segment, param, optional } of parts) {
298
+ if (index > 0) {
299
+ path += '/';
300
+ }
301
+
302
+ index++;
303
+
273
304
  // We don't know what to show for wildcard patterns
274
305
  // Showing the route name seems ok, though whatever we show here will be incorrect
275
306
  // Since the page doesn't actually exist
276
307
  if (segment === '*') {
277
- return route.name;
308
+ path += route.name;
309
+ continue;
278
310
  }
279
311
 
280
312
  // If the path has a pattern for a param, put the param in the path
@@ -283,46 +315,39 @@ export function getPathFromState<ParamList extends {}>(
283
315
 
284
316
  if (value === undefined && optional) {
285
317
  // Optional params without value assigned in route.params should be ignored
286
- return '';
318
+ continue;
287
319
  }
288
320
 
289
321
  // Valid characters according to
290
322
  // https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 (see pchar definition)
291
- return Array.from(String(value))
292
- .map((char) =>
293
- /[^A-Za-z0-9\-._~!$&'()*+,;=:@]/g.test(char)
294
- ? encodeURIComponent(char)
295
- : char
296
- )
297
- .join('');
323
+ path += encodePathParam(String(value));
324
+ continue;
298
325
  }
299
326
 
300
- return encodeURIComponent(segment);
301
- })
302
- .join('/');
327
+ path += encodeURIComponent(segment);
328
+ }
329
+ }
303
330
  } else {
304
331
  path += encodeURIComponent(route.name);
305
332
  }
306
333
 
307
334
  if (!focusedParams && focusedRoute.params) {
308
- focusedParams = Object.fromEntries(
309
- Object.entries(focusedRoute.params).map(([key, value]) => [
310
- key,
311
- String(value),
312
- ])
313
- );
335
+ focusedParams = {};
336
+
337
+ const params = focusedRoute.params as Record<string, unknown>;
338
+
339
+ for (const key in params) {
340
+ const value = String(params[key]);
341
+
342
+ if (value !== 'undefined') {
343
+ focusedParams[key] = value;
344
+ }
345
+ }
314
346
  }
315
347
 
316
348
  if (route.state) {
317
349
  path += '/';
318
350
  } else if (focusedParams) {
319
- for (const param in focusedParams) {
320
- if (focusedParams[param] === 'undefined') {
321
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
322
- delete focusedParams[param];
323
- }
324
- }
325
-
326
351
  const query = queryString.stringify(focusedParams, { sort: false });
327
352
 
328
353
  if (query) {
@@ -399,11 +424,17 @@ const createConfigItem = (
399
424
  const createNormalizedConfigs = (
400
425
  options: PathConfigMap<object>,
401
426
  parts?: PatternPart[]
402
- ): Record<string, ConfigItem> =>
403
- Object.fromEntries(
404
- Object.entries(options).map(([name, c]) => {
405
- const result = createConfigItem(c, parts);
427
+ ): Record<string, ConfigItem> => {
428
+ const configs: Record<string, ConfigItem> = {};
429
+ const screens = options as Record<string, PathConfig<{}> | string>;
406
430
 
407
- return [name, result];
408
- })
409
- );
431
+ for (const name in screens) {
432
+ const config = screens[name];
433
+
434
+ if (config !== undefined) {
435
+ configs[name] = createConfigItem(config, parts);
436
+ }
437
+ }
438
+
439
+ return configs;
440
+ };