@react-navigation/core 7.14.0 → 8.0.0-alpha.1

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 (157) hide show
  1. package/lib/module/BaseNavigationContainer.js +4 -9
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/NavigationIndependentTree.js +12 -7
  4. package/lib/module/NavigationIndependentTree.js.map +1 -1
  5. package/lib/module/NavigationProvider.js +49 -0
  6. package/lib/module/NavigationProvider.js.map +1 -0
  7. package/lib/module/PreventRemoveProvider.js +1 -1
  8. package/lib/module/PreventRemoveProvider.js.map +1 -1
  9. package/lib/module/SceneView.js.map +1 -1
  10. package/lib/module/StaticNavigation.js +32 -21
  11. package/lib/module/StaticNavigation.js.map +1 -1
  12. package/lib/module/createNavigationContainerRef.js.map +1 -1
  13. package/lib/module/getActionFromState.js +3 -2
  14. package/lib/module/getActionFromState.js.map +1 -1
  15. package/lib/module/getPathFromState.js +1 -1
  16. package/lib/module/getPathFromState.js.map +1 -1
  17. package/lib/module/getStateFromPath.js +3 -3
  18. package/lib/module/getStateFromPath.js.map +1 -1
  19. package/lib/module/index.js +1 -2
  20. package/lib/module/index.js.map +1 -1
  21. package/lib/module/theming/ThemeContext.js.map +1 -1
  22. package/lib/module/theming/ThemeProvider.js.map +1 -1
  23. package/lib/module/theming/useTheme.js +1 -1
  24. package/lib/module/theming/useTheme.js.map +1 -1
  25. package/lib/module/types.js +41 -0
  26. package/lib/module/types.js.map +1 -1
  27. package/lib/module/useChildListeners.js +2 -4
  28. package/lib/module/useChildListeners.js.map +1 -1
  29. package/lib/module/useDescriptors.js +5 -9
  30. package/lib/module/useDescriptors.js.map +1 -1
  31. package/lib/module/useEventEmitter.js +9 -20
  32. package/lib/module/useEventEmitter.js.map +1 -1
  33. package/lib/module/useFocusEvents.js +1 -1
  34. package/lib/module/useFocusEvents.js.map +1 -1
  35. package/lib/module/useNavigation.js +31 -8
  36. package/lib/module/useNavigation.js.map +1 -1
  37. package/lib/module/useNavigationBuilder.js +10 -12
  38. package/lib/module/useNavigationBuilder.js.map +1 -1
  39. package/lib/module/useNavigationCache.js +18 -11
  40. package/lib/module/useNavigationCache.js.map +1 -1
  41. package/lib/module/useNavigationHelpers.js +2 -14
  42. package/lib/module/useNavigationHelpers.js.map +1 -1
  43. package/lib/module/useNavigationState.js +42 -9
  44. package/lib/module/useNavigationState.js.map +1 -1
  45. package/lib/module/useOnAction.js +2 -7
  46. package/lib/module/useOnAction.js.map +1 -1
  47. package/lib/module/useOnGetState.js +1 -1
  48. package/lib/module/useOnGetState.js.map +1 -1
  49. package/lib/module/useOnPreventRemove.js +1 -1
  50. package/lib/module/useOnPreventRemove.js.map +1 -1
  51. package/lib/module/useRoute.js +23 -5
  52. package/lib/module/useRoute.js.map +1 -1
  53. package/lib/module/useScheduleUpdate.js +1 -2
  54. package/lib/module/useScheduleUpdate.js.map +1 -1
  55. package/lib/module/useSyncState.js +25 -9
  56. package/lib/module/useSyncState.js.map +1 -1
  57. package/lib/module/utilities.js +2 -0
  58. package/lib/module/utilities.js.map +1 -0
  59. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  60. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  61. package/lib/typescript/src/NavigationProvider.d.ts +44 -0
  62. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -0
  63. package/lib/typescript/src/SceneView.d.ts +1 -1
  64. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  65. package/lib/typescript/src/StaticNavigation.d.ts +231 -80
  66. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  67. package/lib/typescript/src/createNavigationContainerRef.d.ts +2 -2
  68. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  69. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  70. package/lib/typescript/src/index.d.ts +2 -3
  71. package/lib/typescript/src/index.d.ts.map +1 -1
  72. package/lib/typescript/src/theming/ThemeContext.d.ts +2 -1
  73. package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
  74. package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -1
  75. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  76. package/lib/typescript/src/theming/useTheme.d.ts +1 -1
  77. package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
  78. package/lib/typescript/src/types.d.ts +188 -133
  79. package/lib/typescript/src/types.d.ts.map +1 -1
  80. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  81. package/lib/typescript/src/useDescriptors.d.ts +27 -109
  82. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  83. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  84. package/lib/typescript/src/useNavigation.d.ts +7 -5
  85. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  86. package/lib/typescript/src/useNavigationBuilder.d.ts +25 -114
  87. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  88. package/lib/typescript/src/useNavigationCache.d.ts +8 -22
  89. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  90. package/lib/typescript/src/useNavigationContainerRef.d.ts +2 -2
  91. package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
  92. package/lib/typescript/src/useNavigationHelpers.d.ts +3 -11
  93. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  94. package/lib/typescript/src/useNavigationState.d.ts +10 -3
  95. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  96. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  97. package/lib/typescript/src/useRoute.d.ts +8 -2
  98. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  99. package/lib/typescript/src/useRouteCache.d.ts +12 -3
  100. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  101. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  102. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  103. package/lib/typescript/src/utilities.d.ts +99 -0
  104. package/lib/typescript/src/utilities.d.ts.map +1 -0
  105. package/package.json +7 -7
  106. package/src/BaseNavigationContainer.tsx +3 -9
  107. package/src/NavigationIndependentTree.tsx +17 -9
  108. package/src/NavigationProvider.tsx +64 -0
  109. package/src/PreventRemoveProvider.tsx +1 -1
  110. package/src/SceneView.tsx +1 -7
  111. package/src/StaticNavigation.tsx +372 -134
  112. package/src/createNavigationContainerRef.tsx +2 -1
  113. package/src/getActionFromState.tsx +4 -2
  114. package/src/getPathFromState.tsx +6 -5
  115. package/src/getStateFromPath.tsx +11 -11
  116. package/src/index.tsx +8 -4
  117. package/src/theming/ThemeContext.tsx +3 -3
  118. package/src/theming/ThemeProvider.tsx +2 -1
  119. package/src/theming/useTheme.tsx +1 -1
  120. package/src/types.tsx +392 -243
  121. package/src/useChildListeners.tsx +3 -2
  122. package/src/useDescriptors.tsx +11 -17
  123. package/src/useEventEmitter.tsx +14 -31
  124. package/src/useFocusEvents.tsx +1 -1
  125. package/src/useNavigation.tsx +57 -14
  126. package/src/useNavigationBuilder.tsx +10 -13
  127. package/src/useNavigationCache.tsx +40 -18
  128. package/src/useNavigationContainerRef.tsx +2 -2
  129. package/src/useNavigationHelpers.tsx +2 -19
  130. package/src/useNavigationState.tsx +90 -19
  131. package/src/useOnAction.tsx +1 -12
  132. package/src/useOnGetState.tsx +1 -1
  133. package/src/useOnPreventRemove.tsx +1 -1
  134. package/src/useRoute.tsx +52 -7
  135. package/src/useScheduleUpdate.tsx +1 -2
  136. package/src/useSyncState.tsx +28 -13
  137. package/src/utilities.tsx +122 -0
  138. package/lib/module/DeprecatedNavigationInChildContext.js +0 -9
  139. package/lib/module/DeprecatedNavigationInChildContext.js.map +0 -1
  140. package/lib/module/NavigationContext.js +0 -8
  141. package/lib/module/NavigationContext.js.map +0 -1
  142. package/lib/module/NavigationRouteContext.js +0 -9
  143. package/lib/module/NavigationRouteContext.js.map +0 -1
  144. package/lib/module/useClientLayoutEffect.js +0 -9
  145. package/lib/module/useClientLayoutEffect.js.map +0 -1
  146. package/lib/typescript/src/DeprecatedNavigationInChildContext.d.ts +0 -6
  147. package/lib/typescript/src/DeprecatedNavigationInChildContext.d.ts.map +0 -1
  148. package/lib/typescript/src/NavigationContext.d.ts +0 -8
  149. package/lib/typescript/src/NavigationContext.d.ts.map +0 -1
  150. package/lib/typescript/src/NavigationRouteContext.d.ts +0 -7
  151. package/lib/typescript/src/NavigationRouteContext.d.ts.map +0 -1
  152. package/lib/typescript/src/useClientLayoutEffect.d.ts +0 -6
  153. package/lib/typescript/src/useClientLayoutEffect.d.ts.map +0 -1
  154. package/src/DeprecatedNavigationInChildContext.tsx +0 -6
  155. package/src/NavigationContext.tsx +0 -11
  156. package/src/NavigationRouteContext.tsx +0 -9
  157. package/src/useClientLayoutEffect.tsx +0 -10
@@ -1,4 +1,8 @@
1
- import type { NavigationState, ParamListBase } from '@react-navigation/routers';
1
+ import type {
2
+ NavigationState,
3
+ ParamListBase,
4
+ Route,
5
+ } from '@react-navigation/routers';
2
6
  import * as React from 'react';
3
7
  import { isValidElementType } from 'react-is';
4
8
 
@@ -9,100 +13,313 @@ import type {
9
13
  NavigatorScreenParams,
10
14
  NavigatorTypeBagBase,
11
15
  PathConfig,
12
- RouteConfigComponent,
13
- RouteConfigProps,
16
+ PathConfigMap,
14
17
  RouteGroupConfig,
18
+ ScreenListeners,
19
+ Theme,
15
20
  } from './types';
16
21
  import { useRoute } from './useRoute';
22
+ import type {
23
+ AnyToUnknown,
24
+ ExtractParamStrings,
25
+ ExtractParamsType,
26
+ FlatType,
27
+ HasArguments,
28
+ InferParse,
29
+ InferPath,
30
+ KeysOf,
31
+ UnionToIntersection,
32
+ ValidPathPattern,
33
+ } from './utilities';
34
+
35
+ type ParamsForScreenComponent<T> = T extends (...args: any[]) => any
36
+ ? HasArguments<T> extends true
37
+ ? T extends React.ComponentType<{ route: { params: infer Params } }>
38
+ ? Params
39
+ : undefined
40
+ : undefined
41
+ : T extends React.ComponentType<{ route: { params: infer Params } }>
42
+ ? Params
43
+ : undefined;
17
44
 
18
- /**
19
- * Flatten a type to remove all type alias names, unions etc.
20
- * This will show a plain object when hovering over the type.
21
- */
22
- type FlatType<T> = { [K in keyof T]: T[K] } & {};
23
-
24
- /**
25
- * keyof T doesn't work for union types. We can use distributive conditional types instead.
26
- * https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
27
- */
28
- type KeysOf<T> = T extends {} ? keyof T : never;
45
+ type ParamsForScreen<T> =
46
+ // Nested navigator in screen property
47
+ T extends { screen: StaticNavigation<any, any, any> }
48
+ ? NavigatorScreenParams<StaticParamList<T['screen']>> | undefined
49
+ : // Direct nested navigator
50
+ T extends StaticNavigation<any, any, any>
51
+ ? NavigatorScreenParams<StaticParamList<T>> | undefined
52
+ : T extends {
53
+ screen: React.ComponentType<any>;
54
+ }
55
+ ? ParamsForScreenComponent<T['screen']>
56
+ : ParamsForScreenComponent<T>;
57
+
58
+ type ParamsForLinking<Linking> = Linking extends { path: string }
59
+ ? ExtractParamsType<
60
+ ExtractParamStrings<InferPath<Linking>>,
61
+ InferParse<Linking>
62
+ >
63
+ : Linking extends string
64
+ ? ExtractParamsType<ExtractParamStrings<Linking>, undefined>
65
+ : undefined;
29
66
 
30
67
  /**
31
- * We get a union type when using keyof, but we want an intersection instead.
32
- * https://stackoverflow.com/a/50375286/1665026
68
+ * Inferred params type based on both linking config and screen.
69
+ * - When linking is undefined: infers params from screen
70
+ * - When screen is a nested navigator: merges path params with navigator screen params
71
+ * - Otherwise: merges path params with screen component params
33
72
  */
34
- type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
35
- k: infer I
36
- ) => void
37
- ? I
38
- : never;
39
-
40
- type UnknownToUndefined<T> = unknown extends T ? undefined : T;
41
-
42
- type ParamsForScreenComponent<T> = T extends {
43
- screen: React.ComponentType<{ route: { params: infer P } }>;
44
- }
45
- ? P
46
- : T extends React.ComponentType<{ route: { params: infer P } }>
47
- ? P
48
- : undefined;
49
-
50
- type ParamsForScreen<T> = T extends { screen: StaticNavigation<any, any, any> }
51
- ? NavigatorScreenParams<StaticParamList<T['screen']>> | undefined
52
- : T extends StaticNavigation<any, any, any>
53
- ? NavigatorScreenParams<StaticParamList<T>> | undefined
54
- : UnknownToUndefined<ParamsForScreenComponent<T>>;
73
+ type ParamsForConfig<Linking, Screen> = undefined extends Linking
74
+ ? ParamsForScreen<Screen>
75
+ : // Only infer params from linking if it's a pattern (i.e., contains ':')
76
+ // This avoids inferring non-literals like 'string'
77
+ Linking extends ValidPathPattern | { path: ValidPathPattern }
78
+ ? Screen extends StaticNavigation<any, any, any>
79
+ ? FlatType<ParamsForLinking<Linking>> & ParamsForScreen<Screen>
80
+ : // Don't combine if `undefined`, otherwise it'll result in `never`
81
+ undefined extends ParamsForScreen<Screen>
82
+ ? // Only flatten when not a navigator to keep it legible
83
+ FlatType<ParamsForLinking<Linking>>
84
+ : FlatType<ParamsForLinking<Linking> & ParamsForScreen<Screen>>
85
+ : ParamsForScreen<Screen>;
55
86
 
56
87
  type ParamListForScreens<Screens> = {
57
- [Key in KeysOf<Screens>]: ParamsForScreen<Screens[Key]>;
88
+ [Key in KeysOf<Screens>]: Screens[Key] extends StaticScreenConfig<
89
+ infer Linking,
90
+ infer Screen,
91
+ any,
92
+ any,
93
+ any,
94
+ any
95
+ >
96
+ ? ParamsForConfig<Linking, Screen>
97
+ : ParamsForScreen<Screens[Key]>;
58
98
  };
59
99
 
60
100
  type ParamListForGroups<
61
101
  Groups extends
62
102
  | Readonly<{
63
103
  [key: string]: {
64
- screens: StaticConfigScreens<
65
- ParamListBase,
66
- NavigationState,
67
- {},
68
- EventMapBase,
69
- any
70
- >;
104
+ screens: {};
71
105
  };
72
106
  }>
73
107
  | undefined,
74
108
  > = Groups extends {
75
109
  [key: string]: {
76
- screens: StaticConfigScreens<
77
- ParamListBase,
78
- NavigationState,
79
- {},
80
- EventMapBase,
81
- any
82
- >;
110
+ screens: infer Screens;
83
111
  };
84
112
  }
85
- ? ParamListForScreens<UnionToIntersection<Groups[keyof Groups]['screens']>>
113
+ ? ParamListForScreens<UnionToIntersection<Screens>>
86
114
  : {};
87
115
 
88
- type StaticRouteConfig<
89
- ParamList extends ParamListBase,
90
- RouteName extends keyof ParamList,
116
+ type RouteType<Params> = Readonly<
117
+ FlatType<
118
+ Omit<Route<string, AnyToUnknown<Params>>, 'params'> &
119
+ Readonly<
120
+ undefined extends Params
121
+ ? {
122
+ /**
123
+ * Params for this route
124
+ */
125
+ params?: AnyToUnknown<Params>;
126
+ }
127
+ : {
128
+ /**
129
+ * Params for this route
130
+ */
131
+ params: AnyToUnknown<Params>;
132
+ }
133
+ >
134
+ >
135
+ >;
136
+
137
+ type StaticScreenConfigLinkingAlias = {
138
+ /**
139
+ * Path string to match against.
140
+ * e.g. `/users/:id` will match `/users/1` and extract `id` param as `1`.
141
+ */
142
+ path: string;
143
+ /**
144
+ * Whether the path should be consider parent paths or use the exact path.
145
+ * By default, paths are relating to the path config on the parent screen.
146
+ * If `exact` is set to `true`, the parent path configuration is not used.
147
+ */
148
+ exact?: boolean;
149
+ /**
150
+ * An object mapping the param name to a function which parses the param value.
151
+ *
152
+ * @example
153
+ * ```js
154
+ * parse: {
155
+ * id: Number,
156
+ * date: (value) => new Date(value)
157
+ * }
158
+ * ```
159
+ */
160
+ parse?: Record<string, (value: string) => unknown>;
161
+ /**
162
+ * An object mapping the param name to a function which converts the param value to a string.
163
+ * By default, all params are converted to strings using `String(value)`.
164
+ *
165
+ * @example
166
+ * ```js
167
+ * stringify: {
168
+ * date: (value) => value.toISOString()
169
+ * }
170
+ * ```
171
+ */
172
+ stringify?: Record<string, (value: unknown) => string>;
173
+ };
174
+
175
+ export type StaticScreenConfigLinking =
176
+ | string
177
+ | (StaticScreenConfigLinkingAlias & {
178
+ /**
179
+ * Additional path alias that will be matched to the same screen.
180
+ */
181
+ alias?: (string | StaticScreenConfigLinkingAlias)[];
182
+ })
183
+ | undefined;
184
+
185
+ export type StaticScreenConfigScreen =
186
+ | React.ComponentType<any>
187
+ | StaticNavigation<any, any, any>;
188
+
189
+ export type StaticScreenConfig<
190
+ Linking extends StaticScreenConfigLinking,
191
+ Screen,
91
192
  State extends NavigationState,
92
193
  ScreenOptions extends {},
93
194
  EventMap extends EventMapBase,
94
195
  Navigation,
95
- > = RouteConfigProps<
96
- ParamList,
97
- RouteName,
98
- State,
99
- ScreenOptions,
100
- EventMap,
101
- Navigation
102
- > &
103
- RouteConfigComponent<ParamList, RouteName>;
196
+ Params = ParamsForConfig<Linking, Screen>,
197
+ > = {
198
+ /**
199
+ * Static navigation config or Component to render for the screen.
200
+ */
201
+ screen: Screen;
202
+
203
+ /**
204
+ * Callback to determine whether the screen should be rendered or not.
205
+ * This can be useful for conditional rendering of screens,
206
+ *
207
+ * e.g. - if you want to render a different screen for logged in users.
208
+ *
209
+ * You can use a custom hook to use custom logic to determine the return value.
210
+ *
211
+ * @example
212
+ * ```js
213
+ * if: useIsLoggedIn
214
+ * ```
215
+ */
216
+ if?: () => boolean;
104
217
 
105
- export type StaticConfigScreens<
218
+ /**
219
+ * Navigator options for this screen.
220
+ *
221
+ * @example
222
+ * ```js
223
+ * options: {
224
+ * title: 'My Screen',
225
+ * }
226
+ * ```
227
+ */
228
+ options?:
229
+ | ScreenOptions
230
+ | ((props: {
231
+ route: RouteType<Params>;
232
+ navigation: Navigation;
233
+ theme: Theme;
234
+ }) => ScreenOptions);
235
+
236
+ /**
237
+ * Event listeners for this screen.
238
+ *
239
+ * @example
240
+ * ```js
241
+ * listeners: {
242
+ * blur: (event) => {
243
+ * ...
244
+ * },
245
+ * }
246
+ * ```
247
+ */
248
+ listeners?:
249
+ | ScreenListeners<State, EventMap>
250
+ | ((props: {
251
+ route: RouteType<Params>;
252
+ navigation: Navigation;
253
+ }) => ScreenListeners<State, EventMap>);
254
+
255
+ /**
256
+ * Layout for this screen.
257
+ *
258
+ * @example
259
+ * ```js
260
+ * layout: ({ children, route, options, navigation, theme }) => {
261
+ * return (
262
+ * <MyWrapper>
263
+ * {children}
264
+ * </MyWrapper>
265
+ * );
266
+ * }
267
+ * ```
268
+ *
269
+ */
270
+ layout?: (props: {
271
+ route: RouteType<Params>;
272
+ options: ScreenOptions;
273
+ navigation: Navigation;
274
+ theme: Theme;
275
+ children: React.ReactElement;
276
+ }) => React.ReactElement;
277
+
278
+ /**
279
+ * Initial params object for the route.
280
+ *
281
+ * @example
282
+ * ```js
283
+ * initialParams: {
284
+ * someParam: 'someValue'
285
+ * }
286
+ * ```
287
+ */
288
+ initialParams?: AnyToUnknown<Params extends object ? Partial<Params> : never>;
289
+
290
+ /**
291
+ * Function to return an unique ID for this screen.
292
+ *
293
+ * @example
294
+ * ```js
295
+ * getId: ({ params }) => params?.userId,
296
+ * ```
297
+ */
298
+ getId?: (props: { params: AnyToUnknown<Params> }) => string | undefined;
299
+
300
+ /**
301
+ * Linking config for the screen.
302
+ * This can be a string to specify the path, or an object with more options.
303
+ *
304
+ * @example
305
+ * ```js
306
+ * linking: {
307
+ * path: 'profile/:userId',
308
+ * parse: {
309
+ * userId: Number,
310
+ * },
311
+ * },
312
+ * ```
313
+ */
314
+ linking?: Linking;
315
+
316
+ /**
317
+ * Optional key for this screen.
318
+ */
319
+ navigationKey?: string;
320
+ };
321
+
322
+ type StaticConfigScreens<
106
323
  ParamList extends ParamListBase,
107
324
  State extends NavigationState,
108
325
  ScreenOptions extends {},
@@ -112,51 +329,23 @@ export type StaticConfigScreens<
112
329
  [RouteName in keyof ParamList]:
113
330
  | React.ComponentType<any>
114
331
  | StaticNavigation<any, any, any>
115
- | (Omit<
116
- StaticRouteConfig<
117
- ParamList,
118
- RouteName,
119
- State,
120
- ScreenOptions,
121
- EventMap,
122
- NavigationList[RouteName]
123
- >,
124
- 'name' | 'component' | 'getComponent' | 'children'
125
- > & {
126
- /**
127
- * Callback to determine whether the screen should be rendered or not.
128
- * This can be useful for conditional rendering of screens,
129
- * e.g. - if you want to render a different screen for logged in users.
130
- *
131
- * You can use a custom hook to use custom logic to determine the return value.
132
- *
133
- * @example
134
- * ```js
135
- * if: useIsLoggedIn
136
- * ```
137
- */
138
- if?: () => boolean;
139
- /**
140
- * Linking config for the screen.
141
- * This can be a string to specify the path, or an object with more options.
142
- *
143
- * @example
144
- * ```js
145
- * linking: {
146
- * path: 'profile/:id',
147
- * exact: true,
148
- * },
149
- * ```
150
- */
151
- linking?: PathConfig<ParamList> | string;
152
- /**
153
- * Static navigation config or Component to render for the screen.
154
- */
155
- screen: StaticNavigation<any, any, any> | React.ComponentType<any>;
156
- });
332
+ | StaticScreenConfig<
333
+ | {
334
+ path: string;
335
+ parse?: Record<string, (value: string) => any>;
336
+ }
337
+ | string
338
+ | undefined,
339
+ StaticNavigation<any, any, any> | React.ComponentType<any>,
340
+ State,
341
+ ScreenOptions,
342
+ EventMap,
343
+ NavigationList[RouteName],
344
+ any
345
+ >;
157
346
  };
158
347
 
159
- export type StaticConfigGroup<
348
+ type StaticConfigGroup<
160
349
  ParamList extends ParamListBase,
161
350
  State extends NavigationState,
162
351
  ScreenOptions extends {},
@@ -171,6 +360,27 @@ export type StaticConfigGroup<
171
360
  * This can be useful for conditional rendering of group of screens.
172
361
  */
173
362
  if?: () => boolean;
363
+ /**
364
+ * Linking config for the screens in the group.
365
+ * This can be a string to specify the path, or an object following properties:
366
+ * - `path`
367
+ * - `stringify`
368
+ * - `parse`
369
+ *
370
+ * The path specified will be prepended to the paths of the screens in the group.
371
+ * The `parse` and `stringify` properties will be merged.
372
+ *
373
+ * @example
374
+ * ```js
375
+ * linking: {
376
+ * path: 'users/:id',
377
+ * parse: {
378
+ * id: (id) => parseInt(id, 10),
379
+ * }
380
+ * },
381
+ * ```
382
+ */
383
+ linking?: LinkingForGroup;
174
384
  /**
175
385
  * Static navigation config or Component to render for the screen.
176
386
  */
@@ -186,7 +396,6 @@ export type StaticConfigGroup<
186
396
  export type StaticConfig<Bag extends NavigatorTypeBagBase> =
187
397
  StaticConfigInternal<
188
398
  Bag['ParamList'],
189
- Bag['NavigatorID'],
190
399
  Bag['State'],
191
400
  Bag['ScreenOptions'],
192
401
  Bag['EventMap'],
@@ -196,7 +405,6 @@ export type StaticConfig<Bag extends NavigatorTypeBagBase> =
196
405
 
197
406
  type StaticConfigInternal<
198
407
  ParamList extends ParamListBase,
199
- NavigatorID extends string | undefined,
200
408
  State extends NavigationState,
201
409
  ScreenOptions extends {},
202
410
  EventMap extends EventMapBase,
@@ -207,7 +415,6 @@ type StaticConfigInternal<
207
415
  React.ComponentProps<Navigator>,
208
416
  keyof DefaultNavigatorOptions<
209
417
  ParamListBase,
210
- string | undefined,
211
418
  NavigationState,
212
419
  {},
213
420
  EventMapBase,
@@ -216,7 +423,6 @@ type StaticConfigInternal<
216
423
  > &
217
424
  DefaultNavigatorOptions<
218
425
  ParamList,
219
- NavigatorID,
220
426
  State,
221
427
  ScreenOptions,
222
428
  EventMap,
@@ -290,14 +496,7 @@ export type StaticScreenProps<T extends Record<string, unknown> | undefined> = {
290
496
  */
291
497
  export type StaticParamList<
292
498
  T extends {
293
- readonly config: {
294
- readonly screens?: Record<string, any>;
295
- readonly groups?: {
296
- [key: string]: {
297
- screens: Record<string, any>;
298
- };
299
- };
300
- };
499
+ readonly config: any;
301
500
  },
302
501
  > = FlatType<
303
502
  ParamListForScreens<T['config']['screens']> &
@@ -449,6 +648,10 @@ export function createComponentForStaticNavigation(
449
648
  return NavigatorComponent;
450
649
  }
451
650
 
651
+ type LinkingForGroup =
652
+ | Pick<PathConfig<any>, 'path' | 'stringify' | 'parse'>
653
+ | string;
654
+
452
655
  type TreeForPathConfig = {
453
656
  config: {
454
657
  initialRouteName?: string;
@@ -461,6 +664,7 @@ type TreeForPathConfig = {
461
664
  >;
462
665
  groups?: {
463
666
  [key: string]: {
667
+ linking?: LinkingForGroup;
464
668
  screens: StaticConfigScreens<
465
669
  ParamListBase,
466
670
  NavigationState,
@@ -498,9 +702,9 @@ export function createPathConfigForStaticNavigation(
498
702
  initialRouteName?: string;
499
703
  },
500
704
  auto?: boolean
501
- ) {
705
+ ): PathConfigMap<ParamListBase> | undefined {
502
706
  let initialScreenHasPath: boolean = false;
503
- let initialScreenConfig: PathConfig<ParamListBase> | undefined;
707
+ let initialScreenConfig: PathConfig<{}> | undefined;
504
708
 
505
709
  const createPathConfigForTree = (
506
710
  t: TreeForPathConfig,
@@ -517,6 +721,7 @@ export function createPathConfigForStaticNavigation(
517
721
  EventMapBase,
518
722
  Record<string, unknown>
519
723
  >,
724
+ groupLinking: LinkingForGroup | undefined,
520
725
  initialRouteName: string | undefined
521
726
  ) => {
522
727
  return Object.fromEntries(
@@ -535,7 +740,17 @@ export function createPathConfigForStaticNavigation(
535
740
  return 0;
536
741
  })
537
742
  .map(([key, item]) => {
538
- const screenConfig: PathConfig<ParamListBase> = {};
743
+ const screenConfig: PathConfig<{}> = {};
744
+ const groupPath =
745
+ typeof groupLinking === 'string'
746
+ ? groupLinking
747
+ : groupLinking?.path;
748
+
749
+ const normalizePath = (path: string) => {
750
+ return `${groupPath ?? ''}/${path}`
751
+ .replace(/^\//, '') // Remove extra leading slash
752
+ .replace(/\/$/, ''); // Remove extra trailing slash
753
+ };
539
754
 
540
755
  if ('linking' in item) {
541
756
  if (typeof item.linking === 'string') {
@@ -543,14 +758,28 @@ export function createPathConfigForStaticNavigation(
543
758
  } else {
544
759
  Object.assign(screenConfig, item.linking);
545
760
  }
761
+ }
762
+
763
+ if (typeof groupLinking !== 'string') {
764
+ if (groupLinking?.parse != null) {
765
+ screenConfig.parse = {
766
+ ...groupLinking.parse,
767
+ ...screenConfig.parse,
768
+ };
769
+ }
546
770
 
547
- if (typeof screenConfig.path === 'string') {
548
- screenConfig.path = screenConfig.path
549
- .replace(/^\//, '') // Remove extra leading slash
550
- .replace(/\/$/, ''); // Remove extra trailing slash
771
+ if (groupLinking?.stringify != null) {
772
+ screenConfig.stringify = {
773
+ ...groupLinking.stringify,
774
+ ...screenConfig.stringify,
775
+ };
551
776
  }
552
777
  }
553
778
 
779
+ if (typeof screenConfig.path === 'string') {
780
+ screenConfig.path = normalizePath(screenConfig.path);
781
+ }
782
+
554
783
  let screens;
555
784
 
556
785
  const skipInitialDetectionInChild =
@@ -576,12 +805,13 @@ export function createPathConfigForStaticNavigation(
576
805
  }
577
806
 
578
807
  if (screens) {
808
+ // @ts-expect-error - we can't type this properly
579
809
  screenConfig.screens = screens;
580
810
  }
581
811
 
582
812
  if (
583
813
  auto &&
584
- !screenConfig.screens &&
814
+ !('screens' in screenConfig && screenConfig.screens) &&
585
815
  // Skip generating path for screens that specify linking config as `undefined` or `null` explicitly
586
816
  !('linking' in item && item.linking == null)
587
817
  ) {
@@ -596,14 +826,20 @@ export function createPathConfigForStaticNavigation(
596
826
  }
597
827
  }
598
828
  } else {
599
- if (!skipInitialDetection && initialScreenConfig == null) {
829
+ if (
830
+ !groupPath &&
831
+ !skipInitialDetection &&
832
+ initialScreenConfig == null
833
+ ) {
600
834
  initialScreenConfig = screenConfig;
601
835
  }
602
836
 
603
- screenConfig.path = key
604
- .replace(/([A-Z]+)/g, '-$1')
605
- .replace(/^-/, '')
606
- .toLowerCase();
837
+ screenConfig.path = normalizePath(
838
+ key
839
+ .replace(/([A-Z]+)/g, '-$1')
840
+ .replace(/^-/, '')
841
+ .toLowerCase()
842
+ );
607
843
  }
608
844
  }
609
845
 
@@ -623,6 +859,7 @@ export function createPathConfigForStaticNavigation(
623
859
  screens,
624
860
  createPathConfigForScreens(
625
861
  t.config.screens,
862
+ undefined,
626
863
  o?.initialRouteName ?? t.config.initialRouteName
627
864
  )
628
865
  );
@@ -634,6 +871,7 @@ export function createPathConfigForStaticNavigation(
634
871
  screens,
635
872
  createPathConfigForScreens(
636
873
  group.screens,
874
+ group.linking,
637
875
  o?.initialRouteName ?? t.config.initialRouteName
638
876
  )
639
877
  );
@@ -4,13 +4,14 @@ import type {
4
4
  NavigationContainerEventMap,
5
5
  NavigationContainerRef,
6
6
  NavigationContainerRefWithCurrent,
7
+ RootParamList,
7
8
  } from './types';
8
9
 
9
10
  export const NOT_INITIALIZED_ERROR =
10
11
  "The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop#handling-initialization for more details.";
11
12
 
12
13
  export function createNavigationContainerRef<
13
- ParamList extends {} = ReactNavigation.RootParamList,
14
+ ParamList extends {} = RootParamList,
14
15
  >(): NavigationContainerRefWithCurrent<ParamList> {
15
16
  const methods = [
16
17
  ...Object.keys(CommonActions),