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