@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
|
@@ -15,14 +15,13 @@ import * as React from 'react';
|
|
|
15
15
|
import { isValidElementType } from 'react-is';
|
|
16
16
|
import useLatestCallback from 'use-latest-callback';
|
|
17
17
|
|
|
18
|
+
import { ConsumedParamsContext } from './ConsumedParamsContext';
|
|
18
19
|
import { deepFreeze } from './deepFreeze';
|
|
19
20
|
import { Group } from './Group';
|
|
20
21
|
import { isArrayEqual } from './isArrayEqual';
|
|
21
|
-
import {
|
|
22
|
-
import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
22
|
+
import { useNavigationBuilderContext } from './NavigationBuilderContext';
|
|
23
23
|
import { NavigationHelpersContext } from './NavigationHelpersContext';
|
|
24
|
-
import {
|
|
25
|
-
import { NavigationRouteContext } from './NavigationProvider';
|
|
24
|
+
import { IsScreenContext, NavigationRouteContext } from './NavigationProvider';
|
|
26
25
|
import { NavigationStateContext } from './NavigationStateContext';
|
|
27
26
|
import { PreventRemoveProvider } from './PreventRemoveProvider';
|
|
28
27
|
import { Screen } from './Screen';
|
|
@@ -36,17 +35,17 @@ import {
|
|
|
36
35
|
} from './types';
|
|
37
36
|
import { UnhandledActionContext } from './UnhandledActionContext';
|
|
38
37
|
import { useChildListeners } from './useChildListeners';
|
|
39
|
-
import { useComponent } from './useComponent';
|
|
40
|
-
import { useCurrentRender } from './useCurrentRender';
|
|
41
38
|
import { type ScreenConfigWithParent, useDescriptors } from './useDescriptors';
|
|
42
39
|
import { useEventEmitter } from './useEventEmitter';
|
|
43
40
|
import { useFocusedListenersChildrenAdapter } from './useFocusedListenersChildrenAdapter';
|
|
44
41
|
import { useFocusEvents } from './useFocusEvents';
|
|
42
|
+
import { FocusedRouteKeyContext } from './useIsFocused';
|
|
45
43
|
import { useKeyedChildListeners } from './useKeyedChildListeners';
|
|
46
44
|
import { useLazyValue } from './useLazyValue';
|
|
47
45
|
import { useNavigationHelpers } from './useNavigationHelpers';
|
|
48
46
|
import { NavigationStateListenerProvider } from './useNavigationState';
|
|
49
47
|
import { useOnAction } from './useOnAction';
|
|
48
|
+
import { useOnGetNavigation } from './useOnGetNavigation';
|
|
50
49
|
import { useOnGetState } from './useOnGetState';
|
|
51
50
|
import { useOnRouteFocus } from './useOnRouteFocus';
|
|
52
51
|
import { useRegisterNavigator } from './useRegisterNavigator';
|
|
@@ -58,9 +57,17 @@ PrivateValueStore;
|
|
|
58
57
|
|
|
59
58
|
type NavigatorRoute = {
|
|
60
59
|
key: string;
|
|
61
|
-
params?: NavigatorScreenParams<ParamListBase
|
|
60
|
+
params?: NavigatorScreenParams<ParamListBase> | undefined;
|
|
62
61
|
};
|
|
63
62
|
|
|
63
|
+
const isNavigationState = (
|
|
64
|
+
state: unknown
|
|
65
|
+
): state is NavigationState | PartialState<NavigationState> =>
|
|
66
|
+
state != null &&
|
|
67
|
+
typeof state === 'object' &&
|
|
68
|
+
'routes' in state &&
|
|
69
|
+
Array.isArray(state.routes);
|
|
70
|
+
|
|
64
71
|
const isScreen = (
|
|
65
72
|
child: React.ReactElement<unknown>
|
|
66
73
|
): child is React.ReactElement<{
|
|
@@ -95,7 +102,7 @@ const getRouteConfigsFromChildren = <
|
|
|
95
102
|
EventMap extends EventMapBase,
|
|
96
103
|
>(
|
|
97
104
|
children: React.ReactNode,
|
|
98
|
-
|
|
105
|
+
groupKeys: string[] = [],
|
|
99
106
|
groupOptions?: ScreenConfigWithParent<
|
|
100
107
|
State,
|
|
101
108
|
ScreenOptions,
|
|
@@ -138,7 +145,7 @@ const getRouteConfigsFromChildren = <
|
|
|
138
145
|
}
|
|
139
146
|
|
|
140
147
|
acc.push({
|
|
141
|
-
keys: [
|
|
148
|
+
keys: [...groupKeys, child.props.navigationKey],
|
|
142
149
|
options: groupOptions,
|
|
143
150
|
layout: groupLayout,
|
|
144
151
|
props: child.props as RouteConfig<
|
|
@@ -168,7 +175,9 @@ const getRouteConfigsFromChildren = <
|
|
|
168
175
|
acc.push(
|
|
169
176
|
...getRouteConfigsFromChildren<State, ScreenOptions, EventMap>(
|
|
170
177
|
child.props.children as React.ReactNode,
|
|
171
|
-
child.props.navigationKey
|
|
178
|
+
child.props.navigationKey != null
|
|
179
|
+
? [...groupKeys, child.props.navigationKey]
|
|
180
|
+
: groupKeys,
|
|
172
181
|
// FIXME
|
|
173
182
|
// @ts-expect-error: add validation
|
|
174
183
|
child.type !== Group
|
|
@@ -276,9 +285,24 @@ const getRouteConfigsFromChildren = <
|
|
|
276
285
|
return configs;
|
|
277
286
|
};
|
|
278
287
|
|
|
279
|
-
const getStateFromParams = (
|
|
280
|
-
|
|
281
|
-
|
|
288
|
+
const getStateFromParams = (
|
|
289
|
+
params: NavigatorRoute['params'],
|
|
290
|
+
type: string
|
|
291
|
+
): NavigationState | PartialState<NavigationState> | undefined => {
|
|
292
|
+
const state = params?.state;
|
|
293
|
+
|
|
294
|
+
if (isNavigationState(state)) {
|
|
295
|
+
if (state.type != null && state.type !== type) {
|
|
296
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
297
|
+
console.error(
|
|
298
|
+
`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.`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return state;
|
|
282
306
|
} else if (typeof params?.screen === 'string' && params?.initial !== false) {
|
|
283
307
|
return {
|
|
284
308
|
routes: [
|
|
@@ -320,9 +344,14 @@ export function useNavigationBuilder<
|
|
|
320
344
|
) {
|
|
321
345
|
const navigatorKey = useRegisterNavigator();
|
|
322
346
|
|
|
323
|
-
const route = React.
|
|
324
|
-
|
|
325
|
-
|
|
347
|
+
const route = React.use(NavigationRouteContext) as NavigatorRoute | undefined;
|
|
348
|
+
|
|
349
|
+
const consumedParams = React.use(ConsumedParamsContext);
|
|
350
|
+
|
|
351
|
+
const isNestedParamsConsumed =
|
|
352
|
+
typeof route?.params === 'object' && route.params != null
|
|
353
|
+
? consumedParams?.has(route.params)
|
|
354
|
+
: false;
|
|
326
355
|
|
|
327
356
|
const {
|
|
328
357
|
children,
|
|
@@ -366,44 +395,7 @@ export function useNavigationBuilder<
|
|
|
366
395
|
return original;
|
|
367
396
|
});
|
|
368
397
|
|
|
369
|
-
const screens = routeConfigs.reduce<
|
|
370
|
-
Record<string, ScreenConfigWithParent<State, ScreenOptions, EventMap>>
|
|
371
|
-
>((acc, config) => {
|
|
372
|
-
if (config.props.name in acc) {
|
|
373
|
-
throw new Error(
|
|
374
|
-
`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${config.props.name}')`
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
acc[config.props.name] = config;
|
|
379
|
-
return acc;
|
|
380
|
-
}, {});
|
|
381
|
-
|
|
382
398
|
const routeNames = routeConfigs.map((config) => config.props.name);
|
|
383
|
-
const routeKeyList = routeNames.reduce<Record<string, React.Key | undefined>>(
|
|
384
|
-
(acc, curr) => {
|
|
385
|
-
acc[curr] = screens[curr].keys.map((key) => key ?? '').join(':');
|
|
386
|
-
return acc;
|
|
387
|
-
},
|
|
388
|
-
{}
|
|
389
|
-
);
|
|
390
|
-
const routeParamList = routeNames.reduce<Record<string, object | undefined>>(
|
|
391
|
-
(acc, curr) => {
|
|
392
|
-
const { initialParams } = screens[curr].props;
|
|
393
|
-
acc[curr] = initialParams;
|
|
394
|
-
return acc;
|
|
395
|
-
},
|
|
396
|
-
{}
|
|
397
|
-
);
|
|
398
|
-
const routeGetIdList = routeNames.reduce<
|
|
399
|
-
RouterConfigOptions['routeGetIdList']
|
|
400
|
-
>(
|
|
401
|
-
(acc, curr) =>
|
|
402
|
-
Object.assign(acc, {
|
|
403
|
-
[curr]: screens[curr].props.getId,
|
|
404
|
-
}),
|
|
405
|
-
{}
|
|
406
|
-
);
|
|
407
399
|
|
|
408
400
|
if (!routeNames.length) {
|
|
409
401
|
throw new Error(
|
|
@@ -411,6 +403,31 @@ export function useNavigationBuilder<
|
|
|
411
403
|
);
|
|
412
404
|
}
|
|
413
405
|
|
|
406
|
+
const screens: Record<
|
|
407
|
+
string,
|
|
408
|
+
ScreenConfigWithParent<State, ScreenOptions, EventMap>
|
|
409
|
+
> = {};
|
|
410
|
+
|
|
411
|
+
const routeKeyList: Record<string, (string | undefined)[]> = {};
|
|
412
|
+
const routeParamList: Record<string, object | undefined> = {};
|
|
413
|
+
const routeGetIdList: RouterConfigOptions['routeGetIdList'] = {};
|
|
414
|
+
|
|
415
|
+
for (const config of routeConfigs) {
|
|
416
|
+
const name = config.props.name;
|
|
417
|
+
|
|
418
|
+
if (name in screens) {
|
|
419
|
+
throw new Error(
|
|
420
|
+
`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${name}')`
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
screens[name] = config;
|
|
425
|
+
routeKeyList[name] = config.keys;
|
|
426
|
+
routeParamList[name] = config.props.initialParams;
|
|
427
|
+
|
|
428
|
+
Object.assign(routeGetIdList, { [name]: config.props.getId });
|
|
429
|
+
}
|
|
430
|
+
|
|
414
431
|
const isStateValid = React.useCallback(
|
|
415
432
|
(state: NavigationState | PartialState<NavigationState>) =>
|
|
416
433
|
state.type === undefined || state.type === router.type,
|
|
@@ -418,7 +435,9 @@ export function useNavigationBuilder<
|
|
|
418
435
|
);
|
|
419
436
|
|
|
420
437
|
const isStateInitialized = React.useCallback(
|
|
421
|
-
|
|
438
|
+
<T extends NavigationState>(
|
|
439
|
+
state: T | PartialState<T> | undefined
|
|
440
|
+
): state is T =>
|
|
422
441
|
state !== undefined && state.stale === false && isStateValid(state),
|
|
423
442
|
[isStateValid]
|
|
424
443
|
);
|
|
@@ -433,19 +452,36 @@ export function useNavigationBuilder<
|
|
|
433
452
|
state: currentState,
|
|
434
453
|
getState: getCurrentState,
|
|
435
454
|
setState: setCurrentState,
|
|
455
|
+
subscribe,
|
|
436
456
|
setKey,
|
|
437
457
|
getKey,
|
|
438
458
|
getIsInitial,
|
|
439
|
-
} = React.
|
|
459
|
+
} = React.use(NavigationStateContext);
|
|
460
|
+
|
|
461
|
+
const {
|
|
462
|
+
onEmitEvent,
|
|
463
|
+
getIsStateEmitted,
|
|
464
|
+
canGoBack: canGoBackParent,
|
|
465
|
+
} = useNavigationBuilderContext();
|
|
440
466
|
|
|
441
|
-
const
|
|
467
|
+
const mountStateRef = React.useRef<'initial' | 'mounted' | 'unmounted'>(
|
|
468
|
+
'initial'
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
const previousStateRef = React.useRef(currentState);
|
|
472
|
+
const savedStateRef = React.useRef<State | PartialState<State> | undefined>(
|
|
473
|
+
undefined
|
|
474
|
+
);
|
|
442
475
|
|
|
443
476
|
const setState = useLatestCallback(
|
|
444
|
-
(state:
|
|
445
|
-
if (
|
|
477
|
+
(state: State | PartialState<State> | undefined) => {
|
|
478
|
+
if (mountStateRef.current === 'unmounted') {
|
|
479
|
+
// Store the state locally in case the current navigator is in `Activity`
|
|
480
|
+
savedStateRef.current = state;
|
|
481
|
+
|
|
446
482
|
// State might have been already cleaned up due to unmount
|
|
447
|
-
// We
|
|
448
|
-
//
|
|
483
|
+
// We don't want to update `route.state` in parent
|
|
484
|
+
// Otherwise it will be reused if a new navigator gets mounted
|
|
449
485
|
return;
|
|
450
486
|
}
|
|
451
487
|
|
|
@@ -453,19 +489,46 @@ export function useNavigationBuilder<
|
|
|
453
489
|
}
|
|
454
490
|
);
|
|
455
491
|
|
|
492
|
+
const lastState =
|
|
493
|
+
(mountStateRef.current !== 'mounted' ||
|
|
494
|
+
!isStateInitialized(currentState)) &&
|
|
495
|
+
// If the state object differs from previously committed state, we have new state
|
|
496
|
+
// e.g. because of a reset
|
|
497
|
+
// So we need to use it before checking if we should reuse the saved state.
|
|
498
|
+
(currentState === previousStateRef.current ||
|
|
499
|
+
(mountStateRef.current === 'unmounted' && currentState === undefined))
|
|
500
|
+
? // If the navigator is hidden with `Activity`, its state gets cleaned up due to effect cleanup.
|
|
501
|
+
// So we reuse the saved state to avoid remounting screens when the navigator is shown again.
|
|
502
|
+
savedStateRef.current
|
|
503
|
+
: undefined;
|
|
504
|
+
|
|
456
505
|
const [
|
|
457
506
|
stateBeforeInitialization,
|
|
458
507
|
initializedState,
|
|
459
508
|
isFirstStateInitialization,
|
|
509
|
+
paramsUsedForInitialization,
|
|
460
510
|
] = React.useMemo((): [
|
|
461
511
|
PartialState<State> | undefined,
|
|
462
512
|
State | undefined,
|
|
463
513
|
boolean,
|
|
514
|
+
object | undefined,
|
|
464
515
|
] => {
|
|
516
|
+
if (lastState && isStateValid(lastState)) {
|
|
517
|
+
const state: State = isStateInitialized(lastState)
|
|
518
|
+
? lastState
|
|
519
|
+
: router.getRehydratedState(lastState, {
|
|
520
|
+
routeNames,
|
|
521
|
+
routeParamList,
|
|
522
|
+
routeGetIdList,
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
return [undefined, state, false, undefined];
|
|
526
|
+
}
|
|
527
|
+
|
|
465
528
|
const initialRouteParamList = routeNames.reduce<
|
|
466
529
|
Record<string, object | undefined>
|
|
467
530
|
>((acc, curr) => {
|
|
468
|
-
const { initialParams } = screens[curr]
|
|
531
|
+
const { initialParams } = screens[curr]?.props ?? {};
|
|
469
532
|
const initialParamsFromParams =
|
|
470
533
|
route?.params?.state == null &&
|
|
471
534
|
route?.params?.initial !== false &&
|
|
@@ -494,7 +557,8 @@ export function useNavigationBuilder<
|
|
|
494
557
|
!(
|
|
495
558
|
typeof route?.params?.screen === 'string' &&
|
|
496
559
|
route?.params?.initial !== false
|
|
497
|
-
)
|
|
560
|
+
) &&
|
|
561
|
+
!isNestedParamsConsumed
|
|
498
562
|
) {
|
|
499
563
|
return [
|
|
500
564
|
undefined,
|
|
@@ -504,28 +568,48 @@ export function useNavigationBuilder<
|
|
|
504
568
|
routeGetIdList,
|
|
505
569
|
}),
|
|
506
570
|
true,
|
|
571
|
+
undefined,
|
|
507
572
|
];
|
|
508
573
|
} else {
|
|
509
|
-
const
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
574
|
+
const paramsForState = isNestedParamsConsumed ? undefined : route?.params;
|
|
575
|
+
const stateFromParams = paramsForState
|
|
576
|
+
? getStateFromParams(paramsForState, router.type)
|
|
577
|
+
: undefined;
|
|
578
|
+
|
|
579
|
+
const stateBeforeInitialization = (stateFromParams ?? currentState) as
|
|
580
|
+
| PartialState<State>
|
|
581
|
+
| undefined;
|
|
582
|
+
|
|
583
|
+
const hydratedState =
|
|
584
|
+
stateBeforeInitialization == null
|
|
585
|
+
? router.getInitialState({
|
|
586
|
+
routeNames,
|
|
587
|
+
routeParamList: initialRouteParamList,
|
|
588
|
+
routeGetIdList,
|
|
589
|
+
})
|
|
590
|
+
: router.getRehydratedState(stateBeforeInitialization, {
|
|
591
|
+
routeNames,
|
|
592
|
+
routeParamList: initialRouteParamList,
|
|
593
|
+
routeGetIdList,
|
|
594
|
+
});
|
|
520
595
|
|
|
521
596
|
if (
|
|
597
|
+
stateBeforeInitialization != null &&
|
|
598
|
+
isStateValid(stateBeforeInitialization) &&
|
|
522
599
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
523
600
|
doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)
|
|
524
601
|
) {
|
|
525
|
-
return [stateBeforeInitialization, hydratedState, true];
|
|
602
|
+
return [stateBeforeInitialization, hydratedState, true, paramsForState];
|
|
526
603
|
}
|
|
527
604
|
|
|
528
|
-
return [
|
|
605
|
+
return [
|
|
606
|
+
undefined,
|
|
607
|
+
hydratedState,
|
|
608
|
+
false,
|
|
609
|
+
// Current state is already initialized
|
|
610
|
+
// So params weren't used, and need to be handled later
|
|
611
|
+
isStateInitialized(currentState) ? undefined : paramsForState,
|
|
612
|
+
];
|
|
529
613
|
}
|
|
530
614
|
// We explicitly don't include routeNames, route.params etc. in the dep list
|
|
531
615
|
// below. We want to avoid forcing a new state to be calculated in those cases
|
|
@@ -533,16 +617,26 @@ export function useNavigationBuilder<
|
|
|
533
617
|
// that some changes to routeConfigs are explicitly ignored, such as changes
|
|
534
618
|
// to initialParams
|
|
535
619
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
536
|
-
}, [currentState, router, isStateValid]);
|
|
620
|
+
}, [currentState, lastState, router, isStateValid]);
|
|
537
621
|
|
|
538
622
|
const previousRouteKeyListRef = React.useRef(routeKeyList);
|
|
539
623
|
|
|
540
|
-
React.
|
|
624
|
+
React.useInsertionEffect(() => {
|
|
541
625
|
previousRouteKeyListRef.current = routeKeyList;
|
|
542
626
|
});
|
|
543
627
|
|
|
544
628
|
const previousRouteKeyList = previousRouteKeyListRef.current;
|
|
545
629
|
|
|
630
|
+
// Names of the screens whose navigation key changed since the last render
|
|
631
|
+
const routeKeyChanges = Object.keys(routeKeyList).filter((name) => {
|
|
632
|
+
const current = routeKeyList[name];
|
|
633
|
+
const previous = previousRouteKeyList[name];
|
|
634
|
+
|
|
635
|
+
return (
|
|
636
|
+
current != null && previous != null && !isArrayEqual(current, previous)
|
|
637
|
+
);
|
|
638
|
+
});
|
|
639
|
+
|
|
546
640
|
const [unhandledState, setUnhandledState] = React.useState<
|
|
547
641
|
NavigationState | PartialState<NavigationState> | undefined
|
|
548
642
|
>(stateBeforeInitialization);
|
|
@@ -563,17 +657,21 @@ export function useNavigationBuilder<
|
|
|
563
657
|
// If the state isn't initialized, or stale, use the state we initialized instead
|
|
564
658
|
// The state won't update until there's a change needed in the state we have initialized locally
|
|
565
659
|
// So it'll be `undefined` or stale until the first navigation event happens
|
|
566
|
-
isStateInitialized(currentState)
|
|
660
|
+
lastState === undefined && isStateInitialized(currentState)
|
|
567
661
|
? (currentState as State)
|
|
568
662
|
: (initializedState as State);
|
|
569
663
|
|
|
570
664
|
let nextState: State = state;
|
|
571
665
|
let shouldClearUnhandledState = false;
|
|
572
666
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
667
|
+
if (unhandledState != null && !isStateValid(unhandledState)) {
|
|
668
|
+
// The stored unhandled state is for a different type of navigator
|
|
669
|
+
// It can't be used with this navigator, so we discard it
|
|
670
|
+
setUnhandledState(undefined);
|
|
671
|
+
} else if (
|
|
672
|
+
// Previously unhandled state is now valid again
|
|
673
|
+
// And current state no longer has any valid routes
|
|
674
|
+
// We should reuse the unhandled state instead of re-calculating the state
|
|
577
675
|
unhandledState?.routes.every((r) => routeNames.includes(r.name)) &&
|
|
578
676
|
state?.routes.every((r) => !routeNames.includes(r.name))
|
|
579
677
|
) {
|
|
@@ -588,71 +686,68 @@ export function useNavigationBuilder<
|
|
|
588
686
|
);
|
|
589
687
|
} else if (
|
|
590
688
|
!isArrayEqual(state.routeNames, routeNames) ||
|
|
591
|
-
|
|
689
|
+
routeKeyChanges.length !== 0
|
|
592
690
|
) {
|
|
593
691
|
// When the list of route names change, the router should handle it to remove invalid routes
|
|
594
692
|
nextState = router.getStateForRouteNamesChange(state, {
|
|
595
693
|
routeNames,
|
|
596
694
|
routeParamList,
|
|
597
695
|
routeGetIdList,
|
|
598
|
-
routeKeyChanges
|
|
599
|
-
(name) =>
|
|
600
|
-
name in previousRouteKeyList &&
|
|
601
|
-
routeKeyList[name] !== previousRouteKeyList[name]
|
|
602
|
-
),
|
|
696
|
+
routeKeyChanges,
|
|
603
697
|
});
|
|
604
698
|
}
|
|
605
699
|
|
|
606
|
-
|
|
700
|
+
let didConsumeNestedParams = route?.params === paramsUsedForInitialization;
|
|
607
701
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}, [route?.params]);
|
|
702
|
+
if (route?.params && !didConsumeNestedParams) {
|
|
703
|
+
let action: CommonActions.Action | undefined;
|
|
611
704
|
|
|
612
|
-
|
|
613
|
-
|
|
705
|
+
if (isNavigationState(route.params.state) && !isNestedParamsConsumed) {
|
|
706
|
+
didConsumeNestedParams = true;
|
|
614
707
|
|
|
615
|
-
|
|
708
|
+
const stateFromParams = getStateFromParams(route.params, router.type);
|
|
616
709
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
710
|
+
if (stateFromParams != null) {
|
|
711
|
+
if (
|
|
712
|
+
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
713
|
+
doesStateHaveOnlyInvalidRoutes(stateFromParams)
|
|
714
|
+
) {
|
|
715
|
+
if (stateFromParams !== unhandledState) {
|
|
716
|
+
setUnhandledState(stateFromParams);
|
|
717
|
+
}
|
|
718
|
+
} else {
|
|
719
|
+
// If the route was updated with new state, we should reset to it
|
|
720
|
+
action = CommonActions.reset(stateFromParams);
|
|
628
721
|
}
|
|
629
|
-
} else {
|
|
630
|
-
// If the route was updated with new state, we should reset to it
|
|
631
|
-
action = CommonActions.reset(route.params.state);
|
|
632
722
|
}
|
|
633
723
|
} else if (
|
|
634
724
|
typeof route.params.screen === 'string' &&
|
|
635
725
|
((route.params.initial === false && isFirstStateInitialization) ||
|
|
636
|
-
|
|
726
|
+
!isNestedParamsConsumed)
|
|
637
727
|
) {
|
|
728
|
+
didConsumeNestedParams = true;
|
|
729
|
+
|
|
638
730
|
if (
|
|
639
731
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
640
732
|
!routeNames.includes(route.params.screen)
|
|
641
733
|
) {
|
|
642
|
-
const state = getStateFromParams(route.params);
|
|
734
|
+
const state = getStateFromParams(route.params, router.type);
|
|
643
735
|
|
|
644
736
|
if (state != null && !deepEqual(state, unhandledState)) {
|
|
645
737
|
setUnhandledState(state);
|
|
646
738
|
}
|
|
647
739
|
} else {
|
|
648
740
|
// If the route was updated with new screen name and/or params, we should navigate there
|
|
649
|
-
action =
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
741
|
+
action = {
|
|
742
|
+
type: 'NAVIGATE',
|
|
743
|
+
payload: {
|
|
744
|
+
name: route.params.screen,
|
|
745
|
+
params: route.params.params,
|
|
746
|
+
path: route.params.path,
|
|
747
|
+
merge: route.params.merge,
|
|
748
|
+
pop: route.params.pop,
|
|
749
|
+
},
|
|
750
|
+
} as const;
|
|
656
751
|
}
|
|
657
752
|
}
|
|
658
753
|
|
|
@@ -665,6 +760,18 @@ export function useNavigationBuilder<
|
|
|
665
760
|
})
|
|
666
761
|
: null;
|
|
667
762
|
|
|
763
|
+
if (
|
|
764
|
+
process.env.NODE_ENV !== 'production' &&
|
|
765
|
+
action != null &&
|
|
766
|
+
updatedState === null
|
|
767
|
+
) {
|
|
768
|
+
const names = routeNames.map((name) => `'${name}'`).join(', ');
|
|
769
|
+
|
|
770
|
+
console.error(
|
|
771
|
+
`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.`
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
|
|
668
775
|
nextState =
|
|
669
776
|
updatedState !== null
|
|
670
777
|
? router.getRehydratedState(updatedState, {
|
|
@@ -675,14 +782,22 @@ export function useNavigationBuilder<
|
|
|
675
782
|
: nextState;
|
|
676
783
|
}
|
|
677
784
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
785
|
+
React.useInsertionEffect(() => {
|
|
786
|
+
if (
|
|
787
|
+
consumedParams &&
|
|
788
|
+
didConsumeNestedParams &&
|
|
789
|
+
typeof route?.params === 'object' &&
|
|
790
|
+
route.params != null
|
|
791
|
+
) {
|
|
792
|
+
consumedParams.set(route.params, true);
|
|
793
|
+
}
|
|
794
|
+
}, [consumedParams, didConsumeNestedParams, route?.params]);
|
|
795
|
+
|
|
796
|
+
const shouldUpdate = state !== nextState;
|
|
682
797
|
|
|
683
798
|
useScheduleUpdate(() => {
|
|
684
799
|
if (shouldUpdate) {
|
|
685
|
-
//
|
|
800
|
+
// Schedule an update if the state needs to be updated
|
|
686
801
|
setState(nextState);
|
|
687
802
|
|
|
688
803
|
if (shouldClearUnhandledState) {
|
|
@@ -696,45 +811,60 @@ export function useNavigationBuilder<
|
|
|
696
811
|
// So we override the state object we return to use the latest state as soon as possible
|
|
697
812
|
state = nextState;
|
|
698
813
|
|
|
814
|
+
React.useInsertionEffect(() => {
|
|
815
|
+
savedStateRef.current = state;
|
|
816
|
+
previousStateRef.current = currentState;
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
React.useInsertionEffect(() => {
|
|
820
|
+
return () => {
|
|
821
|
+
// An initially hidden Activity doesn't run passive effects or their cleanup.
|
|
822
|
+
// We mark actual unmount here so queued updates can't write state into a replacement navigator.
|
|
823
|
+
mountStateRef.current = 'unmounted';
|
|
824
|
+
};
|
|
825
|
+
}, []);
|
|
826
|
+
|
|
699
827
|
React.useEffect(() => {
|
|
828
|
+
const savedState = savedStateRef.current ?? state;
|
|
829
|
+
|
|
700
830
|
// In strict mode, React will double-invoke effects.
|
|
701
|
-
// So we need to reset the
|
|
702
|
-
|
|
831
|
+
// So we need to reset the status if component was not unmounted
|
|
832
|
+
mountStateRef.current = 'mounted';
|
|
703
833
|
|
|
704
834
|
setKey(navigatorKey);
|
|
705
835
|
|
|
706
|
-
if (!getIsInitial()) {
|
|
707
|
-
//
|
|
708
|
-
//
|
|
836
|
+
if (!getIsInitial() || getIsStateEmitted()) {
|
|
837
|
+
// We need to notify the state update in these scenarios:
|
|
838
|
+
// 1. If it's not the initial render of the component containing the navigator
|
|
839
|
+
// 2. If the container has already emitted state before the navigator mounted
|
|
840
|
+
//
|
|
841
|
+
// This will make sure that the container gets notified of state changes due to new mounts
|
|
709
842
|
// This is necessary for proper screen tracking, URL updates etc.
|
|
710
|
-
|
|
843
|
+
//
|
|
844
|
+
// During hydration, a nested navigator may mount after the container's initial state event.
|
|
845
|
+
// Or mount could be delayed due to conditional rendering, suspense etc.
|
|
846
|
+
// So only checking for the initial render is not enough.
|
|
847
|
+
// We also need to propagate the navigator's initial state when it mounts later,
|
|
848
|
+
// so the container is notified that the nested state is now available.
|
|
849
|
+
setState(savedState);
|
|
711
850
|
}
|
|
712
851
|
|
|
713
852
|
return () => {
|
|
714
853
|
// We need to clean up state for this navigator on unmount
|
|
715
854
|
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
|
716
855
|
setCurrentState(undefined);
|
|
717
|
-
stateCleanedUp.current = true;
|
|
718
856
|
}
|
|
857
|
+
|
|
858
|
+
mountStateRef.current = 'unmounted';
|
|
719
859
|
};
|
|
720
860
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
721
861
|
}, []);
|
|
722
862
|
|
|
723
|
-
// In some cases (e.g. route names change), internal state might have changed
|
|
724
|
-
// But it hasn't been committed yet, so hasn't propagated to the sync external store
|
|
725
|
-
// During this time, we need to return the internal state in `getState`
|
|
726
|
-
// Otherwise it can result in inconsistent state during render in children
|
|
727
|
-
// To avoid this, we use a ref for render phase, and immediately clear it on commit
|
|
728
|
-
const stateRef = React.useRef<State | null>(state);
|
|
729
|
-
|
|
730
|
-
stateRef.current = state;
|
|
731
|
-
|
|
732
|
-
React.useLayoutEffect(() => {
|
|
733
|
-
stateRef.current = null;
|
|
734
|
-
});
|
|
735
|
-
|
|
736
863
|
const getState = useLatestCallback((): State => {
|
|
737
|
-
const currentState =
|
|
864
|
+
const currentState =
|
|
865
|
+
mountStateRef.current === 'unmounted'
|
|
866
|
+
? savedStateRef.current
|
|
867
|
+
: getCurrentState();
|
|
738
868
|
|
|
739
869
|
return deepFreeze(
|
|
740
870
|
(isStateInitialized(currentState)
|
|
@@ -743,8 +873,6 @@ export function useNavigationBuilder<
|
|
|
743
873
|
);
|
|
744
874
|
});
|
|
745
875
|
|
|
746
|
-
const { onEmitEvent } = React.useContext(NavigationBuilderContext);
|
|
747
|
-
|
|
748
876
|
const emitter = useEventEmitter<EventMapCore<State>>((e) => {
|
|
749
877
|
const routeNames = [];
|
|
750
878
|
|
|
@@ -767,43 +895,48 @@ export function useNavigationBuilder<
|
|
|
767
895
|
return;
|
|
768
896
|
}
|
|
769
897
|
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
.concat(
|
|
774
|
-
// Get an array of listeners for all screens + common listeners on navigator
|
|
775
|
-
...[
|
|
776
|
-
screenListeners,
|
|
777
|
-
...routeNames.map((name) => {
|
|
778
|
-
const { listeners } = screens[name].props;
|
|
779
|
-
return listeners;
|
|
780
|
-
}),
|
|
781
|
-
].map((listeners) => {
|
|
782
|
-
const map =
|
|
783
|
-
typeof listeners === 'function'
|
|
784
|
-
? listeners({ route: route as any, navigation })
|
|
785
|
-
: listeners;
|
|
786
|
-
|
|
787
|
-
return map
|
|
788
|
-
? Object.keys(map)
|
|
789
|
-
.filter((type) => type === e.type)
|
|
790
|
-
.map((type) => map?.[type])
|
|
791
|
-
: undefined;
|
|
792
|
-
})
|
|
793
|
-
)
|
|
794
|
-
// We don't want same listener to be called multiple times for same event
|
|
795
|
-
// So we remove any duplicate functions from the array
|
|
796
|
-
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
|
898
|
+
const hasPerScreenListeners = routeNames.some(
|
|
899
|
+
(name) => screens[name]?.props.listeners != null
|
|
900
|
+
);
|
|
797
901
|
|
|
798
|
-
|
|
902
|
+
if (screenListeners != null || hasPerScreenListeners) {
|
|
903
|
+
const descriptor = descriptors[route.key];
|
|
799
904
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
905
|
+
if (descriptor == null) {
|
|
906
|
+
throw new Error(`Couldn't find a descriptor for route '${route.key}'.`);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const navigation = descriptor.navigation;
|
|
910
|
+
|
|
911
|
+
const listeners = ([] as (((e: any) => void) | undefined)[])
|
|
912
|
+
.concat(
|
|
913
|
+
// Get an array of listeners for all screens + common listeners on navigator
|
|
914
|
+
...[
|
|
915
|
+
screenListeners,
|
|
916
|
+
...routeNames.map((name) => {
|
|
917
|
+
const { listeners } = screens[name]?.props ?? {};
|
|
918
|
+
return listeners;
|
|
919
|
+
}),
|
|
920
|
+
].map((listeners) => {
|
|
921
|
+
const map =
|
|
922
|
+
typeof listeners === 'function'
|
|
923
|
+
? listeners({ route: route as any, navigation })
|
|
924
|
+
: listeners;
|
|
925
|
+
|
|
926
|
+
return map
|
|
927
|
+
? Object.keys(map)
|
|
928
|
+
.filter((type) => type === e.type)
|
|
929
|
+
.map((type) => map?.[type])
|
|
930
|
+
: undefined;
|
|
931
|
+
})
|
|
932
|
+
)
|
|
933
|
+
// We don't want same listener to be called multiple times for same event
|
|
934
|
+
// So we remove any duplicate functions from the array
|
|
935
|
+
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
|
936
|
+
|
|
937
|
+
listeners.forEach((listener) => listener?.(e));
|
|
938
|
+
}
|
|
939
|
+
}, onEmitEvent);
|
|
807
940
|
|
|
808
941
|
useFocusEvents({ state, emitter });
|
|
809
942
|
|
|
@@ -837,7 +970,7 @@ export function useNavigationBuilder<
|
|
|
837
970
|
setState,
|
|
838
971
|
});
|
|
839
972
|
|
|
840
|
-
const onUnhandledActionParent = React.
|
|
973
|
+
const onUnhandledActionParent = React.use(UnhandledActionContext);
|
|
841
974
|
|
|
842
975
|
const onUnhandledAction = useLatestCallback((action: NavigationAction) => {
|
|
843
976
|
if (
|
|
@@ -873,6 +1006,31 @@ export function useNavigationBuilder<
|
|
|
873
1006
|
onUnhandledActionParent?.(action);
|
|
874
1007
|
});
|
|
875
1008
|
|
|
1009
|
+
const canGoBack = useLatestCallback((source?: string) => {
|
|
1010
|
+
const state = getState();
|
|
1011
|
+
|
|
1012
|
+
return (
|
|
1013
|
+
router.getStateForAction(
|
|
1014
|
+
state,
|
|
1015
|
+
{ ...CommonActions.goBack(), source },
|
|
1016
|
+
{
|
|
1017
|
+
routeNames: state.routeNames,
|
|
1018
|
+
routeParamList: {},
|
|
1019
|
+
routeGetIdList: {},
|
|
1020
|
+
}
|
|
1021
|
+
) !== null ||
|
|
1022
|
+
canGoBackParent?.(
|
|
1023
|
+
// If the `source` belonged to the current navigator,
|
|
1024
|
+
// rewrite the `source` to the parent screen's key when checking
|
|
1025
|
+
// This mirrors the way actions bubble up to the parent
|
|
1026
|
+
source !== undefined && state.routes.some((r) => r.key === source)
|
|
1027
|
+
? route?.key
|
|
1028
|
+
: source
|
|
1029
|
+
) ||
|
|
1030
|
+
false
|
|
1031
|
+
);
|
|
1032
|
+
});
|
|
1033
|
+
|
|
876
1034
|
const navigation = useNavigationHelpers<
|
|
877
1035
|
State,
|
|
878
1036
|
ActionHelpers,
|
|
@@ -881,10 +1039,10 @@ export function useNavigationBuilder<
|
|
|
881
1039
|
>({
|
|
882
1040
|
onAction,
|
|
883
1041
|
onUnhandledAction,
|
|
1042
|
+
canGoBack,
|
|
884
1043
|
getState,
|
|
885
1044
|
emitter,
|
|
886
1045
|
router,
|
|
887
|
-
stateRef,
|
|
888
1046
|
});
|
|
889
1047
|
|
|
890
1048
|
useFocusedListenersChildrenAdapter({
|
|
@@ -897,22 +1055,24 @@ export function useNavigationBuilder<
|
|
|
897
1055
|
getStateListeners: keyedListeners.getState,
|
|
898
1056
|
});
|
|
899
1057
|
|
|
1058
|
+
useOnGetNavigation({ navigation });
|
|
1059
|
+
|
|
900
1060
|
const descriptors = useDescriptors<
|
|
901
1061
|
State,
|
|
902
1062
|
ActionHelpers,
|
|
903
1063
|
ScreenOptions,
|
|
904
1064
|
EventMap
|
|
905
1065
|
>({
|
|
906
|
-
routes: router.getRoutesFromState
|
|
907
|
-
? router.getRoutesFromState(state)
|
|
908
|
-
: state.routes,
|
|
909
1066
|
screens,
|
|
1067
|
+
state,
|
|
910
1068
|
navigation,
|
|
911
1069
|
screenOptions,
|
|
912
1070
|
screenLayout,
|
|
913
1071
|
onAction,
|
|
1072
|
+
canGoBack,
|
|
914
1073
|
getState,
|
|
915
1074
|
setState,
|
|
1075
|
+
subscribe,
|
|
916
1076
|
onRouteFocus,
|
|
917
1077
|
addListener,
|
|
918
1078
|
addKeyedListener,
|
|
@@ -921,13 +1081,13 @@ export function useNavigationBuilder<
|
|
|
921
1081
|
emitter,
|
|
922
1082
|
});
|
|
923
1083
|
|
|
924
|
-
|
|
925
|
-
state
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1084
|
+
const render = (children: React.ReactNode) => {
|
|
1085
|
+
const focusedRoute = state.routes[state.index];
|
|
1086
|
+
|
|
1087
|
+
if (focusedRoute == null) {
|
|
1088
|
+
throw new Error(`Couldn't find a route at index ${state.index}.`);
|
|
1089
|
+
}
|
|
929
1090
|
|
|
930
|
-
const NavigationContent = useComponent((children: React.ReactNode) => {
|
|
931
1091
|
const element =
|
|
932
1092
|
layout != null
|
|
933
1093
|
? layout({
|
|
@@ -939,20 +1099,29 @@ export function useNavigationBuilder<
|
|
|
939
1099
|
: children;
|
|
940
1100
|
|
|
941
1101
|
return (
|
|
942
|
-
<
|
|
943
|
-
<
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1102
|
+
<NavigationHelpersContext.Provider value={navigation}>
|
|
1103
|
+
<NavigationStateListenerProvider
|
|
1104
|
+
isSynced={!shouldUpdate}
|
|
1105
|
+
state={state}
|
|
1106
|
+
getState={getState}
|
|
1107
|
+
subscribe={subscribe}
|
|
1108
|
+
>
|
|
1109
|
+
<FocusedRouteKeyContext.Provider value={focusedRoute.key}>
|
|
1110
|
+
<PreventRemoveProvider>
|
|
1111
|
+
<IsScreenContext.Provider value={false}>
|
|
1112
|
+
{element}
|
|
1113
|
+
</IsScreenContext.Provider>
|
|
1114
|
+
</PreventRemoveProvider>
|
|
1115
|
+
</FocusedRouteKeyContext.Provider>
|
|
1116
|
+
</NavigationStateListenerProvider>
|
|
1117
|
+
</NavigationHelpersContext.Provider>
|
|
949
1118
|
);
|
|
950
|
-
}
|
|
1119
|
+
};
|
|
951
1120
|
|
|
952
1121
|
return {
|
|
953
1122
|
state,
|
|
954
1123
|
navigation,
|
|
955
1124
|
descriptors,
|
|
956
|
-
|
|
1125
|
+
render,
|
|
957
1126
|
};
|
|
958
1127
|
}
|