@react-navigation/core 8.0.0-alpha.4 → 8.0.0-alpha.41
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/README.md +17 -14
- package/lib/module/BaseNavigationContainer.js +173 -90
- 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 +129 -0
- package/lib/module/DataLoading.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +7 -10
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +54 -9
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +37 -12
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationRootContext.js +8 -0
- package/lib/module/NavigationRootContext.js.map +1 -0
- 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 +40 -31
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +29 -57
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +219 -67
- 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/createNavigationContainerRef.js +7 -9
- 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 +204 -94
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +61 -14
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +608 -272
- 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 +7 -6
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +2 -0
- package/lib/module/internal.js.map +1 -0
- package/lib/module/isRecordEqual.js +1 -1
- package/lib/module/isRecordEqual.js.map +1 -1
- package/lib/module/queryString.js +71 -0
- package/lib/module/queryString.js.map +1 -0
- package/lib/module/theming/useTheme.js +1 -1
- package/lib/module/theming/useTheme.js.map +1 -1
- package/lib/module/types.js +35 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +65 -25
- 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/useFocusEffect.js +4 -2
- package/lib/module/useFocusEffect.js.map +1 -1
- package/lib/module/useFocusEvents.js +15 -5
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +3 -3
- package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
- package/lib/module/useIsFocused.js +8 -12
- package/lib/module/useIsFocused.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +5 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useLazyValue.js.map +1 -1
- package/lib/module/useNavigation.js +4 -17
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +244 -147
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +92 -89
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +22 -29
- 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 +158 -46
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +58 -11
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetNavigation.js +26 -0
- package/lib/module/useOnGetNavigation.js.map +1 -0
- package/lib/module/useOnGetState.js +7 -4
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +40 -31
- package/lib/module/useOnPreventRemove.js.map +1 -1
- package/lib/module/useOnRouteFocus.js +2 -2
- package/lib/module/useOnRouteFocus.js.map +1 -1
- package/lib/module/useOptionsGetters.js +35 -27
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +11 -5
- package/lib/module/usePreventRemove.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +2 -2
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +3 -4
- 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 +51 -35
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +12 -10
- 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 +37 -15
- 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 +22 -14
- 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 +21 -18
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationRootContext.d.ts +8 -0
- package/lib/typescript/src/NavigationRootContext.d.ts.map +1 -0
- 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 +5 -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 -111
- 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/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 +5 -2
- 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/internal.d.ts +3 -0
- package/lib/typescript/src/internal.d.ts.map +1 -0
- package/lib/typescript/src/isRecordEqual.d.ts.map +1 -1
- package/lib/typescript/src/queryString.d.ts +5 -0
- package/lib/typescript/src/queryString.d.ts.map +1 -0
- 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 +265 -167
- 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/useDescriptors.d.ts +13 -11
- 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/useFocusEffect.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 +4 -0
- package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts +4 -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 +22 -63
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +6 -5
- 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 +18 -58
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +19 -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/useOnGetNavigation.d.ts +12 -0
- package/lib/typescript/src/useOnGetNavigation.d.ts.map +1 -0
- 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 +4 -4
- 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/useRegisterNavigator.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 +7 -12
- 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 +79 -39
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +26 -22
- package/src/BaseNavigationContainer.tsx +459 -332
- package/src/ConsumedParamsContext.tsx +5 -0
- package/src/DataLoading.tsx +206 -0
- package/src/NavigationBuilderContext.tsx +44 -25
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +60 -12
- package/src/NavigationProvider.tsx +59 -21
- package/src/NavigationRootContext.tsx +11 -0
- package/src/NavigationStateContext.tsx +6 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +55 -56
- package/src/SceneView.tsx +31 -57
- package/src/StaticNavigation.tsx +715 -328
- package/src/StaticTreeContext.tsx +7 -0
- package/src/createNavigationContainerRef.tsx +12 -11
- package/src/createNavigatorFactory.tsx +92 -8
- package/src/findFocusedRoute.tsx +16 -16
- package/src/getActionFromState.tsx +87 -51
- package/src/getPathFromState.tsx +310 -134
- package/src/getPatternParts.tsx +98 -16
- package/src/getStateFromPath.tsx +971 -344
- package/src/getStateFromRouteParams.tsx +59 -0
- package/src/index.tsx +57 -6
- package/src/internal.tsx +2 -0
- package/src/isRecordEqual.tsx +3 -1
- package/src/queryString.ts +109 -0
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +799 -377
- package/src/useDescriptors.tsx +151 -43
- package/src/useEventEmitter.tsx +53 -39
- package/src/useFocusEffect.tsx +5 -2
- package/src/useFocusEvents.tsx +19 -8
- package/src/useFocusedListenersChildrenAdapter.tsx +3 -3
- package/src/useIsFocused.tsx +18 -21
- package/src/useKeyedChildListeners.tsx +5 -2
- package/src/useLazyValue.tsx +2 -2
- package/src/useNavigation.tsx +9 -26
- package/src/useNavigationBuilder.tsx +370 -201
- package/src/useNavigationCache.tsx +148 -123
- package/src/useNavigationHelpers.tsx +27 -37
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +207 -69
- package/src/useOnAction.tsx +92 -18
- package/src/useOnGetNavigation.tsx +30 -0
- package/src/useOnGetState.tsx +8 -4
- package/src/useOnPreventRemove.tsx +78 -43
- package/src/useOnRouteFocus.tsx +11 -15
- package/src/useOptionsGetters.tsx +44 -30
- package/src/usePreventRemove.tsx +13 -5
- package/src/usePreventRemoveContext.tsx +2 -2
- package/src/useRegisterNavigator.tsx +4 -4
- package/src/useRoute.tsx +20 -6
- package/src/useRouteCache.tsx +57 -35
- package/src/useScheduleUpdate.tsx +13 -11
- package/src/useStateForPath.tsx +1 -1
- package/src/useSyncState.tsx +39 -15
- package/src/utilities.tsx +151 -35
- package/src/validatePathConfig.tsx +86 -57
- package/lib/module/CurrentRenderContext.js +0 -10
- package/lib/module/CurrentRenderContext.js.map +0 -1
- package/lib/module/NavigationMetaContext.js +0 -15
- package/lib/module/NavigationMetaContext.js.map +0 -1
- package/lib/module/checkSerializable.js +0 -46
- package/lib/module/checkSerializable.js.map +0 -1
- package/lib/module/useComponent.js +0 -34
- package/lib/module/useComponent.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/NavigationMetaContext.d.ts +0 -12
- package/lib/typescript/src/NavigationMetaContext.d.ts.map +0 -1
- package/lib/typescript/src/checkSerializable.d.ts +0 -10
- package/lib/typescript/src/checkSerializable.d.ts.map +0 -1
- package/lib/typescript/src/useComponent.d.ts +0 -7
- package/lib/typescript/src/useComponent.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/NavigationMetaContext.tsx +0 -14
- package/src/checkSerializable.tsx +0 -74
- package/src/useComponent.tsx +0 -37
- package/src/useCurrentRender.tsx +0 -31
|
@@ -5,31 +5,30 @@ 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 {
|
|
12
|
-
import { NavigationBuilderContext } from "./NavigationBuilderContext.js";
|
|
12
|
+
import { useNavigationBuilderContext } from "./NavigationBuilderContext.js";
|
|
13
13
|
import { NavigationHelpersContext } from "./NavigationHelpersContext.js";
|
|
14
|
-
import {
|
|
15
|
-
import { NavigationRouteContext } from "./NavigationProvider.js";
|
|
14
|
+
import { IsScreenContext, NavigationRouteContext } from "./NavigationProvider.js";
|
|
16
15
|
import { NavigationStateContext } from "./NavigationStateContext.js";
|
|
17
16
|
import { PreventRemoveProvider } from "./PreventRemoveProvider.js";
|
|
18
17
|
import { Screen } from "./Screen.js";
|
|
19
18
|
import { PrivateValueStore } from "./types.js";
|
|
20
19
|
import { UnhandledActionContext } from "./UnhandledActionContext.js";
|
|
21
20
|
import { useChildListeners } from "./useChildListeners.js";
|
|
22
|
-
import { useComponent } from "./useComponent.js";
|
|
23
|
-
import { useCurrentRender } from "./useCurrentRender.js";
|
|
24
21
|
import { useDescriptors } from "./useDescriptors.js";
|
|
25
22
|
import { useEventEmitter } from "./useEventEmitter.js";
|
|
26
23
|
import { useFocusedListenersChildrenAdapter } from "./useFocusedListenersChildrenAdapter.js";
|
|
27
24
|
import { useFocusEvents } from "./useFocusEvents.js";
|
|
25
|
+
import { FocusedRouteKeyContext } from "./useIsFocused.js";
|
|
28
26
|
import { useKeyedChildListeners } from "./useKeyedChildListeners.js";
|
|
29
27
|
import { useLazyValue } from "./useLazyValue.js";
|
|
30
28
|
import { useNavigationHelpers } from "./useNavigationHelpers.js";
|
|
31
29
|
import { NavigationStateListenerProvider } from "./useNavigationState.js";
|
|
32
30
|
import { useOnAction } from "./useOnAction.js";
|
|
31
|
+
import { useOnGetNavigation } from "./useOnGetNavigation.js";
|
|
33
32
|
import { useOnGetState } from "./useOnGetState.js";
|
|
34
33
|
import { useOnRouteFocus } from "./useOnRouteFocus.js";
|
|
35
34
|
import { useRegisterNavigator } from "./useRegisterNavigator.js";
|
|
@@ -39,6 +38,7 @@ import { useScheduleUpdate } from "./useScheduleUpdate.js";
|
|
|
39
38
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
40
39
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
41
40
|
PrivateValueStore;
|
|
41
|
+
const isNavigationState = state => state != null && typeof state === 'object' && 'routes' in state && Array.isArray(state.routes);
|
|
42
42
|
const isScreen = child => {
|
|
43
43
|
return child.type === Screen;
|
|
44
44
|
};
|
|
@@ -52,7 +52,7 @@ const isValidKey = key => key === undefined || typeof key === 'string' && key !=
|
|
|
52
52
|
*
|
|
53
53
|
* @param children React Elements to extract the config from.
|
|
54
54
|
*/
|
|
55
|
-
const getRouteConfigsFromChildren = (children,
|
|
55
|
+
const getRouteConfigsFromChildren = (children, groupKeys = [], groupOptions, groupLayout) => {
|
|
56
56
|
const configs = React.Children.toArray(children).reduce((acc, child) => {
|
|
57
57
|
if (/*#__PURE__*/React.isValidElement(child)) {
|
|
58
58
|
if (isScreen(child)) {
|
|
@@ -69,7 +69,7 @@ const getRouteConfigsFromChildren = (children, groupKey, groupOptions, groupLayo
|
|
|
69
69
|
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
70
|
}
|
|
71
71
|
acc.push({
|
|
72
|
-
keys: [
|
|
72
|
+
keys: [...groupKeys, child.props.navigationKey],
|
|
73
73
|
options: groupOptions,
|
|
74
74
|
layout: groupLayout,
|
|
75
75
|
props: child.props
|
|
@@ -83,14 +83,14 @@ const getRouteConfigsFromChildren = (children, groupKey, groupOptions, groupLayo
|
|
|
83
83
|
|
|
84
84
|
// When we encounter a fragment or group, we need to dive into its children to extract the configs
|
|
85
85
|
// This is handy to conditionally define a group of screens
|
|
86
|
-
acc.push(...getRouteConfigsFromChildren(child.props.children, child.props.navigationKey,
|
|
86
|
+
acc.push(...getRouteConfigsFromChildren(child.props.children, child.props.navigationKey != null ? [...groupKeys, child.props.navigationKey] : groupKeys,
|
|
87
87
|
// FIXME
|
|
88
88
|
// @ts-expect-error: add validation
|
|
89
89
|
child.type !== Group ? groupOptions : groupOptions != null ? [...groupOptions, child.props.screenOptions] : [child.props.screenOptions], typeof child.props.screenLayout === 'function' ? child.props.screenLayout : groupLayout));
|
|
90
90
|
return acc;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
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'.`);
|
|
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
94
|
}, []);
|
|
95
95
|
if (process.env.NODE_ENV !== 'production') {
|
|
96
96
|
configs.forEach(config => {
|
|
@@ -136,9 +136,16 @@ const getRouteConfigsFromChildren = (children, groupKey, groupOptions, groupLayo
|
|
|
136
136
|
}
|
|
137
137
|
return configs;
|
|
138
138
|
};
|
|
139
|
-
const getStateFromParams = params => {
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
const getStateFromParams = (params, type) => {
|
|
140
|
+
const state = params?.state;
|
|
141
|
+
if (isNavigationState(state)) {
|
|
142
|
+
if (state.type != null && state.type !== type) {
|
|
143
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
144
|
+
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.`);
|
|
145
|
+
}
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
return state;
|
|
142
149
|
} else if (typeof params?.screen === 'string' && params?.initial !== false) {
|
|
143
150
|
return {
|
|
144
151
|
routes: [{
|
|
@@ -160,7 +167,9 @@ const getStateFromParams = params => {
|
|
|
160
167
|
*/
|
|
161
168
|
export function useNavigationBuilder(createRouter, options) {
|
|
162
169
|
const navigatorKey = useRegisterNavigator();
|
|
163
|
-
const route = React.
|
|
170
|
+
const route = React.use(NavigationRouteContext);
|
|
171
|
+
const consumedParams = React.use(ConsumedParamsContext);
|
|
172
|
+
const isNestedParamsConsumed = typeof route?.params === 'object' && route.params != null ? consumedParams?.has(route.params) : false;
|
|
164
173
|
const {
|
|
165
174
|
children,
|
|
166
175
|
layout,
|
|
@@ -185,31 +194,26 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
185
194
|
}
|
|
186
195
|
return original;
|
|
187
196
|
});
|
|
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
197
|
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
198
|
if (!routeNames.length) {
|
|
211
199
|
throw new Error("Couldn't find any screens for the navigator. Have you defined any screens as its children?");
|
|
212
200
|
}
|
|
201
|
+
const screens = {};
|
|
202
|
+
const routeKeyList = {};
|
|
203
|
+
const routeParamList = {};
|
|
204
|
+
const routeGetIdList = {};
|
|
205
|
+
for (const config of routeConfigs) {
|
|
206
|
+
const name = config.props.name;
|
|
207
|
+
if (name in screens) {
|
|
208
|
+
throw new Error(`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${name}')`);
|
|
209
|
+
}
|
|
210
|
+
screens[name] = config;
|
|
211
|
+
routeKeyList[name] = config.keys;
|
|
212
|
+
routeParamList[name] = config.props.initialParams;
|
|
213
|
+
Object.assign(routeGetIdList, {
|
|
214
|
+
[name]: config.props.getId
|
|
215
|
+
});
|
|
216
|
+
}
|
|
213
217
|
const isStateValid = React.useCallback(state => state.type === undefined || state.type === router.type, [router.type]);
|
|
214
218
|
const isStateInitialized = React.useCallback(state => state !== undefined && state.stale === false && isStateValid(state), [isStateValid]);
|
|
215
219
|
const doesStateHaveOnlyInvalidRoutes = React.useCallback(state => state.routes.every(r => !routeNames.includes(r.name)), [routeNames]);
|
|
@@ -217,25 +221,52 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
217
221
|
state: currentState,
|
|
218
222
|
getState: getCurrentState,
|
|
219
223
|
setState: setCurrentState,
|
|
224
|
+
subscribe,
|
|
220
225
|
setKey,
|
|
221
226
|
getKey,
|
|
222
227
|
getIsInitial
|
|
223
|
-
} = React.
|
|
224
|
-
const
|
|
228
|
+
} = React.use(NavigationStateContext);
|
|
229
|
+
const {
|
|
230
|
+
onEmitEvent,
|
|
231
|
+
getIsStateEmitted,
|
|
232
|
+
canGoBack: canGoBackParent
|
|
233
|
+
} = useNavigationBuilderContext();
|
|
234
|
+
const mountStateRef = React.useRef('initial');
|
|
235
|
+
const previousStateRef = React.useRef(currentState);
|
|
236
|
+
const savedStateRef = React.useRef(undefined);
|
|
225
237
|
const setState = useLatestCallback(state => {
|
|
226
|
-
if (
|
|
238
|
+
if (mountStateRef.current === 'unmounted') {
|
|
239
|
+
// Store the state locally in case the current navigator is in `Activity`
|
|
240
|
+
savedStateRef.current = state;
|
|
241
|
+
|
|
227
242
|
// State might have been already cleaned up due to unmount
|
|
228
|
-
// We
|
|
229
|
-
//
|
|
243
|
+
// We don't want to update `route.state` in parent
|
|
244
|
+
// Otherwise it will be reused if a new navigator gets mounted
|
|
230
245
|
return;
|
|
231
246
|
}
|
|
232
247
|
setCurrentState(state);
|
|
233
248
|
});
|
|
234
|
-
const
|
|
249
|
+
const lastState = (mountStateRef.current !== 'mounted' || !isStateInitialized(currentState)) && (
|
|
250
|
+
// If the state object differs from previously committed state, we have new state
|
|
251
|
+
// e.g. because of a reset
|
|
252
|
+
// So we need to use it before checking if we should reuse the saved state.
|
|
253
|
+
currentState === previousStateRef.current || mountStateRef.current === 'unmounted' && currentState === undefined) ?
|
|
254
|
+
// If the navigator is hidden with `Activity`, its state gets cleaned up due to effect cleanup.
|
|
255
|
+
// So we reuse the saved state to avoid remounting screens when the navigator is shown again.
|
|
256
|
+
savedStateRef.current : undefined;
|
|
257
|
+
const [stateBeforeInitialization, initializedState, isFirstStateInitialization, paramsUsedForInitialization] = React.useMemo(() => {
|
|
258
|
+
if (lastState && isStateValid(lastState)) {
|
|
259
|
+
const state = isStateInitialized(lastState) ? lastState : router.getRehydratedState(lastState, {
|
|
260
|
+
routeNames,
|
|
261
|
+
routeParamList,
|
|
262
|
+
routeGetIdList
|
|
263
|
+
});
|
|
264
|
+
return [undefined, state, false, undefined];
|
|
265
|
+
}
|
|
235
266
|
const initialRouteParamList = routeNames.reduce((acc, curr) => {
|
|
236
267
|
const {
|
|
237
268
|
initialParams
|
|
238
|
-
} = screens[curr]
|
|
269
|
+
} = screens[curr]?.props ?? {};
|
|
239
270
|
const initialParamsFromParams = route?.params?.state == null && route?.params?.initial !== false && route?.params?.screen === curr ? route.params.params : undefined;
|
|
240
271
|
acc[curr] = initialParams !== undefined || initialParamsFromParams !== undefined ? {
|
|
241
272
|
...initialParams,
|
|
@@ -248,24 +279,32 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
248
279
|
// We also need to re-initialize it if the state passed from parent was changed (maybe due to reset)
|
|
249
280
|
// Otherwise assume that the state was provided as initial state
|
|
250
281
|
// 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)) {
|
|
282
|
+
if ((currentState === undefined || !isStateValid(currentState)) && route?.params?.state == null && !(typeof route?.params?.screen === 'string' && route?.params?.initial !== false) && !isNestedParamsConsumed) {
|
|
252
283
|
return [undefined, router.getInitialState({
|
|
253
284
|
routeNames,
|
|
254
285
|
routeParamList: initialRouteParamList,
|
|
255
286
|
routeGetIdList
|
|
256
|
-
}), true];
|
|
287
|
+
}), true, undefined];
|
|
257
288
|
} else {
|
|
258
|
-
const
|
|
289
|
+
const paramsForState = isNestedParamsConsumed ? undefined : route?.params;
|
|
290
|
+
const stateFromParams = paramsForState ? getStateFromParams(paramsForState, router.type) : undefined;
|
|
259
291
|
const stateBeforeInitialization = stateFromParams ?? currentState;
|
|
260
|
-
const hydratedState = router.
|
|
292
|
+
const hydratedState = stateBeforeInitialization == null ? router.getInitialState({
|
|
293
|
+
routeNames,
|
|
294
|
+
routeParamList: initialRouteParamList,
|
|
295
|
+
routeGetIdList
|
|
296
|
+
}) : router.getRehydratedState(stateBeforeInitialization, {
|
|
261
297
|
routeNames,
|
|
262
298
|
routeParamList: initialRouteParamList,
|
|
263
299
|
routeGetIdList
|
|
264
300
|
});
|
|
265
|
-
if (options.routeNamesChangeBehavior === 'lastUnhandled' && doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)) {
|
|
266
|
-
return [stateBeforeInitialization, hydratedState, true];
|
|
301
|
+
if (stateBeforeInitialization != null && isStateValid(stateBeforeInitialization) && options.routeNamesChangeBehavior === 'lastUnhandled' && doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)) {
|
|
302
|
+
return [stateBeforeInitialization, hydratedState, true, paramsForState];
|
|
267
303
|
}
|
|
268
|
-
return [undefined, hydratedState, false
|
|
304
|
+
return [undefined, hydratedState, false,
|
|
305
|
+
// Current state is already initialized
|
|
306
|
+
// So params weren't used, and need to be handled later
|
|
307
|
+
isStateInitialized(currentState) ? undefined : paramsForState];
|
|
269
308
|
}
|
|
270
309
|
// We explicitly don't include routeNames, route.params etc. in the dep list
|
|
271
310
|
// below. We want to avoid forcing a new state to be calculated in those cases
|
|
@@ -273,12 +312,19 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
273
312
|
// that some changes to routeConfigs are explicitly ignored, such as changes
|
|
274
313
|
// to initialParams
|
|
275
314
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
276
|
-
}, [currentState, router, isStateValid]);
|
|
315
|
+
}, [currentState, lastState, router, isStateValid]);
|
|
277
316
|
const previousRouteKeyListRef = React.useRef(routeKeyList);
|
|
278
|
-
React.
|
|
317
|
+
React.useInsertionEffect(() => {
|
|
279
318
|
previousRouteKeyListRef.current = routeKeyList;
|
|
280
319
|
});
|
|
281
320
|
const previousRouteKeyList = previousRouteKeyListRef.current;
|
|
321
|
+
|
|
322
|
+
// Names of the screens whose navigation key changed since the last render
|
|
323
|
+
const routeKeyChanges = Object.keys(routeKeyList).filter(name => {
|
|
324
|
+
const current = routeKeyList[name];
|
|
325
|
+
const previous = previousRouteKeyList[name];
|
|
326
|
+
return current != null && previous != null && !isArrayEqual(current, previous);
|
|
327
|
+
});
|
|
282
328
|
const [unhandledState, setUnhandledState] = React.useState(stateBeforeInitialization);
|
|
283
329
|
|
|
284
330
|
// An unhandled state is state that didn't have any valid routes
|
|
@@ -292,60 +338,68 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
292
338
|
// If the state isn't initialized, or stale, use the state we initialized instead
|
|
293
339
|
// The state won't update until there's a change needed in the state we have initialized locally
|
|
294
340
|
// So it'll be `undefined` or stale until the first navigation event happens
|
|
295
|
-
isStateInitialized(currentState) ? currentState : initializedState;
|
|
341
|
+
lastState === undefined && isStateInitialized(currentState) ? currentState : initializedState;
|
|
296
342
|
let nextState = state;
|
|
297
343
|
let shouldClearUnhandledState = false;
|
|
298
|
-
|
|
344
|
+
if (unhandledState != null && !isStateValid(unhandledState)) {
|
|
345
|
+
// The stored unhandled state is for a different type of navigator
|
|
346
|
+
// It can't be used with this navigator, so we discard it
|
|
347
|
+
setUnhandledState(undefined);
|
|
348
|
+
} else if (
|
|
299
349
|
// Previously unhandled state is now valid again
|
|
300
350
|
// And current state no longer has any valid routes
|
|
301
351
|
// We should reuse the unhandled state instead of re-calculating the state
|
|
302
|
-
|
|
352
|
+
unhandledState?.routes.every(r => routeNames.includes(r.name)) && state?.routes.every(r => !routeNames.includes(r.name))) {
|
|
303
353
|
shouldClearUnhandledState = true;
|
|
304
354
|
nextState = router.getRehydratedState(unhandledState, {
|
|
305
355
|
routeNames,
|
|
306
356
|
routeParamList,
|
|
307
357
|
routeGetIdList
|
|
308
358
|
});
|
|
309
|
-
} else if (!isArrayEqual(state.routeNames, routeNames) ||
|
|
359
|
+
} else if (!isArrayEqual(state.routeNames, routeNames) || routeKeyChanges.length !== 0) {
|
|
310
360
|
// When the list of route names change, the router should handle it to remove invalid routes
|
|
311
361
|
nextState = router.getStateForRouteNamesChange(state, {
|
|
312
362
|
routeNames,
|
|
313
363
|
routeParamList,
|
|
314
364
|
routeGetIdList,
|
|
315
|
-
routeKeyChanges
|
|
365
|
+
routeKeyChanges
|
|
316
366
|
});
|
|
317
367
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
previousNestedParamsRef.current = route?.params;
|
|
321
|
-
}, [route?.params]);
|
|
322
|
-
if (route?.params) {
|
|
323
|
-
const previousParams = previousNestedParamsRef.current;
|
|
368
|
+
let didConsumeNestedParams = route?.params === paramsUsedForInitialization;
|
|
369
|
+
if (route?.params && !didConsumeNestedParams) {
|
|
324
370
|
let action;
|
|
325
|
-
if (
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
371
|
+
if (isNavigationState(route.params.state) && !isNestedParamsConsumed) {
|
|
372
|
+
didConsumeNestedParams = true;
|
|
373
|
+
const stateFromParams = getStateFromParams(route.params, router.type);
|
|
374
|
+
if (stateFromParams != null) {
|
|
375
|
+
if (options.routeNamesChangeBehavior === 'lastUnhandled' && doesStateHaveOnlyInvalidRoutes(stateFromParams)) {
|
|
376
|
+
if (stateFromParams !== unhandledState) {
|
|
377
|
+
setUnhandledState(stateFromParams);
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
// If the route was updated with new state, we should reset to it
|
|
381
|
+
action = CommonActions.reset(stateFromParams);
|
|
329
382
|
}
|
|
330
|
-
} else {
|
|
331
|
-
// If the route was updated with new state, we should reset to it
|
|
332
|
-
action = CommonActions.reset(route.params.state);
|
|
333
383
|
}
|
|
334
|
-
} else if (typeof route.params.screen === 'string' && (route.params.initial === false && isFirstStateInitialization ||
|
|
384
|
+
} else if (typeof route.params.screen === 'string' && (route.params.initial === false && isFirstStateInitialization || !isNestedParamsConsumed)) {
|
|
385
|
+
didConsumeNestedParams = true;
|
|
335
386
|
if (options.routeNamesChangeBehavior === 'lastUnhandled' && !routeNames.includes(route.params.screen)) {
|
|
336
|
-
const state = getStateFromParams(route.params);
|
|
387
|
+
const state = getStateFromParams(route.params, router.type);
|
|
337
388
|
if (state != null && !deepEqual(state, unhandledState)) {
|
|
338
389
|
setUnhandledState(state);
|
|
339
390
|
}
|
|
340
391
|
} else {
|
|
341
392
|
// If the route was updated with new screen name and/or params, we should navigate there
|
|
342
|
-
action =
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
393
|
+
action = {
|
|
394
|
+
type: 'NAVIGATE',
|
|
395
|
+
payload: {
|
|
396
|
+
name: route.params.screen,
|
|
397
|
+
params: route.params.params,
|
|
398
|
+
path: route.params.path,
|
|
399
|
+
merge: route.params.merge,
|
|
400
|
+
pop: route.params.pop
|
|
401
|
+
}
|
|
402
|
+
};
|
|
349
403
|
}
|
|
350
404
|
}
|
|
351
405
|
|
|
@@ -355,16 +409,25 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
355
409
|
routeParamList,
|
|
356
410
|
routeGetIdList
|
|
357
411
|
}) : null;
|
|
412
|
+
if (process.env.NODE_ENV !== 'production' && action != null && updatedState === null) {
|
|
413
|
+
const names = routeNames.map(name => `'${name}'`).join(', ');
|
|
414
|
+
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.`);
|
|
415
|
+
}
|
|
358
416
|
nextState = updatedState !== null ? router.getRehydratedState(updatedState, {
|
|
359
417
|
routeNames,
|
|
360
418
|
routeParamList,
|
|
361
419
|
routeGetIdList
|
|
362
420
|
}) : nextState;
|
|
363
421
|
}
|
|
364
|
-
|
|
422
|
+
React.useInsertionEffect(() => {
|
|
423
|
+
if (consumedParams && didConsumeNestedParams && typeof route?.params === 'object' && route.params != null) {
|
|
424
|
+
consumedParams.set(route.params, true);
|
|
425
|
+
}
|
|
426
|
+
}, [consumedParams, didConsumeNestedParams, route?.params]);
|
|
427
|
+
const shouldUpdate = state !== nextState;
|
|
365
428
|
useScheduleUpdate(() => {
|
|
366
429
|
if (shouldUpdate) {
|
|
367
|
-
//
|
|
430
|
+
// Schedule an update if the state needs to be updated
|
|
368
431
|
setState(nextState);
|
|
369
432
|
if (shouldClearUnhandledState) {
|
|
370
433
|
setUnhandledState(undefined);
|
|
@@ -376,44 +439,52 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
376
439
|
// We can't use the outdated state since the screens have changed, which will cause error due to mismatched config
|
|
377
440
|
// So we override the state object we return to use the latest state as soon as possible
|
|
378
441
|
state = nextState;
|
|
442
|
+
React.useInsertionEffect(() => {
|
|
443
|
+
savedStateRef.current = state;
|
|
444
|
+
previousStateRef.current = currentState;
|
|
445
|
+
});
|
|
446
|
+
React.useInsertionEffect(() => {
|
|
447
|
+
return () => {
|
|
448
|
+
// An initially hidden Activity doesn't run passive effects or their cleanup.
|
|
449
|
+
// We mark actual unmount here so queued updates can't write state into a replacement navigator.
|
|
450
|
+
mountStateRef.current = 'unmounted';
|
|
451
|
+
};
|
|
452
|
+
}, []);
|
|
379
453
|
React.useEffect(() => {
|
|
454
|
+
const savedState = savedStateRef.current ?? state;
|
|
455
|
+
|
|
380
456
|
// In strict mode, React will double-invoke effects.
|
|
381
|
-
// So we need to reset the
|
|
382
|
-
|
|
457
|
+
// So we need to reset the status if component was not unmounted
|
|
458
|
+
mountStateRef.current = 'mounted';
|
|
383
459
|
setKey(navigatorKey);
|
|
384
|
-
if (!getIsInitial()) {
|
|
385
|
-
//
|
|
386
|
-
//
|
|
460
|
+
if (!getIsInitial() || getIsStateEmitted()) {
|
|
461
|
+
// We need to notify the state update in these scenarios:
|
|
462
|
+
// 1. If it's not the initial render of the component containing the navigator
|
|
463
|
+
// 2. If the container has already emitted state before the navigator mounted
|
|
464
|
+
//
|
|
465
|
+
// This will make sure that the container gets notified of state changes due to new mounts
|
|
387
466
|
// This is necessary for proper screen tracking, URL updates etc.
|
|
388
|
-
|
|
467
|
+
//
|
|
468
|
+
// During hydration, a nested navigator may mount after the container's initial state event.
|
|
469
|
+
// Or mount could be delayed due to conditional rendering, suspense etc.
|
|
470
|
+
// So only checking for the initial render is not enough.
|
|
471
|
+
// We also need to propagate the navigator's initial state when it mounts later,
|
|
472
|
+
// so the container is notified that the nested state is now available.
|
|
473
|
+
setState(savedState);
|
|
389
474
|
}
|
|
390
475
|
return () => {
|
|
391
476
|
// We need to clean up state for this navigator on unmount
|
|
392
477
|
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
|
393
478
|
setCurrentState(undefined);
|
|
394
|
-
stateCleanedUp.current = true;
|
|
395
479
|
}
|
|
480
|
+
mountStateRef.current = 'unmounted';
|
|
396
481
|
};
|
|
397
482
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
398
483
|
}, []);
|
|
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
484
|
const getState = useLatestCallback(() => {
|
|
411
|
-
const currentState = getCurrentState();
|
|
485
|
+
const currentState = mountStateRef.current === 'unmounted' ? savedStateRef.current : getCurrentState();
|
|
412
486
|
return deepFreeze(isStateInitialized(currentState) ? currentState : initializedState);
|
|
413
487
|
});
|
|
414
|
-
const {
|
|
415
|
-
onEmitEvent
|
|
416
|
-
} = React.useContext(NavigationBuilderContext);
|
|
417
488
|
const emitter = useEventEmitter(e => {
|
|
418
489
|
const routeNames = [];
|
|
419
490
|
let route;
|
|
@@ -429,32 +500,33 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
429
500
|
if (route == null) {
|
|
430
501
|
return;
|
|
431
502
|
}
|
|
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
|
-
|
|
503
|
+
const hasPerScreenListeners = routeNames.some(name => screens[name]?.props.listeners != null);
|
|
504
|
+
if (screenListeners != null || hasPerScreenListeners) {
|
|
505
|
+
const descriptor = descriptors[route.key];
|
|
506
|
+
if (descriptor == null) {
|
|
507
|
+
throw new Error(`Couldn't find a descriptor for route '${route.key}'.`);
|
|
508
|
+
}
|
|
509
|
+
const navigation = descriptor.navigation;
|
|
510
|
+
const listeners = [].concat(
|
|
511
|
+
// Get an array of listeners for all screens + common listeners on navigator
|
|
512
|
+
...[screenListeners, ...routeNames.map(name => {
|
|
513
|
+
const {
|
|
514
|
+
listeners
|
|
515
|
+
} = screens[name]?.props ?? {};
|
|
516
|
+
return listeners;
|
|
517
|
+
})].map(listeners => {
|
|
518
|
+
const map = typeof listeners === 'function' ? listeners({
|
|
519
|
+
route: route,
|
|
520
|
+
navigation
|
|
521
|
+
}) : listeners;
|
|
522
|
+
return map ? Object.keys(map).filter(type => type === e.type).map(type => map?.[type]) : undefined;
|
|
523
|
+
}))
|
|
524
|
+
// We don't want same listener to be called multiple times for same event
|
|
525
|
+
// So we remove any duplicate functions from the array
|
|
526
|
+
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
|
527
|
+
listeners.forEach(listener => listener?.(e));
|
|
528
|
+
}
|
|
529
|
+
}, onEmitEvent);
|
|
458
530
|
useFocusEvents({
|
|
459
531
|
state,
|
|
460
532
|
emitter
|
|
@@ -495,7 +567,7 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
495
567
|
getState,
|
|
496
568
|
setState
|
|
497
569
|
});
|
|
498
|
-
const onUnhandledActionParent = React.
|
|
570
|
+
const onUnhandledActionParent = React.use(UnhandledActionContext);
|
|
499
571
|
const onUnhandledAction = useLatestCallback(action => {
|
|
500
572
|
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
573
|
const state = {
|
|
@@ -509,13 +581,28 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
509
581
|
}
|
|
510
582
|
onUnhandledActionParent?.(action);
|
|
511
583
|
});
|
|
584
|
+
const canGoBack = useLatestCallback(source => {
|
|
585
|
+
const state = getState();
|
|
586
|
+
return router.getStateForAction(state, {
|
|
587
|
+
...CommonActions.goBack(),
|
|
588
|
+
source
|
|
589
|
+
}, {
|
|
590
|
+
routeNames: state.routeNames,
|
|
591
|
+
routeParamList: {},
|
|
592
|
+
routeGetIdList: {}
|
|
593
|
+
}) !== null || canGoBackParent?.(
|
|
594
|
+
// If the `source` belonged to the current navigator,
|
|
595
|
+
// rewrite the `source` to the parent screen's key when checking
|
|
596
|
+
// This mirrors the way actions bubble up to the parent
|
|
597
|
+
source !== undefined && state.routes.some(r => r.key === source) ? route?.key : source) || false;
|
|
598
|
+
});
|
|
512
599
|
const navigation = useNavigationHelpers({
|
|
513
600
|
onAction,
|
|
514
601
|
onUnhandledAction,
|
|
602
|
+
canGoBack,
|
|
515
603
|
getState,
|
|
516
604
|
emitter,
|
|
517
|
-
router
|
|
518
|
-
stateRef
|
|
605
|
+
router
|
|
519
606
|
});
|
|
520
607
|
useFocusedListenersChildrenAdapter({
|
|
521
608
|
navigation,
|
|
@@ -525,15 +612,20 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
525
612
|
getState,
|
|
526
613
|
getStateListeners: keyedListeners.getState
|
|
527
614
|
});
|
|
615
|
+
useOnGetNavigation({
|
|
616
|
+
navigation
|
|
617
|
+
});
|
|
528
618
|
const descriptors = useDescriptors({
|
|
529
|
-
routes: router.getRoutesFromState ? router.getRoutesFromState(state) : state.routes,
|
|
530
619
|
screens,
|
|
620
|
+
state,
|
|
531
621
|
navigation,
|
|
532
622
|
screenOptions,
|
|
533
623
|
screenLayout,
|
|
534
624
|
onAction,
|
|
625
|
+
canGoBack,
|
|
535
626
|
getState,
|
|
536
627
|
setState,
|
|
628
|
+
subscribe,
|
|
537
629
|
onRouteFocus,
|
|
538
630
|
addListener,
|
|
539
631
|
addKeyedListener,
|
|
@@ -541,36 +633,41 @@ export function useNavigationBuilder(createRouter, options) {
|
|
|
541
633
|
// @ts-expect-error: this should have both core and custom events, but too much work right now
|
|
542
634
|
emitter
|
|
543
635
|
});
|
|
544
|
-
|
|
545
|
-
state
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
const NavigationContent = useComponent(children => {
|
|
636
|
+
const render = children => {
|
|
637
|
+
const focusedRoute = state.routes[state.index];
|
|
638
|
+
if (focusedRoute == null) {
|
|
639
|
+
throw new Error(`Couldn't find a route at index ${state.index}.`);
|
|
640
|
+
}
|
|
550
641
|
const element = layout != null ? layout({
|
|
551
642
|
state,
|
|
552
643
|
descriptors,
|
|
553
644
|
navigation,
|
|
554
645
|
children
|
|
555
646
|
}) : children;
|
|
556
|
-
return /*#__PURE__*/_jsx(
|
|
557
|
-
value:
|
|
558
|
-
children: /*#__PURE__*/_jsx(
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
647
|
+
return /*#__PURE__*/_jsx(NavigationHelpersContext.Provider, {
|
|
648
|
+
value: navigation,
|
|
649
|
+
children: /*#__PURE__*/_jsx(NavigationStateListenerProvider, {
|
|
650
|
+
isSynced: !shouldUpdate,
|
|
651
|
+
state: state,
|
|
652
|
+
getState: getState,
|
|
653
|
+
subscribe: subscribe,
|
|
654
|
+
children: /*#__PURE__*/_jsx(FocusedRouteKeyContext.Provider, {
|
|
655
|
+
value: focusedRoute.key,
|
|
562
656
|
children: /*#__PURE__*/_jsx(PreventRemoveProvider, {
|
|
563
|
-
children:
|
|
657
|
+
children: /*#__PURE__*/_jsx(IsScreenContext.Provider, {
|
|
658
|
+
value: false,
|
|
659
|
+
children: element
|
|
660
|
+
})
|
|
564
661
|
})
|
|
565
662
|
})
|
|
566
663
|
})
|
|
567
664
|
});
|
|
568
|
-
}
|
|
665
|
+
};
|
|
569
666
|
return {
|
|
570
667
|
state,
|
|
571
668
|
navigation,
|
|
572
669
|
descriptors,
|
|
573
|
-
|
|
670
|
+
render
|
|
574
671
|
};
|
|
575
672
|
}
|
|
576
673
|
//# sourceMappingURL=useNavigationBuilder.js.map
|