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

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 (285) hide show
  1. package/lib/module/BaseNavigationContainer.js +38 -19
  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 +20 -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 +3 -0
  14. package/lib/module/NavigationStateContext.js.map +1 -1
  15. package/lib/module/PreventRemoveContext.js.map +1 -1
  16. package/lib/module/PreventRemoveProvider.js +37 -27
  17. package/lib/module/PreventRemoveProvider.js.map +1 -1
  18. package/lib/module/SceneView.js +10 -41
  19. package/lib/module/SceneView.js.map +1 -1
  20. package/lib/module/StaticNavigation.js +179 -50
  21. package/lib/module/StaticNavigation.js.map +1 -1
  22. package/lib/module/StaticTreeContext.js +5 -0
  23. package/lib/module/StaticTreeContext.js.map +1 -0
  24. package/lib/module/checkSerializable.js +18 -13
  25. package/lib/module/checkSerializable.js.map +1 -1
  26. package/lib/module/createNavigationContainerRef.js +6 -8
  27. package/lib/module/createNavigationContainerRef.js.map +1 -1
  28. package/lib/module/createNavigatorFactory.js +27 -5
  29. package/lib/module/createNavigatorFactory.js.map +1 -1
  30. package/lib/module/findFocusedRoute.js +7 -4
  31. package/lib/module/findFocusedRoute.js.map +1 -1
  32. package/lib/module/getActionFromState.js +45 -20
  33. package/lib/module/getActionFromState.js.map +1 -1
  34. package/lib/module/getPathFromState.js +171 -90
  35. package/lib/module/getPathFromState.js.map +1 -1
  36. package/lib/module/getPatternParts.js +20 -4
  37. package/lib/module/getPatternParts.js.map +1 -1
  38. package/lib/module/getStateFromPath.js +487 -217
  39. package/lib/module/getStateFromPath.js.map +1 -1
  40. package/lib/module/getStateFromRouteParams.js +23 -0
  41. package/lib/module/getStateFromRouteParams.js.map +1 -0
  42. package/lib/module/index.js +5 -4
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/theming/useTheme.js +1 -1
  45. package/lib/module/theming/useTheme.js.map +1 -1
  46. package/lib/module/types.js +35 -0
  47. package/lib/module/types.js.map +1 -1
  48. package/lib/module/useDescriptors.js +21 -11
  49. package/lib/module/useDescriptors.js.map +1 -1
  50. package/lib/module/useEventEmitter.js +48 -33
  51. package/lib/module/useEventEmitter.js.map +1 -1
  52. package/lib/module/useFocusEvents.js +12 -4
  53. package/lib/module/useFocusEvents.js.map +1 -1
  54. package/lib/module/useFocusedListenersChildrenAdapter.js +2 -2
  55. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  56. package/lib/module/useIsFocused.js +7 -12
  57. package/lib/module/useIsFocused.js.map +1 -1
  58. package/lib/module/useKeyedChildListeners.js +4 -2
  59. package/lib/module/useKeyedChildListeners.js.map +1 -1
  60. package/lib/module/useLazyValue.js.map +1 -1
  61. package/lib/module/useNavigation.js +2 -15
  62. package/lib/module/useNavigation.js.map +1 -1
  63. package/lib/module/useNavigationBuilder.js +204 -131
  64. package/lib/module/useNavigationBuilder.js.map +1 -1
  65. package/lib/module/useNavigationCache.js +22 -17
  66. package/lib/module/useNavigationCache.js.map +1 -1
  67. package/lib/module/useNavigationHelpers.js +28 -10
  68. package/lib/module/useNavigationHelpers.js.map +1 -1
  69. package/lib/module/useNavigationIndependentTree.js +1 -1
  70. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  71. package/lib/module/useNavigationState.js +125 -45
  72. package/lib/module/useNavigationState.js.map +1 -1
  73. package/lib/module/useOnAction.js +37 -7
  74. package/lib/module/useOnAction.js.map +1 -1
  75. package/lib/module/useOnGetState.js +6 -3
  76. package/lib/module/useOnGetState.js.map +1 -1
  77. package/lib/module/useOnPreventRemove.js +39 -30
  78. package/lib/module/useOnPreventRemove.js.map +1 -1
  79. package/lib/module/useOnRouteFocus.js +1 -1
  80. package/lib/module/useOnRouteFocus.js.map +1 -1
  81. package/lib/module/useOptionsGetters.js +10 -5
  82. package/lib/module/useOptionsGetters.js.map +1 -1
  83. package/lib/module/usePreventRemove.js +10 -3
  84. package/lib/module/usePreventRemove.js.map +1 -1
  85. package/lib/module/usePreventRemoveContext.js +1 -1
  86. package/lib/module/usePreventRemoveContext.js.map +1 -1
  87. package/lib/module/useRegisterNavigator.js +2 -2
  88. package/lib/module/useRegisterNavigator.js.map +1 -1
  89. package/lib/module/useRoute.js +2 -0
  90. package/lib/module/useRoute.js.map +1 -1
  91. package/lib/module/useRouteCache.js +17 -11
  92. package/lib/module/useRouteCache.js.map +1 -1
  93. package/lib/module/useScheduleUpdate.js +9 -9
  94. package/lib/module/useScheduleUpdate.js.map +1 -1
  95. package/lib/module/useStateForPath.js +1 -1
  96. package/lib/module/useStateForPath.js.map +1 -1
  97. package/lib/module/useSyncState.js +32 -9
  98. package/lib/module/useSyncState.js.map +1 -1
  99. package/lib/module/validatePathConfig.js +50 -36
  100. package/lib/module/validatePathConfig.js.map +1 -1
  101. package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
  102. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  103. package/lib/typescript/src/ConsumedParamsContext.d.ts +3 -0
  104. package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
  105. package/lib/typescript/src/DataLoading.d.ts +21 -0
  106. package/lib/typescript/src/DataLoading.d.ts.map +1 -0
  107. package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
  108. package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
  109. package/lib/typescript/src/Group.d.ts +1 -1
  110. package/lib/typescript/src/Group.d.ts.map +1 -1
  111. package/lib/typescript/src/NavigationBuilderContext.d.ts +9 -8
  112. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  113. package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
  114. package/lib/typescript/src/NavigationContainerRefContext.d.ts.map +1 -1
  115. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
  116. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
  117. package/lib/typescript/src/NavigationHelpersContext.d.ts +1 -1
  118. package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
  119. package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
  120. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  121. package/lib/typescript/src/NavigationProvider.d.ts +12 -13
  122. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  123. package/lib/typescript/src/NavigationStateContext.d.ts +4 -3
  124. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  125. package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
  126. package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
  127. package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
  128. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  129. package/lib/typescript/src/SceneView.d.ts +4 -2
  130. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  131. package/lib/typescript/src/Screen.d.ts +1 -1
  132. package/lib/typescript/src/Screen.d.ts.map +1 -1
  133. package/lib/typescript/src/StaticContainer.d.ts +1 -1
  134. package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
  135. package/lib/typescript/src/StaticNavigation.d.ts +189 -109
  136. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  137. package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
  138. package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
  139. package/lib/typescript/src/checkSerializable.d.ts +8 -4
  140. package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
  141. package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
  142. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  143. package/lib/typescript/src/createNavigatorFactory.d.ts +23 -5
  144. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  145. package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
  146. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  147. package/lib/typescript/src/getActionFromState.d.ts +4 -4
  148. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  149. package/lib/typescript/src/getPathFromState.d.ts +3 -3
  150. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  151. package/lib/typescript/src/getPatternParts.d.ts +1 -0
  152. package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
  153. package/lib/typescript/src/getStateFromPath.d.ts +4 -7
  154. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  155. package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
  156. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
  157. package/lib/typescript/src/index.d.ts +36 -33
  158. package/lib/typescript/src/index.d.ts.map +1 -1
  159. package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
  160. package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
  161. package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
  162. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  163. package/lib/typescript/src/theming/useTheme.d.ts +1 -1
  164. package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
  165. package/lib/typescript/src/types.d.ts +260 -159
  166. package/lib/typescript/src/types.d.ts.map +1 -1
  167. package/lib/typescript/src/useChildListeners.d.ts +3 -3
  168. package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
  169. package/lib/typescript/src/useComponent.d.ts +1 -1
  170. package/lib/typescript/src/useComponent.d.ts.map +1 -1
  171. package/lib/typescript/src/useDescriptors.d.ts +10 -9
  172. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  173. package/lib/typescript/src/useEventEmitter.d.ts +2 -2
  174. package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
  175. package/lib/typescript/src/useFocusEvents.d.ts +2 -2
  176. package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
  177. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
  178. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts.map +1 -1
  179. package/lib/typescript/src/useIsFocused.d.ts +3 -0
  180. package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
  181. package/lib/typescript/src/useKeyedChildListeners.d.ts +3 -3
  182. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  183. package/lib/typescript/src/useLazyValue.d.ts.map +1 -1
  184. package/lib/typescript/src/useNavigation.d.ts +4 -2
  185. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  186. package/lib/typescript/src/useNavigationBuilder.d.ts +23 -30
  187. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  188. package/lib/typescript/src/useNavigationCache.d.ts +3 -3
  189. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  190. package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
  191. package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
  192. package/lib/typescript/src/useNavigationHelpers.d.ts +19 -27
  193. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  194. package/lib/typescript/src/useNavigationState.d.ts +17 -3
  195. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  196. package/lib/typescript/src/useOnAction.d.ts +9 -9
  197. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  198. package/lib/typescript/src/useOnGetState.d.ts +1 -1
  199. package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
  200. package/lib/typescript/src/useOnPreventRemove.d.ts +5 -9
  201. package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
  202. package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
  203. package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
  204. package/lib/typescript/src/useOptionsGetters.d.ts +1 -1
  205. package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
  206. package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
  207. package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
  208. package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
  209. package/lib/typescript/src/useRoute.d.ts +7 -3
  210. package/lib/typescript/src/useRoute.d.ts.map +1 -1
  211. package/lib/typescript/src/useRouteCache.d.ts +5 -5
  212. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  213. package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
  214. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  215. package/lib/typescript/src/useStateForPath.d.ts +1 -1
  216. package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
  217. package/lib/typescript/src/useSyncState.d.ts +1 -0
  218. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  219. package/lib/typescript/src/utilities.d.ts +74 -37
  220. package/lib/typescript/src/utilities.d.ts.map +1 -1
  221. package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
  222. package/package.json +23 -22
  223. package/src/BaseNavigationContainer.tsx +362 -334
  224. package/src/ConsumedParamsContext.tsx +5 -0
  225. package/src/DataLoading.tsx +203 -0
  226. package/src/NavigationBuilderContext.tsx +14 -9
  227. package/src/NavigationFocusedRouteStateContext.tsx +4 -4
  228. package/src/NavigationIndependentTree.tsx +23 -12
  229. package/src/NavigationProvider.tsx +26 -15
  230. package/src/NavigationStateContext.tsx +9 -6
  231. package/src/PreventRemoveContext.tsx +1 -0
  232. package/src/PreventRemoveProvider.tsx +51 -46
  233. package/src/SceneView.tsx +11 -39
  234. package/src/StaticNavigation.tsx +659 -307
  235. package/src/StaticTreeContext.tsx +7 -0
  236. package/src/checkSerializable.tsx +35 -19
  237. package/src/createNavigationContainerRef.tsx +12 -9
  238. package/src/createNavigatorFactory.tsx +92 -8
  239. package/src/findFocusedRoute.tsx +16 -16
  240. package/src/getActionFromState.tsx +87 -51
  241. package/src/getPathFromState.tsx +254 -128
  242. package/src/getPatternParts.tsx +25 -4
  243. package/src/getStateFromPath.tsx +821 -331
  244. package/src/getStateFromRouteParams.tsx +59 -0
  245. package/src/index.tsx +55 -5
  246. package/src/theming/useTheme.tsx +1 -1
  247. package/src/types.tsx +798 -373
  248. package/src/useDescriptors.tsx +31 -14
  249. package/src/useEventEmitter.tsx +52 -38
  250. package/src/useFocusEvents.tsx +15 -7
  251. package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
  252. package/src/useIsFocused.tsx +14 -21
  253. package/src/useKeyedChildListeners.tsx +4 -2
  254. package/src/useLazyValue.tsx +2 -2
  255. package/src/useNavigation.tsx +7 -24
  256. package/src/useNavigationBuilder.tsx +314 -186
  257. package/src/useNavigationCache.tsx +32 -25
  258. package/src/useNavigationHelpers.tsx +27 -10
  259. package/src/useNavigationIndependentTree.tsx +1 -1
  260. package/src/useNavigationState.tsx +168 -69
  261. package/src/useOnAction.tsx +61 -13
  262. package/src/useOnGetState.tsx +5 -3
  263. package/src/useOnPreventRemove.tsx +75 -42
  264. package/src/useOnRouteFocus.tsx +10 -12
  265. package/src/useOptionsGetters.tsx +11 -5
  266. package/src/usePreventRemove.tsx +12 -3
  267. package/src/usePreventRemoveContext.tsx +1 -1
  268. package/src/useRegisterNavigator.tsx +2 -2
  269. package/src/useRoute.tsx +20 -6
  270. package/src/useRouteCache.tsx +22 -16
  271. package/src/useScheduleUpdate.tsx +9 -10
  272. package/src/useStateForPath.tsx +1 -1
  273. package/src/useSyncState.tsx +35 -9
  274. package/src/utilities.tsx +144 -31
  275. package/src/validatePathConfig.tsx +86 -57
  276. package/lib/module/CurrentRenderContext.js +0 -10
  277. package/lib/module/CurrentRenderContext.js.map +0 -1
  278. package/lib/module/useCurrentRender.js +0 -19
  279. package/lib/module/useCurrentRender.js.map +0 -1
  280. package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
  281. package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
  282. package/lib/typescript/src/useCurrentRender.d.ts +0 -14
  283. package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
  284. package/src/CurrentRenderContext.tsx +0 -9
  285. package/src/useCurrentRender.tsx +0 -31
@@ -0,0 +1,5 @@
1
+ import * as React from 'react';
2
+
3
+ export const ConsumedParamsContext = React.createContext<
4
+ WeakMap<object, true> | undefined
5
+ >(undefined);
@@ -0,0 +1,203 @@
1
+ import type { NavigationState, PartialState } from '@react-navigation/routers';
2
+
3
+ import { getStateFromRouteParams } from './getStateFromRouteParams';
4
+ import type { TreeForPathConfig } from './StaticNavigation';
5
+
6
+ function findScreenInConfig(config: TreeForPathConfig['config'], name: string) {
7
+ const screens = config.screens;
8
+
9
+ if (screens?.[name] != null) {
10
+ return screens[name];
11
+ }
12
+
13
+ if (config.groups) {
14
+ for (const group of Object.values(config.groups)) {
15
+ if (group.screens[name] != null) {
16
+ return group.screens[name];
17
+ }
18
+ }
19
+ }
20
+
21
+ return undefined;
22
+ }
23
+
24
+ function findInitialRouteName(
25
+ config: TreeForPathConfig['config']
26
+ ): string | undefined {
27
+ if (config.initialRouteName != null) {
28
+ return config.initialRouteName;
29
+ }
30
+
31
+ for (const key in config) {
32
+ if (key === 'screens' && config.screens) {
33
+ const name = Object.keys(config.screens)[0];
34
+
35
+ if (name != null) {
36
+ return name;
37
+ }
38
+ }
39
+
40
+ if (key === 'groups' && config.groups) {
41
+ for (const group of Object.values(config.groups)) {
42
+ const name = Object.keys(group.screens)[0];
43
+
44
+ if (name != null) {
45
+ return name;
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ return undefined;
52
+ }
53
+
54
+ /**
55
+ * Get loader for the focused route in a static config tree with given navigation state.
56
+ *
57
+ * @param tree The static navigation config.
58
+ * @param state The navigation state to extract the focused route path from.
59
+ * @returns A function that returns a `Promise<void>`, or `undefined` if no loaders are found.
60
+ *
61
+ * @example
62
+ * ```js
63
+ * const loader = getLoaderForState(RootStack, {
64
+ * index: 0,
65
+ * routes: [{ name: 'Home' }],
66
+ * });
67
+ * await loader?.();
68
+ * ```
69
+ */
70
+ export function getLoaderForState(
71
+ tree: TreeForPathConfig,
72
+ state: PartialState<NavigationState> | NavigationState | undefined
73
+ ): (() => Promise<void>) | undefined {
74
+ return getLoaderForStateChange(tree, state, undefined, undefined);
75
+ }
76
+
77
+ export function getLoaderForStateChange(
78
+ tree: TreeForPathConfig,
79
+ state: PartialState<NavigationState> | NavigationState | undefined,
80
+ previousState: PartialState<NavigationState> | NavigationState | undefined,
81
+ consumedParams: WeakMap<object, true> | undefined
82
+ ): (() => Promise<void>) | undefined {
83
+ const focusedRoute = state?.routes[state.index ?? state.routes.length - 1];
84
+ const previousFocusedRoute =
85
+ previousState?.routes[
86
+ previousState.index ?? previousState.routes.length - 1
87
+ ];
88
+
89
+ if (!focusedRoute) {
90
+ return undefined;
91
+ }
92
+
93
+ const isNewlyFocused =
94
+ previousState === undefined ||
95
+ previousFocusedRoute == null ||
96
+ focusedRoute.name !== previousFocusedRoute.name ||
97
+ (focusedRoute.key != null &&
98
+ previousFocusedRoute.key != null &&
99
+ focusedRoute.key !== previousFocusedRoute.key);
100
+
101
+ const item = findScreenInConfig(tree.config, focusedRoute.name);
102
+
103
+ if (item == null) {
104
+ return undefined;
105
+ }
106
+
107
+ const initialParams =
108
+ typeof item === 'object' && 'initialParams' in item
109
+ ? item.initialParams
110
+ : undefined;
111
+
112
+ const params =
113
+ initialParams != null || focusedRoute.params != null
114
+ ? { ...initialParams, ...focusedRoute.params }
115
+ : undefined;
116
+
117
+ const loaders: (() => Promise<void>)[] = [];
118
+
119
+ if (
120
+ isNewlyFocused &&
121
+ 'UNSTABLE_loader' in item &&
122
+ typeof item.UNSTABLE_loader === 'function'
123
+ ) {
124
+ const loader = item.UNSTABLE_loader;
125
+
126
+ loaders.push(() =>
127
+ loader({
128
+ name: focusedRoute.name,
129
+ params,
130
+ })
131
+ );
132
+ }
133
+
134
+ const nested =
135
+ 'config' in item
136
+ ? item
137
+ : 'screen' in item && 'config' in item.screen
138
+ ? item.screen
139
+ : undefined;
140
+
141
+ if (nested) {
142
+ const initialRouteName = findInitialRouteName(nested.config);
143
+
144
+ const stateFromParams =
145
+ focusedRoute.params != null && consumedParams?.has(focusedRoute.params)
146
+ ? undefined
147
+ : getStateFromRouteParams(params);
148
+
149
+ let childState =
150
+ previousState !== undefined && stateFromParams != null
151
+ ? stateFromParams
152
+ : (focusedRoute.state ?? stateFromParams);
153
+
154
+ if (childState == null && initialRouteName != null) {
155
+ childState = { routes: [{ name: initialRouteName }] };
156
+ }
157
+
158
+ let previousChildState:
159
+ | PartialState<NavigationState>
160
+ | NavigationState
161
+ | undefined;
162
+
163
+ if (!isNewlyFocused) {
164
+ const previousRouteParams = previousFocusedRoute?.params;
165
+ const previousParams =
166
+ initialParams != null || previousRouteParams != null
167
+ ? { ...initialParams, ...previousRouteParams }
168
+ : undefined;
169
+ const previousStateFromParams =
170
+ previousRouteParams != null && consumedParams?.has(previousRouteParams)
171
+ ? undefined
172
+ : getStateFromRouteParams(previousParams);
173
+
174
+ previousChildState =
175
+ previousFocusedRoute?.state ?? previousStateFromParams;
176
+
177
+ if (previousChildState == null && initialRouteName != null) {
178
+ previousChildState = { routes: [{ name: initialRouteName }] };
179
+ }
180
+ }
181
+
182
+ const childLoader = getLoaderForStateChange(
183
+ nested,
184
+ childState,
185
+ previousState === undefined
186
+ ? undefined
187
+ : (previousChildState ?? { routes: [] }),
188
+ consumedParams
189
+ );
190
+
191
+ if (childLoader) {
192
+ loaders.push(childLoader);
193
+ }
194
+ }
195
+
196
+ if (loaders.length === 0) {
197
+ return undefined;
198
+ }
199
+
200
+ return async () => {
201
+ await Promise.all(loaders.map((l) => l()));
202
+ };
203
+ }
@@ -2,6 +2,7 @@ import type {
2
2
  NavigationAction,
3
3
  NavigationState,
4
4
  ParamListBase,
5
+ PartialState,
5
6
  } from '@react-navigation/routers';
6
7
  import * as React from 'react';
7
8
 
@@ -46,19 +47,21 @@ export type FocusedNavigationListener = <T>(
46
47
 
47
48
  export type GetStateListener = () => NavigationState;
48
49
 
49
- export type ChildBeforeRemoveListener = (action: NavigationAction) => boolean;
50
+ export type ChildBeforeRemoveListener = (
51
+ action: NavigationAction,
52
+ nextState: NavigationState | PartialState<NavigationState> | undefined
53
+ ) => boolean;
50
54
 
51
55
  /**
52
56
  * Context which holds the required helpers needed to build nested navigators.
53
57
  */
54
58
  export const NavigationBuilderContext = React.createContext<{
55
- onAction?: (
56
- action: NavigationAction,
57
- visitedNavigators?: Set<string>
58
- ) => boolean;
59
- addListener?: AddListener;
60
- addKeyedListener?: AddKeyedListener;
61
- onRouteFocus?: (key: string) => void;
59
+ onAction?:
60
+ | ((action: NavigationAction, visitedNavigators?: Set<string>) => boolean)
61
+ | undefined;
62
+ addListener?: AddListener | undefined;
63
+ addKeyedListener?: AddKeyedListener | undefined;
64
+ onRouteFocus?: ((key: string) => void) | undefined;
62
65
  onDispatchAction: (action: NavigationAction, noop: boolean) => void;
63
66
  onEmitEvent: (event: {
64
67
  type: string;
@@ -67,13 +70,15 @@ export const NavigationBuilderContext = React.createContext<{
67
70
  data: unknown;
68
71
  }) => void;
69
72
  onOptionsChange: (options: object) => void;
73
+ getIsStateEmitted: () => boolean;
70
74
  scheduleUpdate: (callback: () => void) => void;
71
75
  flushUpdates: () => void;
72
- stackRef?: React.MutableRefObject<string | undefined>;
76
+ stackRef?: React.RefObject<string | undefined> | undefined;
73
77
  }>({
74
78
  onDispatchAction: () => undefined,
75
79
  onEmitEvent: () => undefined,
76
80
  onOptionsChange: () => undefined,
81
+ getIsStateEmitted: () => false,
77
82
  scheduleUpdate: () => {
78
83
  throw new Error("Couldn't find a context for scheduling updates.");
79
84
  },
@@ -3,11 +3,11 @@ import * as React from 'react';
3
3
  export type FocusedRouteState = {
4
4
  routes: [
5
5
  {
6
- key?: string;
6
+ key?: string | undefined;
7
7
  name: string;
8
- params?: object;
9
- path?: string;
10
- state?: FocusedRouteState;
8
+ params?: object | undefined;
9
+ path?: string | undefined;
10
+ state?: FocusedRouteState | undefined;
11
11
  },
12
12
  ];
13
13
  };
@@ -1,12 +1,17 @@
1
1
  import * as React from 'react';
2
2
 
3
+ import { NavigationFocusedRouteStateContext } from './NavigationFocusedRouteStateContext';
3
4
  import { NavigationIndependentTreeContext } from './NavigationIndependentTreeContext';
4
5
  import {
5
6
  NamedRouteContextListContext,
6
7
  NavigationContext,
7
8
  NavigationRouteContext,
8
- NavigationRouteNameContext,
9
9
  } from './NavigationProvider';
10
+ import { IsFocusedContext } from './useIsFocused';
11
+ import {
12
+ NamedNavigationStateListenerListContext,
13
+ NavigationStateListenerContext,
14
+ } from './useNavigationState';
10
15
 
11
16
  /**
12
17
  * Component to make the child navigation container independent of parent containers.
@@ -18,16 +23,22 @@ export function NavigationIndependentTree({
18
23
  }) {
19
24
  return (
20
25
  // We need to clear any existing contexts for nested independent container to work correctly
21
- <NamedRouteContextListContext.Provider value={undefined}>
22
- <NavigationRouteContext.Provider value={undefined}>
23
- <NavigationContext.Provider value={undefined}>
24
- <NavigationRouteNameContext.Provider value={undefined}>
25
- <NavigationIndependentTreeContext.Provider value={true}>
26
- {children}
27
- </NavigationIndependentTreeContext.Provider>
28
- </NavigationRouteNameContext.Provider>
29
- </NavigationContext.Provider>
30
- </NavigationRouteContext.Provider>
31
- </NamedRouteContextListContext.Provider>
26
+ <NavigationStateListenerContext.Provider value={undefined}>
27
+ <NamedNavigationStateListenerListContext.Provider value={undefined}>
28
+ <NamedRouteContextListContext.Provider value={undefined}>
29
+ <NavigationRouteContext.Provider value={undefined}>
30
+ <NavigationContext.Provider value={undefined}>
31
+ <NavigationFocusedRouteStateContext.Provider value={undefined}>
32
+ <IsFocusedContext.Provider value={undefined}>
33
+ <NavigationIndependentTreeContext.Provider value={true}>
34
+ {children}
35
+ </NavigationIndependentTreeContext.Provider>
36
+ </IsFocusedContext.Provider>
37
+ </NavigationFocusedRouteStateContext.Provider>
38
+ </NavigationContext.Provider>
39
+ </NavigationRouteContext.Provider>
40
+ </NamedRouteContextListContext.Provider>
41
+ </NamedNavigationStateListenerListContext.Provider>
42
+ </NavigationStateListenerContext.Provider>
32
43
  );
33
44
  }
@@ -2,7 +2,9 @@ import type { ParamListBase, Route } from '@react-navigation/routers';
2
2
  import * as React from 'react';
3
3
 
4
4
  import type { NavigationProp } from './types';
5
+ import { FocusedRouteKeyContext, IsFocusedContext } from './useIsFocused';
5
6
  import { useLazyValue } from './useLazyValue';
7
+ import { NamedNavigationStateListenerProvider } from './useNavigationState';
6
8
 
7
9
  /**
8
10
  * Context which holds the route prop for a screen.
@@ -18,10 +20,6 @@ export const NavigationContext = React.createContext<
18
20
  NavigationProp<ParamListBase> | undefined
19
21
  >(undefined);
20
22
 
21
- export const NavigationRouteNameContext = React.createContext<
22
- string | undefined
23
- >(undefined);
24
-
25
23
  type Props = {
26
24
  route: Route<string>;
27
25
  navigation: NavigationProp<ParamListBase>;
@@ -48,17 +46,30 @@ export function NavigationProvider({ route, navigation, children }: Props) {
48
46
  [NamedRouteContext, parents, route.name]
49
47
  );
50
48
 
49
+ const parentIsFocused = React.use(IsFocusedContext);
50
+ const focusedRouteKey = React.use(FocusedRouteKeyContext);
51
+
52
+ // Mark route as focused only if:
53
+ // - It doesn't have a parent navigator
54
+ // - Parent navigator is focused
55
+ const isFocused =
56
+ parentIsFocused == null || parentIsFocused
57
+ ? focusedRouteKey === route.key
58
+ : false;
59
+
51
60
  return (
52
- <NamedRouteContextListContext.Provider value={NamedRouteContextList}>
53
- <NamedRouteContext.Provider value={route}>
54
- <NavigationRouteContext.Provider value={route}>
55
- <NavigationContext.Provider value={navigation}>
56
- <NavigationRouteNameContext.Provider value={route.name}>
57
- {children}
58
- </NavigationRouteNameContext.Provider>
59
- </NavigationContext.Provider>
60
- </NavigationRouteContext.Provider>
61
- </NamedRouteContext.Provider>
62
- </NamedRouteContextListContext.Provider>
61
+ <NamedNavigationStateListenerProvider name={route.name}>
62
+ <NamedRouteContextListContext.Provider value={NamedRouteContextList}>
63
+ <NamedRouteContext.Provider value={route}>
64
+ <NavigationRouteContext.Provider value={route}>
65
+ <NavigationContext.Provider value={navigation}>
66
+ <IsFocusedContext.Provider value={isFocused}>
67
+ {children}
68
+ </IsFocusedContext.Provider>
69
+ </NavigationContext.Provider>
70
+ </NavigationRouteContext.Provider>
71
+ </NamedRouteContext.Provider>
72
+ </NamedRouteContextListContext.Provider>
73
+ </NamedNavigationStateListenerProvider>
63
74
  );
64
75
  }
@@ -5,19 +5,19 @@ const MISSING_CONTEXT_ERROR =
5
5
  "Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started for setup instructions.";
6
6
 
7
7
  export const NavigationStateContext = React.createContext<{
8
- isDefault?: true;
9
- state?: NavigationState | PartialState<NavigationState>;
8
+ isDefault?: true | undefined;
9
+ state?: NavigationState | PartialState<NavigationState> | undefined;
10
10
  getKey: () => string | undefined;
11
11
  setKey: (key: string) => void;
12
12
  getState: () => NavigationState | PartialState<NavigationState> | undefined;
13
13
  setState: (
14
14
  state: NavigationState | PartialState<NavigationState> | undefined
15
15
  ) => void;
16
+ subscribe: (callback: () => void) => () => void;
16
17
  getIsInitial: () => boolean;
17
- addOptionsGetter?: (
18
- key: string,
19
- getter: () => object | undefined | null
20
- ) => void;
18
+ addOptionsGetter?:
19
+ | ((key: string, getter: () => object | undefined | null) => void)
20
+ | undefined;
21
21
  }>({
22
22
  isDefault: true,
23
23
 
@@ -33,6 +33,9 @@ export const NavigationStateContext = React.createContext<{
33
33
  get setState(): any {
34
34
  throw new Error(MISSING_CONTEXT_ERROR);
35
35
  },
36
+ get subscribe(): any {
37
+ throw new Error(MISSING_CONTEXT_ERROR);
38
+ },
36
39
  get getIsInitial(): any {
37
40
  throw new Error(MISSING_CONTEXT_ERROR);
38
41
  },
@@ -14,6 +14,7 @@ export const PreventRemoveContext = React.createContext<
14
14
  routeKey: string,
15
15
  preventRemove: boolean
16
16
  ) => void;
17
+ notifyPreventRemove: () => void;
17
18
  }
18
19
  | undefined
19
20
  >(undefined);
@@ -13,13 +13,7 @@ type Props = {
13
13
  children: React.ReactNode;
14
14
  };
15
15
 
16
- type PreventedRoutesMap = Map<
17
- string,
18
- {
19
- routeKey: string;
20
- preventRemove: boolean;
21
- }
22
- >;
16
+ type PreventedRoutesMap = Map<string, string>;
23
17
 
24
18
  /**
25
19
  * Util function to transform map of prevented routes to a simpler object.
@@ -27,17 +21,11 @@ type PreventedRoutesMap = Map<
27
21
  const transformPreventedRoutes = (
28
22
  preventedRoutesMap: PreventedRoutesMap
29
23
  ): PreventedRoutes => {
30
- const preventedRoutesToTransform = [...preventedRoutesMap.values()];
24
+ const preventedRoutes: PreventedRoutes = {};
31
25
 
32
- const preventedRoutes = preventedRoutesToTransform.reduce<PreventedRoutes>(
33
- (acc, { routeKey, preventRemove }) => {
34
- acc[routeKey] = {
35
- preventRemove: acc[routeKey]?.preventRemove || preventRemove,
36
- };
37
- return acc;
38
- },
39
- {}
40
- );
26
+ for (const routeKey of preventedRoutesMap.values()) {
27
+ preventedRoutes[routeKey] = { preventRemove: true };
28
+ }
41
29
 
42
30
  return preventedRoutes;
43
31
  };
@@ -50,12 +38,15 @@ export function PreventRemoveProvider({ children }: Props) {
50
38
  const [preventedRoutesMap, setPreventedRoutesMap] =
51
39
  React.useState<PreventedRoutesMap>(() => new Map());
52
40
 
53
- const navigation = React.useContext(NavigationHelpersContext);
54
- const route = React.useContext(NavigationRouteContext);
41
+ const registry = React.useRef<PreventedRoutesMap>(new Map());
55
42
 
56
- const preventRemoveContextValue = React.useContext(PreventRemoveContext);
43
+ const navigation = React.use(NavigationHelpersContext);
44
+ const route = React.use(NavigationRouteContext);
45
+
46
+ const preventRemoveContextValue = React.use(PreventRemoveContext);
57
47
  // take `setPreventRemove` from parent context - if exist it means we're in a nested context
58
48
  const setParentPrevented = preventRemoveContextValue?.setPreventRemove;
49
+ const notifyParentPrevented = preventRemoveContextValue?.notifyPreventRemove;
59
50
 
60
51
  const setPreventRemove = useLatestCallback(
61
52
  (id: string, routeKey: string, preventRemove: boolean): void => {
@@ -71,36 +62,49 @@ export function PreventRemoveProvider({ children }: Props) {
71
62
  );
72
63
  }
73
64
 
74
- setPreventedRoutesMap((prevPrevented) => {
75
- // values haven't changed - do nothing
76
- if (
77
- routeKey === prevPrevented.get(id)?.routeKey &&
78
- preventRemove === prevPrevented.get(id)?.preventRemove
79
- ) {
80
- return prevPrevented;
81
- }
82
-
83
- const nextPrevented = new Map(prevPrevented);
84
-
85
- if (preventRemove) {
86
- nextPrevented.set(id, {
87
- routeKey,
88
- preventRemove,
89
- });
90
- } else {
91
- nextPrevented.delete(id);
92
- }
93
-
94
- return nextPrevented;
95
- });
65
+ if (preventRemove) {
66
+ registry.current.set(id, routeKey);
67
+ } else {
68
+ registry.current.delete(id);
69
+ }
96
70
  }
97
71
  );
98
72
 
99
- const isPrevented = [...preventedRoutesMap.values()].some(
100
- ({ preventRemove }) => preventRemove
101
- );
73
+ const notifyPreventRemove = useLatestCallback(() => {
74
+ // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
75
+ setPreventedRoutesMap((prevPrevented) => {
76
+ const nextPrevented = registry.current;
102
77
 
78
+ const hasChanged =
79
+ prevPrevented.size !== nextPrevented.size ||
80
+ [...nextPrevented].some(
81
+ ([id, routeKey]) => prevPrevented.get(id) !== routeKey
82
+ );
83
+
84
+ // values haven't changed - do nothing
85
+ if (!hasChanged) {
86
+ return prevPrevented;
87
+ }
88
+
89
+ return new Map(nextPrevented);
90
+ });
91
+ });
92
+
93
+ // Sync the state on every commit in case the registry was changed by a screen
94
+ // unmounting while hidden with `<Activity>`, where no passive effects run
95
+ // Also notify the parent so nested prevention propagates upwards
103
96
  React.useEffect(() => {
97
+ notifyPreventRemove();
98
+ notifyParentPrevented?.();
99
+
100
+ return () => {
101
+ notifyParentPrevented?.();
102
+ };
103
+ });
104
+
105
+ const isPrevented = preventedRoutesMap.size > 0;
106
+
107
+ React.useInsertionEffect(() => {
104
108
  if (route?.key !== undefined && setParentPrevented !== undefined) {
105
109
  // when route is defined (and setParentPrevented) it means we're in a nested stack
106
110
  // route.key then will be the route key of parent
@@ -116,9 +120,10 @@ export function PreventRemoveProvider({ children }: Props) {
116
120
  const value = React.useMemo(
117
121
  () => ({
118
122
  setPreventRemove,
123
+ notifyPreventRemove,
119
124
  preventedRoutes: transformPreventedRoutes(preventedRoutesMap),
120
125
  }),
121
- [setPreventRemove, preventedRoutesMap]
126
+ [setPreventRemove, notifyPreventRemove, preventedRoutesMap]
122
127
  );
123
128
 
124
129
  return (
package/src/SceneView.tsx CHANGED
@@ -24,6 +24,7 @@ type Props<State extends NavigationState, ScreenOptions extends {}> = {
24
24
  routeState: NavigationState | PartialState<NavigationState> | undefined;
25
25
  getState: () => State;
26
26
  setState: (state: State) => void;
27
+ subscribe: (callback: () => void) => () => void;
27
28
  options: object;
28
29
  clearOptions: () => void;
29
30
  };
@@ -42,6 +43,7 @@ export function SceneView<
42
43
  routeState,
43
44
  getState,
44
45
  setState,
46
+ subscribe,
45
47
  options,
46
48
  clearOptions,
47
49
  }: Props<State, ScreenOptions>) {
@@ -70,46 +72,16 @@ export function SceneView<
70
72
  const state = getState();
71
73
 
72
74
  const routes = state.routes.map((r) => {
73
- if (r.key !== route.key) {
74
- return r;
75
+ if (r.key === route.key && r.state !== child) {
76
+ return {
77
+ ...r,
78
+ state: child,
79
+ };
75
80
  }
76
81
 
77
- const nextRoute = r.state !== child ? { ...r, state: child } : r;
78
-
79
- // Before updating the state, cleanup any nested screen and state
80
- // This will avoid the navigator trying to handle them again
81
- if (
82
- nextRoute.params &&
83
- (('state' in nextRoute.params &&
84
- typeof nextRoute.params.state === 'object' &&
85
- nextRoute.params.state !== null) ||
86
- ('screen' in nextRoute.params &&
87
- typeof nextRoute.params.screen === 'string'))
88
- ) {
89
- // @ts-expect-error: we don't have correct type for params
90
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
91
- const { state, screen, params, initial, ...rest } = nextRoute.params;
92
-
93
- if (Object.keys(rest).length) {
94
- return { ...nextRoute, params: rest };
95
- } else {
96
- const {
97
- // We destructure the params to omit them
98
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
99
- params,
100
- ...restRoute
101
- } = nextRoute;
102
-
103
- return restRoute;
104
- }
105
- }
106
-
107
- return nextRoute;
82
+ return r;
108
83
  });
109
84
 
110
- // Make sure not to update state if routes haven't changed
111
- // Otherwise this will result in params cleanup as well
112
- // We only want to cleanup params when state changes - after they are used
113
85
  if (!isArrayEqual(state.routes, routes)) {
114
86
  setState({
115
87
  ...state,
@@ -134,9 +106,7 @@ export function SceneView<
134
106
 
135
107
  const getIsInitial = React.useCallback(() => isInitialRef.current, []);
136
108
 
137
- const parentFocusedRouteState = React.useContext(
138
- NavigationFocusedRouteStateContext
139
- );
109
+ const parentFocusedRouteState = React.use(NavigationFocusedRouteStateContext);
140
110
 
141
111
  const focusedRouteState = React.useMemo(() => {
142
112
  const state: FocusedRouteState = {
@@ -184,6 +154,7 @@ export function SceneView<
184
154
  state: routeState,
185
155
  getState: getCurrentState,
186
156
  setState: setCurrentState,
157
+ subscribe,
187
158
  getKey,
188
159
  setKey,
189
160
  getIsInitial,
@@ -193,6 +164,7 @@ export function SceneView<
193
164
  routeState,
194
165
  getCurrentState,
195
166
  setCurrentState,
167
+ subscribe,
196
168
  getKey,
197
169
  setKey,
198
170
  getIsInitial,