@react-navigation/core 8.0.0-alpha.3 → 8.0.0-alpha.30

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 (283) hide show
  1. package/lib/module/BaseNavigationContainer.js +34 -17
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/ConsumedParamsContext.js +5 -0
  4. package/lib/module/ConsumedParamsContext.js.map +1 -0
  5. package/lib/module/DataLoading.js +127 -0
  6. package/lib/module/DataLoading.js.map +1 -0
  7. package/lib/module/NavigationBuilderContext.js +1 -0
  8. package/lib/module/NavigationBuilderContext.js.map +1 -1
  9. package/lib/module/NavigationIndependentTree.js +17 -8
  10. package/lib/module/NavigationIndependentTree.js.map +1 -1
  11. package/lib/module/NavigationProvider.js +22 -11
  12. package/lib/module/NavigationProvider.js.map +1 -1
  13. package/lib/module/NavigationStateContext.js.map +1 -1
  14. package/lib/module/PreventRemoveContext.js.map +1 -1
  15. package/lib/module/PreventRemoveProvider.js +37 -27
  16. package/lib/module/PreventRemoveProvider.js.map +1 -1
  17. package/lib/module/SceneView.js +7 -40
  18. package/lib/module/SceneView.js.map +1 -1
  19. package/lib/module/StaticNavigation.js +179 -50
  20. package/lib/module/StaticNavigation.js.map +1 -1
  21. package/lib/module/StaticTreeContext.js +5 -0
  22. package/lib/module/StaticTreeContext.js.map +1 -0
  23. package/lib/module/checkSerializable.js +18 -13
  24. package/lib/module/checkSerializable.js.map +1 -1
  25. package/lib/module/createNavigationContainerRef.js +6 -8
  26. package/lib/module/createNavigationContainerRef.js.map +1 -1
  27. package/lib/module/createNavigatorFactory.js +27 -5
  28. package/lib/module/createNavigatorFactory.js.map +1 -1
  29. package/lib/module/findFocusedRoute.js +7 -4
  30. package/lib/module/findFocusedRoute.js.map +1 -1
  31. package/lib/module/getActionFromState.js +45 -20
  32. package/lib/module/getActionFromState.js.map +1 -1
  33. package/lib/module/getPathFromState.js +171 -90
  34. package/lib/module/getPathFromState.js.map +1 -1
  35. package/lib/module/getPatternParts.js +20 -4
  36. package/lib/module/getPatternParts.js.map +1 -1
  37. package/lib/module/getStateFromPath.js +485 -214
  38. package/lib/module/getStateFromPath.js.map +1 -1
  39. package/lib/module/getStateFromRouteParams.js +24 -0
  40. package/lib/module/getStateFromRouteParams.js.map +1 -0
  41. package/lib/module/index.js +5 -4
  42. package/lib/module/index.js.map +1 -1
  43. package/lib/module/theming/useTheme.js +1 -1
  44. package/lib/module/theming/useTheme.js.map +1 -1
  45. package/lib/module/types.js +35 -0
  46. package/lib/module/types.js.map +1 -1
  47. package/lib/module/useDescriptors.js +19 -11
  48. package/lib/module/useDescriptors.js.map +1 -1
  49. package/lib/module/useEventEmitter.js +48 -33
  50. package/lib/module/useEventEmitter.js.map +1 -1
  51. package/lib/module/useFocusEvents.js +12 -4
  52. package/lib/module/useFocusEvents.js.map +1 -1
  53. package/lib/module/useFocusedListenersChildrenAdapter.js +2 -2
  54. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  55. package/lib/module/useIsFocused.js +7 -12
  56. package/lib/module/useIsFocused.js.map +1 -1
  57. package/lib/module/useKeyedChildListeners.js +4 -2
  58. package/lib/module/useKeyedChildListeners.js.map +1 -1
  59. package/lib/module/useLazyValue.js.map +1 -1
  60. package/lib/module/useNavigation.js +2 -15
  61. package/lib/module/useNavigation.js.map +1 -1
  62. package/lib/module/useNavigationBuilder.js +201 -131
  63. package/lib/module/useNavigationBuilder.js.map +1 -1
  64. package/lib/module/useNavigationCache.js +22 -17
  65. package/lib/module/useNavigationCache.js.map +1 -1
  66. package/lib/module/useNavigationHelpers.js +28 -10
  67. package/lib/module/useNavigationHelpers.js.map +1 -1
  68. package/lib/module/useNavigationIndependentTree.js +1 -1
  69. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  70. package/lib/module/useNavigationState.js +70 -35
  71. package/lib/module/useNavigationState.js.map +1 -1
  72. package/lib/module/useOnAction.js +37 -7
  73. package/lib/module/useOnAction.js.map +1 -1
  74. package/lib/module/useOnGetState.js +6 -3
  75. package/lib/module/useOnGetState.js.map +1 -1
  76. package/lib/module/useOnPreventRemove.js +39 -30
  77. package/lib/module/useOnPreventRemove.js.map +1 -1
  78. package/lib/module/useOnRouteFocus.js +1 -1
  79. package/lib/module/useOnRouteFocus.js.map +1 -1
  80. package/lib/module/useOptionsGetters.js +10 -5
  81. package/lib/module/useOptionsGetters.js.map +1 -1
  82. package/lib/module/usePreventRemove.js +10 -3
  83. package/lib/module/usePreventRemove.js.map +1 -1
  84. package/lib/module/usePreventRemoveContext.js +1 -1
  85. package/lib/module/usePreventRemoveContext.js.map +1 -1
  86. package/lib/module/useRegisterNavigator.js +2 -2
  87. package/lib/module/useRegisterNavigator.js.map +1 -1
  88. package/lib/module/useRoute.js +2 -0
  89. package/lib/module/useRoute.js.map +1 -1
  90. package/lib/module/useRouteCache.js +17 -11
  91. package/lib/module/useRouteCache.js.map +1 -1
  92. package/lib/module/useScheduleUpdate.js +9 -9
  93. package/lib/module/useScheduleUpdate.js.map +1 -1
  94. package/lib/module/useStateForPath.js +1 -1
  95. package/lib/module/useStateForPath.js.map +1 -1
  96. package/lib/module/useSyncState.js +7 -3
  97. package/lib/module/useSyncState.js.map +1 -1
  98. package/lib/module/validatePathConfig.js +50 -36
  99. package/lib/module/validatePathConfig.js.map +1 -1
  100. package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
  101. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  102. package/lib/typescript/src/ConsumedParamsContext.d.ts +3 -0
  103. package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
  104. package/lib/typescript/src/DataLoading.d.ts +21 -0
  105. package/lib/typescript/src/DataLoading.d.ts.map +1 -0
  106. package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
  107. package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
  108. package/lib/typescript/src/Group.d.ts +1 -1
  109. package/lib/typescript/src/Group.d.ts.map +1 -1
  110. package/lib/typescript/src/NavigationBuilderContext.d.ts +9 -8
  111. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  112. package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
  113. package/lib/typescript/src/NavigationContainerRefContext.d.ts.map +1 -1
  114. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
  115. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
  116. package/lib/typescript/src/NavigationHelpersContext.d.ts +1 -1
  117. package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
  118. package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
  119. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  120. package/lib/typescript/src/NavigationProvider.d.ts +12 -13
  121. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  122. package/lib/typescript/src/NavigationStateContext.d.ts +3 -3
  123. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  124. package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
  125. package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
  126. package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
  127. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  128. package/lib/typescript/src/SceneView.d.ts +3 -2
  129. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  130. package/lib/typescript/src/Screen.d.ts +1 -1
  131. package/lib/typescript/src/Screen.d.ts.map +1 -1
  132. package/lib/typescript/src/StaticContainer.d.ts +1 -1
  133. package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
  134. package/lib/typescript/src/StaticNavigation.d.ts +189 -109
  135. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  136. package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
  137. package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
  138. package/lib/typescript/src/checkSerializable.d.ts +8 -4
  139. package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
  140. package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
  141. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  142. package/lib/typescript/src/createNavigatorFactory.d.ts +23 -5
  143. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  144. package/lib/typescript/src/findFocusedRoute.d.ts +3 -3
  145. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  146. package/lib/typescript/src/getActionFromState.d.ts +4 -4
  147. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  148. package/lib/typescript/src/getPathFromState.d.ts +3 -3
  149. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  150. package/lib/typescript/src/getPatternParts.d.ts +1 -0
  151. package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
  152. package/lib/typescript/src/getStateFromPath.d.ts +5 -5
  153. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  154. package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
  155. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
  156. package/lib/typescript/src/index.d.ts +36 -33
  157. package/lib/typescript/src/index.d.ts.map +1 -1
  158. package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
  159. package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
  160. package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
  161. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  162. package/lib/typescript/src/theming/useTheme.d.ts +1 -1
  163. package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
  164. package/lib/typescript/src/types.d.ts +260 -159
  165. package/lib/typescript/src/types.d.ts.map +1 -1
  166. package/lib/typescript/src/useChildListeners.d.ts +3 -3
  167. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  168. package/lib/typescript/src/useComponent.d.ts +1 -1
  169. package/lib/typescript/src/useComponent.d.ts.map +1 -1
  170. package/lib/typescript/src/useDescriptors.d.ts +8 -8
  171. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  172. package/lib/typescript/src/useEventEmitter.d.ts +2 -2
  173. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  174. package/lib/typescript/src/useFocusEvents.d.ts +2 -2
  175. package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
  176. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
  177. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts.map +1 -1
  178. package/lib/typescript/src/useIsFocused.d.ts +3 -0
  179. package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
  180. package/lib/typescript/src/useKeyedChildListeners.d.ts +3 -3
  181. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  182. package/lib/typescript/src/useLazyValue.d.ts.map +1 -1
  183. package/lib/typescript/src/useNavigation.d.ts +4 -2
  184. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  185. package/lib/typescript/src/useNavigationBuilder.d.ts +23 -30
  186. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  187. package/lib/typescript/src/useNavigationCache.d.ts +3 -3
  188. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  189. package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
  190. package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
  191. package/lib/typescript/src/useNavigationHelpers.d.ts +19 -27
  192. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  193. package/lib/typescript/src/useNavigationState.d.ts +13 -3
  194. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  195. package/lib/typescript/src/useOnAction.d.ts +9 -9
  196. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  197. package/lib/typescript/src/useOnGetState.d.ts +1 -1
  198. package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
  199. package/lib/typescript/src/useOnPreventRemove.d.ts +5 -9
  200. package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
  201. package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
  202. package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
  203. package/lib/typescript/src/useOptionsGetters.d.ts +1 -1
  204. package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
  205. package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
  206. package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
  207. package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
  208. package/lib/typescript/src/useRoute.d.ts +7 -3
  209. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  210. package/lib/typescript/src/useRouteCache.d.ts +5 -5
  211. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  212. package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
  213. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  214. package/lib/typescript/src/useStateForPath.d.ts +1 -1
  215. package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
  216. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  217. package/lib/typescript/src/utilities.d.ts +74 -37
  218. package/lib/typescript/src/utilities.d.ts.map +1 -1
  219. package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
  220. package/package.json +23 -22
  221. package/src/BaseNavigationContainer.tsx +351 -333
  222. package/src/ConsumedParamsContext.tsx +5 -0
  223. package/src/DataLoading.tsx +203 -0
  224. package/src/NavigationBuilderContext.tsx +14 -9
  225. package/src/NavigationFocusedRouteStateContext.tsx +4 -4
  226. package/src/NavigationIndependentTree.tsx +18 -12
  227. package/src/NavigationProvider.tsx +26 -15
  228. package/src/NavigationStateContext.tsx +5 -6
  229. package/src/PreventRemoveContext.tsx +1 -0
  230. package/src/PreventRemoveProvider.tsx +51 -46
  231. package/src/SceneView.tsx +7 -39
  232. package/src/StaticNavigation.tsx +659 -307
  233. package/src/StaticTreeContext.tsx +7 -0
  234. package/src/checkSerializable.tsx +35 -19
  235. package/src/createNavigationContainerRef.tsx +12 -9
  236. package/src/createNavigatorFactory.tsx +92 -8
  237. package/src/findFocusedRoute.tsx +13 -8
  238. package/src/getActionFromState.tsx +86 -51
  239. package/src/getPathFromState.tsx +254 -128
  240. package/src/getPatternParts.tsx +25 -4
  241. package/src/getStateFromPath.tsx +811 -309
  242. package/src/getStateFromRouteParams.tsx +60 -0
  243. package/src/index.tsx +55 -5
  244. package/src/theming/useTheme.tsx +1 -1
  245. package/src/types.tsx +798 -373
  246. package/src/useDescriptors.tsx +28 -14
  247. package/src/useEventEmitter.tsx +52 -38
  248. package/src/useFocusEvents.tsx +15 -7
  249. package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
  250. package/src/useIsFocused.tsx +14 -21
  251. package/src/useKeyedChildListeners.tsx +4 -2
  252. package/src/useLazyValue.tsx +2 -2
  253. package/src/useNavigation.tsx +7 -24
  254. package/src/useNavigationBuilder.tsx +311 -186
  255. package/src/useNavigationCache.tsx +32 -25
  256. package/src/useNavigationHelpers.tsx +27 -10
  257. package/src/useNavigationIndependentTree.tsx +1 -1
  258. package/src/useNavigationState.tsx +93 -59
  259. package/src/useOnAction.tsx +61 -13
  260. package/src/useOnGetState.tsx +5 -3
  261. package/src/useOnPreventRemove.tsx +75 -42
  262. package/src/useOnRouteFocus.tsx +10 -12
  263. package/src/useOptionsGetters.tsx +11 -5
  264. package/src/usePreventRemove.tsx +12 -3
  265. package/src/usePreventRemoveContext.tsx +1 -1
  266. package/src/useRegisterNavigator.tsx +2 -2
  267. package/src/useRoute.tsx +20 -6
  268. package/src/useRouteCache.tsx +22 -16
  269. package/src/useScheduleUpdate.tsx +9 -10
  270. package/src/useStateForPath.tsx +1 -1
  271. package/src/useSyncState.tsx +8 -3
  272. package/src/utilities.tsx +144 -31
  273. package/src/validatePathConfig.tsx +86 -57
  274. package/lib/module/CurrentRenderContext.js +0 -10
  275. package/lib/module/CurrentRenderContext.js.map +0 -1
  276. package/lib/module/useCurrentRender.js +0 -19
  277. package/lib/module/useCurrentRender.js.map +0 -1
  278. package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
  279. package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
  280. package/lib/typescript/src/useCurrentRender.d.ts +0 -14
  281. package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
  282. package/src/CurrentRenderContext.tsx +0 -9
  283. package/src/useCurrentRender.tsx +0 -31
@@ -5,10 +5,10 @@ import deepEqual from 'fast-deep-equal';
5
5
  import * as React from 'react';
6
6
  import { isValidElementType } from 'react-is';
7
7
  import useLatestCallback from 'use-latest-callback';
8
+ import { ConsumedParamsContext } from "./ConsumedParamsContext.js";
8
9
  import { deepFreeze } from "./deepFreeze.js";
9
10
  import { Group } from "./Group.js";
10
11
  import { isArrayEqual } from "./isArrayEqual.js";
11
- import { isRecordEqual } from "./isRecordEqual.js";
12
12
  import { NavigationBuilderContext } from "./NavigationBuilderContext.js";
13
13
  import { NavigationHelpersContext } from "./NavigationHelpersContext.js";
14
14
  import { NavigationMetaContext } from "./NavigationMetaContext.js";
@@ -20,11 +20,11 @@ import { PrivateValueStore } from "./types.js";
20
20
  import { UnhandledActionContext } from "./UnhandledActionContext.js";
21
21
  import { useChildListeners } from "./useChildListeners.js";
22
22
  import { useComponent } from "./useComponent.js";
23
- import { useCurrentRender } from "./useCurrentRender.js";
24
23
  import { useDescriptors } from "./useDescriptors.js";
25
24
  import { useEventEmitter } from "./useEventEmitter.js";
26
25
  import { useFocusedListenersChildrenAdapter } from "./useFocusedListenersChildrenAdapter.js";
27
26
  import { useFocusEvents } from "./useFocusEvents.js";
27
+ import { FocusedRouteKeyContext } from "./useIsFocused.js";
28
28
  import { useKeyedChildListeners } from "./useKeyedChildListeners.js";
29
29
  import { useLazyValue } from "./useLazyValue.js";
30
30
  import { useNavigationHelpers } from "./useNavigationHelpers.js";
@@ -39,6 +39,7 @@ import { useScheduleUpdate } from "./useScheduleUpdate.js";
39
39
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
40
40
  import { jsx as _jsx } from "react/jsx-runtime";
41
41
  PrivateValueStore;
42
+ const isNavigationState = state => state != null && typeof state === 'object' && 'routes' in state && Array.isArray(state.routes);
42
43
  const isScreen = child => {
43
44
  return child.type === Screen;
44
45
  };
@@ -52,7 +53,7 @@ const isValidKey = key => key === undefined || typeof key === 'string' && key !=
52
53
  *
53
54
  * @param children React Elements to extract the config from.
54
55
  */
55
- const getRouteConfigsFromChildren = (children, groupKey, groupOptions, groupLayout) => {
56
+ const getRouteConfigsFromChildren = (children, groupKeys = [], groupOptions, groupLayout) => {
56
57
  const configs = React.Children.toArray(children).reduce((acc, child) => {
57
58
  if (/*#__PURE__*/React.isValidElement(child)) {
58
59
  if (isScreen(child)) {
@@ -69,7 +70,7 @@ const getRouteConfigsFromChildren = (children, groupKey, groupOptions, groupLayo
69
70
  throw new Error(`Got an invalid 'navigationKey' prop (${JSON.stringify(child.props.navigationKey)}) for the screen '${child.props.name}'. It must be a non-empty string or 'undefined'.`);
70
71
  }
71
72
  acc.push({
72
- keys: [groupKey, child.props.navigationKey],
73
+ keys: [...groupKeys, child.props.navigationKey],
73
74
  options: groupOptions,
74
75
  layout: groupLayout,
75
76
  props: child.props
@@ -83,14 +84,14 @@ const getRouteConfigsFromChildren = (children, groupKey, groupOptions, groupLayo
83
84
 
84
85
  // When we encounter a fragment or group, we need to dive into its children to extract the configs
85
86
  // This is handy to conditionally define a group of screens
86
- acc.push(...getRouteConfigsFromChildren(child.props.children, child.props.navigationKey,
87
+ acc.push(...getRouteConfigsFromChildren(child.props.children, child.props.navigationKey != null ? [...groupKeys, child.props.navigationKey] : groupKeys,
87
88
  // FIXME
88
89
  // @ts-expect-error: add validation
89
90
  child.type !== Group ? groupOptions : groupOptions != null ? [...groupOptions, child.props.screenOptions] : [child.props.screenOptions], typeof child.props.screenLayout === 'function' ? child.props.screenLayout : groupLayout));
90
91
  return acc;
91
92
  }
92
93
  }
93
- throw new Error(`A navigator can only contain 'Screen', 'Group' or 'React.Fragment' as its direct children (found ${/*#__PURE__*/React.isValidElement(child) ? `'${typeof child.type === 'string' ? child.type : child.type?.name}'${child.props != null && typeof child.props === 'object' && 'name' in child.props && child.props?.name ? ` for the screen '${child.props.name}'` : ''}` : typeof child === 'object' ? JSON.stringify(child) : `'${String(child)}'`}). To render this component in the navigator, pass it in the 'component' prop to 'Screen'.`);
94
+ throw new Error(`A navigator can only contain 'Screen', 'Group' or 'React.Fragment' as its direct children (found ${ /*#__PURE__*/React.isValidElement(child) ? `'${typeof child.type === 'string' ? child.type : child.type?.name}'${child.props != null && typeof child.props === 'object' && 'name' in child.props && child.props?.name ? ` for the screen '${child.props.name}'` : ''}` : typeof child === 'object' ? JSON.stringify(child) : `'${String(child)}'`}). To render this component in the navigator, pass it in the 'component' prop to 'Screen'.`);
94
95
  }, []);
95
96
  if (process.env.NODE_ENV !== 'production') {
96
97
  configs.forEach(config => {
@@ -136,9 +137,16 @@ const getRouteConfigsFromChildren = (children, groupKey, groupOptions, groupLayo
136
137
  }
137
138
  return configs;
138
139
  };
139
- const getStateFromParams = params => {
140
- if (params?.state != null) {
141
- return params.state;
140
+ const getStateFromParams = (params, type) => {
141
+ const state = params?.state;
142
+ if (isNavigationState(state)) {
143
+ if (state.type != null && state.type !== type) {
144
+ if (process.env.NODE_ENV !== 'production') {
145
+ console.error(`The state passed in the params is for a navigator of type '${state.type}', but it was passed to a navigator of type '${type}'. This can happen if the state was meant for a different navigator. The state will be discarded.`);
146
+ }
147
+ return undefined;
148
+ }
149
+ return state;
142
150
  } else if (typeof params?.screen === 'string' && params?.initial !== false) {
143
151
  return {
144
152
  routes: [{
@@ -160,7 +168,9 @@ const getStateFromParams = params => {
160
168
  */
161
169
  export function useNavigationBuilder(createRouter, options) {
162
170
  const navigatorKey = useRegisterNavigator();
163
- const route = React.useContext(NavigationRouteContext);
171
+ const route = React.use(NavigationRouteContext);
172
+ const consumedParams = React.use(ConsumedParamsContext);
173
+ const isNestedParamsConsumed = typeof route?.params === 'object' && route.params != null ? consumedParams?.has(route.params) : false;
164
174
  const {
165
175
  children,
166
176
  layout,
@@ -185,31 +195,26 @@ export function useNavigationBuilder(createRouter, options) {
185
195
  }
186
196
  return original;
187
197
  });
188
- const screens = routeConfigs.reduce((acc, config) => {
189
- if (config.props.name in acc) {
190
- throw new Error(`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${config.props.name}')`);
191
- }
192
- acc[config.props.name] = config;
193
- return acc;
194
- }, {});
195
198
  const routeNames = routeConfigs.map(config => config.props.name);
196
- const routeKeyList = routeNames.reduce((acc, curr) => {
197
- acc[curr] = screens[curr].keys.map(key => key ?? '').join(':');
198
- return acc;
199
- }, {});
200
- const routeParamList = routeNames.reduce((acc, curr) => {
201
- const {
202
- initialParams
203
- } = screens[curr].props;
204
- acc[curr] = initialParams;
205
- return acc;
206
- }, {});
207
- const routeGetIdList = routeNames.reduce((acc, curr) => Object.assign(acc, {
208
- [curr]: screens[curr].props.getId
209
- }), {});
210
199
  if (!routeNames.length) {
211
200
  throw new Error("Couldn't find any screens for the navigator. Have you defined any screens as its children?");
212
201
  }
202
+ const screens = {};
203
+ const routeKeyList = {};
204
+ const routeParamList = {};
205
+ const routeGetIdList = {};
206
+ for (const config of routeConfigs) {
207
+ const name = config.props.name;
208
+ if (name in screens) {
209
+ throw new Error(`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${name}')`);
210
+ }
211
+ screens[name] = config;
212
+ routeKeyList[name] = config.keys;
213
+ routeParamList[name] = config.props.initialParams;
214
+ Object.assign(routeGetIdList, {
215
+ [name]: config.props.getId
216
+ });
217
+ }
213
218
  const isStateValid = React.useCallback(state => state.type === undefined || state.type === router.type, [router.type]);
214
219
  const isStateInitialized = React.useCallback(state => state !== undefined && state.stale === false && isStateValid(state), [isStateValid]);
215
220
  const doesStateHaveOnlyInvalidRoutes = React.useCallback(state => state.routes.every(r => !routeNames.includes(r.name)), [routeNames]);
@@ -220,22 +225,41 @@ export function useNavigationBuilder(createRouter, options) {
220
225
  setKey,
221
226
  getKey,
222
227
  getIsInitial
223
- } = React.useContext(NavigationStateContext);
224
- const stateCleanedUp = React.useRef(false);
228
+ } = React.use(NavigationStateContext);
229
+ const {
230
+ onEmitEvent,
231
+ getIsStateEmitted
232
+ } = React.use(NavigationBuilderContext);
233
+ const stateCleanupRef = React.useRef(false);
234
+ const lastStateRef = React.useRef(undefined);
225
235
  const setState = useLatestCallback(state => {
226
- if (stateCleanedUp.current) {
236
+ if (stateCleanupRef.current) {
237
+ // Store the state locally in case the current navigator is in `Activity`
238
+ lastStateRef.current = state;
239
+
227
240
  // State might have been already cleaned up due to unmount
228
- // We do not want to expose API allowing to override this
229
- // This would lead to old data preservation on main navigator unmount
241
+ // We don't want to update `route.state` in parent
242
+ // Otherwise it will be reused if a new navigator gets mounted
230
243
  return;
231
244
  }
232
245
  setCurrentState(state);
233
246
  });
234
- const [stateBeforeInitialization, initializedState, isFirstStateInitialization] = React.useMemo(() => {
247
+ const [stateBeforeInitialization, initializedState, isFirstStateInitialization, paramsUsedForInitialization] = React.useMemo(() => {
248
+ // If the state was already cleaned up, but we have it stored in ref,
249
+ // It likely got cleaned up due to `<Activity mode="hidden">`
250
+ // We should reuse this state to avoid remounting screens
251
+ if (stateCleanupRef.current && lastStateRef.current && isStateValid(lastStateRef.current)) {
252
+ const state = isStateInitialized(lastStateRef.current) ? lastStateRef.current : router.getRehydratedState(lastStateRef.current, {
253
+ routeNames,
254
+ routeParamList,
255
+ routeGetIdList
256
+ });
257
+ return [undefined, state, false, undefined];
258
+ }
235
259
  const initialRouteParamList = routeNames.reduce((acc, curr) => {
236
260
  const {
237
261
  initialParams
238
- } = screens[curr].props;
262
+ } = screens[curr]?.props ?? {};
239
263
  const initialParamsFromParams = route?.params?.state == null && route?.params?.initial !== false && route?.params?.screen === curr ? route.params.params : undefined;
240
264
  acc[curr] = initialParams !== undefined || initialParamsFromParams !== undefined ? {
241
265
  ...initialParams,
@@ -248,24 +272,32 @@ export function useNavigationBuilder(createRouter, options) {
248
272
  // We also need to re-initialize it if the state passed from parent was changed (maybe due to reset)
249
273
  // Otherwise assume that the state was provided as initial state
250
274
  // So we need to rehydrate it to make it usable
251
- if ((currentState === undefined || !isStateValid(currentState)) && route?.params?.state == null && !(typeof route?.params?.screen === 'string' && route?.params?.initial !== false)) {
275
+ if ((currentState === undefined || !isStateValid(currentState)) && route?.params?.state == null && !(typeof route?.params?.screen === 'string' && route?.params?.initial !== false) && !isNestedParamsConsumed) {
252
276
  return [undefined, router.getInitialState({
253
277
  routeNames,
254
278
  routeParamList: initialRouteParamList,
255
279
  routeGetIdList
256
- }), true];
280
+ }), true, undefined];
257
281
  } else {
258
- const stateFromParams = getStateFromParams(route?.params);
282
+ const paramsForState = isNestedParamsConsumed ? undefined : route?.params;
283
+ const stateFromParams = paramsForState ? getStateFromParams(paramsForState, router.type) : undefined;
259
284
  const stateBeforeInitialization = stateFromParams ?? currentState;
260
- const hydratedState = router.getRehydratedState(stateBeforeInitialization, {
285
+ const hydratedState = stateBeforeInitialization == null ? router.getInitialState({
286
+ routeNames,
287
+ routeParamList: initialRouteParamList,
288
+ routeGetIdList
289
+ }) : router.getRehydratedState(stateBeforeInitialization, {
261
290
  routeNames,
262
291
  routeParamList: initialRouteParamList,
263
292
  routeGetIdList
264
293
  });
265
- if (options.routeNamesChangeBehavior === 'lastUnhandled' && doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)) {
266
- return [stateBeforeInitialization, hydratedState, true];
294
+ if (stateBeforeInitialization != null && isStateValid(stateBeforeInitialization) && options.routeNamesChangeBehavior === 'lastUnhandled' && doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)) {
295
+ return [stateBeforeInitialization, hydratedState, true, paramsForState];
267
296
  }
268
- return [undefined, hydratedState, false];
297
+ return [undefined, hydratedState, false,
298
+ // Current state is already initialized
299
+ // So params weren't used, and need to be handled later
300
+ isStateInitialized(currentState) ? undefined : paramsForState];
269
301
  }
270
302
  // We explicitly don't include routeNames, route.params etc. in the dep list
271
303
  // below. We want to avoid forcing a new state to be calculated in those cases
@@ -275,10 +307,17 @@ export function useNavigationBuilder(createRouter, options) {
275
307
  // eslint-disable-next-line react-hooks/exhaustive-deps
276
308
  }, [currentState, router, isStateValid]);
277
309
  const previousRouteKeyListRef = React.useRef(routeKeyList);
278
- React.useEffect(() => {
310
+ React.useInsertionEffect(() => {
279
311
  previousRouteKeyListRef.current = routeKeyList;
280
312
  });
281
313
  const previousRouteKeyList = previousRouteKeyListRef.current;
314
+
315
+ // Names of the screens whose navigation key changed since the last render
316
+ const routeKeyChanges = Object.keys(routeKeyList).filter(name => {
317
+ const current = routeKeyList[name];
318
+ const previous = previousRouteKeyList[name];
319
+ return current != null && previous != null && !isArrayEqual(current, previous);
320
+ });
282
321
  const [unhandledState, setUnhandledState] = React.useState(stateBeforeInitialization);
283
322
 
284
323
  // An unhandled state is state that didn't have any valid routes
@@ -295,57 +334,65 @@ export function useNavigationBuilder(createRouter, options) {
295
334
  isStateInitialized(currentState) ? currentState : initializedState;
296
335
  let nextState = state;
297
336
  let shouldClearUnhandledState = false;
298
-
337
+ if (unhandledState != null && !isStateValid(unhandledState)) {
338
+ // The stored unhandled state is for a different type of navigator
339
+ // It can't be used with this navigator, so we discard it
340
+ setUnhandledState(undefined);
341
+ } else if (
299
342
  // Previously unhandled state is now valid again
300
343
  // And current state no longer has any valid routes
301
344
  // We should reuse the unhandled state instead of re-calculating the state
302
- if (unhandledState?.routes.every(r => routeNames.includes(r.name)) && state?.routes.every(r => !routeNames.includes(r.name))) {
345
+ unhandledState?.routes.every(r => routeNames.includes(r.name)) && state?.routes.every(r => !routeNames.includes(r.name))) {
303
346
  shouldClearUnhandledState = true;
304
347
  nextState = router.getRehydratedState(unhandledState, {
305
348
  routeNames,
306
349
  routeParamList,
307
350
  routeGetIdList
308
351
  });
309
- } else if (!isArrayEqual(state.routeNames, routeNames) || !isRecordEqual(routeKeyList, previousRouteKeyList)) {
352
+ } else if (!isArrayEqual(state.routeNames, routeNames) || routeKeyChanges.length !== 0) {
310
353
  // When the list of route names change, the router should handle it to remove invalid routes
311
354
  nextState = router.getStateForRouteNamesChange(state, {
312
355
  routeNames,
313
356
  routeParamList,
314
357
  routeGetIdList,
315
- routeKeyChanges: Object.keys(routeKeyList).filter(name => name in previousRouteKeyList && routeKeyList[name] !== previousRouteKeyList[name])
358
+ routeKeyChanges
316
359
  });
317
360
  }
318
- const previousNestedParamsRef = React.useRef(route?.params);
319
- React.useEffect(() => {
320
- previousNestedParamsRef.current = route?.params;
321
- }, [route?.params]);
322
- if (route?.params) {
323
- const previousParams = previousNestedParamsRef.current;
361
+ let didConsumeNestedParams = route?.params === paramsUsedForInitialization;
362
+ if (route?.params && !didConsumeNestedParams) {
324
363
  let action;
325
- if (typeof route.params.state === 'object' && route.params.state != null && route.params !== previousParams) {
326
- if (options.routeNamesChangeBehavior === 'lastUnhandled' && doesStateHaveOnlyInvalidRoutes(route.params.state)) {
327
- if (route.params.state !== unhandledState) {
328
- setUnhandledState(route.params.state);
364
+ if (isNavigationState(route.params.state) && !isNestedParamsConsumed) {
365
+ didConsumeNestedParams = true;
366
+ const stateFromParams = getStateFromParams(route.params, router.type);
367
+ if (stateFromParams != null) {
368
+ if (options.routeNamesChangeBehavior === 'lastUnhandled' && doesStateHaveOnlyInvalidRoutes(stateFromParams)) {
369
+ if (stateFromParams !== unhandledState) {
370
+ setUnhandledState(stateFromParams);
371
+ }
372
+ } else {
373
+ // If the route was updated with new state, we should reset to it
374
+ action = CommonActions.reset(stateFromParams);
329
375
  }
330
- } else {
331
- // If the route was updated with new state, we should reset to it
332
- action = CommonActions.reset(route.params.state);
333
376
  }
334
- } else if (typeof route.params.screen === 'string' && (route.params.initial === false && isFirstStateInitialization || route.params !== previousParams)) {
377
+ } else if (typeof route.params.screen === 'string' && (route.params.initial === false && isFirstStateInitialization || !isNestedParamsConsumed)) {
378
+ didConsumeNestedParams = true;
335
379
  if (options.routeNamesChangeBehavior === 'lastUnhandled' && !routeNames.includes(route.params.screen)) {
336
- const state = getStateFromParams(route.params);
380
+ const state = getStateFromParams(route.params, router.type);
337
381
  if (state != null && !deepEqual(state, unhandledState)) {
338
382
  setUnhandledState(state);
339
383
  }
340
384
  } else {
341
385
  // If the route was updated with new screen name and/or params, we should navigate there
342
- action = CommonActions.navigate({
343
- name: route.params.screen,
344
- params: route.params.params,
345
- path: route.params.path,
346
- merge: route.params.merge,
347
- pop: route.params.pop
348
- });
386
+ action = {
387
+ type: 'NAVIGATE',
388
+ payload: {
389
+ name: route.params.screen,
390
+ params: route.params.params,
391
+ path: route.params.path,
392
+ merge: route.params.merge,
393
+ pop: route.params.pop
394
+ }
395
+ };
349
396
  }
350
397
  }
351
398
 
@@ -355,16 +402,25 @@ export function useNavigationBuilder(createRouter, options) {
355
402
  routeParamList,
356
403
  routeGetIdList
357
404
  }) : null;
405
+ if (process.env.NODE_ENV !== 'production' && action != null && updatedState === null) {
406
+ const names = routeNames.map(name => `'${name}'`).join(', ');
407
+ console.error(`The 'state' or 'screen' passed in the params couldn't be applied to the navigator with the screens: ${names}. This can happen if the params contain names of screens that don't exist in the navigator. The navigation specified in the params will be ignored.`);
408
+ }
358
409
  nextState = updatedState !== null ? router.getRehydratedState(updatedState, {
359
410
  routeNames,
360
411
  routeParamList,
361
412
  routeGetIdList
362
413
  }) : nextState;
363
414
  }
364
- const shouldUpdate = state !== nextState || typeof route?.params?.state === 'object' || typeof route?.params?.screen === 'string';
415
+ React.useEffect(() => {
416
+ if (consumedParams && didConsumeNestedParams && typeof route?.params === 'object' && route.params != null) {
417
+ consumedParams.set(route.params, true);
418
+ }
419
+ }, [consumedParams, didConsumeNestedParams, route?.params]);
420
+ const shouldUpdate = state !== nextState;
365
421
  useScheduleUpdate(() => {
366
422
  if (shouldUpdate) {
367
- // If the state needs to be updated, we'll schedule an update
423
+ // Schedule an update if the state needs to be updated
368
424
  setState(nextState);
369
425
  if (shouldClearUnhandledState) {
370
426
  setUnhandledState(undefined);
@@ -376,44 +432,54 @@ export function useNavigationBuilder(createRouter, options) {
376
432
  // We can't use the outdated state since the screens have changed, which will cause error due to mismatched config
377
433
  // So we override the state object we return to use the latest state as soon as possible
378
434
  state = nextState;
435
+
436
+ // Last state to reuse if component gets cleaned up due to `<Activity mode="hidden">`
437
+ React.useEffect(() => {
438
+ lastStateRef.current = state;
439
+ });
440
+ const lastNotifiedStateRef = React.useRef(null);
379
441
  React.useEffect(() => {
380
442
  // In strict mode, React will double-invoke effects.
381
443
  // So we need to reset the flag if component was not unmounted
382
- stateCleanedUp.current = false;
444
+ stateCleanupRef.current = false;
383
445
  setKey(navigatorKey);
384
- if (!getIsInitial()) {
385
- // If it's not initial render, we need to update the state
386
- // This will make sure that our container gets notifier of state changes due to new mounts
446
+ if ((!getIsInitial() || getIsStateEmitted()) && lastNotifiedStateRef.current !== state) {
447
+ // We need to notify the state update in these scenarios:
448
+ // 1. If it's not the initial render of the component containing the navigator
449
+ // 2. If the container has already emitted state before the navigator mounted
450
+ //
451
+ // This will make sure that the container gets notified of state changes due to new mounts
387
452
  // This is necessary for proper screen tracking, URL updates etc.
388
- setState(nextState);
453
+ //
454
+ // During hydration, a nested navigator may mount after the container's initial state event.
455
+ // Or mount could be delayed due to conditional rendering, suspense etc.
456
+ // So only checking for the initial render is not enough.
457
+ // We also need to propagate the navigator's initial state when it mounts later,
458
+ // so the container is notified that the nested state is now available.
459
+ //
460
+ // We only notify if the state is different from what we already notified
461
+ // Otherwise, this goes into a loop when inside `<Activity mode="hidden">`
462
+ setState(state);
463
+ lastNotifiedStateRef.current = state;
389
464
  }
390
465
  return () => {
391
466
  // We need to clean up state for this navigator on unmount
392
467
  if (getCurrentState() !== undefined && getKey() === navigatorKey) {
393
468
  setCurrentState(undefined);
394
- stateCleanedUp.current = true;
469
+ stateCleanupRef.current = true;
395
470
  }
471
+
472
+ // Reset so that StrictMode's second mount re-propagates state correctly.
473
+ // Without this, the guard above sees the same reference and skips setState,
474
+ // causing the initial state to be lost after cleanup wipes the container state.
475
+ lastNotifiedStateRef.current = null;
396
476
  };
397
477
  // eslint-disable-next-line react-hooks/exhaustive-deps
398
478
  }, []);
399
-
400
- // In some cases (e.g. route names change), internal state might have changed
401
- // But it hasn't been committed yet, so hasn't propagated to the sync external store
402
- // During this time, we need to return the internal state in `getState`
403
- // Otherwise it can result in inconsistent state during render in children
404
- // To avoid this, we use a ref for render phase, and immediately clear it on commit
405
- const stateRef = React.useRef(state);
406
- stateRef.current = state;
407
- React.useLayoutEffect(() => {
408
- stateRef.current = null;
409
- });
410
479
  const getState = useLatestCallback(() => {
411
480
  const currentState = getCurrentState();
412
481
  return deepFreeze(isStateInitialized(currentState) ? currentState : initializedState);
413
482
  });
414
- const {
415
- onEmitEvent
416
- } = React.useContext(NavigationBuilderContext);
417
483
  const emitter = useEventEmitter(e => {
418
484
  const routeNames = [];
419
485
  let route;
@@ -429,32 +495,33 @@ export function useNavigationBuilder(createRouter, options) {
429
495
  if (route == null) {
430
496
  return;
431
497
  }
432
- const navigation = descriptors[route.key].navigation;
433
- const listeners = [].concat(
434
- // Get an array of listeners for all screens + common listeners on navigator
435
- ...[screenListeners, ...routeNames.map(name => {
436
- const {
437
- listeners
438
- } = screens[name].props;
439
- return listeners;
440
- })].map(listeners => {
441
- const map = typeof listeners === 'function' ? listeners({
442
- route: route,
443
- navigation
444
- }) : listeners;
445
- return map ? Object.keys(map).filter(type => type === e.type).map(type => map?.[type]) : undefined;
446
- }))
447
- // We don't want same listener to be called multiple times for same event
448
- // So we remove any duplicate functions from the array
449
- .filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
450
- listeners.forEach(listener => listener?.(e));
451
- onEmitEvent({
452
- type: e.type,
453
- data: e.data,
454
- target: e.target,
455
- defaultPrevented: e.defaultPrevented
456
- });
457
- });
498
+ const hasPerScreenListeners = routeNames.some(name => screens[name]?.props.listeners != null);
499
+ if (screenListeners != null || hasPerScreenListeners) {
500
+ const descriptor = descriptors[route.key];
501
+ if (descriptor == null) {
502
+ throw new Error(`Couldn't find a descriptor for route '${route.key}'.`);
503
+ }
504
+ const navigation = descriptor.navigation;
505
+ const listeners = [].concat(
506
+ // Get an array of listeners for all screens + common listeners on navigator
507
+ ...[screenListeners, ...routeNames.map(name => {
508
+ const {
509
+ listeners
510
+ } = screens[name]?.props ?? {};
511
+ return listeners;
512
+ })].map(listeners => {
513
+ const map = typeof listeners === 'function' ? listeners({
514
+ route: route,
515
+ navigation
516
+ }) : listeners;
517
+ return map ? Object.keys(map).filter(type => type === e.type).map(type => map?.[type]) : undefined;
518
+ }))
519
+ // We don't want same listener to be called multiple times for same event
520
+ // So we remove any duplicate functions from the array
521
+ .filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
522
+ listeners.forEach(listener => listener?.(e));
523
+ }
524
+ }, onEmitEvent);
458
525
  useFocusEvents({
459
526
  state,
460
527
  emitter
@@ -495,7 +562,7 @@ export function useNavigationBuilder(createRouter, options) {
495
562
  getState,
496
563
  setState
497
564
  });
498
- const onUnhandledActionParent = React.useContext(UnhandledActionContext);
565
+ const onUnhandledActionParent = React.use(UnhandledActionContext);
499
566
  const onUnhandledAction = useLatestCallback(action => {
500
567
  if (options.routeNamesChangeBehavior === 'lastUnhandled' && action.type === 'NAVIGATE' && action.payload != null && 'name' in action.payload && typeof action.payload.name === 'string' && !routeNames.includes(action.payload.name)) {
501
568
  const state = {
@@ -513,9 +580,9 @@ export function useNavigationBuilder(createRouter, options) {
513
580
  onAction,
514
581
  onUnhandledAction,
515
582
  getState,
583
+ state,
516
584
  emitter,
517
- router,
518
- stateRef
585
+ router
519
586
  });
520
587
  useFocusedListenersChildrenAdapter({
521
588
  navigation,
@@ -526,7 +593,7 @@ export function useNavigationBuilder(createRouter, options) {
526
593
  getStateListeners: keyedListeners.getState
527
594
  });
528
595
  const descriptors = useDescriptors({
529
- routes: router.getRoutesFromState ? router.getRoutesFromState(state) : state.routes,
596
+ routes: state.routes,
530
597
  screens,
531
598
  navigation,
532
599
  screenOptions,
@@ -541,12 +608,11 @@ export function useNavigationBuilder(createRouter, options) {
541
608
  // @ts-expect-error: this should have both core and custom events, but too much work right now
542
609
  emitter
543
610
  });
544
- useCurrentRender({
545
- state,
546
- navigation,
547
- descriptors
548
- });
549
611
  const NavigationContent = useComponent(children => {
612
+ const focusedRoute = state.routes[state.index];
613
+ if (focusedRoute == null) {
614
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
615
+ }
550
616
  const element = layout != null ? layout({
551
617
  state,
552
618
  descriptors,
@@ -559,8 +625,12 @@ export function useNavigationBuilder(createRouter, options) {
559
625
  value: navigation,
560
626
  children: /*#__PURE__*/_jsx(NavigationStateListenerProvider, {
561
627
  state: state,
562
- children: /*#__PURE__*/_jsx(PreventRemoveProvider, {
563
- children: element
628
+ getState: navigation.getState,
629
+ children: /*#__PURE__*/_jsx(FocusedRouteKeyContext.Provider, {
630
+ value: focusedRoute.key,
631
+ children: /*#__PURE__*/_jsx(PreventRemoveProvider, {
632
+ children: element
633
+ })
564
634
  })
565
635
  })
566
636
  })