@amazon-devices/react-navigation__native 8.0.9000000000 → 8.0.9000000002
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/SystemModules/amzn__react-navigation__native-8.private.modules.txt +38 -33
- package/kepler-compatibility.json +4 -2
- package/lib/module/index.js +0 -19
- package/oss-attribution/attribution.txt +50 -0
- package/oss-attribution/licenseInfos.json +18 -0
- package/package.json +1 -1
- package/src/index.tsx +1 -17
- package/SystemBundles/0fc5c971c5cf41a0dab235bcc6d58e5c06d9aaff650fa9815b525f8b9bb70a03.bundle +0 -9116
- package/SystemBundles/0fc5c971c5cf41a0dab235bcc6d58e5c06d9aaff650fa9815b525f8b9bb70a03.map +0 -3543
- package/lib/module/Link.js +0 -62
- package/lib/module/LinkingContext.js +0 -11
- package/lib/module/LocaleDirContext.js +0 -6
- package/lib/module/NavigationContainer.js +0 -128
- package/lib/module/ServerContainer.js +0 -55
- package/lib/module/ServerContext.js +0 -5
- package/lib/module/UnhandledLinkingContext.js +0 -14
- package/lib/module/__stubs__/createStackNavigator.js +0 -18
- package/lib/module/__stubs__/window.js +0 -75
- package/lib/module/createMemoryHistory.js +0 -216
- package/lib/module/createStaticNavigation.js +0 -54
- package/lib/module/extractPathFromURL.js +0 -19
- package/lib/module/theming/DarkTheme.js +0 -16
- package/lib/module/theming/DefaultTheme.js +0 -16
- package/lib/module/theming/fonts.js +0 -61
- package/lib/module/types.js +0 -4
- package/lib/module/useBackButton.js +0 -7
- package/lib/module/useBackButton.native.js +0 -21
- package/lib/module/useDocumentTitle.js +0 -26
- package/lib/module/useDocumentTitle.native.js +0 -6
- package/lib/module/useLinkBuilder.js +0 -85
- package/lib/module/useLinkProps.js +0 -93
- package/lib/module/useLinkTo.js +0 -26
- package/lib/module/useLinking.js +0 -320
- package/lib/module/useLinking.native.js +0 -148
- package/lib/module/useLocale.js +0 -18
- package/lib/module/useRoutePath.js +0 -30
- package/lib/module/useScrollToTop.js +0 -91
- package/lib/module/useThenable.js +0 -36
- package/src/Link.tsx +0 -69
- package/src/LinkingContext.tsx +0 -16
- package/src/LocaleDirContext.tsx +0 -7
- package/src/NavigationContainer.tsx +0 -211
- package/src/ServerContainer.tsx +0 -57
- package/src/ServerContext.tsx +0 -12
- package/src/UnhandledLinkingContext.tsx +0 -18
- package/src/__stubs__/createStackNavigator.tsx +0 -46
- package/src/__stubs__/window.tsx +0 -77
- package/src/createMemoryHistory.tsx +0 -229
- package/src/createStaticNavigation.tsx +0 -109
- package/src/extractPathFromURL.tsx +0 -29
- package/src/theming/DarkTheme.tsx +0 -15
- package/src/theming/DefaultTheme.tsx +0 -15
- package/src/theming/fonts.tsx +0 -63
- package/src/types.tsx +0 -191
- package/src/useBackButton.native.tsx +0 -33
- package/src/useBackButton.tsx +0 -11
- package/src/useDocumentTitle.native.tsx +0 -3
- package/src/useDocumentTitle.tsx +0 -41
- package/src/useLinkBuilder.tsx +0 -127
- package/src/useLinkProps.tsx +0 -156
- package/src/useLinkTo.tsx +0 -31
- package/src/useLinking.native.tsx +0 -217
- package/src/useLinking.tsx +0 -442
- package/src/useLocale.tsx +0 -18
- package/src/useRoutePath.tsx +0 -34
- package/src/useScrollToTop.tsx +0 -120
- package/src/useThenable.tsx +0 -42
package/src/useDocumentTitle.tsx
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
NavigationContainerRef,
|
|
3
|
-
ParamListBase,
|
|
4
|
-
} from '@amazon-devices/react-navigation__core';
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
|
|
7
|
-
import type { DocumentTitleOptions } from './types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Set the document title for the active screen
|
|
11
|
-
*/
|
|
12
|
-
export function useDocumentTitle(
|
|
13
|
-
ref: React.RefObject<NavigationContainerRef<ParamListBase> | null>,
|
|
14
|
-
{
|
|
15
|
-
enabled = true,
|
|
16
|
-
formatter = (options, route) => options?.title ?? route?.name,
|
|
17
|
-
}: DocumentTitleOptions = {}
|
|
18
|
-
) {
|
|
19
|
-
React.useEffect(() => {
|
|
20
|
-
if (!enabled) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const navigation = ref.current;
|
|
25
|
-
|
|
26
|
-
if (navigation) {
|
|
27
|
-
const title = formatter(
|
|
28
|
-
navigation.getCurrentOptions(),
|
|
29
|
-
navigation.getCurrentRoute()
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
document.title = title;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return navigation?.addListener('options', (e) => {
|
|
36
|
-
const title = formatter(e.data.options, navigation?.getCurrentRoute());
|
|
37
|
-
|
|
38
|
-
document.title = title;
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
}
|
package/src/useLinkBuilder.tsx
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CommonActions,
|
|
3
|
-
findFocusedRoute,
|
|
4
|
-
getActionFromState,
|
|
5
|
-
getPathFromState,
|
|
6
|
-
getStateFromPath,
|
|
7
|
-
NavigationHelpersContext,
|
|
8
|
-
NavigationRouteContext,
|
|
9
|
-
useStateForPath,
|
|
10
|
-
} from '@amazon-devices/react-navigation__core';
|
|
11
|
-
import * as React from 'react';
|
|
12
|
-
|
|
13
|
-
import { LinkingContext } from './LinkingContext';
|
|
14
|
-
|
|
15
|
-
type MinimalState = {
|
|
16
|
-
routes: [{ name: string; params?: object; state?: MinimalState }];
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Helpers to build href or action based on the linking options.
|
|
21
|
-
*
|
|
22
|
-
* @returns `buildHref` to build an `href` for screen and `buildAction` to build an action from an `href`.
|
|
23
|
-
*/
|
|
24
|
-
export function useLinkBuilder() {
|
|
25
|
-
const navigation = React.useContext(NavigationHelpersContext);
|
|
26
|
-
const route = React.useContext(NavigationRouteContext);
|
|
27
|
-
|
|
28
|
-
const { options } = React.useContext(LinkingContext);
|
|
29
|
-
|
|
30
|
-
const focusedRouteState = useStateForPath();
|
|
31
|
-
|
|
32
|
-
const getPathFromStateHelper = options?.getPathFromState ?? getPathFromState;
|
|
33
|
-
const getStateFromPathHelper = options?.getStateFromPath ?? getStateFromPath;
|
|
34
|
-
const getActionFromStateHelper =
|
|
35
|
-
options?.getActionFromState ?? getActionFromState;
|
|
36
|
-
|
|
37
|
-
const buildHref = React.useCallback(
|
|
38
|
-
(name: string, params?: object) => {
|
|
39
|
-
if (options?.enabled === false) {
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Check that we're inside:
|
|
44
|
-
// - navigator's context
|
|
45
|
-
// - route context of the navigator (could be a screen, tab, etc.)
|
|
46
|
-
// - route matches the state for path (from the screen's context)
|
|
47
|
-
// This ensures that we're inside a screen
|
|
48
|
-
const isScreen =
|
|
49
|
-
navigation && route?.key && focusedRouteState
|
|
50
|
-
? route.key === findFocusedRoute(focusedRouteState)?.key &&
|
|
51
|
-
navigation.getState().routes.some((r) => r.key === route.key)
|
|
52
|
-
: false;
|
|
53
|
-
|
|
54
|
-
const stateForRoute: MinimalState = {
|
|
55
|
-
routes: [{ name, params }],
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const constructState = (
|
|
59
|
-
state: MinimalState | undefined
|
|
60
|
-
): MinimalState => {
|
|
61
|
-
if (state) {
|
|
62
|
-
const route = state.routes[0];
|
|
63
|
-
|
|
64
|
-
// If we're inside a screen and at the innermost route
|
|
65
|
-
// We need to replace the state with the provided one
|
|
66
|
-
// This assumes that we're navigating to a sibling route
|
|
67
|
-
if (isScreen && !route.state) {
|
|
68
|
-
return stateForRoute;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Otherwise, dive into the nested state of the route
|
|
72
|
-
return {
|
|
73
|
-
routes: [
|
|
74
|
-
{
|
|
75
|
-
...route,
|
|
76
|
-
state: constructState(route.state),
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Once there is no more nested state, we're at the innermost route
|
|
83
|
-
// We can add a state based on provided parameters
|
|
84
|
-
// This assumes that we're navigating to a child of this route
|
|
85
|
-
// In this case, the helper is used in a navigator for its routes
|
|
86
|
-
return stateForRoute;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const state = constructState(focusedRouteState);
|
|
90
|
-
const path = getPathFromStateHelper(state, options?.config);
|
|
91
|
-
|
|
92
|
-
return path;
|
|
93
|
-
},
|
|
94
|
-
[
|
|
95
|
-
options?.enabled,
|
|
96
|
-
options?.config,
|
|
97
|
-
route?.key,
|
|
98
|
-
navigation,
|
|
99
|
-
focusedRouteState,
|
|
100
|
-
getPathFromStateHelper,
|
|
101
|
-
]
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
const buildAction = React.useCallback(
|
|
105
|
-
(href: string) => {
|
|
106
|
-
if (!href.startsWith('/')) {
|
|
107
|
-
throw new Error(`The href must start with '/' (${href}).`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const state = getStateFromPathHelper(href, options?.config);
|
|
111
|
-
|
|
112
|
-
if (state) {
|
|
113
|
-
const action = getActionFromStateHelper(state, options?.config);
|
|
114
|
-
|
|
115
|
-
return action ?? CommonActions.reset(state);
|
|
116
|
-
} else {
|
|
117
|
-
throw new Error('Failed to parse the href to a navigation state.');
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
[options?.config, getStateFromPathHelper, getActionFromStateHelper]
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
buildHref,
|
|
125
|
-
buildAction,
|
|
126
|
-
};
|
|
127
|
-
}
|
package/src/useLinkProps.tsx
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getPathFromState,
|
|
3
|
-
type NavigationAction,
|
|
4
|
-
NavigationContainerRefContext,
|
|
5
|
-
NavigationHelpersContext,
|
|
6
|
-
type NavigatorScreenParams,
|
|
7
|
-
type ParamListBase,
|
|
8
|
-
} from '@amazon-devices/react-navigation__core';
|
|
9
|
-
import type { NavigationState, PartialState } from '@amazon-devices/react-navigation__routers';
|
|
10
|
-
import * as React from 'react';
|
|
11
|
-
import { type GestureResponderEvent, Platform } from 'react-native';
|
|
12
|
-
|
|
13
|
-
import { LinkingContext } from './LinkingContext';
|
|
14
|
-
|
|
15
|
-
export type LinkProps<
|
|
16
|
-
ParamList extends ReactNavigation.RootParamList,
|
|
17
|
-
RouteName extends keyof ParamList = keyof ParamList,
|
|
18
|
-
> =
|
|
19
|
-
| ({
|
|
20
|
-
href?: string;
|
|
21
|
-
action?: NavigationAction;
|
|
22
|
-
} & {
|
|
23
|
-
[Screen in keyof ParamList]: undefined extends ParamList[Screen]
|
|
24
|
-
? { screen: Screen; params?: ParamList[Screen] }
|
|
25
|
-
: { screen: Screen; params: ParamList[Screen] };
|
|
26
|
-
}[RouteName])
|
|
27
|
-
| {
|
|
28
|
-
href?: string;
|
|
29
|
-
action: NavigationAction;
|
|
30
|
-
screen?: undefined;
|
|
31
|
-
params?: undefined;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const getStateFromParams = (
|
|
35
|
-
params: NavigatorScreenParams<ParamListBase> | undefined
|
|
36
|
-
): PartialState<NavigationState> | NavigationState | undefined => {
|
|
37
|
-
if (params?.state) {
|
|
38
|
-
return params.state;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (params?.screen) {
|
|
42
|
-
return {
|
|
43
|
-
routes: [
|
|
44
|
-
{
|
|
45
|
-
name: params.screen,
|
|
46
|
-
params: params.params,
|
|
47
|
-
// @ts-expect-error this is fine 🔥
|
|
48
|
-
state: params.screen
|
|
49
|
-
? getStateFromParams(
|
|
50
|
-
params.params as
|
|
51
|
-
| NavigatorScreenParams<ParamListBase>
|
|
52
|
-
| undefined
|
|
53
|
-
)
|
|
54
|
-
: undefined,
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return undefined;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Hook to get props for an anchor tag so it can work with in page navigation.
|
|
65
|
-
*
|
|
66
|
-
* @param props.screen Name of the screen to navigate to (e.g. `'Feeds'`).
|
|
67
|
-
* @param props.params Params to pass to the screen to navigate to (e.g. `{ sort: 'hot' }`).
|
|
68
|
-
* @param props.href Optional absolute path to use for the href (e.g. `/feeds/hot`).
|
|
69
|
-
* @param props.action Optional action to use for in-page navigation. By default, the path is parsed to an action based on linking config.
|
|
70
|
-
*/
|
|
71
|
-
export function useLinkProps<ParamList extends ReactNavigation.RootParamList>({
|
|
72
|
-
screen,
|
|
73
|
-
params,
|
|
74
|
-
href,
|
|
75
|
-
action,
|
|
76
|
-
}: LinkProps<ParamList>) {
|
|
77
|
-
const root = React.useContext(NavigationContainerRefContext);
|
|
78
|
-
const navigation = React.useContext(NavigationHelpersContext);
|
|
79
|
-
const { options } = React.useContext(LinkingContext);
|
|
80
|
-
|
|
81
|
-
const onPress = (
|
|
82
|
-
e?: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
|
|
83
|
-
) => {
|
|
84
|
-
let shouldHandle = false;
|
|
85
|
-
|
|
86
|
-
if (Platform.OS !== 'web' || !e) {
|
|
87
|
-
e?.preventDefault?.();
|
|
88
|
-
shouldHandle = true;
|
|
89
|
-
} else {
|
|
90
|
-
// ignore clicks with modifier keys
|
|
91
|
-
const hasModifierKey =
|
|
92
|
-
('metaKey' in e && e.metaKey) ||
|
|
93
|
-
('altKey' in e && e.altKey) ||
|
|
94
|
-
('ctrlKey' in e && e.ctrlKey) ||
|
|
95
|
-
('shiftKey' in e && e.shiftKey);
|
|
96
|
-
|
|
97
|
-
// only handle left clicks
|
|
98
|
-
const isLeftClick =
|
|
99
|
-
'button' in e ? e.button == null || e.button === 0 : true;
|
|
100
|
-
|
|
101
|
-
// let browser handle "target=_blank" etc.
|
|
102
|
-
const isSelfTarget =
|
|
103
|
-
e.currentTarget && 'target' in e.currentTarget
|
|
104
|
-
? [undefined, null, '', 'self'].includes(e.currentTarget.target)
|
|
105
|
-
: true;
|
|
106
|
-
|
|
107
|
-
if (!hasModifierKey && isLeftClick && isSelfTarget) {
|
|
108
|
-
e.preventDefault?.();
|
|
109
|
-
shouldHandle = true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (shouldHandle) {
|
|
114
|
-
if (action) {
|
|
115
|
-
if (navigation) {
|
|
116
|
-
navigation.dispatch(action);
|
|
117
|
-
} else if (root) {
|
|
118
|
-
root.dispatch(action);
|
|
119
|
-
} else {
|
|
120
|
-
throw new Error(
|
|
121
|
-
"Couldn't find a navigation object. Is your component inside NavigationContainer?"
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
} else {
|
|
125
|
-
// @ts-expect-error This is already type-checked by the prop types
|
|
126
|
-
navigation?.navigate(screen, params);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const getPathFromStateHelper = options?.getPathFromState ?? getPathFromState;
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
href:
|
|
135
|
-
href ??
|
|
136
|
-
(Platform.OS === 'web' && screen != null
|
|
137
|
-
? getPathFromStateHelper(
|
|
138
|
-
{
|
|
139
|
-
routes: [
|
|
140
|
-
{
|
|
141
|
-
// @ts-expect-error this is fine 🔥
|
|
142
|
-
name: screen,
|
|
143
|
-
// @ts-expect-error this is fine 🔥
|
|
144
|
-
params: params,
|
|
145
|
-
// @ts-expect-error this is fine 🔥
|
|
146
|
-
state: getStateFromParams(params),
|
|
147
|
-
},
|
|
148
|
-
],
|
|
149
|
-
},
|
|
150
|
-
options?.config
|
|
151
|
-
)
|
|
152
|
-
: undefined),
|
|
153
|
-
role: 'link' as const,
|
|
154
|
-
onPress,
|
|
155
|
-
};
|
|
156
|
-
}
|
package/src/useLinkTo.tsx
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { NavigationContainerRefContext } from '@amazon-devices/react-navigation__core';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
|
|
4
|
-
import { useLinkBuilder } from './useLinkBuilder';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Helper to navigate to a screen using a href based on the linking options.
|
|
8
|
-
*
|
|
9
|
-
* @returns function that receives the href to navigate to.
|
|
10
|
-
*/
|
|
11
|
-
export function useLinkTo() {
|
|
12
|
-
const navigation = React.useContext(NavigationContainerRefContext);
|
|
13
|
-
const { buildAction } = useLinkBuilder();
|
|
14
|
-
|
|
15
|
-
const linkTo = React.useCallback(
|
|
16
|
-
(href: string) => {
|
|
17
|
-
if (navigation === undefined) {
|
|
18
|
-
throw new Error(
|
|
19
|
-
"Couldn't find a navigation object. Is your component inside NavigationContainer?"
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const action = buildAction(href);
|
|
24
|
-
|
|
25
|
-
navigation.dispatch(action);
|
|
26
|
-
},
|
|
27
|
-
[buildAction, navigation]
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
return linkTo;
|
|
31
|
-
}
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getActionFromState as getActionFromStateDefault,
|
|
3
|
-
getStateFromPath as getStateFromPathDefault,
|
|
4
|
-
type NavigationContainerRef,
|
|
5
|
-
type ParamListBase,
|
|
6
|
-
useNavigationIndependentTree,
|
|
7
|
-
} from '@amazon-devices/react-navigation__core';
|
|
8
|
-
import * as React from 'react';
|
|
9
|
-
import { Linking, Platform } from 'react-native';
|
|
10
|
-
|
|
11
|
-
import { extractPathFromURL } from './extractPathFromURL';
|
|
12
|
-
import type { LinkingOptions } from './types';
|
|
13
|
-
|
|
14
|
-
type ResultState = ReturnType<typeof getStateFromPathDefault>;
|
|
15
|
-
|
|
16
|
-
type Options = LinkingOptions<ParamListBase>;
|
|
17
|
-
|
|
18
|
-
const linkingHandlers: symbol[] = [];
|
|
19
|
-
|
|
20
|
-
export function useLinking(
|
|
21
|
-
ref: React.RefObject<NavigationContainerRef<ParamListBase> | null>,
|
|
22
|
-
{
|
|
23
|
-
enabled = true,
|
|
24
|
-
prefixes,
|
|
25
|
-
filter,
|
|
26
|
-
config,
|
|
27
|
-
getInitialURL = () =>
|
|
28
|
-
Promise.race([
|
|
29
|
-
Linking.getInitialURL(),
|
|
30
|
-
new Promise<undefined>((resolve) => {
|
|
31
|
-
// Timeout in 150ms if `getInitialState` doesn't resolve
|
|
32
|
-
// Workaround for https://github.com/facebook/react-native/issues/25675
|
|
33
|
-
setTimeout(resolve, 150);
|
|
34
|
-
}),
|
|
35
|
-
]),
|
|
36
|
-
subscribe = (listener) => {
|
|
37
|
-
const callback = ({ url }: { url: string }) => listener(url);
|
|
38
|
-
|
|
39
|
-
const subscription = Linking.addEventListener('url', callback) as
|
|
40
|
-
| { remove(): void }
|
|
41
|
-
| undefined;
|
|
42
|
-
|
|
43
|
-
// Storing this in a local variable stops Jest from complaining about import after teardown
|
|
44
|
-
// @ts-expect-error: removeEventListener is not present in newer RN versions
|
|
45
|
-
const removeEventListener = Linking.removeEventListener?.bind(Linking);
|
|
46
|
-
|
|
47
|
-
return () => {
|
|
48
|
-
// https://github.com/facebook/react-native/commit/6d1aca806cee86ad76de771ed3a1cc62982ebcd7
|
|
49
|
-
if (subscription?.remove) {
|
|
50
|
-
subscription.remove();
|
|
51
|
-
} else {
|
|
52
|
-
removeEventListener?.('url', callback);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
},
|
|
56
|
-
getStateFromPath = getStateFromPathDefault,
|
|
57
|
-
getActionFromState = getActionFromStateDefault,
|
|
58
|
-
}: Options,
|
|
59
|
-
onUnhandledLinking: (lastUnhandledLining: string | undefined) => void
|
|
60
|
-
) {
|
|
61
|
-
const independent = useNavigationIndependentTree();
|
|
62
|
-
|
|
63
|
-
React.useEffect(() => {
|
|
64
|
-
if (process.env.NODE_ENV === 'production') {
|
|
65
|
-
return undefined;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (independent) {
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (enabled !== false && linkingHandlers.length) {
|
|
73
|
-
console.error(
|
|
74
|
-
[
|
|
75
|
-
'Looks like you have configured linking in multiple places. This is likely an error since deep links should only be handled in one place to avoid conflicts. Make sure that:',
|
|
76
|
-
"- You don't have multiple NavigationContainers in the app each with 'linking' enabled",
|
|
77
|
-
'- Only a single instance of the root component is rendered',
|
|
78
|
-
Platform.OS === 'android'
|
|
79
|
-
? "- You have set 'android:launchMode=singleTask' in the '<activity />' section of the 'AndroidManifest.xml' file to avoid launching multiple instances"
|
|
80
|
-
: '',
|
|
81
|
-
]
|
|
82
|
-
.join('\n')
|
|
83
|
-
.trim()
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const handler = Symbol();
|
|
88
|
-
|
|
89
|
-
if (enabled !== false) {
|
|
90
|
-
linkingHandlers.push(handler);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return () => {
|
|
94
|
-
const index = linkingHandlers.indexOf(handler);
|
|
95
|
-
|
|
96
|
-
if (index > -1) {
|
|
97
|
-
linkingHandlers.splice(index, 1);
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
}, [enabled, independent]);
|
|
101
|
-
|
|
102
|
-
// We store these options in ref to avoid re-creating getInitialState and re-subscribing listeners
|
|
103
|
-
// This lets user avoid wrapping the items in `React.useCallback` or `React.useMemo`
|
|
104
|
-
// Not re-creating `getInitialState` is important coz it makes it easier for the user to use in an effect
|
|
105
|
-
const enabledRef = React.useRef(enabled);
|
|
106
|
-
const prefixesRef = React.useRef(prefixes);
|
|
107
|
-
const filterRef = React.useRef(filter);
|
|
108
|
-
const configRef = React.useRef(config);
|
|
109
|
-
const getInitialURLRef = React.useRef(getInitialURL);
|
|
110
|
-
const getStateFromPathRef = React.useRef(getStateFromPath);
|
|
111
|
-
const getActionFromStateRef = React.useRef(getActionFromState);
|
|
112
|
-
|
|
113
|
-
React.useEffect(() => {
|
|
114
|
-
enabledRef.current = enabled;
|
|
115
|
-
prefixesRef.current = prefixes;
|
|
116
|
-
filterRef.current = filter;
|
|
117
|
-
configRef.current = config;
|
|
118
|
-
getInitialURLRef.current = getInitialURL;
|
|
119
|
-
getStateFromPathRef.current = getStateFromPath;
|
|
120
|
-
getActionFromStateRef.current = getActionFromState;
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const getStateFromURL = React.useCallback(
|
|
124
|
-
(url: string | null | undefined) => {
|
|
125
|
-
if (!url || (filterRef.current && !filterRef.current(url))) {
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const path = extractPathFromURL(prefixesRef.current, url);
|
|
130
|
-
|
|
131
|
-
return path !== undefined
|
|
132
|
-
? getStateFromPathRef.current(path, configRef.current)
|
|
133
|
-
: undefined;
|
|
134
|
-
},
|
|
135
|
-
[]
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
const getInitialState = React.useCallback(() => {
|
|
139
|
-
let state: ResultState | undefined;
|
|
140
|
-
|
|
141
|
-
if (enabledRef.current) {
|
|
142
|
-
const url = getInitialURLRef.current();
|
|
143
|
-
|
|
144
|
-
if (url != null) {
|
|
145
|
-
if (typeof url !== 'string') {
|
|
146
|
-
return url.then((url) => {
|
|
147
|
-
const state = getStateFromURL(url);
|
|
148
|
-
|
|
149
|
-
if (typeof url === 'string') {
|
|
150
|
-
// If the link were handled, it gets cleared in NavigationContainer
|
|
151
|
-
onUnhandledLinking(extractPathFromURL(prefixes, url));
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return state;
|
|
155
|
-
});
|
|
156
|
-
} else {
|
|
157
|
-
onUnhandledLinking(extractPathFromURL(prefixes, url));
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
state = getStateFromURL(url);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const thenable = {
|
|
165
|
-
then(onfulfilled?: (state: ResultState | undefined) => void) {
|
|
166
|
-
return Promise.resolve(onfulfilled ? onfulfilled(state) : state);
|
|
167
|
-
},
|
|
168
|
-
catch() {
|
|
169
|
-
return thenable;
|
|
170
|
-
},
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
return thenable as PromiseLike<ResultState | undefined>;
|
|
174
|
-
}, [getStateFromURL, onUnhandledLinking, prefixes]);
|
|
175
|
-
|
|
176
|
-
React.useEffect(() => {
|
|
177
|
-
const listener = (url: string) => {
|
|
178
|
-
if (!enabled) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const navigation = ref.current;
|
|
183
|
-
const state = navigation ? getStateFromURL(url) : undefined;
|
|
184
|
-
|
|
185
|
-
if (navigation && state) {
|
|
186
|
-
// If the link were handled, it gets cleared in NavigationContainer
|
|
187
|
-
onUnhandledLinking(extractPathFromURL(prefixes, url));
|
|
188
|
-
|
|
189
|
-
const action = getActionFromStateRef.current(state, configRef.current);
|
|
190
|
-
|
|
191
|
-
if (action !== undefined) {
|
|
192
|
-
try {
|
|
193
|
-
navigation.dispatch(action);
|
|
194
|
-
} catch (e) {
|
|
195
|
-
// Ignore any errors from deep linking.
|
|
196
|
-
// This could happen in case of malformed links, navigation object not being initialized etc.
|
|
197
|
-
console.warn(
|
|
198
|
-
`An error occurred when trying to handle the link '${url}': ${
|
|
199
|
-
typeof e === 'object' && e != null && 'message' in e
|
|
200
|
-
? e.message
|
|
201
|
-
: e
|
|
202
|
-
}`
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
} else {
|
|
206
|
-
navigation.resetRoot(state);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
return subscribe(listener);
|
|
212
|
-
}, [enabled, getStateFromURL, onUnhandledLinking, prefixes, ref, subscribe]);
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
getInitialState,
|
|
216
|
-
};
|
|
217
|
-
}
|