@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.
- package/lib/module/BaseNavigationContainer.js +38 -19
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/ConsumedParamsContext.js +5 -0
- package/lib/module/ConsumedParamsContext.js.map +1 -0
- package/lib/module/DataLoading.js +127 -0
- package/lib/module/DataLoading.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +1 -0
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +20 -8
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +22 -11
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationStateContext.js +3 -0
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/PreventRemoveContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +37 -27
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +10 -41
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +179 -50
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/StaticTreeContext.js +5 -0
- package/lib/module/StaticTreeContext.js.map +1 -0
- package/lib/module/checkSerializable.js +18 -13
- package/lib/module/checkSerializable.js.map +1 -1
- package/lib/module/createNavigationContainerRef.js +6 -8
- package/lib/module/createNavigationContainerRef.js.map +1 -1
- package/lib/module/createNavigatorFactory.js +27 -5
- package/lib/module/createNavigatorFactory.js.map +1 -1
- package/lib/module/findFocusedRoute.js +7 -4
- package/lib/module/findFocusedRoute.js.map +1 -1
- package/lib/module/getActionFromState.js +45 -20
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getPathFromState.js +171 -90
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +20 -4
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +487 -217
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +23 -0
- package/lib/module/getStateFromRouteParams.js.map +1 -0
- package/lib/module/index.js +5 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/theming/useTheme.js +1 -1
- package/lib/module/theming/useTheme.js.map +1 -1
- package/lib/module/types.js +35 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +21 -11
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useEventEmitter.js +48 -33
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useFocusEvents.js +12 -4
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +2 -2
- package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
- package/lib/module/useIsFocused.js +7 -12
- package/lib/module/useIsFocused.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +4 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useLazyValue.js.map +1 -1
- package/lib/module/useNavigation.js +2 -15
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +204 -131
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +22 -17
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +28 -10
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationIndependentTree.js +1 -1
- package/lib/module/useNavigationIndependentTree.js.map +1 -1
- package/lib/module/useNavigationState.js +125 -45
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +37 -7
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetState.js +6 -3
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +39 -30
- package/lib/module/useOnPreventRemove.js.map +1 -1
- package/lib/module/useOnRouteFocus.js +1 -1
- package/lib/module/useOnRouteFocus.js.map +1 -1
- package/lib/module/useOptionsGetters.js +10 -5
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +10 -3
- package/lib/module/usePreventRemove.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +1 -1
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +2 -2
- package/lib/module/useRegisterNavigator.js.map +1 -1
- package/lib/module/useRoute.js +2 -0
- package/lib/module/useRoute.js.map +1 -1
- package/lib/module/useRouteCache.js +17 -11
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +9 -9
- package/lib/module/useScheduleUpdate.js.map +1 -1
- package/lib/module/useStateForPath.js +1 -1
- package/lib/module/useStateForPath.js.map +1 -1
- package/lib/module/useSyncState.js +32 -9
- package/lib/module/useSyncState.js.map +1 -1
- package/lib/module/validatePathConfig.js +50 -36
- package/lib/module/validatePathConfig.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/ConsumedParamsContext.d.ts +3 -0
- package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
- package/lib/typescript/src/DataLoading.d.ts +21 -0
- package/lib/typescript/src/DataLoading.d.ts.map +1 -0
- package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
- package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
- package/lib/typescript/src/Group.d.ts +1 -1
- package/lib/typescript/src/Group.d.ts.map +1 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts +9 -8
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationHelpersContext.d.ts +1 -1
- package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +12 -13
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationStateContext.d.ts +4 -3
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
- package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +4 -2
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/Screen.d.ts +1 -1
- package/lib/typescript/src/Screen.d.ts.map +1 -1
- package/lib/typescript/src/StaticContainer.d.ts +1 -1
- package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts +189 -109
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
- package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
- package/lib/typescript/src/checkSerializable.d.ts +8 -4
- package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts +23 -5
- package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
- package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
- package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts +4 -4
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPathFromState.d.ts +3 -3
- package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPatternParts.d.ts +1 -0
- package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +4 -7
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
- package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +36 -33
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
- package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
- package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +260 -159
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useChildListeners.d.ts +3 -3
- package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useComponent.d.ts +1 -1
- package/lib/typescript/src/useComponent.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +10 -9
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts +2 -2
- package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
- package/lib/typescript/src/useFocusEvents.d.ts +2 -2
- package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts.map +1 -1
- package/lib/typescript/src/useIsFocused.d.ts +3 -0
- package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts +3 -3
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useLazyValue.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts +4 -2
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +23 -30
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +3 -3
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +19 -27
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +17 -3
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnAction.d.ts +9 -9
- package/lib/typescript/src/useOnAction.d.ts.map +1 -1
- package/lib/typescript/src/useOnGetState.d.ts +1 -1
- package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
- package/lib/typescript/src/useOnPreventRemove.d.ts +5 -9
- package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
- package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
- package/lib/typescript/src/useOptionsGetters.d.ts +1 -1
- package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/useRoute.d.ts +7 -3
- package/lib/typescript/src/useRoute.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts +5 -5
- package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
- package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/lib/typescript/src/useStateForPath.d.ts +1 -1
- package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
- package/lib/typescript/src/useSyncState.d.ts +1 -0
- package/lib/typescript/src/useSyncState.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +74 -37
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +23 -22
- package/src/BaseNavigationContainer.tsx +362 -334
- package/src/ConsumedParamsContext.tsx +5 -0
- package/src/DataLoading.tsx +203 -0
- package/src/NavigationBuilderContext.tsx +14 -9
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +23 -12
- package/src/NavigationProvider.tsx +26 -15
- package/src/NavigationStateContext.tsx +9 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +51 -46
- package/src/SceneView.tsx +11 -39
- package/src/StaticNavigation.tsx +659 -307
- package/src/StaticTreeContext.tsx +7 -0
- package/src/checkSerializable.tsx +35 -19
- package/src/createNavigationContainerRef.tsx +12 -9
- package/src/createNavigatorFactory.tsx +92 -8
- package/src/findFocusedRoute.tsx +16 -16
- package/src/getActionFromState.tsx +87 -51
- package/src/getPathFromState.tsx +254 -128
- package/src/getPatternParts.tsx +25 -4
- package/src/getStateFromPath.tsx +821 -331
- package/src/getStateFromRouteParams.tsx +59 -0
- package/src/index.tsx +55 -5
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +798 -373
- package/src/useDescriptors.tsx +31 -14
- package/src/useEventEmitter.tsx +52 -38
- package/src/useFocusEvents.tsx +15 -7
- package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
- package/src/useIsFocused.tsx +14 -21
- package/src/useKeyedChildListeners.tsx +4 -2
- package/src/useLazyValue.tsx +2 -2
- package/src/useNavigation.tsx +7 -24
- package/src/useNavigationBuilder.tsx +314 -186
- package/src/useNavigationCache.tsx +32 -25
- package/src/useNavigationHelpers.tsx +27 -10
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +168 -69
- package/src/useOnAction.tsx +61 -13
- package/src/useOnGetState.tsx +5 -3
- package/src/useOnPreventRemove.tsx +75 -42
- package/src/useOnRouteFocus.tsx +10 -12
- package/src/useOptionsGetters.tsx +11 -5
- package/src/usePreventRemove.tsx +12 -3
- package/src/usePreventRemoveContext.tsx +1 -1
- package/src/useRegisterNavigator.tsx +2 -2
- package/src/useRoute.tsx +20 -6
- package/src/useRouteCache.tsx +22 -16
- package/src/useScheduleUpdate.tsx +9 -10
- package/src/useStateForPath.tsx +1 -1
- package/src/useSyncState.tsx +35 -9
- package/src/utilities.tsx +144 -31
- package/src/validatePathConfig.tsx +86 -57
- package/lib/module/CurrentRenderContext.js +0 -10
- package/lib/module/CurrentRenderContext.js.map +0 -1
- package/lib/module/useCurrentRender.js +0 -19
- package/lib/module/useCurrentRender.js.map +0 -1
- package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
- package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
- package/lib/typescript/src/useCurrentRender.d.ts +0 -14
- package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
- package/src/CurrentRenderContext.tsx +0 -9
- package/src/useCurrentRender.tsx +0 -31
package/src/useOnGetState.tsx
CHANGED
|
@@ -14,8 +14,8 @@ type Options = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export function useOnGetState({ getState, getStateListeners }: Options) {
|
|
17
|
-
const { addKeyedListener } = React.
|
|
18
|
-
const route = React.
|
|
17
|
+
const { addKeyedListener } = React.use(NavigationBuilderContext);
|
|
18
|
+
const route = React.use(NavigationRouteContext);
|
|
19
19
|
const key = route ? route.key : 'root';
|
|
20
20
|
|
|
21
21
|
const getRehydratedState = React.useCallback(() => {
|
|
@@ -39,7 +39,9 @@ export function useOnGetState({ getState, getStateListeners }: Options) {
|
|
|
39
39
|
return { ...state, routes };
|
|
40
40
|
}, [getState, getStateListeners]);
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
// Use insertion effect to preserve the listener under `<Activity mode="hidden">`
|
|
43
|
+
// So `getRootState` will still return state of nested navigators
|
|
44
|
+
React.useInsertionEffect(() => {
|
|
43
45
|
return addKeyedListener?.('getState', key, getRehydratedState);
|
|
44
46
|
}, [addKeyedListener, getRehydratedState, key]);
|
|
45
47
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
NavigationAction,
|
|
3
|
+
NavigationRoute,
|
|
3
4
|
NavigationState,
|
|
5
|
+
ParamListBase,
|
|
6
|
+
PartialRoute,
|
|
4
7
|
} from '@react-navigation/routers';
|
|
5
8
|
import * as React from 'react';
|
|
6
9
|
|
|
@@ -23,50 +26,76 @@ const VISITED_ROUTE_KEYS = Symbol('VISITED_ROUTE_KEYS');
|
|
|
23
26
|
export const shouldPreventRemove = (
|
|
24
27
|
emitter: NavigationEventEmitter<EventMapCore<any>>,
|
|
25
28
|
beforeRemoveListeners: Record<string, ChildBeforeRemoveListener | undefined>,
|
|
26
|
-
currentRoutes:
|
|
27
|
-
nextRoutes:
|
|
29
|
+
currentRoutes: NavigationRoute<ParamListBase, string>[],
|
|
30
|
+
nextRoutes: (
|
|
31
|
+
| NavigationRoute<ParamListBase, string>
|
|
32
|
+
| PartialRoute<NavigationRoute<ParamListBase, string>>
|
|
33
|
+
)[],
|
|
28
34
|
action: NavigationAction
|
|
29
35
|
) => {
|
|
30
|
-
const
|
|
36
|
+
const nextRoutesByKey = new Map(
|
|
37
|
+
nextRoutes
|
|
38
|
+
.map((route) => [route.key, route] as const)
|
|
39
|
+
.filter(([, route]) => route.key != null)
|
|
40
|
+
);
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const visitedRouteKeys: Set<string> =
|
|
38
|
-
// @ts-expect-error: add this property to mark that we've already emitted this action
|
|
39
|
-
action[VISITED_ROUTE_KEYS] ?? new Set<string>();
|
|
42
|
+
const visitedRouteKeys =
|
|
43
|
+
VISITED_ROUTE_KEYS in action && action[VISITED_ROUTE_KEYS] instanceof Set
|
|
44
|
+
? action[VISITED_ROUTE_KEYS]
|
|
45
|
+
: new Set<string>();
|
|
40
46
|
|
|
41
47
|
const beforeRemoveAction = {
|
|
42
48
|
...action,
|
|
43
49
|
[VISITED_ROUTE_KEYS]: visitedRouteKeys,
|
|
44
50
|
};
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
// Call these in reverse order so last screens handle the event first
|
|
53
|
+
const reversedCurrentRoutes = [...currentRoutes].reverse();
|
|
54
|
+
|
|
55
|
+
for (const route of reversedCurrentRoutes) {
|
|
47
56
|
if (visitedRouteKeys.has(route.key)) {
|
|
48
57
|
// Skip if we've already emitted this action for this screen
|
|
49
58
|
continue;
|
|
50
59
|
}
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
if (!nextRoutesByKey.has(route.key)) {
|
|
62
|
+
// The route is not in next state, so it's being removed
|
|
63
|
+
// First, we need to check if any child screens want to prevent it
|
|
64
|
+
const isPrevented = beforeRemoveListeners[route.key]?.(
|
|
65
|
+
beforeRemoveAction,
|
|
66
|
+
undefined
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (isPrevented) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
visitedRouteKeys.add(route.key);
|
|
74
|
+
|
|
75
|
+
const event = emitter.emit({
|
|
76
|
+
type: 'beforeRemove',
|
|
77
|
+
target: route.key,
|
|
78
|
+
data: { action: beforeRemoveAction },
|
|
79
|
+
canPreventDefault: true,
|
|
80
|
+
});
|
|
60
81
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
82
|
+
if (event.defaultPrevented) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// The route is kept but its nested state changed, so propagate the check into the nested navigator
|
|
87
|
+
const nextRoute = nextRoutesByKey.get(route.key);
|
|
88
|
+
|
|
89
|
+
if (route.state != null && route.state !== nextRoute?.state) {
|
|
90
|
+
const isPrevented = beforeRemoveListeners[route.key]?.(
|
|
91
|
+
beforeRemoveAction,
|
|
92
|
+
nextRoute?.state
|
|
93
|
+
);
|
|
67
94
|
|
|
68
|
-
|
|
69
|
-
|
|
95
|
+
if (isPrevented) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
101
|
|
|
@@ -78,23 +107,27 @@ export function useOnPreventRemove({
|
|
|
78
107
|
emitter,
|
|
79
108
|
beforeRemoveListeners,
|
|
80
109
|
}: Options) {
|
|
81
|
-
const { addKeyedListener } = React.
|
|
82
|
-
const route = React.
|
|
110
|
+
const { addKeyedListener } = React.use(NavigationBuilderContext);
|
|
111
|
+
const route = React.use(NavigationRouteContext);
|
|
83
112
|
const routeKey = route?.key;
|
|
84
113
|
|
|
85
|
-
React.
|
|
114
|
+
React.useInsertionEffect(() => {
|
|
86
115
|
if (routeKey) {
|
|
87
|
-
return addKeyedListener?.(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
return addKeyedListener?.(
|
|
117
|
+
'beforeRemove',
|
|
118
|
+
routeKey,
|
|
119
|
+
(action, nextState) => {
|
|
120
|
+
const state = getState();
|
|
121
|
+
|
|
122
|
+
return shouldPreventRemove(
|
|
123
|
+
emitter,
|
|
124
|
+
beforeRemoveListeners,
|
|
125
|
+
state.routes,
|
|
126
|
+
nextState?.routes ?? [],
|
|
127
|
+
action
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
);
|
|
98
131
|
}
|
|
99
132
|
}, [addKeyedListener, beforeRemoveListeners, emitter, getState, routeKey]);
|
|
100
133
|
}
|
package/src/useOnRouteFocus.tsx
CHANGED
|
@@ -7,11 +7,11 @@ import * as React from 'react';
|
|
|
7
7
|
|
|
8
8
|
import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
9
9
|
|
|
10
|
-
type Options<Action extends NavigationAction> = {
|
|
11
|
-
router: Router<
|
|
12
|
-
getState: () =>
|
|
13
|
-
setState: (state:
|
|
14
|
-
key?: string;
|
|
10
|
+
type Options<State extends NavigationState, Action extends NavigationAction> = {
|
|
11
|
+
router: Router<State, Action>;
|
|
12
|
+
getState: () => State;
|
|
13
|
+
setState: (state: State) => void;
|
|
14
|
+
key?: string | undefined;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -19,13 +19,11 @@ type Options<Action extends NavigationAction> = {
|
|
|
19
19
|
* Focus action needs to be treated specially, coz when a nested route is focused,
|
|
20
20
|
* the parent navigators also needs to be focused.
|
|
21
21
|
*/
|
|
22
|
-
export function useOnRouteFocus<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}: Options<Action>) {
|
|
28
|
-
const { onRouteFocus: onRouteFocusParent } = React.useContext(
|
|
22
|
+
export function useOnRouteFocus<
|
|
23
|
+
State extends NavigationState,
|
|
24
|
+
Action extends NavigationAction,
|
|
25
|
+
>({ router, getState, key: sourceRouteKey, setState }: Options<State, Action>) {
|
|
26
|
+
const { onRouteFocus: onRouteFocusParent } = React.use(
|
|
29
27
|
NavigationBuilderContext
|
|
30
28
|
);
|
|
31
29
|
|
|
@@ -17,8 +17,8 @@ export function useOptionsGetters({ key, options, navigation }: Options) {
|
|
|
17
17
|
Record<string, () => object | undefined | null>
|
|
18
18
|
>({});
|
|
19
19
|
|
|
20
|
-
const { onOptionsChange } = React.
|
|
21
|
-
const { addOptionsGetter: parentAddOptionsGetter } = React.
|
|
20
|
+
const { onOptionsChange } = React.use(NavigationBuilderContext);
|
|
21
|
+
const { addOptionsGetter: parentAddOptionsGetter } = React.use(
|
|
22
22
|
NavigationStateContext
|
|
23
23
|
);
|
|
24
24
|
|
|
@@ -31,8 +31,11 @@ export function useOptionsGetters({ key, options, navigation }: Options) {
|
|
|
31
31
|
}
|
|
32
32
|
}, [navigation, onOptionsChange]);
|
|
33
33
|
|
|
34
|
-
React.
|
|
34
|
+
React.useInsertionEffect(() => {
|
|
35
35
|
optionsRef.current = options;
|
|
36
|
+
}, [options]);
|
|
37
|
+
|
|
38
|
+
React.useEffect(() => {
|
|
36
39
|
optionsChangeListener();
|
|
37
40
|
|
|
38
41
|
return navigation?.addListener('focus', optionsChangeListener);
|
|
@@ -69,8 +72,11 @@ export function useOptionsGetters({ key, options, navigation }: Options) {
|
|
|
69
72
|
return optionsRef.current;
|
|
70
73
|
}, [navigation, getOptionsFromListener]);
|
|
71
74
|
|
|
72
|
-
React.
|
|
73
|
-
|
|
75
|
+
React.useInsertionEffect(() => {
|
|
76
|
+
// We don't have a parent at the root
|
|
77
|
+
if (key != null) {
|
|
78
|
+
return parentAddOptionsGetter?.(key, getCurrentOptions);
|
|
79
|
+
}
|
|
74
80
|
}, [getCurrentOptions, parentAddOptionsGetter, key]);
|
|
75
81
|
|
|
76
82
|
const addOptionsGetter = React.useCallback(
|
package/src/usePreventRemove.tsx
CHANGED
|
@@ -23,15 +23,24 @@ export function usePreventRemove(
|
|
|
23
23
|
const navigation = useNavigation();
|
|
24
24
|
const { key: routeKey } = useRoute();
|
|
25
25
|
|
|
26
|
-
const { setPreventRemove } = usePreventRemoveContext();
|
|
26
|
+
const { setPreventRemove, notifyPreventRemove } = usePreventRemoveContext();
|
|
27
27
|
|
|
28
|
-
React.
|
|
28
|
+
React.useInsertionEffect(() => {
|
|
29
29
|
setPreventRemove(id, routeKey, preventRemove);
|
|
30
|
+
|
|
30
31
|
return () => {
|
|
31
32
|
setPreventRemove(id, routeKey, false);
|
|
32
33
|
};
|
|
33
34
|
}, [setPreventRemove, id, routeKey, preventRemove]);
|
|
34
35
|
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
notifyPreventRemove();
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
notifyPreventRemove();
|
|
41
|
+
};
|
|
42
|
+
}, [id, routeKey, preventRemove, notifyPreventRemove]);
|
|
43
|
+
|
|
35
44
|
const beforeRemoveListener = useLatestCallback<
|
|
36
45
|
EventListenerCallback<EventMapCore<any>, 'beforeRemove'>
|
|
37
46
|
>((e) => {
|
|
@@ -44,7 +53,7 @@ export function usePreventRemove(
|
|
|
44
53
|
callback({ data: e.data });
|
|
45
54
|
});
|
|
46
55
|
|
|
47
|
-
React.
|
|
56
|
+
React.useInsertionEffect(
|
|
48
57
|
() => navigation?.addListener('beforeRemove', beforeRemoveListener),
|
|
49
58
|
[navigation, beforeRemoveListener]
|
|
50
59
|
);
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { PreventRemoveContext } from './PreventRemoveContext';
|
|
4
4
|
|
|
5
5
|
export function usePreventRemoveContext() {
|
|
6
|
-
const value = React.
|
|
6
|
+
const value = React.use(PreventRemoveContext);
|
|
7
7
|
|
|
8
8
|
if (value == null) {
|
|
9
9
|
throw new Error(
|
|
@@ -9,7 +9,7 @@ import { SingleNavigatorContext } from './EnsureSingleNavigator';
|
|
|
9
9
|
*/
|
|
10
10
|
export function useRegisterNavigator() {
|
|
11
11
|
const [key] = React.useState(() => nanoid());
|
|
12
|
-
const container = React.
|
|
12
|
+
const container = React.use(SingleNavigatorContext);
|
|
13
13
|
|
|
14
14
|
if (container === undefined) {
|
|
15
15
|
throw new Error(
|
|
@@ -17,7 +17,7 @@ export function useRegisterNavigator() {
|
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
React.
|
|
20
|
+
React.useInsertionEffect(() => {
|
|
21
21
|
const { register, unregister } = container;
|
|
22
22
|
|
|
23
23
|
register(key);
|
package/src/useRoute.tsx
CHANGED
|
@@ -5,15 +5,26 @@ import {
|
|
|
5
5
|
NamedRouteContextListContext,
|
|
6
6
|
NavigationRouteContext,
|
|
7
7
|
} from './NavigationProvider';
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
NestedParamLists,
|
|
10
|
+
RootParamList,
|
|
11
|
+
RouteForName,
|
|
12
|
+
RouteProp,
|
|
13
|
+
} from './types';
|
|
14
|
+
import type { KeyOf } from './utilities';
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* Get all possible route names from a param list and its nested navigators.
|
|
18
|
+
* Recurses into the param lists directly instead of using `RouteForName`,
|
|
19
|
+
* So the route objects don't need to be built just to get the names.
|
|
12
20
|
*/
|
|
13
|
-
type AllRouteNames<ParamList extends {}> =
|
|
14
|
-
ParamList
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
type AllRouteNames<ParamList extends {}> =
|
|
22
|
+
| KeyOf<ParamList>
|
|
23
|
+
| AllNestedRouteNames<NestedParamLists<ParamList>>;
|
|
24
|
+
|
|
25
|
+
type AllNestedRouteNames<ParamLists> = ParamLists extends {}
|
|
26
|
+
? AllRouteNames<ParamLists>
|
|
27
|
+
: never;
|
|
17
28
|
|
|
18
29
|
/**
|
|
19
30
|
* Hook to access the route prop of the parent screen anywhere.
|
|
@@ -22,7 +33,10 @@ type AllRouteNames<ParamList extends {}> = RouteForName<
|
|
|
22
33
|
*/
|
|
23
34
|
export function useRoute<
|
|
24
35
|
const ParamList extends {} = RootParamList,
|
|
25
|
-
|
|
36
|
+
// The `& string` reduces the constraint to a plain union of names,
|
|
37
|
+
// so errors for invalid names list the valid names
|
|
38
|
+
const RouteName extends AllRouteNames<ParamList> & string =
|
|
39
|
+
AllRouteNames<ParamList> & string,
|
|
26
40
|
>(name: RouteName): RouteForName<ParamList, RouteName>;
|
|
27
41
|
export function useRoute<
|
|
28
42
|
const ParamList extends {} = RootParamList,
|
package/src/useRouteCache.tsx
CHANGED
|
@@ -4,8 +4,6 @@ import * as React from 'react';
|
|
|
4
4
|
import { isRecordEqual } from './isRecordEqual';
|
|
5
5
|
import type { RouteProp } from './types';
|
|
6
6
|
|
|
7
|
-
type RouteCache = Map<string, RouteProp<ParamListBase>>;
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* Utilities such as `getFocusedRouteNameFromRoute` need to access state.
|
|
11
9
|
* So we need a way to suppress the warning for those use cases.
|
|
@@ -21,9 +19,12 @@ export function useRouteCache<State extends NavigationState>(
|
|
|
21
19
|
routes: State['routes']
|
|
22
20
|
) {
|
|
23
21
|
// Cache object which holds route objects for each screen
|
|
24
|
-
const cache = React.useMemo(
|
|
22
|
+
const cache = React.useMemo(
|
|
23
|
+
() => ({ current: new Map<string, RouteProp<ParamListBase>>() }),
|
|
24
|
+
[]
|
|
25
|
+
);
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
const next = routes.reduce((acc, route) => {
|
|
27
28
|
const previous = cache.current.get(route.key);
|
|
28
29
|
const { state, ...routeWithoutState } = route;
|
|
29
30
|
|
|
@@ -36,13 +37,11 @@ export function useRouteCache<State extends NavigationState>(
|
|
|
36
37
|
proxy = routeWithoutState;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
40
|
+
if (process.env.NODE_ENV !== 'production' && proxy !== previous) {
|
|
40
41
|
// FIXME: since the state is updated with mutation, the route object cannot be frozen
|
|
41
42
|
// As a workaround, loop through the object and make the properties readonly
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const value = proxy[key];
|
|
45
|
-
|
|
43
|
+
// Only needed once per proxy - skip if we're reusing a previously-frozen one
|
|
44
|
+
for (const [key, value] of Object.entries(proxy)) {
|
|
46
45
|
Object.defineProperty(proxy, key, {
|
|
47
46
|
enumerable: true,
|
|
48
47
|
configurable: true,
|
|
@@ -52,16 +51,23 @@ export function useRouteCache<State extends NavigationState>(
|
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
// @ts-expect-error: this isn't in type definitions coz we want this private
|
|
55
|
+
if (proxy[CHILD_STATE] !== state) {
|
|
56
|
+
Object.defineProperty(proxy, CHILD_STATE, {
|
|
57
|
+
enumerable: false,
|
|
58
|
+
configurable: true,
|
|
59
|
+
value: state,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
60
62
|
|
|
61
63
|
acc.set(route.key, proxy);
|
|
62
64
|
|
|
63
65
|
return acc;
|
|
64
|
-
}, new Map()
|
|
66
|
+
}, new Map<string, RouteProp<ParamListBase>>());
|
|
67
|
+
|
|
68
|
+
React.useInsertionEffect(() => {
|
|
69
|
+
cache.current = next;
|
|
70
|
+
});
|
|
65
71
|
|
|
66
|
-
return Array.from(
|
|
72
|
+
return Array.from(next.values());
|
|
67
73
|
}
|
|
@@ -4,19 +4,18 @@ import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* When screen config changes, we want to update the navigator in the same update phase.
|
|
7
|
-
* However, navigation state is in the root component and React won't let us update it from a child.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* However, navigation state is in the root component and React won't let us update it from a child during render.
|
|
8
|
+
* The render could also be interrupted in concurrent mode, so we need to update after commit.
|
|
9
|
+
* So we queue the update in an insertion effect and flush it in a layout effect.
|
|
10
|
+
* Insertion effects run before layout effects, so every navigator in the tree has queued its update before we flush.
|
|
11
|
+
* This lets nested updates be applied from the root down without clobbering each other.
|
|
11
12
|
*/
|
|
12
13
|
export function useScheduleUpdate(callback: () => void) {
|
|
13
|
-
const { scheduleUpdate, flushUpdates } = React.
|
|
14
|
-
NavigationBuilderContext
|
|
15
|
-
);
|
|
14
|
+
const { scheduleUpdate, flushUpdates } = React.use(NavigationBuilderContext);
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
React.useInsertionEffect(() => {
|
|
17
|
+
scheduleUpdate(callback);
|
|
18
|
+
});
|
|
20
19
|
|
|
21
20
|
React.useLayoutEffect(flushUpdates);
|
|
22
21
|
}
|
package/src/useStateForPath.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import { NavigationFocusedRouteStateContext } from './NavigationFocusedRouteStat
|
|
|
9
9
|
* @returns Minimal state to build a path for the current route.
|
|
10
10
|
*/
|
|
11
11
|
export function useStateForPath() {
|
|
12
|
-
const state = React.
|
|
12
|
+
const state = React.use(NavigationFocusedRouteStateContext);
|
|
13
13
|
|
|
14
14
|
return state;
|
|
15
15
|
}
|
package/src/useSyncState.tsx
CHANGED
|
@@ -24,12 +24,29 @@ const createStore = <T,>(getInitialState: () => T) => {
|
|
|
24
24
|
let isBatching = false;
|
|
25
25
|
let didUpdate = false;
|
|
26
26
|
|
|
27
|
+
const notify = () => {
|
|
28
|
+
let error: { value: unknown } | undefined;
|
|
29
|
+
|
|
30
|
+
listeners.forEach((listener) => {
|
|
31
|
+
try {
|
|
32
|
+
listener();
|
|
33
|
+
} catch (e) {
|
|
34
|
+
error = error ?? { value: e };
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (error) {
|
|
39
|
+
throw error.value;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
27
43
|
const setState = (newState: T) => {
|
|
28
44
|
state = deepFreeze(newState);
|
|
29
|
-
didUpdate = true;
|
|
30
45
|
|
|
31
|
-
if (
|
|
32
|
-
|
|
46
|
+
if (isBatching) {
|
|
47
|
+
didUpdate = true;
|
|
48
|
+
} else {
|
|
49
|
+
notify();
|
|
33
50
|
}
|
|
34
51
|
};
|
|
35
52
|
|
|
@@ -43,12 +60,16 @@ const createStore = <T,>(getInitialState: () => T) => {
|
|
|
43
60
|
|
|
44
61
|
const batchUpdates = (callback: () => void) => {
|
|
45
62
|
isBatching = true;
|
|
46
|
-
callback();
|
|
47
|
-
isBatching = false;
|
|
48
63
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
try {
|
|
65
|
+
callback();
|
|
66
|
+
} finally {
|
|
67
|
+
isBatching = false;
|
|
68
|
+
|
|
69
|
+
if (didUpdate) {
|
|
70
|
+
didUpdate = false;
|
|
71
|
+
notify();
|
|
72
|
+
}
|
|
52
73
|
}
|
|
53
74
|
};
|
|
54
75
|
|
|
@@ -100,7 +121,11 @@ export function useSyncState<T>(getInitialState: () => T) {
|
|
|
100
121
|
|
|
101
122
|
if (pendingUpdates.length !== 0) {
|
|
102
123
|
store.batchUpdates(() => {
|
|
103
|
-
//
|
|
124
|
+
// Updates are queued child-first as insertion effects run bottom-up.
|
|
125
|
+
// The root navigator replaces the whole state while nested navigators merge into it.
|
|
126
|
+
// So we apply them root-first to avoid the root clobbering nested updates.
|
|
127
|
+
pendingUpdates.reverse();
|
|
128
|
+
|
|
104
129
|
for (const update of pendingUpdates) {
|
|
105
130
|
update();
|
|
106
131
|
}
|
|
@@ -114,6 +139,7 @@ export function useSyncState<T>(getInitialState: () => T) {
|
|
|
114
139
|
state,
|
|
115
140
|
getState: store.getState,
|
|
116
141
|
setState: store.setState,
|
|
142
|
+
subscribe: store.subscribe,
|
|
117
143
|
scheduleUpdate,
|
|
118
144
|
flushUpdates,
|
|
119
145
|
} as const;
|