@react-navigation/core 7.0.0-alpha.8 → 7.0.0-rc.0

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 (290) hide show
  1. package/lib/commonjs/BaseNavigationContainer.js +18 -19
  2. package/lib/commonjs/BaseNavigationContainer.js.map +1 -1
  3. package/lib/commonjs/CurrentRenderContext.js +1 -1
  4. package/lib/commonjs/CurrentRenderContext.js.map +1 -1
  5. package/lib/commonjs/DeprecatedNavigationInChildContext.js +1 -1
  6. package/lib/commonjs/DeprecatedNavigationInChildContext.js.map +1 -1
  7. package/lib/commonjs/EnsureSingleNavigator.js +4 -5
  8. package/lib/commonjs/EnsureSingleNavigator.js.map +1 -1
  9. package/lib/commonjs/Group.js.map +1 -1
  10. package/lib/commonjs/NavigationBuilderContext.js +1 -1
  11. package/lib/commonjs/NavigationBuilderContext.js.map +1 -1
  12. package/lib/commonjs/NavigationContainerRefContext.js +1 -1
  13. package/lib/commonjs/NavigationContainerRefContext.js.map +1 -1
  14. package/lib/commonjs/NavigationContext.js +1 -1
  15. package/lib/commonjs/NavigationContext.js.map +1 -1
  16. package/lib/commonjs/NavigationHelpersContext.js +1 -1
  17. package/lib/commonjs/NavigationHelpersContext.js.map +1 -1
  18. package/lib/commonjs/NavigationIndependentTree.js +4 -5
  19. package/lib/commonjs/NavigationIndependentTree.js.map +1 -1
  20. package/lib/commonjs/NavigationIndependentTreeContext.js +1 -1
  21. package/lib/commonjs/NavigationIndependentTreeContext.js.map +1 -1
  22. package/lib/commonjs/NavigationRouteContext.js +1 -1
  23. package/lib/commonjs/NavigationRouteContext.js.map +1 -1
  24. package/lib/commonjs/NavigationStateContext.js +1 -1
  25. package/lib/commonjs/NavigationStateContext.js.map +1 -1
  26. package/lib/commonjs/PreventRemoveContext.js +1 -1
  27. package/lib/commonjs/PreventRemoveContext.js.map +1 -1
  28. package/lib/commonjs/PreventRemoveProvider.js +12 -17
  29. package/lib/commonjs/PreventRemoveProvider.js.map +1 -1
  30. package/lib/commonjs/SceneView.js +11 -12
  31. package/lib/commonjs/SceneView.js.map +1 -1
  32. package/lib/commonjs/Screen.js.map +1 -1
  33. package/lib/commonjs/StaticContainer.js +1 -1
  34. package/lib/commonjs/StaticContainer.js.map +1 -1
  35. package/lib/commonjs/StaticNavigation.js +85 -37
  36. package/lib/commonjs/StaticNavigation.js.map +1 -1
  37. package/lib/commonjs/UnhandledActionContext.js +1 -1
  38. package/lib/commonjs/UnhandledActionContext.js.map +1 -1
  39. package/lib/commonjs/checkDuplicateRouteNames.js.map +1 -1
  40. package/lib/commonjs/checkSerializable.js.map +1 -1
  41. package/lib/commonjs/createNavigationContainerRef.js +2 -6
  42. package/lib/commonjs/createNavigationContainerRef.js.map +1 -1
  43. package/lib/commonjs/createNavigatorFactory.js.map +1 -1
  44. package/lib/commonjs/deepFreeze.js +37 -0
  45. package/lib/commonjs/deepFreeze.js.map +1 -0
  46. package/lib/commonjs/findFocusedRoute.js.map +1 -1
  47. package/lib/commonjs/getActionFromState.js +1 -2
  48. package/lib/commonjs/getActionFromState.js.map +1 -1
  49. package/lib/commonjs/getFocusedRouteNameFromRoute.js.map +1 -1
  50. package/lib/commonjs/getPathFromState.js +8 -14
  51. package/lib/commonjs/getPathFromState.js.map +1 -1
  52. package/lib/commonjs/getStateFromPath.js +48 -20
  53. package/lib/commonjs/getStateFromPath.js.map +1 -1
  54. package/lib/commonjs/index.js.map +1 -1
  55. package/lib/commonjs/isArrayEqual.js.map +1 -1
  56. package/lib/commonjs/isRecordEqual.js.map +1 -1
  57. package/lib/commonjs/theming/ThemeContext.js +1 -1
  58. package/lib/commonjs/theming/ThemeContext.js.map +1 -1
  59. package/lib/commonjs/theming/ThemeProvider.js +5 -6
  60. package/lib/commonjs/theming/ThemeProvider.js.map +1 -1
  61. package/lib/commonjs/theming/useTheme.js +1 -1
  62. package/lib/commonjs/theming/useTheme.js.map +1 -1
  63. package/lib/commonjs/types.js.map +1 -1
  64. package/lib/commonjs/useChildListeners.js +1 -1
  65. package/lib/commonjs/useChildListeners.js.map +1 -1
  66. package/lib/commonjs/useComponent.js +8 -10
  67. package/lib/commonjs/useComponent.js.map +1 -1
  68. package/lib/commonjs/useCurrentRender.js +6 -7
  69. package/lib/commonjs/useCurrentRender.js.map +1 -1
  70. package/lib/commonjs/useDescriptors.js +16 -17
  71. package/lib/commonjs/useDescriptors.js.map +1 -1
  72. package/lib/commonjs/useEventEmitter.js +7 -8
  73. package/lib/commonjs/useEventEmitter.js.map +1 -1
  74. package/lib/commonjs/useFocusEffect.js +3 -3
  75. package/lib/commonjs/useFocusEffect.js.map +1 -1
  76. package/lib/commonjs/useFocusEvents.js +5 -6
  77. package/lib/commonjs/useFocusEvents.js.map +1 -1
  78. package/lib/commonjs/useFocusedListenersChildrenAdapter.js +5 -6
  79. package/lib/commonjs/useFocusedListenersChildrenAdapter.js.map +1 -1
  80. package/lib/commonjs/useIsFocused.js +1 -1
  81. package/lib/commonjs/useIsFocused.js.map +1 -1
  82. package/lib/commonjs/useIsomorphicLayoutEffect.js.map +1 -1
  83. package/lib/commonjs/useIsomorphicLayoutEffect.native.js.map +1 -1
  84. package/lib/commonjs/useKeyedChildListeners.js +1 -1
  85. package/lib/commonjs/useKeyedChildListeners.js.map +1 -1
  86. package/lib/commonjs/useLazyValue.js +17 -0
  87. package/lib/commonjs/useLazyValue.js.map +1 -0
  88. package/lib/commonjs/useNavigation.js +1 -1
  89. package/lib/commonjs/useNavigation.js.map +1 -1
  90. package/lib/commonjs/useNavigationBuilder.js +16 -8
  91. package/lib/commonjs/useNavigationBuilder.js.map +1 -1
  92. package/lib/commonjs/useNavigationCache.js +12 -18
  93. package/lib/commonjs/useNavigationCache.js.map +1 -1
  94. package/lib/commonjs/useNavigationContainerRef.js +1 -1
  95. package/lib/commonjs/useNavigationContainerRef.js.map +1 -1
  96. package/lib/commonjs/useNavigationHelpers.js +9 -12
  97. package/lib/commonjs/useNavigationHelpers.js.map +1 -1
  98. package/lib/commonjs/useNavigationIndependentTree.js +1 -1
  99. package/lib/commonjs/useNavigationIndependentTree.js.map +1 -1
  100. package/lib/commonjs/useNavigationState.js +1 -1
  101. package/lib/commonjs/useNavigationState.js.map +1 -1
  102. package/lib/commonjs/useOnAction.js +12 -14
  103. package/lib/commonjs/useOnAction.js.map +1 -1
  104. package/lib/commonjs/useOnGetState.js +5 -6
  105. package/lib/commonjs/useOnGetState.js.map +1 -1
  106. package/lib/commonjs/useOnPreventRemove.js +6 -7
  107. package/lib/commonjs/useOnPreventRemove.js.map +1 -1
  108. package/lib/commonjs/useOnRouteFocus.js +7 -8
  109. package/lib/commonjs/useOnRouteFocus.js.map +1 -1
  110. package/lib/commonjs/useOptionsGetters.js +6 -7
  111. package/lib/commonjs/useOptionsGetters.js.map +1 -1
  112. package/lib/commonjs/usePreventRemove.js +2 -2
  113. package/lib/commonjs/usePreventRemove.js.map +1 -1
  114. package/lib/commonjs/usePreventRemoveContext.js +1 -1
  115. package/lib/commonjs/usePreventRemoveContext.js.map +1 -1
  116. package/lib/commonjs/useRegisterNavigator.js +1 -1
  117. package/lib/commonjs/useRegisterNavigator.js.map +1 -1
  118. package/lib/commonjs/useRoute.js +1 -1
  119. package/lib/commonjs/useRoute.js.map +1 -1
  120. package/lib/commonjs/useRouteCache.js +16 -2
  121. package/lib/commonjs/useRouteCache.js.map +1 -1
  122. package/lib/commonjs/useSyncState.js +13 -4
  123. package/lib/commonjs/useSyncState.js.map +1 -1
  124. package/lib/commonjs/validatePathConfig.js +3 -8
  125. package/lib/commonjs/validatePathConfig.js.map +1 -1
  126. package/lib/module/BaseNavigationContainer.js +16 -17
  127. package/lib/module/BaseNavigationContainer.js.map +1 -1
  128. package/lib/module/CurrentRenderContext.js.map +1 -1
  129. package/lib/module/DeprecatedNavigationInChildContext.js.map +1 -1
  130. package/lib/module/EnsureSingleNavigator.js +3 -4
  131. package/lib/module/EnsureSingleNavigator.js.map +1 -1
  132. package/lib/module/Group.js.map +1 -1
  133. package/lib/module/NavigationBuilderContext.js.map +1 -1
  134. package/lib/module/NavigationContainerRefContext.js.map +1 -1
  135. package/lib/module/NavigationContext.js.map +1 -1
  136. package/lib/module/NavigationHelpersContext.js.map +1 -1
  137. package/lib/module/NavigationIndependentTree.js +3 -4
  138. package/lib/module/NavigationIndependentTree.js.map +1 -1
  139. package/lib/module/NavigationIndependentTreeContext.js.map +1 -1
  140. package/lib/module/NavigationRouteContext.js.map +1 -1
  141. package/lib/module/NavigationStateContext.js.map +1 -1
  142. package/lib/module/PreventRemoveContext.js.map +1 -1
  143. package/lib/module/PreventRemoveProvider.js +10 -15
  144. package/lib/module/PreventRemoveProvider.js.map +1 -1
  145. package/lib/module/SceneView.js +10 -11
  146. package/lib/module/SceneView.js.map +1 -1
  147. package/lib/module/Screen.js.map +1 -1
  148. package/lib/module/StaticContainer.js.map +1 -1
  149. package/lib/module/StaticNavigation.js +84 -36
  150. package/lib/module/StaticNavigation.js.map +1 -1
  151. package/lib/module/UnhandledActionContext.js.map +1 -1
  152. package/lib/module/checkDuplicateRouteNames.js.map +1 -1
  153. package/lib/module/checkSerializable.js.map +1 -1
  154. package/lib/module/createNavigationContainerRef.js +2 -6
  155. package/lib/module/createNavigationContainerRef.js.map +1 -1
  156. package/lib/module/createNavigatorFactory.js +1 -0
  157. package/lib/module/createNavigatorFactory.js.map +1 -1
  158. package/lib/module/deepFreeze.js +29 -0
  159. package/lib/module/deepFreeze.js.map +1 -0
  160. package/lib/module/findFocusedRoute.js.map +1 -1
  161. package/lib/module/getActionFromState.js +1 -2
  162. package/lib/module/getActionFromState.js.map +1 -1
  163. package/lib/module/getFocusedRouteNameFromRoute.js.map +1 -1
  164. package/lib/module/getPathFromState.js +7 -13
  165. package/lib/module/getPathFromState.js.map +1 -1
  166. package/lib/module/getStateFromPath.js +46 -18
  167. package/lib/module/getStateFromPath.js.map +1 -1
  168. package/lib/module/index.js.map +1 -1
  169. package/lib/module/isArrayEqual.js.map +1 -1
  170. package/lib/module/isRecordEqual.js.map +1 -1
  171. package/lib/module/theming/ThemeContext.js.map +1 -1
  172. package/lib/module/theming/ThemeProvider.js +4 -5
  173. package/lib/module/theming/ThemeProvider.js.map +1 -1
  174. package/lib/module/theming/useTheme.js.map +1 -1
  175. package/lib/module/types.js.map +1 -1
  176. package/lib/module/useChildListeners.js.map +1 -1
  177. package/lib/module/useComponent.js +7 -9
  178. package/lib/module/useComponent.js.map +1 -1
  179. package/lib/module/useCurrentRender.js +5 -6
  180. package/lib/module/useCurrentRender.js.map +1 -1
  181. package/lib/module/useDescriptors.js +15 -16
  182. package/lib/module/useDescriptors.js.map +1 -1
  183. package/lib/module/useEventEmitter.js +6 -7
  184. package/lib/module/useEventEmitter.js.map +1 -1
  185. package/lib/module/useFocusEffect.js +2 -2
  186. package/lib/module/useFocusEffect.js.map +1 -1
  187. package/lib/module/useFocusEvents.js +4 -5
  188. package/lib/module/useFocusEvents.js.map +1 -1
  189. package/lib/module/useFocusedListenersChildrenAdapter.js +4 -5
  190. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  191. package/lib/module/useIsFocused.js.map +1 -1
  192. package/lib/module/useIsomorphicLayoutEffect.js.map +1 -1
  193. package/lib/module/useIsomorphicLayoutEffect.native.js.map +1 -1
  194. package/lib/module/useKeyedChildListeners.js.map +1 -1
  195. package/lib/module/useLazyValue.js +9 -0
  196. package/lib/module/useLazyValue.js.map +1 -0
  197. package/lib/module/useNavigation.js.map +1 -1
  198. package/lib/module/useNavigationBuilder.js +14 -6
  199. package/lib/module/useNavigationBuilder.js.map +1 -1
  200. package/lib/module/useNavigationCache.js +11 -17
  201. package/lib/module/useNavigationCache.js.map +1 -1
  202. package/lib/module/useNavigationContainerRef.js.map +1 -1
  203. package/lib/module/useNavigationHelpers.js +8 -11
  204. package/lib/module/useNavigationHelpers.js.map +1 -1
  205. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  206. package/lib/module/useNavigationState.js.map +1 -1
  207. package/lib/module/useOnAction.js +11 -13
  208. package/lib/module/useOnAction.js.map +1 -1
  209. package/lib/module/useOnGetState.js +4 -5
  210. package/lib/module/useOnGetState.js.map +1 -1
  211. package/lib/module/useOnPreventRemove.js +5 -6
  212. package/lib/module/useOnPreventRemove.js.map +1 -1
  213. package/lib/module/useOnRouteFocus.js +6 -7
  214. package/lib/module/useOnRouteFocus.js.map +1 -1
  215. package/lib/module/useOptionsGetters.js +5 -6
  216. package/lib/module/useOptionsGetters.js.map +1 -1
  217. package/lib/module/usePreventRemove.js.map +1 -1
  218. package/lib/module/usePreventRemoveContext.js.map +1 -1
  219. package/lib/module/useRegisterNavigator.js.map +1 -1
  220. package/lib/module/useRoute.js.map +1 -1
  221. package/lib/module/useRouteCache.js +15 -1
  222. package/lib/module/useRouteCache.js.map +1 -1
  223. package/lib/module/useSyncState.js +12 -3
  224. package/lib/module/useSyncState.js.map +1 -1
  225. package/lib/module/validatePathConfig.js +3 -8
  226. package/lib/module/validatePathConfig.js.map +1 -1
  227. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  228. package/lib/typescript/src/CurrentRenderContext.d.ts +1 -1
  229. package/lib/typescript/src/CurrentRenderContext.d.ts.map +1 -1
  230. package/lib/typescript/src/Group.d.ts +1 -1
  231. package/lib/typescript/src/Group.d.ts.map +1 -1
  232. package/lib/typescript/src/NavigationBuilderContext.d.ts +5 -5
  233. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  234. package/lib/typescript/src/NavigationStateContext.d.ts +3 -19
  235. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  236. package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
  237. package/lib/typescript/src/Screen.d.ts +1 -1
  238. package/lib/typescript/src/Screen.d.ts.map +1 -1
  239. package/lib/typescript/src/StaticNavigation.d.ts +43 -19
  240. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  241. package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
  242. package/lib/typescript/src/createNavigatorFactory.d.ts +1 -9
  243. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  244. package/lib/typescript/src/deepFreeze.d.ts +3 -0
  245. package/lib/typescript/src/deepFreeze.d.ts.map +1 -0
  246. package/lib/typescript/src/findFocusedRoute.d.ts +1 -11
  247. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  248. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  249. package/lib/typescript/src/index.d.ts +1 -1
  250. package/lib/typescript/src/index.d.ts.map +1 -1
  251. package/lib/typescript/src/types.d.ts +69 -24
  252. package/lib/typescript/src/types.d.ts.map +1 -1
  253. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  254. package/lib/typescript/src/useComponent.d.ts.map +1 -1
  255. package/lib/typescript/src/useDescriptors.d.ts +35 -45
  256. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  257. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  258. package/lib/typescript/src/useLazyValue.d.ts +2 -0
  259. package/lib/typescript/src/useLazyValue.d.ts.map +1 -0
  260. package/lib/typescript/src/useNavigation.d.ts +4 -1
  261. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  262. package/lib/typescript/src/useNavigationBuilder.d.ts +57 -93
  263. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  264. package/lib/typescript/src/useNavigationCache.d.ts +17 -22
  265. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  266. package/lib/typescript/src/useNavigationHelpers.d.ts +21 -26
  267. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  268. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  269. package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
  270. package/lib/typescript/src/useRouteCache.d.ts +1 -1
  271. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  272. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  273. package/package.json +5 -5
  274. package/src/BaseNavigationContainer.tsx +3 -0
  275. package/src/Group.tsx +2 -1
  276. package/src/Screen.tsx +11 -1
  277. package/src/StaticNavigation.tsx +299 -72
  278. package/src/createNavigatorFactory.tsx +1 -36
  279. package/src/deepFreeze.tsx +34 -0
  280. package/src/getPathFromState.tsx +6 -1
  281. package/src/getStateFromPath.tsx +60 -16
  282. package/src/index.tsx +1 -0
  283. package/src/types.tsx +138 -23
  284. package/src/useDescriptors.tsx +8 -1
  285. package/src/useFocusEffect.tsx +2 -2
  286. package/src/useLazyValue.tsx +11 -0
  287. package/src/useNavigation.tsx +4 -1
  288. package/src/useNavigationBuilder.tsx +33 -11
  289. package/src/useRouteCache.tsx +17 -1
  290. package/src/useSyncState.tsx +16 -3
@@ -5,9 +5,12 @@ import { isValidElementType } from 'react-is';
5
5
  import type {
6
6
  DefaultNavigatorOptions,
7
7
  EventMapBase,
8
+ NavigationListBase,
8
9
  NavigatorScreenParams,
10
+ NavigatorTypeBagBase,
9
11
  PathConfig,
10
- RouteConfig,
12
+ RouteConfigComponent,
13
+ RouteConfigProps,
11
14
  RouteGroupConfig,
12
15
  } from './types';
13
16
  import { useRoute } from './useRoute';
@@ -62,7 +65,8 @@ type ParamListForGroups<
62
65
  ParamListBase,
63
66
  NavigationState,
64
67
  {},
65
- EventMapBase
68
+ EventMapBase,
69
+ any
66
70
  >;
67
71
  };
68
72
  }>
@@ -73,24 +77,53 @@ type ParamListForGroups<
73
77
  ParamListBase,
74
78
  NavigationState,
75
79
  {},
76
- EventMapBase
80
+ EventMapBase,
81
+ any
77
82
  >;
78
83
  };
79
84
  }
80
85
  ? ParamListForScreens<UnionToIntersection<Groups[keyof Groups]['screens']>>
81
86
  : {};
82
87
 
88
+ type StaticRouteConfig<
89
+ ParamList extends ParamListBase,
90
+ RouteName extends keyof ParamList,
91
+ State extends NavigationState,
92
+ ScreenOptions extends {},
93
+ EventMap extends EventMapBase,
94
+ Navigation,
95
+ > = RouteConfigProps<
96
+ // FIXME: the param list is inferred from the screen component
97
+ // So we can't use the type here
98
+ // Fallback to ParamListBase for now
99
+ ParamListBase,
100
+ string,
101
+ State,
102
+ ScreenOptions,
103
+ EventMap,
104
+ Navigation
105
+ > &
106
+ RouteConfigComponent<ParamList, RouteName>;
107
+
83
108
  type StaticConfigScreens<
84
109
  ParamList extends ParamListBase,
85
110
  State extends NavigationState,
86
111
  ScreenOptions extends {},
87
112
  EventMap extends EventMapBase,
113
+ NavigationList extends NavigationListBase<ParamList>,
88
114
  > = {
89
- [key in keyof ParamList]:
115
+ [RouteName in keyof ParamList]:
90
116
  | React.ComponentType<any>
91
117
  | StaticNavigation<any, any, any>
92
118
  | (Omit<
93
- RouteConfig<ParamList, keyof ParamList, State, ScreenOptions, EventMap>,
119
+ StaticRouteConfig<
120
+ ParamList,
121
+ RouteName,
122
+ State,
123
+ ScreenOptions,
124
+ EventMap,
125
+ NavigationList[RouteName]
126
+ >,
94
127
  'name' | 'component' | 'getComponent' | 'children'
95
128
  > & {
96
129
  /**
@@ -131,7 +164,11 @@ type GroupConfig<
131
164
  State extends NavigationState,
132
165
  ScreenOptions extends {},
133
166
  EventMap extends EventMapBase,
134
- > = Omit<RouteGroupConfig<ParamList, ScreenOptions>, 'screens' | 'children'> & {
167
+ NavigationList extends NavigationListBase<ParamList>,
168
+ > = Omit<
169
+ RouteGroupConfig<ParamList, ScreenOptions, NavigationList[keyof ParamList]>,
170
+ 'screens' | 'children'
171
+ > & {
135
172
  /**
136
173
  * Callback to determine whether the screens in the group should be rendered or not.
137
174
  * This can be useful for conditional rendering of group of screens.
@@ -140,39 +177,106 @@ type GroupConfig<
140
177
  /**
141
178
  * Static navigation config or Component to render for the screen.
142
179
  */
143
- screens: StaticConfigScreens<ParamList, State, ScreenOptions, EventMap>;
180
+ screens: StaticConfigScreens<
181
+ ParamList,
182
+ State,
183
+ ScreenOptions,
184
+ EventMap,
185
+ NavigationList
186
+ >;
144
187
  };
145
188
 
146
- export type StaticConfig<
189
+ export type StaticConfig<Bag extends NavigatorTypeBagBase> =
190
+ StaticConfigInternal<
191
+ Bag['ParamList'],
192
+ Bag['NavigatorID'],
193
+ Bag['State'],
194
+ Bag['ScreenOptions'],
195
+ Bag['EventMap'],
196
+ Bag['NavigationList'],
197
+ Bag['Navigator']
198
+ >;
199
+
200
+ type StaticConfigInternal<
147
201
  ParamList extends ParamListBase,
202
+ NavigatorID extends string | undefined,
148
203
  State extends NavigationState,
149
204
  ScreenOptions extends {},
150
205
  EventMap extends EventMapBase,
151
- Navigator extends React.ComponentType<{}>,
206
+ NavigationList extends NavigationListBase<ParamList>,
207
+ Navigator extends React.ComponentType<any>,
152
208
  > = Omit<
153
209
  Omit<
154
210
  React.ComponentProps<Navigator>,
155
211
  keyof DefaultNavigatorOptions<
156
212
  ParamListBase,
213
+ string | undefined,
157
214
  NavigationState,
158
215
  {},
159
- EventMapBase
216
+ EventMapBase,
217
+ NavigationList[keyof ParamList]
160
218
  >
161
219
  > &
162
- DefaultNavigatorOptions<ParamList, State, ScreenOptions, EventMap>,
220
+ DefaultNavigatorOptions<
221
+ ParamList,
222
+ NavigatorID,
223
+ State,
224
+ ScreenOptions,
225
+ EventMap,
226
+ NavigationList[keyof ParamList]
227
+ >,
163
228
  'screens' | 'children'
164
- > & {
165
- /**
166
- * Screens to render in the navigator and their configuration.
167
- */
168
- screens: StaticConfigScreens<ParamList, State, ScreenOptions, EventMap>;
169
- /**
170
- * Groups of screens to render in the navigator and their configuration.
171
- */
172
- groups?: {
173
- [key: string]: GroupConfig<ParamList, State, ScreenOptions, EventMap>;
174
- };
175
- };
229
+ > &
230
+ (
231
+ | {
232
+ /**
233
+ * Screens to render in the navigator and their configuration.
234
+ */
235
+ screens: StaticConfigScreens<
236
+ ParamList,
237
+ State,
238
+ ScreenOptions,
239
+ EventMap,
240
+ NavigationList
241
+ >;
242
+ /**
243
+ * Groups of screens to render in the navigator and their configuration.
244
+ */
245
+ groups?: {
246
+ [key: string]: GroupConfig<
247
+ ParamList,
248
+ State,
249
+ ScreenOptions,
250
+ EventMap,
251
+ NavigationList
252
+ >;
253
+ };
254
+ }
255
+ | {
256
+ /**
257
+ * Screens to render in the navigator and their configuration.
258
+ */
259
+ screens?: StaticConfigScreens<
260
+ ParamList,
261
+ State,
262
+ ScreenOptions,
263
+ EventMap,
264
+ NavigationList
265
+ >;
266
+ /**
267
+ * Groups of screens to render in the navigator and their configuration.
268
+ */
269
+ groups: {
270
+ [key: string]: GroupConfig<
271
+ ParamList,
272
+ State,
273
+ ScreenOptions,
274
+ EventMap,
275
+ NavigationList
276
+ >;
277
+ };
278
+ }
279
+ );
176
280
 
177
281
  /**
178
282
  * Props for a screen component which is rendered by a static navigator.
@@ -190,7 +294,7 @@ export type StaticScreenProps<T extends Record<string, unknown> | undefined> = {
190
294
  export type StaticParamList<
191
295
  T extends {
192
296
  readonly config: {
193
- readonly screens: Record<string, any>;
297
+ readonly screens?: Record<string, any>;
194
298
  readonly groups?: {
195
299
  [key: string]: {
196
300
  screens: Record<string, any>;
@@ -207,13 +311,7 @@ export type StaticNavigation<NavigatorProps, GroupProps, ScreenProps> = {
207
311
  Navigator: React.ComponentType<NavigatorProps>;
208
312
  Group: React.ComponentType<GroupProps>;
209
313
  Screen: React.ComponentType<ScreenProps>;
210
- config: StaticConfig<
211
- ParamListBase,
212
- NavigationState,
213
- {},
214
- EventMapBase,
215
- React.ComponentType<any>
216
- >;
314
+ config: StaticConfig<NavigatorTypeBagBase>;
217
315
  };
218
316
 
219
317
  const MemoizedScreen = React.memo(
@@ -227,7 +325,7 @@ const MemoizedScreen = React.memo(
227
325
 
228
326
  const getItemsFromScreens = (
229
327
  Screen: React.ComponentType<any>,
230
- screens: StaticConfigScreens<any, any, any, any>
328
+ screens: StaticConfigScreens<any, any, any, any, any>
231
329
  ) => {
232
330
  return Object.entries(screens).map(([name, item]) => {
233
331
  let component: React.ComponentType<any> | undefined;
@@ -300,13 +398,13 @@ export function createComponentForStaticNavigation(
300
398
  const { Navigator, Group, Screen, config } = tree;
301
399
  const { screens, groups, ...rest } = config;
302
400
 
303
- if (screens == null) {
401
+ if (screens == null && groups == null) {
304
402
  throw new Error(
305
- "Couldn't find a 'screens' property. Make sure to define your screens under a 'screens' property in the configuration."
403
+ "Couldn't find a 'screens' or 'groups' property. Make sure to define your screens under a 'screens' property in the configuration."
306
404
  );
307
405
  }
308
406
 
309
- const items = getItemsFromScreens(Screen, screens);
407
+ const items = screens ? getItemsFromScreens(Screen, screens) : [];
310
408
 
311
409
  if (groups) {
312
410
  items.push(
@@ -344,10 +442,36 @@ export function createComponentForStaticNavigation(
344
442
  return NavigatorComponent;
345
443
  }
346
444
 
445
+ type TreeForPathConfig = {
446
+ config: {
447
+ initialRouteName?: string;
448
+ screens?: StaticConfigScreens<
449
+ ParamListBase,
450
+ NavigationState,
451
+ {},
452
+ EventMapBase,
453
+ Record<string, unknown>
454
+ >;
455
+ groups?: {
456
+ [key: string]: {
457
+ screens: StaticConfigScreens<
458
+ ParamListBase,
459
+ NavigationState,
460
+ {},
461
+ EventMapBase,
462
+ Record<string, unknown>
463
+ >;
464
+ };
465
+ };
466
+ };
467
+ };
468
+
347
469
  /**
348
470
  * Create a path config object from a static navigation config for deep linking.
349
471
  *
350
472
  * @param tree Static navigation config.
473
+ * @param options Additional options from `linking.config`.
474
+ * @param auto Whether to automatically generate paths for leaf screens.
351
475
  * @returns Path config object to use in linking config.
352
476
  *
353
477
  * @example
@@ -361,43 +485,146 @@ export function createComponentForStaticNavigation(
361
485
  * };
362
486
  * ```
363
487
  */
364
- export function createPathConfigForStaticNavigation(tree: {
365
- config: {
366
- screens: StaticConfigScreens<
367
- ParamListBase,
368
- NavigationState,
369
- {},
370
- EventMapBase
371
- >;
488
+ export function createPathConfigForStaticNavigation(
489
+ tree: TreeForPathConfig,
490
+ options?: {
491
+ initialRouteName?: string;
492
+ },
493
+ auto?: boolean
494
+ ) {
495
+ let initialScreenConfig: PathConfig<ParamListBase> | undefined;
496
+
497
+ const createPathConfigForTree = (
498
+ t: TreeForPathConfig,
499
+ o: { initialRouteName?: string } | undefined,
500
+ // If a screen is a leaf node, but inside a screen with path,
501
+ // It should not be used for initial detection
502
+ skipInitialDetection: boolean
503
+ ) => {
504
+ const createPathConfigForScreens = (
505
+ screens: StaticConfigScreens<
506
+ ParamListBase,
507
+ NavigationState,
508
+ {},
509
+ EventMapBase,
510
+ Record<string, unknown>
511
+ >,
512
+ initialRouteName: string | undefined
513
+ ) => {
514
+ return Object.fromEntries(
515
+ Object.entries(screens)
516
+ // Re-order to move the initial route to the front
517
+ // This way we can detect the initial route correctly
518
+ .sort(([a], [b]) => {
519
+ if (a === initialRouteName) {
520
+ return -1;
521
+ }
522
+
523
+ if (b === initialRouteName) {
524
+ return 1;
525
+ }
526
+
527
+ return 0;
528
+ })
529
+ .map(([key, item]) => {
530
+ const screenConfig: PathConfig<ParamListBase> = {};
531
+
532
+ if ('linking' in item) {
533
+ if (typeof item.linking === 'string') {
534
+ screenConfig.path = item.linking;
535
+ } else {
536
+ Object.assign(screenConfig, item.linking);
537
+ }
538
+ }
539
+
540
+ let screens;
541
+
542
+ if ('config' in item) {
543
+ screens = createPathConfigForTree(
544
+ item,
545
+ undefined,
546
+ skipInitialDetection || screenConfig.path != null
547
+ );
548
+ } else if (
549
+ 'screen' in item &&
550
+ 'config' in item.screen &&
551
+ (item.screen.config.screens || item.screen.config.groups)
552
+ ) {
553
+ screens = createPathConfigForTree(
554
+ item.screen,
555
+ undefined,
556
+ skipInitialDetection || screenConfig.path != null
557
+ );
558
+ }
559
+
560
+ if (screens) {
561
+ screenConfig.screens = screens;
562
+ }
563
+
564
+ if (auto && !screenConfig.screens && !('linking' in item)) {
565
+ if (screenConfig.path) {
566
+ if (!skipInitialDetection) {
567
+ // Normalize the path to remove leading and trailing slashes
568
+ const path = screenConfig.path
569
+ ?.split('/')
570
+ .filter(Boolean)
571
+ .join('/');
572
+
573
+ // We encounter a leaf screen with empty path,
574
+ // Clear the initial screen config as it's not needed anymore
575
+ if (!skipInitialDetection && path === '') {
576
+ initialScreenConfig = undefined;
577
+ }
578
+ }
579
+ } else {
580
+ if (!skipInitialDetection && initialScreenConfig == null) {
581
+ initialScreenConfig = screenConfig;
582
+ }
583
+
584
+ screenConfig.path = key
585
+ .replace(/([A-Z]+)/g, '-$1')
586
+ .replace(/^-/, '')
587
+ .toLowerCase();
588
+ }
589
+ }
590
+
591
+ return [key, screenConfig] as const;
592
+ })
593
+ .filter(([, screen]) => Object.keys(screen).length > 0)
594
+ );
595
+ };
596
+
597
+ const screens = t.config.screens
598
+ ? createPathConfigForScreens(
599
+ t.config.screens,
600
+ o?.initialRouteName ?? t.config.initialRouteName
601
+ )
602
+ : {};
603
+
604
+ if (t.config.groups) {
605
+ Object.entries(t.config.groups).forEach(([, group]) => {
606
+ Object.assign(
607
+ screens,
608
+ createPathConfigForScreens(
609
+ group.screens,
610
+ o?.initialRouteName ?? t.config.initialRouteName
611
+ )
612
+ );
613
+ });
614
+ }
615
+
616
+ if (Object.keys(screens).length === 0) {
617
+ return undefined;
618
+ }
619
+
620
+ return screens;
372
621
  };
373
- }) {
374
- return Object.fromEntries(
375
- Object.entries(tree.config.screens)
376
- .map(([key, item]) => {
377
- const screenConfig: PathConfig<ParamListBase> = {};
378
-
379
- if ('linking' in item) {
380
- if (typeof item.linking === 'string') {
381
- screenConfig.path = item.linking;
382
- } else {
383
- Object.assign(screenConfig, item.linking);
384
- }
385
- }
386
-
387
- if ('config' in item) {
388
- screenConfig.screens = createPathConfigForStaticNavigation(item);
389
- } else if (
390
- 'screen' in item &&
391
- 'config' in item.screen &&
392
- item.screen.config.screens
393
- ) {
394
- screenConfig.screens = createPathConfigForStaticNavigation(
395
- item.screen
396
- );
397
- }
398
622
 
399
- return [key, screenConfig] as const;
400
- })
401
- .filter(([, screen]) => Object.keys(screen).length > 0)
402
- );
623
+ const screens = createPathConfigForTree(tree, options, false);
624
+
625
+ if (auto && initialScreenConfig) {
626
+ initialScreenConfig.path = '';
627
+ }
628
+
629
+ return screens;
403
630
  }
@@ -1,10 +1,7 @@
1
- import type { NavigationState, ParamListBase } from '@react-navigation/routers';
2
1
  import type * as React from 'react';
3
2
 
4
3
  import { Group } from './Group';
5
4
  import { Screen } from './Screen';
6
- import type { StaticConfig } from './StaticNavigation';
7
- import type { EventMapBase, TypedNavigator } from './types';
8
5
 
9
6
  /**
10
7
  * Higher order component to create a `Navigator` and `Screen` pair.
@@ -13,39 +10,7 @@ import type { EventMapBase, TypedNavigator } from './types';
13
10
  * @param Navigator The navigator component to wrap.
14
11
  * @returns Factory method to create a `Navigator` and `Screen` pair.
15
12
  */
16
- export function createNavigatorFactory<
17
- State extends NavigationState,
18
- ScreenOptions extends {},
19
- EventMap extends EventMapBase,
20
- NavigatorComponent extends React.ComponentType<any>,
21
- >(Navigator: NavigatorComponent) {
22
- function createNavigator<ParamList extends ParamListBase>(): TypedNavigator<
23
- ParamList,
24
- State,
25
- ScreenOptions,
26
- EventMap,
27
- typeof Navigator
28
- >;
29
-
30
- function createNavigator<
31
- ParamList extends ParamListBase,
32
- Config extends StaticConfig<
33
- ParamList,
34
- State,
35
- ScreenOptions,
36
- EventMap,
37
- typeof Navigator
38
- >,
39
- >(
40
- config: Config
41
- ): TypedNavigator<
42
- ParamList,
43
- State,
44
- ScreenOptions,
45
- EventMap,
46
- typeof Navigator
47
- > & { config: Config };
48
-
13
+ export function createNavigatorFactory(Navigator: React.ComponentType<any>) {
49
14
  function createNavigator(config?: any): any {
50
15
  if (config != null) {
51
16
  return {
@@ -0,0 +1,34 @@
1
+ export const isPlainObject = (value: unknown): value is object => {
2
+ if (typeof value === 'object' && value !== null) {
3
+ return Object.getPrototypeOf(value) === Object.prototype;
4
+ }
5
+
6
+ return false;
7
+ };
8
+
9
+ export const deepFreeze = <T,>(object: T): Readonly<T> => {
10
+ // We only freeze in development to catch issues early
11
+ // Don't freeze in production to avoid unnecessary performance overhead
12
+ if (process.env.NODE_ENV === 'production') {
13
+ return object;
14
+ }
15
+
16
+ if (Object.isFrozen(object)) {
17
+ return object;
18
+ }
19
+
20
+ if (!isPlainObject(object) && !Array.isArray(object)) {
21
+ return object;
22
+ }
23
+
24
+ // Freeze properties before freezing self
25
+ for (const key in object) {
26
+ if (Object.getOwnPropertyDescriptor(object, key)?.configurable) {
27
+ const value = object[key];
28
+
29
+ deepFreeze(value);
30
+ }
31
+ }
32
+
33
+ return Object.freeze(object);
34
+ };
@@ -196,7 +196,12 @@ export function getPathFromState<ParamList extends {}>(
196
196
  return '';
197
197
  }
198
198
 
199
- return encodeURIComponent(value);
199
+ // Valid characters according to
200
+ // https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 (see pchar definition)
201
+ return String(value).replace(
202
+ /[^A-Za-z0-9\-._~!$&'()*+,;=:@]/g,
203
+ (char) => encodeURIComponent(char)
204
+ );
200
205
  }
201
206
 
202
207
  return encodeURIComponent(p);
@@ -287,29 +287,73 @@ const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
287
287
 
288
288
  // If our regex matches, we need to extract params from the path
289
289
  if (match) {
290
- const matchedParams = config.pattern
291
- ?.split('/')
292
- .filter((p) => p.startsWith(':'))
293
- .reduce<Record<string, any>>(
294
- (acc, p, i) =>
295
- Object.assign(acc, {
296
- // The param segments appear every second item starting from 2 in the regex match result
297
- [p]: match![(i + 1) * 2].replace(/\//, ''),
290
+ const matchResult = config.pattern?.split('/').reduce<{
291
+ pos: number; // Position of the current path param segment in the path (e.g in pattern `a/:b/:c`, `:a` is 0 and `:b` is 1)
292
+ matchedParams: Record<string, Record<string, string>>; // The extracted params
293
+ }>(
294
+ (acc, p, index) => {
295
+ if (!p.startsWith(':')) {
296
+ return acc;
297
+ }
298
+
299
+ // Path parameter so increment position for the segment
300
+ acc.pos += 1;
301
+
302
+ const decodedParamSegment = decodeURIComponent(
303
+ // The param segments appear every second item starting from 2 in the regex match result
304
+ match![(acc.pos + 1) * 2]
305
+ // Remove trailing slash
306
+ .replace(/\/$/, '')
307
+ );
308
+
309
+ Object.assign(acc.matchedParams, {
310
+ [p]: Object.assign(acc.matchedParams[p] || {}, {
311
+ [index]: decodedParamSegment,
298
312
  }),
299
- {}
300
- );
313
+ });
314
+
315
+ return acc;
316
+ },
317
+ { pos: -1, matchedParams: {} }
318
+ );
319
+
320
+ const matchedParams = matchResult.matchedParams || {};
301
321
 
302
322
  routes = config.routeNames.map((name) => {
303
- const config = configs.find((c) => c.screen === name);
304
- const params = config?.path
323
+ const routeConfig = configs.find((c) => {
324
+ // Check matching name AND pattern in case same screen is used at different levels in config
325
+ return c.screen === name && config.pattern.startsWith(c.pattern);
326
+ });
327
+
328
+ // Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.
329
+ const normalizedPath = routeConfig?.path
330
+ .split('/')
331
+ .filter(Boolean)
332
+ .join('/');
333
+
334
+ // Get the number of segments in the initial pattern
335
+ const numInitialSegments = routeConfig?.pattern
336
+ // Extract the prefix from the pattern by removing the ending path pattern (e.g pattern=`a/b/c/d` and normalizedPath=`c/d` becomes `a/b`)
337
+ .replace(new RegExp(`${escape(normalizedPath!)}$`), '')
338
+ ?.split('/').length;
339
+
340
+ const params = normalizedPath
305
341
  ?.split('/')
306
- .filter((p) => p.startsWith(':'))
307
- .reduce<Record<string, any>>((acc, p) => {
308
- const value = matchedParams[p];
342
+ .reduce<Record<string, unknown>>((acc, p, index) => {
343
+ if (!p.startsWith(':')) {
344
+ return acc;
345
+ }
346
+
347
+ // Get the real index of the path parameter in the matched path
348
+ // by offsetting by the number of segments in the initial pattern
349
+ const offset = numInitialSegments ? numInitialSegments - 1 : 0;
350
+ const value = matchedParams[p]?.[index + offset];
309
351
 
310
352
  if (value) {
311
353
  const key = p.replace(/^:/, '').replace(/\?$/, '');
312
- acc[key] = config.parse?.[key] ? config.parse[key](value) : value;
354
+ acc[key] = routeConfig?.parse?.[key]
355
+ ? routeConfig.parse[key](value)
356
+ : value;
313
357
  }
314
358
 
315
359
  return acc;
package/src/index.tsx CHANGED
@@ -17,6 +17,7 @@ export { PreventRemoveProvider } from './PreventRemoveProvider';
17
17
  export {
18
18
  createComponentForStaticNavigation,
19
19
  createPathConfigForStaticNavigation,
20
+ type StaticConfig,
20
21
  type StaticNavigation,
21
22
  type StaticParamList,
22
23
  type StaticScreenProps,