@react-navigation/core 8.0.0-alpha.4 → 8.0.0-alpha.40

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 (323) hide show
  1. package/README.md +17 -14
  2. package/lib/module/BaseNavigationContainer.js +168 -87
  3. package/lib/module/BaseNavigationContainer.js.map +1 -1
  4. package/lib/module/ConsumedParamsContext.js +5 -0
  5. package/lib/module/ConsumedParamsContext.js.map +1 -0
  6. package/lib/module/DataLoading.js +129 -0
  7. package/lib/module/DataLoading.js.map +1 -0
  8. package/lib/module/NavigationBuilderContext.js +7 -10
  9. package/lib/module/NavigationBuilderContext.js.map +1 -1
  10. package/lib/module/NavigationIndependentTree.js +54 -9
  11. package/lib/module/NavigationIndependentTree.js.map +1 -1
  12. package/lib/module/NavigationProvider.js +36 -11
  13. package/lib/module/NavigationProvider.js.map +1 -1
  14. package/lib/module/NavigationRootContext.js +8 -0
  15. package/lib/module/NavigationRootContext.js.map +1 -0
  16. package/lib/module/NavigationStateContext.js +3 -0
  17. package/lib/module/NavigationStateContext.js.map +1 -1
  18. package/lib/module/PreventRemoveContext.js.map +1 -1
  19. package/lib/module/PreventRemoveProvider.js +40 -31
  20. package/lib/module/PreventRemoveProvider.js.map +1 -1
  21. package/lib/module/SceneView.js +12 -42
  22. package/lib/module/SceneView.js.map +1 -1
  23. package/lib/module/StaticNavigation.js +219 -67
  24. package/lib/module/StaticNavigation.js.map +1 -1
  25. package/lib/module/StaticTreeContext.js +5 -0
  26. package/lib/module/StaticTreeContext.js.map +1 -0
  27. package/lib/module/createNavigationContainerRef.js +7 -9
  28. package/lib/module/createNavigationContainerRef.js.map +1 -1
  29. package/lib/module/createNavigatorFactory.js +27 -5
  30. package/lib/module/createNavigatorFactory.js.map +1 -1
  31. package/lib/module/findFocusedRoute.js +7 -4
  32. package/lib/module/findFocusedRoute.js.map +1 -1
  33. package/lib/module/getActionFromState.js +45 -20
  34. package/lib/module/getActionFromState.js.map +1 -1
  35. package/lib/module/getPathFromState.js +204 -94
  36. package/lib/module/getPathFromState.js.map +1 -1
  37. package/lib/module/getPatternParts.js +61 -14
  38. package/lib/module/getPatternParts.js.map +1 -1
  39. package/lib/module/getStateFromPath.js +608 -272
  40. package/lib/module/getStateFromPath.js.map +1 -1
  41. package/lib/module/getStateFromRouteParams.js +23 -0
  42. package/lib/module/getStateFromRouteParams.js.map +1 -0
  43. package/lib/module/index.js +7 -6
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/module/internal.js +2 -0
  46. package/lib/module/internal.js.map +1 -0
  47. package/lib/module/isRecordEqual.js +1 -1
  48. package/lib/module/isRecordEqual.js.map +1 -1
  49. package/lib/module/queryString.js +71 -0
  50. package/lib/module/queryString.js.map +1 -0
  51. package/lib/module/theming/useTheme.js +1 -1
  52. package/lib/module/theming/useTheme.js.map +1 -1
  53. package/lib/module/types.js +35 -1
  54. package/lib/module/types.js.map +1 -1
  55. package/lib/module/useDescriptors.js +65 -25
  56. package/lib/module/useDescriptors.js.map +1 -1
  57. package/lib/module/useEventEmitter.js +48 -33
  58. package/lib/module/useEventEmitter.js.map +1 -1
  59. package/lib/module/useFocusEffect.js +4 -2
  60. package/lib/module/useFocusEffect.js.map +1 -1
  61. package/lib/module/useFocusEvents.js +15 -5
  62. package/lib/module/useFocusEvents.js.map +1 -1
  63. package/lib/module/useFocusedListenersChildrenAdapter.js +3 -3
  64. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  65. package/lib/module/useIsFocused.js +8 -12
  66. package/lib/module/useIsFocused.js.map +1 -1
  67. package/lib/module/useKeyedChildListeners.js +5 -2
  68. package/lib/module/useKeyedChildListeners.js.map +1 -1
  69. package/lib/module/useLazyValue.js.map +1 -1
  70. package/lib/module/useNavigation.js +4 -17
  71. package/lib/module/useNavigation.js.map +1 -1
  72. package/lib/module/useNavigationBuilder.js +244 -147
  73. package/lib/module/useNavigationBuilder.js.map +1 -1
  74. package/lib/module/useNavigationCache.js +92 -89
  75. package/lib/module/useNavigationCache.js.map +1 -1
  76. package/lib/module/useNavigationHelpers.js +22 -29
  77. package/lib/module/useNavigationHelpers.js.map +1 -1
  78. package/lib/module/useNavigationIndependentTree.js +1 -1
  79. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  80. package/lib/module/useNavigationState.js +158 -46
  81. package/lib/module/useNavigationState.js.map +1 -1
  82. package/lib/module/useOnAction.js +58 -11
  83. package/lib/module/useOnAction.js.map +1 -1
  84. package/lib/module/useOnGetNavigation.js +26 -0
  85. package/lib/module/useOnGetNavigation.js.map +1 -0
  86. package/lib/module/useOnGetState.js +7 -4
  87. package/lib/module/useOnGetState.js.map +1 -1
  88. package/lib/module/useOnPreventRemove.js +40 -31
  89. package/lib/module/useOnPreventRemove.js.map +1 -1
  90. package/lib/module/useOnRouteFocus.js +2 -2
  91. package/lib/module/useOnRouteFocus.js.map +1 -1
  92. package/lib/module/useOptionsGetters.js +34 -24
  93. package/lib/module/useOptionsGetters.js.map +1 -1
  94. package/lib/module/usePreventRemove.js +11 -5
  95. package/lib/module/usePreventRemove.js.map +1 -1
  96. package/lib/module/usePreventRemoveContext.js +2 -2
  97. package/lib/module/usePreventRemoveContext.js.map +1 -1
  98. package/lib/module/useRegisterNavigator.js +3 -4
  99. package/lib/module/useRegisterNavigator.js.map +1 -1
  100. package/lib/module/useRoute.js +2 -0
  101. package/lib/module/useRoute.js.map +1 -1
  102. package/lib/module/useRouteCache.js +51 -35
  103. package/lib/module/useRouteCache.js.map +1 -1
  104. package/lib/module/useScheduleUpdate.js +12 -10
  105. package/lib/module/useScheduleUpdate.js.map +1 -1
  106. package/lib/module/useStateForPath.js +1 -1
  107. package/lib/module/useStateForPath.js.map +1 -1
  108. package/lib/module/useSyncState.js +37 -15
  109. package/lib/module/useSyncState.js.map +1 -1
  110. package/lib/module/validatePathConfig.js +50 -36
  111. package/lib/module/validatePathConfig.js.map +1 -1
  112. package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
  113. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  114. package/lib/typescript/src/ConsumedParamsContext.d.ts +3 -0
  115. package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
  116. package/lib/typescript/src/DataLoading.d.ts +21 -0
  117. package/lib/typescript/src/DataLoading.d.ts.map +1 -0
  118. package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
  119. package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
  120. package/lib/typescript/src/Group.d.ts +1 -1
  121. package/lib/typescript/src/Group.d.ts.map +1 -1
  122. package/lib/typescript/src/NavigationBuilderContext.d.ts +22 -14
  123. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  124. package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
  125. package/lib/typescript/src/NavigationContainerRefContext.d.ts.map +1 -1
  126. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
  127. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
  128. package/lib/typescript/src/NavigationHelpersContext.d.ts +1 -1
  129. package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
  130. package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
  131. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  132. package/lib/typescript/src/NavigationProvider.d.ts +21 -18
  133. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  134. package/lib/typescript/src/NavigationRootContext.d.ts +8 -0
  135. package/lib/typescript/src/NavigationRootContext.d.ts.map +1 -0
  136. package/lib/typescript/src/NavigationStateContext.d.ts +4 -3
  137. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  138. package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
  139. package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
  140. package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
  141. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  142. package/lib/typescript/src/SceneView.d.ts +5 -2
  143. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  144. package/lib/typescript/src/Screen.d.ts +1 -1
  145. package/lib/typescript/src/Screen.d.ts.map +1 -1
  146. package/lib/typescript/src/StaticContainer.d.ts +1 -1
  147. package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
  148. package/lib/typescript/src/StaticNavigation.d.ts +189 -111
  149. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  150. package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
  151. package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
  152. package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
  153. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  154. package/lib/typescript/src/createNavigatorFactory.d.ts +23 -5
  155. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  156. package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
  157. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  158. package/lib/typescript/src/getActionFromState.d.ts +4 -4
  159. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  160. package/lib/typescript/src/getPathFromState.d.ts +3 -3
  161. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  162. package/lib/typescript/src/getPatternParts.d.ts +5 -2
  163. package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
  164. package/lib/typescript/src/getStateFromPath.d.ts +4 -7
  165. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  166. package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
  167. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
  168. package/lib/typescript/src/index.d.ts +36 -33
  169. package/lib/typescript/src/index.d.ts.map +1 -1
  170. package/lib/typescript/src/internal.d.ts +3 -0
  171. package/lib/typescript/src/internal.d.ts.map +1 -0
  172. package/lib/typescript/src/isRecordEqual.d.ts.map +1 -1
  173. package/lib/typescript/src/queryString.d.ts +5 -0
  174. package/lib/typescript/src/queryString.d.ts.map +1 -0
  175. package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
  176. package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
  177. package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
  178. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  179. package/lib/typescript/src/theming/useTheme.d.ts +1 -1
  180. package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
  181. package/lib/typescript/src/types.d.ts +265 -167
  182. package/lib/typescript/src/types.d.ts.map +1 -1
  183. package/lib/typescript/src/useChildListeners.d.ts +3 -3
  184. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  185. package/lib/typescript/src/useDescriptors.d.ts +13 -11
  186. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  187. package/lib/typescript/src/useEventEmitter.d.ts +2 -2
  188. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  189. package/lib/typescript/src/useFocusEffect.d.ts.map +1 -1
  190. package/lib/typescript/src/useFocusEvents.d.ts +2 -2
  191. package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
  192. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
  193. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts.map +1 -1
  194. package/lib/typescript/src/useIsFocused.d.ts +4 -0
  195. package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
  196. package/lib/typescript/src/useKeyedChildListeners.d.ts +4 -3
  197. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  198. package/lib/typescript/src/useLazyValue.d.ts.map +1 -1
  199. package/lib/typescript/src/useNavigation.d.ts +4 -2
  200. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  201. package/lib/typescript/src/useNavigationBuilder.d.ts +22 -63
  202. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  203. package/lib/typescript/src/useNavigationCache.d.ts +6 -5
  204. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  205. package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
  206. package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
  207. package/lib/typescript/src/useNavigationHelpers.d.ts +18 -58
  208. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  209. package/lib/typescript/src/useNavigationState.d.ts +19 -3
  210. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  211. package/lib/typescript/src/useOnAction.d.ts +9 -9
  212. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  213. package/lib/typescript/src/useOnGetNavigation.d.ts +12 -0
  214. package/lib/typescript/src/useOnGetNavigation.d.ts.map +1 -0
  215. package/lib/typescript/src/useOnGetState.d.ts +1 -1
  216. package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
  217. package/lib/typescript/src/useOnPreventRemove.d.ts +5 -9
  218. package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
  219. package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
  220. package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
  221. package/lib/typescript/src/useOptionsGetters.d.ts +2 -4
  222. package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
  223. package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
  224. package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
  225. package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
  226. package/lib/typescript/src/useRegisterNavigator.d.ts.map +1 -1
  227. package/lib/typescript/src/useRoute.d.ts +7 -3
  228. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  229. package/lib/typescript/src/useRouteCache.d.ts +7 -12
  230. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  231. package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
  232. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  233. package/lib/typescript/src/useStateForPath.d.ts +1 -1
  234. package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
  235. package/lib/typescript/src/useSyncState.d.ts +1 -0
  236. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  237. package/lib/typescript/src/utilities.d.ts +79 -39
  238. package/lib/typescript/src/utilities.d.ts.map +1 -1
  239. package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
  240. package/package.json +26 -22
  241. package/src/BaseNavigationContainer.tsx +468 -333
  242. package/src/ConsumedParamsContext.tsx +5 -0
  243. package/src/DataLoading.tsx +206 -0
  244. package/src/NavigationBuilderContext.tsx +44 -25
  245. package/src/NavigationFocusedRouteStateContext.tsx +4 -4
  246. package/src/NavigationIndependentTree.tsx +60 -12
  247. package/src/NavigationProvider.tsx +47 -20
  248. package/src/NavigationRootContext.tsx +11 -0
  249. package/src/NavigationStateContext.tsx +9 -6
  250. package/src/PreventRemoveContext.tsx +1 -0
  251. package/src/PreventRemoveProvider.tsx +55 -56
  252. package/src/SceneView.tsx +14 -40
  253. package/src/StaticNavigation.tsx +715 -328
  254. package/src/StaticTreeContext.tsx +7 -0
  255. package/src/createNavigationContainerRef.tsx +12 -11
  256. package/src/createNavigatorFactory.tsx +92 -8
  257. package/src/findFocusedRoute.tsx +16 -16
  258. package/src/getActionFromState.tsx +87 -51
  259. package/src/getPathFromState.tsx +310 -134
  260. package/src/getPatternParts.tsx +98 -16
  261. package/src/getStateFromPath.tsx +971 -344
  262. package/src/getStateFromRouteParams.tsx +59 -0
  263. package/src/index.tsx +57 -6
  264. package/src/internal.tsx +2 -0
  265. package/src/isRecordEqual.tsx +3 -1
  266. package/src/queryString.ts +109 -0
  267. package/src/theming/useTheme.tsx +1 -1
  268. package/src/types.tsx +799 -377
  269. package/src/useDescriptors.tsx +151 -43
  270. package/src/useEventEmitter.tsx +53 -39
  271. package/src/useFocusEffect.tsx +5 -2
  272. package/src/useFocusEvents.tsx +19 -8
  273. package/src/useFocusedListenersChildrenAdapter.tsx +3 -3
  274. package/src/useIsFocused.tsx +18 -21
  275. package/src/useKeyedChildListeners.tsx +5 -2
  276. package/src/useLazyValue.tsx +2 -2
  277. package/src/useNavigation.tsx +9 -26
  278. package/src/useNavigationBuilder.tsx +370 -201
  279. package/src/useNavigationCache.tsx +148 -123
  280. package/src/useNavigationHelpers.tsx +27 -37
  281. package/src/useNavigationIndependentTree.tsx +1 -1
  282. package/src/useNavigationState.tsx +207 -69
  283. package/src/useOnAction.tsx +92 -18
  284. package/src/useOnGetNavigation.tsx +30 -0
  285. package/src/useOnGetState.tsx +8 -4
  286. package/src/useOnPreventRemove.tsx +78 -43
  287. package/src/useOnRouteFocus.tsx +11 -15
  288. package/src/useOptionsGetters.tsx +41 -28
  289. package/src/usePreventRemove.tsx +13 -5
  290. package/src/usePreventRemoveContext.tsx +2 -2
  291. package/src/useRegisterNavigator.tsx +4 -4
  292. package/src/useRoute.tsx +20 -6
  293. package/src/useRouteCache.tsx +57 -35
  294. package/src/useScheduleUpdate.tsx +13 -11
  295. package/src/useStateForPath.tsx +1 -1
  296. package/src/useSyncState.tsx +39 -15
  297. package/src/utilities.tsx +151 -35
  298. package/src/validatePathConfig.tsx +86 -57
  299. package/lib/module/CurrentRenderContext.js +0 -10
  300. package/lib/module/CurrentRenderContext.js.map +0 -1
  301. package/lib/module/NavigationMetaContext.js +0 -15
  302. package/lib/module/NavigationMetaContext.js.map +0 -1
  303. package/lib/module/checkSerializable.js +0 -46
  304. package/lib/module/checkSerializable.js.map +0 -1
  305. package/lib/module/useComponent.js +0 -34
  306. package/lib/module/useComponent.js.map +0 -1
  307. package/lib/module/useCurrentRender.js +0 -19
  308. package/lib/module/useCurrentRender.js.map +0 -1
  309. package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
  310. package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
  311. package/lib/typescript/src/NavigationMetaContext.d.ts +0 -12
  312. package/lib/typescript/src/NavigationMetaContext.d.ts.map +0 -1
  313. package/lib/typescript/src/checkSerializable.d.ts +0 -10
  314. package/lib/typescript/src/checkSerializable.d.ts.map +0 -1
  315. package/lib/typescript/src/useComponent.d.ts +0 -7
  316. package/lib/typescript/src/useComponent.d.ts.map +0 -1
  317. package/lib/typescript/src/useCurrentRender.d.ts +0 -14
  318. package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
  319. package/src/CurrentRenderContext.tsx +0 -9
  320. package/src/NavigationMetaContext.tsx +0 -14
  321. package/src/checkSerializable.tsx +0 -74
  322. package/src/useComponent.tsx +0 -37
  323. package/src/useCurrentRender.tsx +0 -31
@@ -6,11 +6,15 @@ import type {
6
6
  Router,
7
7
  } from '@react-navigation/routers';
8
8
  import * as React from 'react';
9
+ import useLatestCallback from 'use-latest-callback';
9
10
 
11
+ import { isArrayEqual } from './isArrayEqual';
12
+ import { isRecordEqual } from './isRecordEqual';
10
13
  import {
11
14
  type AddKeyedListener,
12
15
  type AddListener,
13
16
  NavigationBuilderContext,
17
+ useNavigationBuilderContext,
14
18
  } from './NavigationBuilderContext';
15
19
  import { NavigationProvider } from './NavigationProvider';
16
20
  import { SceneView } from './SceneView';
@@ -67,17 +71,19 @@ type Options<
67
71
  ScreenOptions extends {},
68
72
  EventMap extends EventMapBase,
69
73
  > = {
70
- routes: State['routes'];
71
74
  screens: Record<
72
75
  string,
73
76
  ScreenConfigWithParent<State, ScreenOptions, EventMap>
74
77
  >;
75
- navigation: NavigationHelpers<ParamListBase>;
78
+ state: State;
79
+ navigation: NavigationHelpers<ParamListBase, State>;
76
80
  screenOptions: ScreenOptionsOrCallback<ScreenOptions> | undefined;
77
81
  screenLayout: ScreenLayout<ScreenOptions> | undefined;
78
82
  onAction: (action: NavigationAction) => boolean;
83
+ canGoBack: (source?: string) => boolean;
79
84
  getState: () => State;
80
85
  setState: (state: State) => void;
86
+ subscribe: (callback: () => void) => () => void;
81
87
  addListener: AddListener;
82
88
  addKeyedListener: AddKeyedListener;
83
89
  onRouteFocus: (key: string) => void;
@@ -85,6 +91,30 @@ type Options<
85
91
  emitter: NavigationEventEmitter<EventMap>;
86
92
  };
87
93
 
94
+ type DescriptorCache<
95
+ State extends NavigationState,
96
+ ScreenOptions extends {},
97
+ EventMap extends EventMapBase,
98
+ ActionHelpers extends Record<string, (...args: any) => void>,
99
+ > = Record<
100
+ string,
101
+ {
102
+ descriptor: Descriptor<
103
+ ScreenOptions,
104
+ NavigationProp<
105
+ ParamListBase,
106
+ string,
107
+ State,
108
+ ScreenOptions,
109
+ EventMap,
110
+ ActionHelpers
111
+ >,
112
+ RouteProp<ParamListBase>
113
+ >;
114
+ deps: unknown[];
115
+ }
116
+ >;
117
+
88
118
  /**
89
119
  * Hook to create descriptor objects for the child routes.
90
120
  *
@@ -99,59 +129,67 @@ export function useDescriptors<
99
129
  ScreenOptions extends {},
100
130
  EventMap extends EventMapBase,
101
131
  >({
102
- routes,
103
132
  screens,
133
+ state,
104
134
  navigation,
105
135
  screenOptions,
106
136
  screenLayout,
107
137
  onAction,
138
+ canGoBack,
108
139
  getState,
109
140
  setState,
141
+ subscribe,
110
142
  addListener,
111
143
  addKeyedListener,
112
144
  onRouteFocus,
113
145
  router,
114
146
  emitter,
115
147
  }: Options<State, ScreenOptions, EventMap>) {
116
- const theme = React.useContext(ThemeContext);
117
- const [options, setOptions] = React.useState<Record<string, ScreenOptions>>(
118
- {}
119
- );
148
+ const theme = React.use(ThemeContext);
149
+
150
+ const [options, setOptions] = React.useState<
151
+ Record<string, Partial<ScreenOptions> | undefined>
152
+ >({});
120
153
  const {
121
154
  onDispatchAction,
122
155
  onEmitEvent,
123
156
  onOptionsChange,
124
157
  scheduleUpdate,
125
158
  flushUpdates,
126
- stackRef,
127
- } = React.useContext(NavigationBuilderContext);
159
+ getIsStateEmitted,
160
+ withStackTrace,
161
+ } = useNavigationBuilderContext();
128
162
 
129
163
  const context = React.useMemo(
130
164
  () => ({
131
165
  navigation,
132
166
  onAction,
167
+ canGoBack,
133
168
  addListener,
134
169
  addKeyedListener,
135
170
  onRouteFocus,
136
171
  onDispatchAction,
137
172
  onEmitEvent,
138
173
  onOptionsChange,
174
+ getIsStateEmitted,
139
175
  scheduleUpdate,
140
176
  flushUpdates,
141
- stackRef,
177
+ withStackTrace,
142
178
  }),
143
179
  [
144
180
  navigation,
145
181
  onAction,
182
+ canGoBack,
146
183
  addListener,
147
184
  addKeyedListener,
148
185
  onRouteFocus,
149
186
  onDispatchAction,
150
187
  onEmitEvent,
151
188
  onOptionsChange,
189
+ getIsStateEmitted,
152
190
  scheduleUpdate,
153
191
  flushUpdates,
154
- stackRef,
192
+ withStackTrace,
155
193
  ]
156
194
  );
157
195
 
@@ -161,7 +199,8 @@ export function useDescriptors<
161
199
  EventMap,
162
200
  ActionHelpers
163
201
  >({
164
- routes,
202
+ routes: state.routes,
203
+ canGoBack,
165
204
  getState,
166
205
  navigation,
167
206
  setOptions,
@@ -169,7 +208,15 @@ export function useDescriptors<
169
208
  emitter,
170
209
  });
171
210
 
172
- const cachedRoutes = useRouteCache(routes);
211
+ const cachedRoutes = useRouteCache(state.routes);
212
+
213
+ const getFocusedRouteKey = useLatestCallback(
214
+ () => state.routes[state.index]?.key
215
+ );
216
+
217
+ const cache = React.useMemo<{
218
+ current: DescriptorCache<State, ScreenOptions, EventMap, ActionHelpers>;
219
+ }>(() => ({ current: {} }), []);
173
220
 
174
221
  const getOptions = (
175
222
  route: RouteProp<ParamListBase, string>,
@@ -180,20 +227,20 @@ export function useDescriptors<
180
227
  ScreenOptions,
181
228
  EventMap
182
229
  >,
183
- overrides: Record<string, ScreenOptions>
230
+ overrides: Partial<ScreenOptions> | undefined
184
231
  ) => {
185
232
  const config = screens[route.name];
186
- const screen = config.props;
233
+ const screen = config?.props;
187
234
 
188
235
  const optionsList = [
189
236
  // The default `screenOptions` passed to the navigator
190
237
  screenOptions,
191
238
  // The `screenOptions` props passed to `Group` elements
192
- ...((config.options
239
+ ...((config?.options
193
240
  ? config.options.filter(Boolean)
194
241
  : []) as ScreenOptionsOrCallback<ScreenOptions>[]),
195
242
  // The `options` prop passed to `Screen` elements,
196
- screen.options,
243
+ screen?.options,
197
244
  // The options set via `navigation.setOptions`
198
245
  overrides,
199
246
  ];
@@ -219,15 +266,19 @@ export function useDescriptors<
219
266
  EventMap
220
267
  >,
221
268
  customOptions: ScreenOptions,
222
- routeState: NavigationState | PartialState<NavigationState> | undefined
269
+ routeState: NavigationState | PartialState<NavigationState> | undefined,
270
+ layout: ScreenLayout<ScreenOptions> | undefined
223
271
  ) => {
224
272
  const config = screens[route.name];
225
- const screen = config.props;
273
+ const screen = config?.props;
274
+
275
+ if (screen == null) {
276
+ throw new Error(`Couldn't find a screen named '${route.name}'.`);
277
+ }
226
278
 
227
279
  const clearOptions = () =>
228
280
  setOptions((o) => {
229
281
  if (route.key in o) {
230
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
231
282
  const { [route.key]: _, ...rest } = o;
232
283
  return rest;
233
284
  }
@@ -235,22 +286,16 @@ export function useDescriptors<
235
286
  return o;
236
287
  });
237
288
 
238
- const layout =
239
- // The `layout` prop passed to `Screen` elements,
240
- screen.layout ??
241
- // The `screenLayout` props passed to `Group` elements
242
- config.layout ??
243
- // The default `screenLayout` passed to the navigator
244
- screenLayout;
245
-
246
289
  let element = (
247
290
  <SceneView
248
291
  navigation={navigation}
249
292
  route={route}
250
293
  screen={screen}
251
294
  routeState={routeState}
295
+ getFocusedRouteKey={getFocusedRouteKey}
252
296
  getState={getState}
253
297
  setState={setState}
298
+ subscribe={subscribe}
254
299
  options={customOptions}
255
300
  clearOptions={clearOptions}
256
301
  />
@@ -276,38 +321,101 @@ export function useDescriptors<
276
321
  );
277
322
  };
278
323
 
324
+ const next: DescriptorCache<State, ScreenOptions, EventMap, ActionHelpers> =
325
+ {};
326
+
279
327
  const descriptors = cachedRoutes.reduce<
280
328
  Record<
281
329
  string,
282
- Descriptor<
330
+ DescriptorCache<
331
+ State,
283
332
  ScreenOptions,
284
- NavigationProp<
285
- ParamListBase,
286
- string,
287
- State,
288
- ScreenOptions,
289
- EventMap,
290
- ActionHelpers
291
- >,
292
- RouteProp<ParamListBase>
293
- >
333
+ EventMap,
334
+ ActionHelpers
335
+ >[string]['descriptor']
294
336
  >
295
337
  >((acc, route, i) => {
296
338
  const navigation = navigations[route.key];
297
- const customOptions = getOptions(route, navigation, options[route.key]);
298
- const element = render(route, navigation, customOptions, routes[i]?.state);
339
+ const overrides = options[route.key];
340
+
341
+ if (navigation == null) {
342
+ throw new Error(
343
+ `Couldn't find a navigation object for route '${route.key}'.`
344
+ );
345
+ }
346
+
347
+ const customOptions = getOptions(route, navigation, overrides);
299
348
 
300
- acc[route.key] = {
349
+ const routeState = state.routes[i]?.state;
350
+ const config = screens[route.name];
351
+ const screen = config?.props;
352
+
353
+ const layout =
354
+ // The `layout` prop passed to `Screen` elements,
355
+ screen?.layout ??
356
+ // The `screenLayout` props passed to `Group` elements
357
+ config?.layout ??
358
+ // The default `screenLayout` passed to the navigator
359
+ screenLayout;
360
+
361
+ const deps = [
362
+ route,
363
+ navigation,
364
+ routeState,
365
+ screen?.component,
366
+ screen?.getComponent,
367
+ screen?.children,
368
+ layout,
369
+ context,
370
+ theme,
371
+ getFocusedRouteKey,
372
+ getState,
373
+ setState,
374
+ subscribe,
375
+ ];
376
+
377
+ const previous = cache.current[route.key];
378
+
379
+ if (
380
+ previous &&
381
+ isArrayEqual(previous.deps, deps) &&
382
+ isRecordEqual(previous.descriptor.options, customOptions)
383
+ ) {
384
+ next[route.key] = previous;
385
+ acc[route.key] = previous.descriptor;
386
+
387
+ return acc;
388
+ }
389
+
390
+ const element = render(
391
+ route,
392
+ navigation,
393
+ customOptions,
394
+ routeState,
395
+ layout
396
+ );
397
+
398
+ const descriptor = {
301
399
  route,
302
400
  navigation,
303
401
  render() {
304
402
  return element;
305
403
  },
306
- options: customOptions as ScreenOptions,
404
+ options: customOptions,
405
+ };
406
+
407
+ acc[route.key] = descriptor;
408
+ next[route.key] = {
409
+ descriptor,
410
+ deps,
307
411
  };
308
412
 
309
413
  return acc;
310
414
  }, {});
311
415
 
416
+ React.useInsertionEffect(() => {
417
+ cache.current = next;
418
+ });
419
+
312
420
  return descriptors;
313
421
  }
@@ -13,12 +13,15 @@ type Listeners = Set<(e: any) => void>;
13
13
  * Hook to manage the event system used by the navigator to notify screens of various events.
14
14
  */
15
15
  export function useEventEmitter<T extends Record<string, any>>(
16
- listen?: (e: any) => void
16
+ listen?: (e: any) => void,
17
+ onPostEmit?: (e: any) => void
17
18
  ): NavigationEventEmitter<T> {
18
19
  const listenRef = React.useRef(listen);
20
+ const onPostEmitRef = React.useRef(onPostEmit);
19
21
 
20
- React.useEffect(() => {
22
+ React.useInsertionEffect(() => {
21
23
  listenRef.current = listen;
24
+ onPostEmitRef.current = onPostEmit;
22
25
  });
23
26
 
24
27
  const listeners = React.useRef<Record<string, Record<string, Listeners>>>(
@@ -56,65 +59,76 @@ export function useEventEmitter<T extends Record<string, any>>(
56
59
  }: {
57
60
  type: string;
58
61
  data?: any;
59
- target?: string;
62
+ target?: string | undefined;
60
63
  canPreventDefault?: boolean;
61
64
  }) => {
62
- const items = listeners.current[type] || {};
65
+ const items = listeners.current[type];
63
66
 
64
67
  // Copy the current list of callbacks in case they are mutated during execution
65
- const callbacks = new Set(
66
- Object.values(target ? { [target]: items[target] } : items).flatMap(
67
- (t) => (t ? Array.from(t) : [])
68
- )
69
- );
68
+ let callbacks: Set<(e: any) => void> | undefined;
69
+
70
+ if (items) {
71
+ if (target !== undefined) {
72
+ const targetSet = items[target];
73
+
74
+ if (targetSet && targetSet.size) {
75
+ callbacks = new Set(targetSet);
76
+ }
77
+ } else {
78
+ for (const key in items) {
79
+ const set = items[key];
80
+
81
+ if (set && set.size) {
82
+ callbacks ??= new Set();
83
+
84
+ for (const cb of set) {
85
+ callbacks.add(cb);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
70
91
 
71
- const event: EventArg<any, any, any> = {
72
- get type() {
73
- return type;
74
- },
92
+ const descriptors: PropertyDescriptorMap = {
93
+ type: { enumerable: true, value: type },
75
94
  };
76
95
 
77
96
  if (target !== undefined) {
78
- Object.defineProperty(event, 'target', {
79
- enumerable: true,
80
- get() {
81
- return target;
82
- },
83
- });
97
+ descriptors.target = { enumerable: true, value: target };
84
98
  }
85
99
 
86
100
  if (data !== undefined) {
87
- Object.defineProperty(event, 'data', {
88
- enumerable: true,
89
- get() {
90
- return data;
91
- },
92
- });
101
+ descriptors.data = { enumerable: true, value: data };
93
102
  }
94
103
 
104
+ let defaultPrevented = false;
105
+
95
106
  if (canPreventDefault) {
96
- let defaultPrevented = false;
97
-
98
- Object.defineProperties(event, {
99
- defaultPrevented: {
100
- enumerable: true,
101
- get() {
102
- return defaultPrevented;
103
- },
107
+ descriptors.defaultPrevented = {
108
+ enumerable: true,
109
+ get() {
110
+ return defaultPrevented;
104
111
  },
105
- preventDefault: {
106
- enumerable: true,
107
- value() {
108
- defaultPrevented = true;
109
- },
112
+ };
113
+ descriptors.preventDefault = {
114
+ enumerable: true,
115
+ value() {
116
+ defaultPrevented = true;
110
117
  },
111
- });
118
+ };
112
119
  }
113
120
 
121
+ const event: EventArg<any, any, any> = Object.defineProperties(
122
+ {} as EventArg<any, any, any>,
123
+ descriptors
124
+ );
125
+
114
126
  listenRef.current?.(event);
115
127
 
116
128
  callbacks?.forEach((cb) => cb(event));
117
129
 
130
+ onPostEmitRef.current?.(event);
131
+
118
132
  return event as any;
119
133
  },
120
134
  []
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
 
3
+ import { IsFocusedGetterContext } from './useIsFocused';
3
4
  import { useNavigation } from './useNavigation';
4
5
 
5
6
  type EffectCallback = () => undefined | void | (() => void);
@@ -14,6 +15,8 @@ type EffectCallback = () => undefined | void | (() => void);
14
15
  export function useFocusEffect(effect: EffectCallback) {
15
16
  const navigation = useNavigation();
16
17
 
18
+ const getIsFocused = React.use(IsFocusedGetterContext);
19
+
17
20
  // eslint-disable-next-line prefer-rest-params
18
21
  if (arguments[1] !== undefined) {
19
22
  const message =
@@ -72,7 +75,7 @@ export function useFocusEffect(effect: EffectCallback) {
72
75
  };
73
76
 
74
77
  // We need to run the effect on initial render/dep changes if the screen is focused
75
- if (navigation.isFocused()) {
78
+ if (getIsFocused?.() ?? true) {
76
79
  cleanup = callback();
77
80
  isFocused = true;
78
81
  }
@@ -109,5 +112,5 @@ export function useFocusEffect(effect: EffectCallback) {
109
112
  unsubscribeFocus();
110
113
  unsubscribeBlur();
111
114
  };
112
- }, [effect, navigation]);
115
+ }, [effect, navigation, getIsFocused]);
113
116
  }
@@ -4,6 +4,7 @@ import * as React from 'react';
4
4
  import { NavigationContext } from './NavigationProvider';
5
5
  import type { EventMapCore } from './types';
6
6
  import type { NavigationEventEmitter } from './useEventEmitter';
7
+ import { IsFocusedGetterContext } from './useIsFocused';
7
8
 
8
9
  type Options<State extends NavigationState> = {
9
10
  state: State;
@@ -17,10 +18,18 @@ export function useFocusEvents<State extends NavigationState>({
17
18
  state,
18
19
  emitter,
19
20
  }: Options<State>) {
20
- const navigation = React.useContext(NavigationContext);
21
+ const navigation = React.use(NavigationContext);
22
+ const getIsFocused = React.use(IsFocusedGetterContext);
23
+
21
24
  const lastFocusedKeyRef = React.useRef<string | undefined>(undefined);
22
25
 
23
- const currentFocusedKey = state.routes[state.index].key;
26
+ const currentFocusedRoute = state.routes[state.index];
27
+
28
+ if (currentFocusedRoute == null) {
29
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
30
+ }
31
+
32
+ const currentFocusedKey = currentFocusedRoute.key;
24
33
 
25
34
  // When the parent screen changes its focus state, we also need to change child's focus
26
35
  // Coz the child screen can't be focused if the parent screen is out of focus
@@ -45,7 +54,12 @@ export function useFocusEvents<State extends NavigationState>({
45
54
  React.useEffect(() => {
46
55
  const lastFocusedKey = lastFocusedKeyRef.current;
47
56
 
48
- lastFocusedKeyRef.current = currentFocusedKey;
57
+ const isFocused = getIsFocused?.() ?? true;
58
+
59
+ if (isFocused) {
60
+ // Remember the current route as focused if the navigator is focused
61
+ lastFocusedKeyRef.current = currentFocusedKey;
62
+ }
49
63
 
50
64
  // We wouldn't have `lastFocusedKey` on initial mount
51
65
  // Fire focus event for the current route on mount if there's no parent navigator
@@ -55,10 +69,7 @@ export function useFocusEvents<State extends NavigationState>({
55
69
 
56
70
  // We should only emit events when the focused key changed and navigator is focused
57
71
  // When navigator is not focused, screens inside shouldn't receive focused status either
58
- if (
59
- lastFocusedKey === currentFocusedKey ||
60
- !(navigation ? navigation.isFocused() : true)
61
- ) {
72
+ if (lastFocusedKey === currentFocusedKey || !isFocused) {
62
73
  return;
63
74
  }
64
75
 
@@ -69,5 +80,5 @@ export function useFocusEvents<State extends NavigationState>({
69
80
 
70
81
  emitter.emit({ type: 'blur', target: lastFocusedKey });
71
82
  emitter.emit({ type: 'focus', target: currentFocusedKey });
72
- }, [currentFocusedKey, emitter, navigation]);
83
+ }, [currentFocusedKey, emitter, navigation, getIsFocused]);
73
84
  }
@@ -4,7 +4,7 @@ import * as React from 'react';
4
4
  import {
5
5
  type FocusedNavigationCallback,
6
6
  type FocusedNavigationListener,
7
- NavigationBuilderContext,
7
+ useNavigationBuilderContext,
8
8
  } from './NavigationBuilderContext';
9
9
  import type { NavigationHelpers } from './types';
10
10
 
@@ -20,7 +20,7 @@ export function useFocusedListenersChildrenAdapter({
20
20
  navigation,
21
21
  focusedListeners,
22
22
  }: Options) {
23
- const { addListener } = React.useContext(NavigationBuilderContext);
23
+ const { addListener } = useNavigationBuilderContext();
24
24
 
25
25
  const listener = React.useCallback(
26
26
  (callback: FocusedNavigationCallback<any>) => {
@@ -41,7 +41,7 @@ export function useFocusedListenersChildrenAdapter({
41
41
  [focusedListeners, navigation]
42
42
  );
43
43
 
44
- React.useEffect(
44
+ React.useInsertionEffect(
45
45
  () => addListener?.('focus', listener),
46
46
  [addListener, listener]
47
47
  );
@@ -1,32 +1,29 @@
1
1
  import * as React from 'react';
2
2
 
3
- import { useNavigation } from './useNavigation';
3
+ export const FocusedRouteKeyContext = React.createContext<string | undefined>(
4
+ undefined
5
+ );
6
+
7
+ export const IsFocusedContext = React.createContext<boolean | undefined>(
8
+ undefined
9
+ );
10
+
11
+ export const IsFocusedGetterContext = React.createContext<
12
+ (() => boolean) | undefined
13
+ >(undefined);
4
14
 
5
15
  /**
6
16
  * Hook to get the current focus state of the screen. Returns a `true` if screen is focused, otherwise `false`.
7
17
  * This can be used if a component needs to render something based on the focus state.
8
18
  */
9
19
  export function useIsFocused(): boolean {
10
- const navigation = useNavigation();
11
-
12
- const subscribe = React.useCallback(
13
- (callback: () => void) => {
14
- const unsubscribeFocus = navigation.addListener('focus', callback);
15
- const unsubscribeBlur = navigation.addListener('blur', callback);
16
-
17
- return () => {
18
- unsubscribeFocus();
19
- unsubscribeBlur();
20
- };
21
- },
22
- [navigation]
23
- );
20
+ const isFocused = React.use(IsFocusedContext);
24
21
 
25
- const value = React.useSyncExternalStore(
26
- subscribe,
27
- navigation.isFocused,
28
- navigation.isFocused
29
- );
22
+ if (isFocused === undefined) {
23
+ throw new Error(
24
+ "Couldn't determine focus state. Is your component inside a screen in a navigator?"
25
+ );
26
+ }
30
27
 
31
- return value;
28
+ return isFocused;
32
29
  }
@@ -14,6 +14,7 @@ export function useKeyedChildListeners() {
14
14
  }>(
15
15
  Object.assign(Object.create(null), {
16
16
  getState: {},
17
+ getNavigation: {},
17
18
  beforeRemove: {},
18
19
  })
19
20
  );
@@ -28,8 +29,10 @@ export function useKeyedChildListeners() {
28
29
  keyedListeners[type][key] = listener;
29
30
 
30
31
  return () => {
31
- // @ts-expect-error: according to ref stated above you can use `key` to index type
32
- keyedListeners[type][key] = undefined;
32
+ if (keyedListeners[type][key] === listener) {
33
+ // @ts-expect-error: according to ref stated above you can use `key` to index type
34
+ keyedListeners[type][key] = undefined;
35
+ }
33
36
  };
34
37
  },
35
38
  [keyedListeners]
@@ -1,11 +1,11 @@
1
1
  import * as React from 'react';
2
2
 
3
- export function useLazyValue<T>(create: () => T) {
3
+ export function useLazyValue<T>(create: () => T): T {
4
4
  const lazyRef = React.useRef<T>(undefined);
5
5
 
6
6
  if (lazyRef.current === undefined) {
7
7
  lazyRef.current = create();
8
8
  }
9
9
 
10
- return lazyRef.current as T;
10
+ return lazyRef.current;
11
11
  }