1 | import {
|
2 | BaseNavigationContainer,
|
3 | getActionFromState,
|
4 | getPathFromState,
|
5 | getStateFromPath,
|
6 | NavigationContainerProps,
|
7 | NavigationContainerRef,
|
8 | ParamListBase,
|
9 | validatePathConfig,
|
10 | } from '@react-navigation/core';
|
11 | import * as React from 'react';
|
12 |
|
13 | import LinkingContext from './LinkingContext';
|
14 | import DefaultTheme from './theming/DefaultTheme';
|
15 | import ThemeProvider from './theming/ThemeProvider';
|
16 | import type { DocumentTitleOptions, LinkingOptions, Theme } from './types';
|
17 | import useBackButton from './useBackButton';
|
18 | import useDocumentTitle from './useDocumentTitle';
|
19 | import useLinking from './useLinking';
|
20 | import useThenable from './useThenable';
|
21 |
|
22 | declare global {
|
23 | var REACT_NAVIGATION_DEVTOOLS: WeakMap<
|
24 | NavigationContainerRef<any>,
|
25 | { readonly linking: LinkingOptions<any> }
|
26 | >;
|
27 | }
|
28 |
|
29 | global.REACT_NAVIGATION_DEVTOOLS = new WeakMap();
|
30 |
|
31 | type Props<ParamList extends {}> = NavigationContainerProps & {
|
32 | theme?: Theme;
|
33 | linking?: LinkingOptions<ParamList>;
|
34 | fallback?: React.ReactNode;
|
35 | documentTitle?: DocumentTitleOptions;
|
36 | onReady?: () => void;
|
37 | };
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | function NavigationContainerInner(
|
54 | {
|
55 | theme = DefaultTheme,
|
56 | linking,
|
57 | fallback = null,
|
58 | documentTitle,
|
59 | onReady,
|
60 | ...rest
|
61 | }: Props<ParamListBase>,
|
62 | ref?: React.Ref<NavigationContainerRef<ParamListBase> | null>
|
63 | ) {
|
64 | const isLinkingEnabled = linking ? linking.enabled !== false : false;
|
65 |
|
66 | if (linking?.config) {
|
67 | validatePathConfig(linking.config);
|
68 | }
|
69 |
|
70 | const refContainer =
|
71 | React.useRef<NavigationContainerRef<ParamListBase>>(null);
|
72 |
|
73 | useBackButton(refContainer);
|
74 | useDocumentTitle(refContainer, documentTitle);
|
75 |
|
76 | const { getInitialState } = useLinking(refContainer, {
|
77 | independent: rest.independent,
|
78 | enabled: isLinkingEnabled,
|
79 | prefixes: [],
|
80 | ...linking,
|
81 | });
|
82 |
|
83 |
|
84 |
|
85 | React.useEffect(() => {
|
86 | if (refContainer.current) {
|
87 | REACT_NAVIGATION_DEVTOOLS.set(refContainer.current, {
|
88 | get linking() {
|
89 | return {
|
90 | ...linking,
|
91 | enabled: isLinkingEnabled,
|
92 | prefixes: linking?.prefixes ?? [],
|
93 | getStateFromPath: linking?.getStateFromPath ?? getStateFromPath,
|
94 | getPathFromState: linking?.getPathFromState ?? getPathFromState,
|
95 | getActionFromState:
|
96 | linking?.getActionFromState ?? getActionFromState,
|
97 | };
|
98 | },
|
99 | });
|
100 | }
|
101 | });
|
102 |
|
103 | const [isResolved, initialState] = useThenable(getInitialState);
|
104 |
|
105 | React.useImperativeHandle(ref, () => refContainer.current);
|
106 |
|
107 | const linkingContext = React.useMemo(() => ({ options: linking }), [linking]);
|
108 |
|
109 | const isReady = rest.initialState != null || !isLinkingEnabled || isResolved;
|
110 |
|
111 | const onReadyRef = React.useRef(onReady);
|
112 |
|
113 | React.useEffect(() => {
|
114 | onReadyRef.current = onReady;
|
115 | });
|
116 |
|
117 | React.useEffect(() => {
|
118 | if (isReady) {
|
119 | onReadyRef.current?.();
|
120 | }
|
121 | }, [isReady]);
|
122 |
|
123 | if (!isReady) {
|
124 |
|
125 |
|
126 | return fallback as React.ReactElement;
|
127 | }
|
128 |
|
129 | return (
|
130 | <LinkingContext.Provider value={linkingContext}>
|
131 | <ThemeProvider value={theme}>
|
132 | <BaseNavigationContainer
|
133 | {...rest}
|
134 | initialState={
|
135 | rest.initialState == null ? initialState : rest.initialState
|
136 | }
|
137 | ref={refContainer}
|
138 | />
|
139 | </ThemeProvider>
|
140 | </LinkingContext.Provider>
|
141 | );
|
142 | }
|
143 |
|
144 | const NavigationContainer = React.forwardRef(NavigationContainerInner) as <
|
145 | RootParamList extends {} = ReactNavigation.RootParamList
|
146 | >(
|
147 | props: Props<RootParamList> & {
|
148 | ref?: React.Ref<NavigationContainerRef<RootParamList>>;
|
149 | }
|
150 | ) => React.ReactElement;
|
151 |
|
152 | export default NavigationContainer;
|