@react-navigation/core 8.0.0-alpha.3 → 8.0.0-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/BaseNavigationContainer.js +34 -17
- 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 +17 -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.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 +7 -40
- 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 +485 -214
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +24 -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 +19 -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 +201 -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 +70 -35
- 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 +7 -3
- 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 +3 -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 +3 -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 -3
- 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 +5 -5
- 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 +8 -8
- 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 +13 -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.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 +351 -333
- 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 +18 -12
- package/src/NavigationProvider.tsx +26 -15
- package/src/NavigationStateContext.tsx +5 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +51 -46
- package/src/SceneView.tsx +7 -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 +13 -8
- package/src/getActionFromState.tsx +86 -51
- package/src/getPathFromState.tsx +254 -128
- package/src/getPatternParts.tsx +25 -4
- package/src/getStateFromPath.tsx +811 -309
- package/src/getStateFromRouteParams.tsx +60 -0
- package/src/index.tsx +55 -5
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +798 -373
- package/src/useDescriptors.tsx +28 -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 +311 -186
- package/src/useNavigationCache.tsx +32 -25
- package/src/useNavigationHelpers.tsx +27 -10
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +93 -59
- 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 +8 -3
- 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
|
@@ -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
|
@@ -26,9 +26,10 @@ const createStore = <T,>(getInitialState: () => T) => {
|
|
|
26
26
|
|
|
27
27
|
const setState = (newState: T) => {
|
|
28
28
|
state = deepFreeze(newState);
|
|
29
|
-
didUpdate = true;
|
|
30
29
|
|
|
31
|
-
if (
|
|
30
|
+
if (isBatching) {
|
|
31
|
+
didUpdate = true;
|
|
32
|
+
} else {
|
|
32
33
|
listeners.forEach((listener) => listener());
|
|
33
34
|
}
|
|
34
35
|
};
|
|
@@ -100,7 +101,11 @@ export function useSyncState<T>(getInitialState: () => T) {
|
|
|
100
101
|
|
|
101
102
|
if (pendingUpdates.length !== 0) {
|
|
102
103
|
store.batchUpdates(() => {
|
|
103
|
-
//
|
|
104
|
+
// Updates are queued child-first as insertion effects run bottom-up.
|
|
105
|
+
// The root navigator replaces the whole state while nested navigators merge into it.
|
|
106
|
+
// So we apply them root-first to avoid the root clobbering nested updates.
|
|
107
|
+
pendingUpdates.reverse();
|
|
108
|
+
|
|
104
109
|
for (const update of pendingUpdates) {
|
|
105
110
|
update();
|
|
106
111
|
}
|