@react-navigation/core 8.0.0-alpha.19 → 8.0.0-alpha.20

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 (144) hide show
  1. package/lib/module/BaseNavigationContainer.js +6 -2
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/StaticNavigation.js +72 -61
  4. package/lib/module/StaticNavigation.js.map +1 -1
  5. package/lib/module/findFocusedRoute.js +7 -4
  6. package/lib/module/findFocusedRoute.js.map +1 -1
  7. package/lib/module/getActionFromState.js +25 -12
  8. package/lib/module/getActionFromState.js.map +1 -1
  9. package/lib/module/getPathFromState.js +24 -9
  10. package/lib/module/getPathFromState.js.map +1 -1
  11. package/lib/module/getPatternParts.js +3 -0
  12. package/lib/module/getPatternParts.js.map +1 -1
  13. package/lib/module/getStateFromPath.js +164 -78
  14. package/lib/module/getStateFromPath.js.map +1 -1
  15. package/lib/module/index.js +1 -1
  16. package/lib/module/index.js.map +1 -1
  17. package/lib/module/types.js +8 -0
  18. package/lib/module/types.js.map +1 -1
  19. package/lib/module/useDescriptors.js +13 -6
  20. package/lib/module/useDescriptors.js.map +1 -1
  21. package/lib/module/useFocusEvents.js +5 -1
  22. package/lib/module/useFocusEvents.js.map +1 -1
  23. package/lib/module/useNavigation.js.map +1 -1
  24. package/lib/module/useNavigationBuilder.js +18 -5
  25. package/lib/module/useNavigationBuilder.js.map +1 -1
  26. package/lib/module/useNavigationCache.js +1 -1
  27. package/lib/module/useNavigationCache.js.map +1 -1
  28. package/lib/module/useNavigationState.js.map +1 -1
  29. package/lib/module/useOnAction.js +1 -1
  30. package/lib/module/useOnAction.js.map +1 -1
  31. package/lib/module/useRoute.js.map +1 -1
  32. package/lib/module/validatePathConfig.js +2 -1
  33. package/lib/module/validatePathConfig.js.map +1 -1
  34. package/lib/typescript/src/BaseNavigationContainer.d.ts +2 -2
  35. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  36. package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
  37. package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
  38. package/lib/typescript/src/Group.d.ts +1 -1
  39. package/lib/typescript/src/Group.d.ts.map +1 -1
  40. package/lib/typescript/src/NavigationBuilderContext.d.ts +1 -1
  41. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  42. package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
  43. package/lib/typescript/src/NavigationContainerRefContext.d.ts.map +1 -1
  44. package/lib/typescript/src/NavigationHelpersContext.d.ts +1 -1
  45. package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
  46. package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
  47. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  48. package/lib/typescript/src/NavigationProvider.d.ts +6 -6
  49. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  50. package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
  51. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  52. package/lib/typescript/src/SceneView.d.ts +3 -2
  53. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  54. package/lib/typescript/src/Screen.d.ts +1 -1
  55. package/lib/typescript/src/Screen.d.ts.map +1 -1
  56. package/lib/typescript/src/StaticNavigation.d.ts +68 -73
  57. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  58. package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
  59. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  60. package/lib/typescript/src/createNavigatorFactory.d.ts +3 -3
  61. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  62. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  63. package/lib/typescript/src/getActionFromState.d.ts +1 -1
  64. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  65. package/lib/typescript/src/getPathFromState.d.ts +1 -1
  66. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  67. package/lib/typescript/src/getPatternParts.d.ts +1 -0
  68. package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
  69. package/lib/typescript/src/getStateFromPath.d.ts +2 -2
  70. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  71. package/lib/typescript/src/index.d.ts +34 -33
  72. package/lib/typescript/src/index.d.ts.map +1 -1
  73. package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
  74. package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
  75. package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
  76. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  77. package/lib/typescript/src/theming/useTheme.d.ts +1 -1
  78. package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
  79. package/lib/typescript/src/types.d.ts +72 -37
  80. package/lib/typescript/src/types.d.ts.map +1 -1
  81. package/lib/typescript/src/useChildListeners.d.ts +3 -3
  82. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  83. package/lib/typescript/src/useComponent.d.ts +1 -1
  84. package/lib/typescript/src/useComponent.d.ts.map +1 -1
  85. package/lib/typescript/src/useDescriptors.d.ts +5 -5
  86. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  87. package/lib/typescript/src/useEventEmitter.d.ts +1 -1
  88. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  89. package/lib/typescript/src/useFocusEvents.d.ts +2 -2
  90. package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
  91. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
  92. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts.map +1 -1
  93. package/lib/typescript/src/useKeyedChildListeners.d.ts +3 -3
  94. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  95. package/lib/typescript/src/useNavigation.d.ts +5 -3
  96. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  97. package/lib/typescript/src/useNavigationBuilder.d.ts +7 -7
  98. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  99. package/lib/typescript/src/useNavigationCache.d.ts +3 -3
  100. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  101. package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
  102. package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
  103. package/lib/typescript/src/useNavigationHelpers.d.ts +4 -4
  104. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  105. package/lib/typescript/src/useNavigationState.d.ts +2 -2
  106. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  107. package/lib/typescript/src/useOnAction.d.ts +3 -3
  108. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  109. package/lib/typescript/src/useOnGetState.d.ts +1 -1
  110. package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
  111. package/lib/typescript/src/useOnPreventRemove.d.ts +3 -3
  112. package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
  113. package/lib/typescript/src/useOptionsGetters.d.ts +1 -1
  114. package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
  115. package/lib/typescript/src/usePreventRemoveContext.d.ts +1 -1
  116. package/lib/typescript/src/useRoute.d.ts +2 -2
  117. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  118. package/lib/typescript/src/useRouteCache.d.ts +2 -2
  119. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  120. package/lib/typescript/src/useStateForPath.d.ts +1 -1
  121. package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
  122. package/lib/typescript/src/utilities.d.ts +4 -3
  123. package/lib/typescript/src/utilities.d.ts.map +1 -1
  124. package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
  125. package/package.json +18 -17
  126. package/src/BaseNavigationContainer.tsx +7 -2
  127. package/src/StaticNavigation.tsx +220 -248
  128. package/src/findFocusedRoute.tsx +10 -5
  129. package/src/getActionFromState.tsx +43 -30
  130. package/src/getPathFromState.tsx +40 -20
  131. package/src/getPatternParts.tsx +8 -0
  132. package/src/getStateFromPath.tsx +244 -67
  133. package/src/index.tsx +39 -1
  134. package/src/types.tsx +167 -122
  135. package/src/useDescriptors.tsx +22 -10
  136. package/src/useFocusEvents.tsx +7 -1
  137. package/src/useNavigation.tsx +8 -4
  138. package/src/useNavigationBuilder.tsx +22 -7
  139. package/src/useNavigationCache.tsx +4 -4
  140. package/src/useNavigationState.tsx +3 -3
  141. package/src/useOnAction.tsx +1 -1
  142. package/src/useRoute.tsx +4 -2
  143. package/src/utilities.tsx +17 -11
  144. package/src/validatePathConfig.tsx +1 -0
@@ -1,11 +1,12 @@
1
- import type {
2
- NavigationState,
3
- ParamListBase,
4
- Route,
5
- } from '@react-navigation/routers';
1
+ import type { NavigationState, ParamListBase } from '@react-navigation/routers';
6
2
  import * as React from 'react';
7
3
  import { isValidElementType } from 'react-is';
8
4
 
5
+ import {
6
+ combinePatternParts,
7
+ getPatternParts,
8
+ type PatternPart,
9
+ } from './getPatternParts';
9
10
  import type {
10
11
  DefaultNavigatorOptions,
11
12
  EventMapBase,
@@ -31,50 +32,54 @@ import type {
31
32
  ValidPathPattern,
32
33
  } from './utilities';
33
34
 
35
+ type ScreenComponentParams<T> = [T] extends [
36
+ React.ComponentType<{ route: { params: infer Params } }>,
37
+ ]
38
+ ? Params
39
+ : undefined;
40
+
34
41
  type ParamsForScreenComponent<T> = [T] extends [(...args: any[]) => any]
35
- ? HasArguments<T> extends true
36
- ? [T] extends [React.ComponentType<{ route: { params: infer Params } }>]
37
- ? Params
38
- : undefined
42
+ ? // Don't infer params from a parameterless function component
43
+ // It'd infer `unknown` - but we want `undefined` if no params are accepted
44
+ HasArguments<T> extends true
45
+ ? ScreenComponentParams<T>
39
46
  : undefined
40
- : [T] extends [React.ComponentType<{ route: { params: infer Params } }>]
41
- ? Params
42
- : undefined;
47
+ : ScreenComponentParams<T>;
43
48
 
44
49
  // If every nested route's params include `undefined`, the nested navigator
45
50
  // itself can be omitted. Otherwise, require `NavigatorScreenParams`.
46
51
  type ParamsForNestedNavigator<
47
52
  T extends { config: any },
48
53
  ParamList extends {} = StaticParamList<T>,
54
+ Params = NavigatorScreenParams<ParamList>,
49
55
  > = {
50
- // Exclude routes with optional params so the resulting union only contains route names with required params.
51
- // If there are no routes with required params, the resulting union will be `never`.
56
+ // Map each route to `never` when params are optional, or name when params are required
57
+ // If every route has optional params, the resulting union is `never`
52
58
  [RouteName in keyof ParamList]-?: undefined extends ParamList[RouteName]
53
59
  ? never
54
60
  : RouteName;
55
61
  }[keyof ParamList] extends never
56
- ? NavigatorScreenParams<ParamList> | undefined
57
- : NavigatorScreenParams<ParamList>;
58
-
59
- type ParamsForScreen<T> =
60
- // Nested navigator in screen property
61
- T extends { screen: infer Screen }
62
- ? ParamsForScreenInner<Screen>
63
- : // Direct nested navigator
64
- T extends { config: any }
65
- ? ParamsForNestedNavigator<T>
66
- : ParamsForScreenComponent<T>;
67
-
68
- // `screen` can be a union when users build their screens map from a
69
- // `Record<K, V>`. A naked `T extends ...` conditional would distribute over
70
- // every screen in that union, creating a large params union for each route.
71
- // Wrapping `T` in a tuple checks the union as a whole and avoids that fanout.
72
- type ParamsForScreenInner<T> = [T] extends [{ config: any }]
62
+ ? Params | undefined
63
+ : Params;
64
+
65
+ // If the screens were constructed from a `Record<K, V>`,
66
+ // the screen value (`T`) may be a union.
67
+ // A naked `T extends ...` conditional would distribute over every screen in the union,
68
+ // creating a large params union per route.
69
+ // Wrapping `T` in a tuple checks the union as a whole instead of distributing,
70
+ // https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
71
+ type ParamsForScreen<T> = [T] extends [{ config: any }]
73
72
  ? ParamsForNestedNavigator<T>
74
73
  : [T] extends [React.ComponentType<any>]
75
74
  ? ParamsForScreenComponent<T>
76
75
  : undefined;
77
76
 
77
+ // Unlike `ParamsForScreen`, we want to distribute for `Record<string, Component | StaticNavigation>`
78
+ // This creates union like:
79
+ // `C extends C ? ParamsForScreen<C> : never) | (S extends S ? ParamsForScreen<S> : never)`
80
+ // `= ParamsForScreen<C> | ParamsForScreen<S>`
81
+ type ParamsForScreenEntry<T> = T extends T ? ParamsForScreen<T> : never;
82
+
78
83
  // Only infer params from linking if it's a pattern (i.e., contains ':')
79
84
  // or if parse is present for query params.
80
85
  // This avoids inferring non-literals like 'string' without parse.
@@ -85,30 +90,25 @@ type ShouldInferFromLinking<Linking> = Linking extends
85
90
  ? true
86
91
  : false;
87
92
 
88
- type MergeLinkingAndScreenParams<LinkingParams, ScreenParams> =
89
- undefined extends ScreenParams
90
- ? FlatType<LinkingParams>
91
- : FlatType<LinkingParams & ScreenParams>;
92
-
93
93
  /**
94
- * Inferred params type based on both linking config and screen.
95
- * - When linking is undefined: infers params from screen
96
- * - When screen is a nested navigator: merges path params with navigator screen params
97
- * - Otherwise: merges path params with screen component params
94
+ * Params type derived from both linking and screen.
95
+ *
96
+ * - Linking has no extractable params (no ':' in path, no `parse`): returns
97
+ * screen params alone.
98
+ * - Linking has params + screen is a nested navigator: intersects path params
99
+ * with the navigator's screen params.
100
+ * - Linking has params + screen is a component without route params: returns
101
+ * path params alone (avoids `LP & undefined = never`).
102
+ * - Linking has params + screen has route params: intersects them.
98
103
  */
99
- type ParamsForConfig<Linking, Screen> = ParamsForConfigInternal<
100
- Linking,
101
- Screen,
102
- ParamsForScreenInner<Screen>
103
- >;
104
-
105
- type ParamsForConfigInternal<Linking, Screen, SP> = undefined extends Linking
106
- ? SP
107
- : ShouldInferFromLinking<Linking> extends true
104
+ type ParamsForConfig<Linking, Screen, Params = ParamsForScreen<Screen>> =
105
+ ShouldInferFromLinking<Linking> extends true
108
106
  ? [Screen] extends [{ config: any }]
109
- ? FlatType<InferParamsFromLinking<Linking>> & SP
110
- : MergeLinkingAndScreenParams<InferParamsFromLinking<Linking>, SP>
111
- : SP;
107
+ ? FlatType<InferParamsFromLinking<Linking>> & Params
108
+ : undefined extends Params
109
+ ? FlatType<InferParamsFromLinking<Linking>>
110
+ : FlatType<InferParamsFromLinking<Linking> & Params>
111
+ : Params;
112
112
 
113
113
  type ParamListForScreens<Screens> = {
114
114
  [Key in KeysOf<Screens>]: Screens[Key] extends StaticScreenConfig<
@@ -117,10 +117,11 @@ type ParamListForScreens<Screens> = {
117
117
  any,
118
118
  any,
119
119
  any,
120
+ any,
120
121
  any
121
122
  >
122
123
  ? ParamsForConfig<Linking, Screen>
123
- : ParamsForScreen<Screens[Key]>;
124
+ : ParamsForScreenEntry<Screens[Key]>;
124
125
  };
125
126
 
126
127
  type ParamListForGroups<
@@ -139,25 +140,25 @@ type ParamListForGroups<
139
140
  ? ParamListForScreens<UnionToIntersection<Screens>>
140
141
  : {};
141
142
 
142
- type RouteType<Params> = Readonly<
143
- FlatType<
144
- Omit<Route<string, AnyToUnknown<Params>>, 'params'> &
145
- Readonly<
146
- undefined extends Params
147
- ? {
148
- /**
149
- * Params for this route
150
- */
151
- params?: AnyToUnknown<Params>;
152
- }
153
- : {
154
- /**
155
- * Params for this route
156
- */
157
- params: AnyToUnknown<Params>;
158
- }
159
- >
160
- >
143
+ type RouteType<Params, P = AnyToUnknown<Params>> = Readonly<
144
+ {
145
+ key: string;
146
+ name: string;
147
+ path?: string | undefined;
148
+ history?: { type: 'params'; params: object }[] | undefined;
149
+ } & (undefined extends Params
150
+ ? {
151
+ /**
152
+ * Params for this route
153
+ */
154
+ params?: P;
155
+ }
156
+ : {
157
+ /**
158
+ * Params for this route
159
+ */
160
+ params: P;
161
+ })
161
162
  >;
162
163
 
163
164
  type StaticScreenConfigLinkingAlias = {
@@ -200,6 +201,21 @@ type StaticScreenConfigLinkingAlias = {
200
201
  * ```
201
202
  */
202
203
  stringify?: Record<string, (value: unknown) => string>;
204
+ /**
205
+ * Whether this path can resolve to multiple routes.
206
+ * Both routes should specify `shared: true` for this to work.
207
+ *
208
+ * When automatic path generation is enabled,
209
+ * screens using the same path pattern and the same screen component
210
+ * or navigator will be automatically marked as shared.
211
+ * Explicitly specifying the option overrides the automatic detection.
212
+ *
213
+ * This is useful when same screen used in multiple navigators,
214
+ * e.g. tabs with stacks containing profile screen in each stack.
215
+ *
216
+ * The path defined first will be the canonical path.
217
+ */
218
+ shared?: boolean;
203
219
  };
204
220
 
205
221
  export type StaticScreenConfigLinking =
@@ -397,11 +413,10 @@ type StaticConfigScreens<
397
413
  in out NavigationList extends NavigationListBase<ParamList>,
398
414
  > = {
399
415
  [RouteName in keyof ParamList]:
400
- | React.ComponentType<any>
401
- | StaticNavigation<any>
416
+ | StaticScreenConfigScreen
402
417
  | StaticScreenConfig<
403
418
  StaticScreenConfigLinking,
404
- StaticNavigation<any> | React.ComponentType<any>,
419
+ StaticScreenConfigScreen,
405
420
  State,
406
421
  ScreenOptions,
407
422
  EventMap,
@@ -425,27 +440,6 @@ type StaticConfigGroup<
425
440
  * This can be useful for conditional rendering of group of screens.
426
441
  */
427
442
  if?: () => boolean;
428
- /**
429
- * Linking config for the screens in the group.
430
- * This can be a string to specify the path, or an object following properties:
431
- * - `path`
432
- * - `stringify`
433
- * - `parse`
434
- *
435
- * The path specified will be prepended to the paths of the screens in the group.
436
- * The `parse` and `stringify` properties will be merged.
437
- *
438
- * @example
439
- * ```js
440
- * linking: {
441
- * path: 'users/:id',
442
- * parse: {
443
- * id: (id) => parseInt(id, 10),
444
- * }
445
- * },
446
- * ```
447
- */
448
- linking?: LinkingForGroup;
449
443
  /**
450
444
  * Static navigation config or Component to render for the screen.
451
445
  */
@@ -475,6 +469,22 @@ type StaticConfigInternal<
475
469
  EventMap extends EventMapBase,
476
470
  NavigationList extends NavigationListBase<ParamList>,
477
471
  Navigator extends React.ComponentType<any>,
472
+ Screens = StaticConfigScreens<
473
+ ParamList,
474
+ State,
475
+ ScreenOptions,
476
+ EventMap,
477
+ NavigationList
478
+ >,
479
+ Groups = {
480
+ [key: string]: StaticConfigGroup<
481
+ ParamList,
482
+ State,
483
+ ScreenOptions,
484
+ EventMap,
485
+ NavigationList
486
+ >;
487
+ },
478
488
  > = Omit<
479
489
  Omit<
480
490
  React.ComponentProps<Navigator>,
@@ -494,49 +504,21 @@ type StaticConfigInternal<
494
504
  /**
495
505
  * Screens to render in the navigator and their configuration.
496
506
  */
497
- screens: StaticConfigScreens<
498
- ParamList,
499
- State,
500
- ScreenOptions,
501
- EventMap,
502
- NavigationList
503
- >;
507
+ screens: Screens;
504
508
  /**
505
509
  * Groups of screens to render in the navigator and their configuration.
506
510
  */
507
- groups?: {
508
- [key: string]: StaticConfigGroup<
509
- ParamList,
510
- State,
511
- ScreenOptions,
512
- EventMap,
513
- NavigationList
514
- >;
515
- };
511
+ groups?: Groups;
516
512
  }
517
513
  | {
518
514
  /**
519
515
  * Screens to render in the navigator and their configuration.
520
516
  */
521
- screens?: StaticConfigScreens<
522
- ParamList,
523
- State,
524
- ScreenOptions,
525
- EventMap,
526
- NavigationList
527
- >;
517
+ screens?: Screens;
528
518
  /**
529
519
  * Groups of screens to render in the navigator and their configuration.
530
520
  */
531
- groups: {
532
- [key: string]: StaticConfigGroup<
533
- ParamList,
534
- State,
535
- ScreenOptions,
536
- EventMap,
537
- NavigationList
538
- >;
539
- };
521
+ groups: Groups;
540
522
  }
541
523
  );
542
524
 
@@ -754,10 +736,6 @@ export function createComponentForStaticConfig<
754
736
  return NavigatorComponent;
755
737
  }
756
738
 
757
- type LinkingForGroup =
758
- | Pick<PathConfig<any>, 'path' | 'stringify' | 'parse'>
759
- | string;
760
-
761
739
  type TreeForPathConfig = {
762
740
  config: ConfigForPathConfig;
763
741
  };
@@ -765,12 +743,7 @@ type TreeForPathConfig = {
765
743
  type ConfigForPathConfig = {
766
744
  initialRouteName?: string;
767
745
  screens?: Record<string, ScreenForPathConfig>;
768
- groups?: {
769
- [key: string]: {
770
- linking?: LinkingForGroup;
771
- screens: Record<string, ScreenForPathConfig>;
772
- };
773
- };
746
+ groups?: Record<string, { screens: Record<string, ScreenForPathConfig> }>;
774
747
  };
775
748
 
776
749
  type LinkingForPathConfig =
@@ -783,14 +756,95 @@ type LinkingForPathConfig =
783
756
  | null
784
757
  | undefined;
785
758
 
759
+ type ScreenValueForPathConfig = React.ComponentType<{}> | TreeForPathConfig;
760
+
786
761
  type ScreenForPathConfig =
787
- | React.ComponentType<{}>
788
- | TreeForPathConfig
762
+ | ScreenValueForPathConfig
789
763
  | {
790
- screen: React.ComponentType<{}> | TreeForPathConfig;
764
+ screen: ScreenValueForPathConfig;
791
765
  linking?: LinkingForPathConfig;
792
766
  };
793
767
 
768
+ type PathConfigMapForStaticNavigation = Record<
769
+ string,
770
+ string | PathConfigForStaticNavigation | undefined
771
+ >;
772
+
773
+ type PathConfigForStaticNavigation = Omit<
774
+ PathConfig<ParamListBase>,
775
+ 'screens'
776
+ > & {
777
+ initialRouteName?: string | undefined;
778
+ screens?: PathConfigMapForStaticNavigation | undefined;
779
+ };
780
+
781
+ // Mark screens that resolve to the same pattern and same component or navigator
782
+ const markSharedPathConfigs = (
783
+ screens: PathConfigMapForStaticNavigation,
784
+ sources: WeakMap<PathConfigForStaticNavigation, ScreenValueForPathConfig>,
785
+ blocked: WeakSet<PathConfigForStaticNavigation>
786
+ ) => {
787
+ const candidates = new Map<string, PathConfigForStaticNavigation[]>();
788
+
789
+ const collect = (
790
+ screens: PathConfigMapForStaticNavigation,
791
+ parentParts: PatternPart[],
792
+ disabled: boolean
793
+ ) => {
794
+ for (const config of Object.values(screens)) {
795
+ if (config == null || typeof config === 'string') {
796
+ continue;
797
+ }
798
+
799
+ const parts =
800
+ typeof config.path === 'string'
801
+ ? combinePatternParts(
802
+ parentParts,
803
+ getPatternParts(config.path),
804
+ config.exact
805
+ )
806
+ : parentParts;
807
+
808
+ if (sources.has(config) && typeof config.path === 'string') {
809
+ if (disabled) {
810
+ blocked.add(config);
811
+ }
812
+
813
+ const pattern = parts.map((part) => part.segment).join('/');
814
+ const entries = candidates.get(pattern) ?? [];
815
+
816
+ entries.push(config);
817
+ candidates.set(pattern, entries);
818
+ }
819
+
820
+ if (config.screens) {
821
+ collect(config.screens, parts, disabled || config.shared === false);
822
+ }
823
+ }
824
+ };
825
+
826
+ collect(screens, [], false);
827
+
828
+ for (const entries of candidates.values()) {
829
+ for (const entry of entries) {
830
+ const source = sources.get(entry);
831
+
832
+ if (
833
+ entry.shared === undefined &&
834
+ !blocked.has(entry) &&
835
+ entries.some(
836
+ (candidate) =>
837
+ candidate !== entry &&
838
+ !blocked.has(candidate) &&
839
+ sources.get(candidate) === source
840
+ )
841
+ ) {
842
+ entry.shared = true;
843
+ }
844
+ }
845
+ }
846
+ };
847
+
794
848
  /**
795
849
  * Create a path config object from a static navigation config for deep linking.
796
850
  *
@@ -821,6 +875,12 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
821
875
  let initialScreenConfig: PathConfig<{}> | undefined;
822
876
  let hasEmptyPath = false;
823
877
 
878
+ const blocked = new WeakSet<PathConfigForStaticNavigation>();
879
+ const sources = new WeakMap<
880
+ PathConfigForStaticNavigation,
881
+ ScreenValueForPathConfig
882
+ >();
883
+
824
884
  const createPathConfigForTree = (
825
885
  t: TreeForPathConfig,
826
886
  o: { initialRouteName?: string | undefined } | undefined,
@@ -847,7 +907,6 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
847
907
 
848
908
  const createPathConfigForScreens = (
849
909
  screens: Record<string, ScreenForPathConfig>,
850
- groupLinking: LinkingForGroup | undefined,
851
910
  initialRouteName: string | undefined
852
911
  ) => {
853
912
  return Object.fromEntries(
@@ -866,26 +925,15 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
866
925
  return 0;
867
926
  })
868
927
  .map(([key, item]) => {
869
- const screenConfig: PathConfig<{}> = {};
870
- const groupPath =
871
- typeof groupLinking === 'string'
872
- ? groupLinking
873
- : groupLinking?.path;
874
-
875
- const normalizePath = (path: string, exact?: boolean) => {
876
- const normalizePart = (part: string) =>
877
- part.replace(/^\/+|\/+$/g, '');
878
-
879
- if (exact) {
880
- return normalizePart(path);
881
- }
928
+ const screenConfig: PathConfigForStaticNavigation = {};
929
+
930
+ sources.set(
931
+ screenConfig,
932
+ typeof item === 'object' && 'screen' in item ? item.screen : item
933
+ );
882
934
 
883
- return [groupPath, path]
884
- .filter((part): part is string => part != null && part !== '')
885
- .map(normalizePart)
886
- .filter(Boolean)
887
- .join('/');
888
- };
935
+ const normalizePath = (path: string) =>
936
+ path.replace(/^\/+|\/+$/g, '');
889
937
 
890
938
  if ('linking' in item && item.linking !== undefined) {
891
939
  if (typeof item.linking === 'string') {
@@ -894,7 +942,7 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
894
942
  item.linking != null &&
895
943
  typeof item.linking === 'object'
896
944
  ) {
897
- Object.assign(screenConfig, item.linking);
945
+ Object.assign(screenConfig, { ...item.linking });
898
946
  }
899
947
  }
900
948
 
@@ -905,10 +953,7 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
905
953
  }
906
954
 
907
955
  if (typeof screenConfig.path === 'string') {
908
- screenConfig.path = normalizePath(
909
- screenConfig.path,
910
- screenConfig.exact
911
- );
956
+ screenConfig.path = normalizePath(screenConfig.path);
912
957
  }
913
958
 
914
959
  if (screenConfig.alias != null) {
@@ -917,29 +962,9 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
917
962
  return normalizePath(alias);
918
963
  }
919
964
 
920
- const groupParse =
921
- typeof groupLinking === 'string'
922
- ? undefined
923
- : groupLinking?.parse;
924
- const hasGroupParams =
925
- groupParse != null &&
926
- Object.keys(groupParse).some((name) =>
927
- alias.path
928
- .split('/')
929
- .some((part) => part.startsWith(`:${name}`))
930
- );
931
-
932
965
  return {
933
966
  ...alias,
934
- ...(hasGroupParams
935
- ? {
936
- parse: {
937
- ...groupParse,
938
- ...alias.parse,
939
- },
940
- }
941
- : {}),
942
- path: normalizePath(alias.path, alias.exact),
967
+ path: normalizePath(alias.path),
943
968
  };
944
969
  });
945
970
  }
@@ -950,11 +975,6 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
950
975
  'screens' in screenConfig && screenConfig.screens != null;
951
976
  const hasDisabledLinking =
952
977
  'linking' in item && item.linking === null;
953
- const hasNestedStaticConfig =
954
- 'config' in item ||
955
- ('screen' in item &&
956
- 'config' in item.screen &&
957
- (item.screen.config.screens || item.screen.config.groups));
958
978
  const childOptions =
959
979
  'initialRouteName' in screenConfig &&
960
980
  typeof screenConfig.initialRouteName === 'string'
@@ -973,15 +993,6 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
973
993
  );
974
994
  }
975
995
 
976
- if (
977
- hasNestedStaticConfig &&
978
- screenConfig.path == null &&
979
- groupPath != null &&
980
- !hasDisabledLinking
981
- ) {
982
- screenConfig.path = normalizePath('');
983
- }
984
-
985
996
  const skipInitialDetectionInChild =
986
997
  skipInitialDetection ||
987
998
  (screenConfig.path != null && screenConfig.path !== '');
@@ -1016,7 +1027,6 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
1016
1027
  }
1017
1028
 
1018
1029
  if (screens) {
1019
- // @ts-expect-error - we can't type this properly
1020
1030
  screenConfig.screens = screens;
1021
1031
  }
1022
1032
 
@@ -1049,7 +1059,6 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
1049
1059
  }
1050
1060
  } else {
1051
1061
  if (
1052
- !groupPath &&
1053
1062
  !skipInitialDetection &&
1054
1063
  allowAutoEmptyPath &&
1055
1064
  (initialRouteName == null || key === initialRouteName) &&
@@ -1068,54 +1077,13 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
1068
1077
  }
1069
1078
  }
1070
1079
 
1071
- const groupOptionKeys =
1072
- typeof groupLinking === 'string'
1073
- ? []
1074
- : Object.keys({
1075
- ...groupLinking?.parse,
1076
- ...groupLinking?.stringify,
1077
- });
1078
- const hasAliasWithGroupParams =
1079
- groupOptionKeys.length > 0 &&
1080
- screenConfig.alias?.some((alias) => {
1081
- if (typeof alias !== 'string') {
1082
- return false;
1083
- }
1084
-
1085
- return groupOptionKeys.some((name) =>
1086
- alias.split('/').some((part) => part.startsWith(`:${name}`))
1087
- );
1088
- });
1089
- const shouldUseGroupOptions =
1090
- typeof groupLinking !== 'string' &&
1091
- groupLinking != null &&
1092
- screenConfig.path != null &&
1093
- screenConfig.path !== '' &&
1094
- (!screenConfig.exact || hasAliasWithGroupParams);
1095
-
1096
- if (shouldUseGroupOptions) {
1097
- if (groupLinking.parse != null) {
1098
- screenConfig.parse = {
1099
- ...groupLinking.parse,
1100
- ...screenConfig.parse,
1101
- };
1102
- }
1103
-
1104
- if (groupLinking.stringify != null && !screenConfig.exact) {
1105
- screenConfig.stringify = {
1106
- ...groupLinking.stringify,
1107
- ...screenConfig.stringify,
1108
- };
1109
- }
1110
- }
1111
-
1112
1080
  return [key, screenConfig] as const;
1113
1081
  })
1114
1082
  .filter(([, screen]) => Object.keys(screen).length > 0)
1115
1083
  );
1116
1084
  };
1117
1085
 
1118
- const screens = {};
1086
+ const screens: PathConfigMapForStaticNavigation = {};
1119
1087
 
1120
1088
  // Loop through the config to find screens and groups
1121
1089
  // So we add the screens and groups in the same order as they are defined
@@ -1125,7 +1093,6 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
1125
1093
  screens,
1126
1094
  createPathConfigForScreens(
1127
1095
  t.config.screens,
1128
- undefined,
1129
1096
  o?.initialRouteName ?? t.config.initialRouteName
1130
1097
  )
1131
1098
  );
@@ -1137,7 +1104,6 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
1137
1104
  screens,
1138
1105
  createPathConfigForScreens(
1139
1106
  group.screens,
1140
- group.linking,
1141
1107
  o?.initialRouteName ?? t.config.initialRouteName
1142
1108
  )
1143
1109
  );
@@ -1158,5 +1124,11 @@ export function createPathConfigForStaticNavigation<ParamList extends {}>(
1158
1124
  initialScreenConfig.path = '';
1159
1125
  }
1160
1126
 
1161
- return screens;
1127
+ if (!screens) {
1128
+ return undefined;
1129
+ }
1130
+
1131
+ markSharedPathConfigs(screens, sources, blocked);
1132
+
1133
+ return screens as PathConfigMap<ParamList>;
1162
1134
  }