@react-navigation/native 7.0.0-alpha.1 → 7.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/Link.js +13 -5
- package/lib/commonjs/Link.js.map +1 -1
- package/lib/commonjs/LinkingContext.js +7 -5
- package/lib/commonjs/LinkingContext.js.map +1 -1
- package/lib/commonjs/LocaleDirContext.js +12 -0
- package/lib/commonjs/LocaleDirContext.js.map +1 -0
- package/lib/commonjs/NavigationContainer.js +57 -19
- package/lib/commonjs/NavigationContainer.js.map +1 -1
- package/lib/commonjs/ServerContainer.js +3 -4
- package/lib/commonjs/ServerContainer.js.map +1 -1
- package/lib/commonjs/ServerContext.js +3 -4
- package/lib/commonjs/ServerContext.js.map +1 -1
- package/lib/commonjs/UnhandledLinkingContext.js +20 -0
- package/lib/commonjs/UnhandledLinkingContext.js.map +1 -0
- package/lib/commonjs/__stubs__/createStackNavigator.js +19 -0
- package/lib/commonjs/__stubs__/createStackNavigator.js.map +1 -0
- package/lib/commonjs/__stubs__/window.js +79 -0
- package/lib/commonjs/__stubs__/window.js.map +1 -0
- package/lib/commonjs/createMemoryHistory.js +4 -7
- package/lib/commonjs/createMemoryHistory.js.map +1 -1
- package/lib/commonjs/createStaticNavigation.js +6 -4
- package/lib/commonjs/createStaticNavigation.js.map +1 -1
- package/lib/commonjs/extractPathFromURL.js +3 -3
- package/lib/commonjs/extractPathFromURL.js.map +1 -1
- package/lib/commonjs/index.js +17 -17
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/theming/DarkTheme.js +1 -2
- package/lib/commonjs/theming/DarkTheme.js.map +1 -1
- package/lib/commonjs/theming/DefaultTheme.js +1 -2
- package/lib/commonjs/theming/DefaultTheme.js.map +1 -1
- package/lib/commonjs/theming/fonts.js +1 -2
- package/lib/commonjs/theming/fonts.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/useBackButton.js +3 -19
- package/lib/commonjs/useBackButton.js.map +1 -1
- package/lib/commonjs/useBackButton.native.js +27 -0
- package/lib/commonjs/useBackButton.native.js.map +1 -0
- package/lib/commonjs/useDocumentTitle.js +5 -5
- package/lib/commonjs/useDocumentTitle.js.map +1 -1
- package/lib/commonjs/useDocumentTitle.native.js.map +1 -1
- package/lib/commonjs/useLinkBuilder.js +80 -0
- package/lib/commonjs/useLinkBuilder.js.map +1 -0
- package/lib/commonjs/useLinkProps.js +20 -23
- package/lib/commonjs/useLinkProps.js.map +1 -1
- package/lib/commonjs/useLinkTo.js +30 -0
- package/lib/commonjs/useLinkTo.js.map +1 -0
- package/lib/commonjs/useLinking.js +34 -35
- package/lib/commonjs/useLinking.js.map +1 -1
- package/lib/commonjs/useLinking.native.js +30 -23
- package/lib/commonjs/useLinking.native.js.map +1 -1
- package/lib/commonjs/useLocale.js +23 -0
- package/lib/commonjs/useLocale.js.map +1 -0
- package/lib/commonjs/useScrollToTop.js +8 -6
- package/lib/commonjs/useScrollToTop.js.map +1 -1
- package/lib/commonjs/useThenable.js +3 -2
- package/lib/commonjs/useThenable.js.map +1 -1
- package/lib/commonjs/useUnhandledLinking.js +75 -0
- package/lib/commonjs/useUnhandledLinking.js.map +1 -0
- package/lib/module/Link.js +11 -3
- package/lib/module/Link.js.map +1 -1
- package/lib/module/LinkingContext.js +4 -1
- package/lib/module/LinkingContext.js.map +1 -1
- package/lib/module/LocaleDirContext.js +4 -0
- package/lib/module/LocaleDirContext.js.map +1 -0
- package/lib/module/NavigationContainer.js +53 -15
- package/lib/module/NavigationContainer.js.map +1 -1
- package/lib/module/ServerContainer.js.map +1 -1
- package/lib/module/ServerContext.js.map +1 -1
- package/lib/module/UnhandledLinkingContext.js +12 -0
- package/lib/module/UnhandledLinkingContext.js.map +1 -0
- package/lib/module/__stubs__/createStackNavigator.js +11 -0
- package/lib/module/__stubs__/createStackNavigator.js.map +1 -0
- package/lib/module/__stubs__/window.js +73 -0
- package/lib/module/__stubs__/window.js.map +1 -0
- package/lib/module/createMemoryHistory.js +4 -7
- package/lib/module/createMemoryHistory.js.map +1 -1
- package/lib/module/createStaticNavigation.js +4 -2
- package/lib/module/createStaticNavigation.js.map +1 -1
- package/lib/module/extractPathFromURL.js +3 -3
- package/lib/module/extractPathFromURL.js.map +1 -1
- package/lib/module/index.js +3 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/theming/DarkTheme.js.map +1 -1
- package/lib/module/theming/DefaultTheme.js.map +1 -1
- package/lib/module/theming/fonts.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useBackButton.js +3 -17
- package/lib/module/useBackButton.js.map +1 -1
- package/lib/module/useBackButton.native.js +19 -0
- package/lib/module/useBackButton.native.js.map +1 -0
- package/lib/module/useDocumentTitle.js +3 -3
- package/lib/module/useDocumentTitle.js.map +1 -1
- package/lib/module/useDocumentTitle.native.js.map +1 -1
- package/lib/module/{useLinkTools.js → useLinkBuilder.js} +10 -10
- package/lib/module/useLinkBuilder.js.map +1 -0
- package/lib/module/useLinkProps.js +18 -21
- package/lib/module/useLinkProps.js.map +1 -1
- package/lib/module/useLinkTo.js +23 -0
- package/lib/module/useLinkTo.js.map +1 -0
- package/lib/module/useLinking.js +31 -34
- package/lib/module/useLinking.js.map +1 -1
- package/lib/module/useLinking.native.js +28 -21
- package/lib/module/useLinking.native.js.map +1 -1
- package/lib/module/useLocale.js +16 -0
- package/lib/module/useLocale.js.map +1 -0
- package/lib/module/useScrollToTop.js +7 -5
- package/lib/module/useScrollToTop.js.map +1 -1
- package/lib/module/useThenable.js +1 -0
- package/lib/module/useThenable.js.map +1 -1
- package/lib/module/useUnhandledLinking.js +69 -0
- package/lib/module/useUnhandledLinking.js.map +1 -0
- package/lib/typescript/src/Link.d.ts +3 -3
- package/lib/typescript/src/Link.d.ts.map +1 -1
- package/lib/typescript/src/LinkingContext.d.ts +1 -1
- package/lib/typescript/src/LinkingContext.d.ts.map +1 -1
- package/lib/typescript/src/LocaleDirContext.d.ts +4 -0
- package/lib/typescript/src/LocaleDirContext.d.ts.map +1 -0
- package/lib/typescript/src/NavigationContainer.d.ts +4 -4
- package/lib/typescript/src/NavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/ServerContainer.d.ts +1 -1
- package/lib/typescript/src/ServerContainer.d.ts.map +1 -1
- package/lib/typescript/src/UnhandledLinkingContext.d.ts +6 -0
- package/lib/typescript/src/UnhandledLinkingContext.d.ts.map +1 -0
- package/lib/typescript/src/__stubs__/createStackNavigator.d.ts +32 -0
- package/lib/typescript/src/__stubs__/createStackNavigator.d.ts.map +1 -0
- package/lib/typescript/src/{__mocks__ → __stubs__}/window.d.ts +1 -1
- package/lib/typescript/src/{__mocks__ → __stubs__}/window.d.ts.map +1 -1
- package/lib/typescript/src/createStaticNavigation.d.ts +2 -2
- package/lib/typescript/src/createStaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/extractPathFromURL.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +37 -18
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useBackButton.d.ts +2 -2
- package/lib/typescript/src/useBackButton.d.ts.map +1 -1
- package/lib/typescript/src/useBackButton.native.d.ts +4 -0
- package/lib/typescript/src/useBackButton.native.d.ts.map +1 -0
- package/lib/typescript/src/useLinkBuilder.d.ts +25 -0
- package/lib/typescript/src/useLinkBuilder.d.ts.map +1 -0
- package/lib/typescript/src/useLinkProps.d.ts +2 -2
- package/lib/typescript/src/useLinkProps.d.ts.map +1 -1
- package/lib/typescript/src/useLinkTo.d.ts +6 -0
- package/lib/typescript/src/useLinkTo.d.ts.map +1 -0
- package/lib/typescript/src/useLinking.d.ts +8 -20
- package/lib/typescript/src/useLinking.d.ts.map +1 -1
- package/lib/typescript/src/useLinking.native.d.ts +4 -20
- package/lib/typescript/src/useLinking.native.d.ts.map +1 -1
- package/lib/typescript/src/useLocale.d.ts +7 -0
- package/lib/typescript/src/useLocale.d.ts.map +1 -0
- package/lib/typescript/src/useScrollToTop.d.ts.map +1 -1
- package/lib/typescript/src/useThenable.d.ts.map +1 -1
- package/lib/typescript/src/useUnhandledLinking.d.ts +7 -0
- package/lib/typescript/src/useUnhandledLinking.d.ts.map +1 -0
- package/package.json +15 -15
- package/src/Link.tsx +11 -2
- package/src/LinkingContext.tsx +8 -2
- package/src/LocaleDirContext.tsx +7 -0
- package/src/NavigationContainer.tsx +80 -24
- package/src/ServerContainer.tsx +1 -1
- package/src/UnhandledLinkingContext.tsx +18 -0
- package/src/{__mocks__ → __stubs__}/window.tsx +7 -5
- package/src/createStaticNavigation.tsx +11 -4
- package/src/extractPathFromURL.tsx +4 -1
- package/src/index.tsx +3 -3
- package/src/types.tsx +40 -18
- package/src/useBackButton.native.tsx +33 -0
- package/src/useBackButton.tsx +3 -25
- package/src/{useLinkTools.tsx → useLinkBuilder.tsx} +8 -8
- package/src/useLinkProps.tsx +20 -19
- package/src/useLinkTo.tsx +30 -0
- package/src/useLinking.native.tsx +26 -20
- package/src/useLinking.tsx +43 -41
- package/src/useLocale.tsx +18 -0
- package/src/useScrollToTop.tsx +13 -7
- package/src/useThenable.tsx +1 -0
- package/src/useUnhandledLinking.tsx +91 -0
- package/lib/commonjs/theming/ThemeContext.js +0 -14
- package/lib/commonjs/theming/ThemeContext.js.map +0 -1
- package/lib/commonjs/theming/ThemeProvider.js +0 -20
- package/lib/commonjs/theming/ThemeProvider.js.map +0 -1
- package/lib/commonjs/theming/useTheme.js +0 -15
- package/lib/commonjs/theming/useTheme.js.map +0 -1
- package/lib/commonjs/useLinkTools.js +0 -80
- package/lib/commonjs/useLinkTools.js.map +0 -1
- package/lib/module/theming/ThemeContext.js +0 -5
- package/lib/module/theming/ThemeContext.js.map +0 -1
- package/lib/module/theming/ThemeProvider.js +0 -12
- package/lib/module/theming/ThemeProvider.js.map +0 -1
- package/lib/module/theming/useTheme.js +0 -7
- package/lib/module/theming/useTheme.js.map +0 -1
- package/lib/module/useLinkTools.js.map +0 -1
- package/lib/typescript/src/__mocks__/createStackNavigator.d.ts +0 -56
- package/lib/typescript/src/__mocks__/createStackNavigator.d.ts.map +0 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts +0 -4
- package/lib/typescript/src/theming/ThemeContext.d.ts.map +0 -1
- package/lib/typescript/src/theming/ThemeProvider.d.ts +0 -9
- package/lib/typescript/src/theming/ThemeProvider.d.ts.map +0 -1
- package/lib/typescript/src/theming/useTheme.d.ts +0 -2
- package/lib/typescript/src/theming/useTheme.d.ts.map +0 -1
- package/lib/typescript/src/useLinkTools.d.ts +0 -33
- package/lib/typescript/src/useLinkTools.d.ts.map +0 -1
- package/src/theming/ThemeContext.tsx +0 -8
- package/src/theming/ThemeProvider.tsx +0 -15
- package/src/theming/useTheme.tsx +0 -9
- /package/src/{__mocks__ → __stubs__}/createStackNavigator.tsx +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NavigationContainerRef,
|
|
3
|
+
ParamListBase,
|
|
4
|
+
} from '@react-navigation/core';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { BackHandler } from 'react-native';
|
|
7
|
+
|
|
8
|
+
export function useBackButton(
|
|
9
|
+
ref: React.RefObject<NavigationContainerRef<ParamListBase>>
|
|
10
|
+
) {
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
const subscription = BackHandler.addEventListener(
|
|
13
|
+
'hardwareBackPress',
|
|
14
|
+
() => {
|
|
15
|
+
const navigation = ref.current;
|
|
16
|
+
|
|
17
|
+
if (navigation == null) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (navigation.canGoBack()) {
|
|
22
|
+
navigation.goBack();
|
|
23
|
+
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return () => subscription.remove();
|
|
32
|
+
}, [ref]);
|
|
33
|
+
}
|
package/src/useBackButton.tsx
CHANGED
|
@@ -2,32 +2,10 @@ import type {
|
|
|
2
2
|
NavigationContainerRef,
|
|
3
3
|
ParamListBase,
|
|
4
4
|
} from '@react-navigation/core';
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
import { BackHandler } from 'react-native';
|
|
7
5
|
|
|
8
6
|
export function useBackButton(
|
|
9
|
-
|
|
7
|
+
_: React.RefObject<NavigationContainerRef<ParamListBase>>
|
|
10
8
|
) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
'hardwareBackPress',
|
|
14
|
-
() => {
|
|
15
|
-
const navigation = ref.current;
|
|
16
|
-
|
|
17
|
-
if (navigation == null) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (navigation.canGoBack()) {
|
|
22
|
-
navigation.goBack();
|
|
23
|
-
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
return () => subscription.remove();
|
|
32
|
-
}, [ref]);
|
|
9
|
+
// No-op
|
|
10
|
+
// BackHandler is not available on web
|
|
33
11
|
}
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
getActionFromState,
|
|
4
4
|
getPathFromState,
|
|
5
5
|
getStateFromPath,
|
|
6
|
-
NavigationHelpers,
|
|
6
|
+
type NavigationHelpers,
|
|
7
7
|
NavigationHelpersContext,
|
|
8
|
-
NavigationProp,
|
|
9
|
-
ParamListBase,
|
|
8
|
+
type NavigationProp,
|
|
9
|
+
type ParamListBase,
|
|
10
10
|
} from '@react-navigation/core';
|
|
11
11
|
import * as React from 'react';
|
|
12
12
|
|
|
@@ -45,10 +45,10 @@ const getRootStateForNavigate = (
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
48
|
+
* Helpers to build href or action based on the linking options.
|
|
49
|
+
* @returns `buildHref` to build an `href` for screen and `buildAction` to build an action from an `href`.
|
|
50
50
|
*/
|
|
51
|
-
export function
|
|
51
|
+
export function useLinkBuilder() {
|
|
52
52
|
const navigation = React.useContext(NavigationHelpersContext);
|
|
53
53
|
const linking = React.useContext(LinkingContext);
|
|
54
54
|
|
|
@@ -84,7 +84,7 @@ export function useLinkTools() {
|
|
|
84
84
|
const buildAction = React.useCallback(
|
|
85
85
|
(href: string) => {
|
|
86
86
|
if (!href.startsWith('/')) {
|
|
87
|
-
throw new Error(`The
|
|
87
|
+
throw new Error(`The href must start with '/' (${href}).`);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
const { options } = linking;
|
|
@@ -98,7 +98,7 @@ export function useLinkTools() {
|
|
|
98
98
|
|
|
99
99
|
return action ?? CommonActions.reset(state);
|
|
100
100
|
} else {
|
|
101
|
-
throw new Error('Failed to parse the
|
|
101
|
+
throw new Error('Failed to parse the href to a navigation state.');
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
[linking]
|
package/src/useLinkProps.tsx
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPathFromState,
|
|
3
|
-
NavigationAction,
|
|
3
|
+
type NavigationAction,
|
|
4
4
|
NavigationContainerRefContext,
|
|
5
5
|
NavigationHelpersContext,
|
|
6
|
-
NavigatorScreenParams,
|
|
7
|
-
ParamListBase,
|
|
6
|
+
type NavigatorScreenParams,
|
|
7
|
+
type ParamListBase,
|
|
8
8
|
} from '@react-navigation/core';
|
|
9
9
|
import type { NavigationState, PartialState } from '@react-navigation/routers';
|
|
10
10
|
import * as React from 'react';
|
|
11
|
-
import { GestureResponderEvent, Platform } from 'react-native';
|
|
11
|
+
import { type GestureResponderEvent, Platform } from 'react-native';
|
|
12
12
|
|
|
13
13
|
import { LinkingContext } from './LinkingContext';
|
|
14
14
|
|
|
15
15
|
export type Props<
|
|
16
16
|
ParamList extends ReactNavigation.RootParamList,
|
|
17
|
-
RouteName extends keyof ParamList = keyof ParamList
|
|
17
|
+
RouteName extends keyof ParamList = keyof ParamList,
|
|
18
18
|
> =
|
|
19
19
|
| ({
|
|
20
20
|
screen: Extract<RouteName, string>;
|
|
@@ -43,7 +43,7 @@ const getStateFromParams = (
|
|
|
43
43
|
{
|
|
44
44
|
name: params.screen,
|
|
45
45
|
params: params.params,
|
|
46
|
-
// @ts-expect-error
|
|
46
|
+
// @ts-expect-error this is fine 🔥
|
|
47
47
|
state: params.screen
|
|
48
48
|
? getStateFromParams(
|
|
49
49
|
params.params as
|
|
@@ -80,19 +80,20 @@ export function useLinkProps<ParamList extends ReactNavigation.RootParamList>({
|
|
|
80
80
|
const onPress = (
|
|
81
81
|
e?: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
|
|
82
82
|
) => {
|
|
83
|
+
// @ts-expect-error: these properties exist on web, but not in React Native
|
|
84
|
+
const hasModifierKey = e.metaKey || e.altKey || e.ctrlKey || e.shiftKey; // ignore clicks with modifier keys
|
|
85
|
+
// @ts-expect-error: these properties exist on web, but not in React Native
|
|
86
|
+
const isLeftClick = e.button == null || e.button === 0; // only handle left clicks
|
|
87
|
+
const isSelfTarget = [undefined, null, '', 'self'].includes(
|
|
88
|
+
// @ts-expect-error: these properties exist on web, but not in React Native
|
|
89
|
+
e.currentTarget?.target
|
|
90
|
+
); // let browser handle "target=_blank" etc.
|
|
91
|
+
|
|
83
92
|
let shouldHandle = false;
|
|
84
93
|
|
|
85
94
|
if (Platform.OS !== 'web' || !e) {
|
|
86
|
-
shouldHandle =
|
|
87
|
-
} else if (
|
|
88
|
-
!e.defaultPrevented && // onPress prevented default
|
|
89
|
-
// @ts-expect-error: these properties exist on web, but not in React Native
|
|
90
|
-
!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys
|
|
91
|
-
// @ts-expect-error: these properties exist on web, but not in React Native
|
|
92
|
-
(e.button == null || e.button === 0) && // ignore everything but left clicks
|
|
93
|
-
// @ts-expect-error: these properties exist on web, but not in React Native
|
|
94
|
-
[undefined, null, '', 'self'].includes(e.currentTarget?.target) // let browser handle "target=_blank" etc.
|
|
95
|
-
) {
|
|
95
|
+
shouldHandle = true;
|
|
96
|
+
} else if (!hasModifierKey && isLeftClick && isSelfTarget) {
|
|
96
97
|
e.preventDefault();
|
|
97
98
|
shouldHandle = true;
|
|
98
99
|
}
|
|
@@ -109,7 +110,7 @@ export function useLinkProps<ParamList extends ReactNavigation.RootParamList>({
|
|
|
109
110
|
);
|
|
110
111
|
}
|
|
111
112
|
} else {
|
|
112
|
-
// @ts-expect-error
|
|
113
|
+
// @ts-expect-error This is already type-checked by the prop types
|
|
113
114
|
navigation?.navigate(screen, params);
|
|
114
115
|
}
|
|
115
116
|
}
|
|
@@ -126,9 +127,9 @@ export function useLinkProps<ParamList extends ReactNavigation.RootParamList>({
|
|
|
126
127
|
routes: [
|
|
127
128
|
{
|
|
128
129
|
name: screen,
|
|
129
|
-
// @ts-expect-error
|
|
130
|
+
// @ts-expect-error this is fine 🔥
|
|
130
131
|
params: params,
|
|
131
|
-
// @ts-expect-error
|
|
132
|
+
// @ts-expect-error this is fine 🔥
|
|
132
133
|
state: getStateFromParams(params),
|
|
133
134
|
},
|
|
134
135
|
],
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NavigationContainerRefContext } from '@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
|
+
* @returns function that receives the href to navigate to.
|
|
9
|
+
*/
|
|
10
|
+
export function useLinkTo() {
|
|
11
|
+
const navigation = React.useContext(NavigationContainerRefContext);
|
|
12
|
+
const { buildAction } = useLinkBuilder();
|
|
13
|
+
|
|
14
|
+
const linkTo = React.useCallback(
|
|
15
|
+
(href: string) => {
|
|
16
|
+
if (navigation === undefined) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"Couldn't find a navigation object. Is your component inside NavigationContainer?"
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const action = buildAction(href);
|
|
23
|
+
|
|
24
|
+
navigation.dispatch(action);
|
|
25
|
+
},
|
|
26
|
+
[buildAction, navigation]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
return linkTo;
|
|
30
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getActionFromState as getActionFromStateDefault,
|
|
3
3
|
getStateFromPath as getStateFromPathDefault,
|
|
4
|
-
NavigationContainerRef,
|
|
5
|
-
ParamListBase,
|
|
4
|
+
type NavigationContainerRef,
|
|
5
|
+
type ParamListBase,
|
|
6
6
|
useNavigationIndependentTree,
|
|
7
7
|
} from '@react-navigation/core';
|
|
8
8
|
import * as React from 'react';
|
|
@@ -15,7 +15,7 @@ type ResultState = ReturnType<typeof getStateFromPathDefault>;
|
|
|
15
15
|
|
|
16
16
|
type Options = LinkingOptions<ParamListBase>;
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const linkingHandlers: symbol[] = [];
|
|
19
19
|
|
|
20
20
|
export function useLinking(
|
|
21
21
|
ref: React.RefObject<NavigationContainerRef<ParamListBase>>,
|
|
@@ -27,11 +27,11 @@ export function useLinking(
|
|
|
27
27
|
getInitialURL = () =>
|
|
28
28
|
Promise.race([
|
|
29
29
|
Linking.getInitialURL(),
|
|
30
|
-
new Promise<undefined>((resolve) =>
|
|
30
|
+
new Promise<undefined>((resolve) => {
|
|
31
31
|
// Timeout in 150ms if `getInitialState` doesn't resolve
|
|
32
32
|
// Workaround for https://github.com/facebook/react-native/issues/25675
|
|
33
|
-
setTimeout(resolve, 150)
|
|
34
|
-
),
|
|
33
|
+
setTimeout(resolve, 150);
|
|
34
|
+
}),
|
|
35
35
|
]),
|
|
36
36
|
subscribe = (listener) => {
|
|
37
37
|
const callback = ({ url }: { url: string }) => listener(url);
|
|
@@ -55,7 +55,8 @@ export function useLinking(
|
|
|
55
55
|
},
|
|
56
56
|
getStateFromPath = getStateFromPathDefault,
|
|
57
57
|
getActionFromState = getActionFromStateDefault,
|
|
58
|
-
}: Options
|
|
58
|
+
}: Options,
|
|
59
|
+
onUnhandledLinking: (lastUnhandledLining: string | undefined) => void
|
|
59
60
|
) {
|
|
60
61
|
const independent = useNavigationIndependentTree();
|
|
61
62
|
|
|
@@ -140,12 +141,21 @@ export function useLinking(
|
|
|
140
141
|
if (enabledRef.current) {
|
|
141
142
|
const url = getInitialURLRef.current();
|
|
142
143
|
|
|
143
|
-
if (url != null
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
if (url != null) {
|
|
145
|
+
if (typeof url !== 'string') {
|
|
146
|
+
return url.then((url) => {
|
|
147
|
+
const state = getStateFromURL(url);
|
|
146
148
|
|
|
147
|
-
|
|
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
|
+
}
|
|
149
159
|
}
|
|
150
160
|
|
|
151
161
|
state = getStateFromURL(url);
|
|
@@ -161,7 +171,7 @@ export function useLinking(
|
|
|
161
171
|
};
|
|
162
172
|
|
|
163
173
|
return thenable as PromiseLike<ResultState | undefined>;
|
|
164
|
-
}, [getStateFromURL]);
|
|
174
|
+
}, [getStateFromURL, onUnhandledLinking, prefixes]);
|
|
165
175
|
|
|
166
176
|
React.useEffect(() => {
|
|
167
177
|
const listener = (url: string) => {
|
|
@@ -173,14 +183,10 @@ export function useLinking(
|
|
|
173
183
|
const state = navigation ? getStateFromURL(url) : undefined;
|
|
174
184
|
|
|
175
185
|
if (navigation && state) {
|
|
176
|
-
//
|
|
177
|
-
|
|
186
|
+
// If the link were handled, it gets cleared in NavigationContainer
|
|
187
|
+
onUnhandledLinking(extractPathFromURL(prefixes, url));
|
|
178
188
|
const rootState = navigation.getRootState();
|
|
179
|
-
|
|
180
189
|
if (state.routes.some((r) => !rootState?.routeNames.includes(r.name))) {
|
|
181
|
-
console.warn(
|
|
182
|
-
"The navigation state parsed from the URL contains routes not present in the root navigator. This usually means that the linking configuration doesn't match the navigation structure. See https://reactnavigation.org/docs/configuring-links for more details on how to specify a linking configuration."
|
|
183
|
-
);
|
|
184
190
|
return;
|
|
185
191
|
}
|
|
186
192
|
|
|
@@ -207,7 +213,7 @@ export function useLinking(
|
|
|
207
213
|
};
|
|
208
214
|
|
|
209
215
|
return subscribe(listener);
|
|
210
|
-
}, [enabled, getStateFromURL, ref, subscribe]);
|
|
216
|
+
}, [enabled, getStateFromURL, onUnhandledLinking, prefixes, ref, subscribe]);
|
|
211
217
|
|
|
212
218
|
return {
|
|
213
219
|
getInitialState,
|
package/src/useLinking.tsx
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
getActionFromState as getActionFromStateDefault,
|
|
4
4
|
getPathFromState as getPathFromStateDefault,
|
|
5
5
|
getStateFromPath as getStateFromPathDefault,
|
|
6
|
-
NavigationContainerRef,
|
|
7
|
-
NavigationState,
|
|
8
|
-
ParamListBase,
|
|
6
|
+
type NavigationContainerRef,
|
|
7
|
+
type NavigationState,
|
|
8
|
+
type ParamListBase,
|
|
9
9
|
useNavigationIndependentTree,
|
|
10
10
|
} from '@react-navigation/core';
|
|
11
11
|
import isEqual from 'fast-deep-equal';
|
|
@@ -60,39 +60,16 @@ const findMatchingState = <T extends NavigationState>(
|
|
|
60
60
|
/**
|
|
61
61
|
* Run async function in series as it's called.
|
|
62
62
|
*/
|
|
63
|
-
const series = (cb: () => Promise<void>) => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const callback = async () => {
|
|
69
|
-
try {
|
|
70
|
-
if (handling) {
|
|
71
|
-
// If we're currently handling a previous event, wait before handling this one
|
|
72
|
-
// Add the callback to the beginning of the queue
|
|
73
|
-
queue.unshift(callback);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
handling = true;
|
|
78
|
-
|
|
79
|
-
await cb();
|
|
80
|
-
} finally {
|
|
81
|
-
handling = false;
|
|
82
|
-
|
|
83
|
-
if (queue.length) {
|
|
84
|
-
// If we have queued items, handle the last one
|
|
85
|
-
const last = queue.pop();
|
|
86
|
-
|
|
87
|
-
last?.();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
63
|
+
export const series = (cb: () => Promise<void>) => {
|
|
64
|
+
let queue = Promise.resolve();
|
|
65
|
+
const callback = () => {
|
|
66
|
+
// eslint-disable-next-line promise/no-callback-in-promise
|
|
67
|
+
queue = queue.then(cb);
|
|
90
68
|
};
|
|
91
|
-
|
|
92
69
|
return callback;
|
|
93
70
|
};
|
|
94
71
|
|
|
95
|
-
|
|
72
|
+
const linkingHandlers: symbol[] = [];
|
|
96
73
|
|
|
97
74
|
type Options = LinkingOptions<ParamListBase>;
|
|
98
75
|
|
|
@@ -104,7 +81,8 @@ export function useLinking(
|
|
|
104
81
|
getStateFromPath = getStateFromPathDefault,
|
|
105
82
|
getPathFromState = getPathFromStateDefault,
|
|
106
83
|
getActionFromState = getActionFromStateDefault,
|
|
107
|
-
}: Options
|
|
84
|
+
}: Options,
|
|
85
|
+
onUnhandledLinking: (lastUnhandledLining: string | undefined) => void
|
|
108
86
|
) {
|
|
109
87
|
const independent = useNavigationIndependentTree();
|
|
110
88
|
|
|
@@ -163,6 +141,17 @@ export function useLinking(
|
|
|
163
141
|
getActionFromStateRef.current = getActionFromState;
|
|
164
142
|
});
|
|
165
143
|
|
|
144
|
+
const validateRoutesNotExistInRootState = React.useCallback(
|
|
145
|
+
(state: ResultState) => {
|
|
146
|
+
const navigation = ref.current;
|
|
147
|
+
const rootState = navigation?.getRootState();
|
|
148
|
+
// Make sure that the routes in the state exist in the root navigator
|
|
149
|
+
// Otherwise there's an error in the linking configuration
|
|
150
|
+
return state?.routes.some((r) => !rootState?.routeNames.includes(r.name));
|
|
151
|
+
},
|
|
152
|
+
[ref]
|
|
153
|
+
);
|
|
154
|
+
|
|
166
155
|
const server = React.useContext(ServerContext);
|
|
167
156
|
|
|
168
157
|
const getInitialState = React.useCallback(() => {
|
|
@@ -178,6 +167,9 @@ export function useLinking(
|
|
|
178
167
|
if (path) {
|
|
179
168
|
value = getStateFromPathRef.current(path, configRef.current);
|
|
180
169
|
}
|
|
170
|
+
|
|
171
|
+
// If the link were handled, it gets cleared in NavigationContainer
|
|
172
|
+
onUnhandledLinking(path);
|
|
181
173
|
}
|
|
182
174
|
|
|
183
175
|
const thenable = {
|
|
@@ -207,6 +199,8 @@ export function useLinking(
|
|
|
207
199
|
return;
|
|
208
200
|
}
|
|
209
201
|
|
|
202
|
+
const { location } = window;
|
|
203
|
+
|
|
210
204
|
const path = location.pathname + location.search;
|
|
211
205
|
const index = history.index;
|
|
212
206
|
|
|
@@ -230,14 +224,11 @@ export function useLinking(
|
|
|
230
224
|
// We should only dispatch an action when going forward
|
|
231
225
|
// Otherwise the action will likely add items to history, which would mess things up
|
|
232
226
|
if (state) {
|
|
227
|
+
// If the link were handled, it gets cleared in NavigationContainer
|
|
228
|
+
onUnhandledLinking(path);
|
|
233
229
|
// Make sure that the routes in the state exist in the root navigator
|
|
234
230
|
// Otherwise there's an error in the linking configuration
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (state.routes.some((r) => !rootState?.routeNames.includes(r.name))) {
|
|
238
|
-
console.warn(
|
|
239
|
-
"The navigation state parsed from the URL contains routes not present in the root navigator. This usually means that the linking configuration doesn't match the navigation structure. See https://reactnavigation.org/docs/configuring-links for more details on how to specify a linking configuration."
|
|
240
|
-
);
|
|
231
|
+
if (validateRoutesNotExistInRootState(state)) {
|
|
241
232
|
return;
|
|
242
233
|
}
|
|
243
234
|
|
|
@@ -272,7 +263,13 @@ export function useLinking(
|
|
|
272
263
|
navigation.resetRoot(state);
|
|
273
264
|
}
|
|
274
265
|
});
|
|
275
|
-
}, [
|
|
266
|
+
}, [
|
|
267
|
+
enabled,
|
|
268
|
+
history,
|
|
269
|
+
onUnhandledLinking,
|
|
270
|
+
ref,
|
|
271
|
+
validateRoutesNotExistInRootState,
|
|
272
|
+
]);
|
|
276
273
|
|
|
277
274
|
React.useEffect(() => {
|
|
278
275
|
if (!enabled) {
|
|
@@ -381,7 +378,12 @@ export function useLinking(
|
|
|
381
378
|
const currentIndex = history.index;
|
|
382
379
|
|
|
383
380
|
try {
|
|
384
|
-
if (
|
|
381
|
+
if (
|
|
382
|
+
nextIndex !== -1 &&
|
|
383
|
+
nextIndex < currentIndex &&
|
|
384
|
+
// We should only go back if the entry exists and it's less than current index
|
|
385
|
+
history.get(nextIndex - currentIndex)
|
|
386
|
+
) {
|
|
385
387
|
// An existing entry for this path exists and it's less than current index, go back to that
|
|
386
388
|
await history.go(nextIndex - currentIndex);
|
|
387
389
|
} else {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { LocaleDirContext } from './LocaleDirContext';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook to access the text direction specified in the `NavigationContainer`.
|
|
7
|
+
*/
|
|
8
|
+
export function useLocale() {
|
|
9
|
+
const direction = React.useContext(LocaleDirContext);
|
|
10
|
+
|
|
11
|
+
if (direction === undefined) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"Couldn't determine the text direction. Is your component inside NavigationContainer?"
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return { direction };
|
|
18
|
+
}
|
package/src/useScrollToTop.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
EventArg,
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
type EventArg,
|
|
3
|
+
NavigationContext,
|
|
4
|
+
type NavigationProp,
|
|
5
|
+
type ParamListBase,
|
|
5
6
|
useRoute,
|
|
6
7
|
} from '@react-navigation/core';
|
|
7
8
|
import * as React from 'react';
|
|
@@ -49,13 +50,18 @@ function getScrollableNode(ref: React.RefObject<ScrollableWrapper>) {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export function useScrollToTop(ref: React.RefObject<ScrollableWrapper>) {
|
|
52
|
-
const navigation =
|
|
53
|
+
const navigation = React.useContext(NavigationContext);
|
|
53
54
|
const route = useRoute();
|
|
54
55
|
|
|
56
|
+
if (navigation === undefined) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"Couldn't find a navigation object. Is your component inside NavigationContainer?"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
React.useEffect(() => {
|
|
56
|
-
|
|
63
|
+
const tabNavigations: NavigationProp<ParamListBase>[] = [];
|
|
57
64
|
let currentNavigation = navigation;
|
|
58
|
-
|
|
59
65
|
// If the screen is nested inside multiple tab navigators, we should scroll to top for any of them
|
|
60
66
|
// So we need to find all the parent tab navigators and add the listeners there
|
|
61
67
|
while (currentNavigation) {
|
|
@@ -74,7 +80,7 @@ export function useScrollToTop(ref: React.RefObject<ScrollableWrapper>) {
|
|
|
74
80
|
return tab.addListener(
|
|
75
81
|
// We don't wanna import tab types here to avoid extra deps
|
|
76
82
|
// in addition, there are multiple tab implementations
|
|
77
|
-
// @ts-expect-error
|
|
83
|
+
// @ts-expect-error the `tabPress` event is only available when navigation type is tab
|
|
78
84
|
'tabPress',
|
|
79
85
|
(e: EventArg<'tabPress', true>) => {
|
|
80
86
|
// We should scroll to top only when the screen is focused
|
package/src/useThenable.tsx
CHANGED
|
@@ -6,6 +6,7 @@ export function useThenable<T>(create: () => PromiseLike<T>) {
|
|
|
6
6
|
let initialState: [boolean, T | undefined] = [false, undefined];
|
|
7
7
|
|
|
8
8
|
// Check if our thenable is synchronous
|
|
9
|
+
// eslint-disable-next-line promise/catch-or-return, promise/always-return
|
|
9
10
|
promise.then((result) => {
|
|
10
11
|
initialState = [true, result];
|
|
11
12
|
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getStateFromPath,
|
|
3
|
+
NavigationContext,
|
|
4
|
+
type NavigationState,
|
|
5
|
+
type PartialState,
|
|
6
|
+
} from '@react-navigation/core';
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import useLatestCallback from 'use-latest-callback';
|
|
9
|
+
|
|
10
|
+
import { LinkingContext } from './LinkingContext';
|
|
11
|
+
import { UnhandledLinkingContext } from './UnhandledLinkingContext';
|
|
12
|
+
|
|
13
|
+
// FIXME: don't rely on depth only to get the navigator state
|
|
14
|
+
function extractNavigatorSpecificState(
|
|
15
|
+
_: NavigationState,
|
|
16
|
+
pathState: PartialState<NavigationState>,
|
|
17
|
+
depth: number
|
|
18
|
+
) {
|
|
19
|
+
let partialPathState: PartialState<NavigationState> | undefined = pathState;
|
|
20
|
+
|
|
21
|
+
let currentDepth = depth;
|
|
22
|
+
while (currentDepth) {
|
|
23
|
+
if (!partialPathState) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
partialPathState =
|
|
27
|
+
partialPathState.routes[partialPathState.routes.length - 1].state;
|
|
28
|
+
currentDepth--;
|
|
29
|
+
}
|
|
30
|
+
return partialPathState;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function UNSTABLE_useUnhandledLinking() {
|
|
34
|
+
const navigation = React.useContext(NavigationContext);
|
|
35
|
+
const linking = React.useContext(LinkingContext);
|
|
36
|
+
const { setLastUnhandledLink, lastUnhandledLink } = React.useContext(
|
|
37
|
+
UnhandledLinkingContext
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const { options } = linking;
|
|
41
|
+
|
|
42
|
+
const getStateForRouteNamesChange = (
|
|
43
|
+
currentState: NavigationState
|
|
44
|
+
): PartialState<NavigationState> | undefined => {
|
|
45
|
+
if (lastUnhandledLink == null) {
|
|
46
|
+
// noop, nothing to handle
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// at web, the path is already extracted
|
|
51
|
+
const path = lastUnhandledLink;
|
|
52
|
+
if (!lastUnhandledLink) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// First, we parse the URL to get the desired state
|
|
57
|
+
const getStateFromPathHelper =
|
|
58
|
+
options?.getStateFromPath ?? getStateFromPath;
|
|
59
|
+
|
|
60
|
+
const pathState = getStateFromPathHelper(path, options?.config);
|
|
61
|
+
|
|
62
|
+
if (!pathState) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let depth = 0;
|
|
67
|
+
let parent = navigation;
|
|
68
|
+
while (parent) {
|
|
69
|
+
depth++;
|
|
70
|
+
parent = parent.getParent();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const state = extractNavigatorSpecificState(currentState, pathState, depth);
|
|
74
|
+
|
|
75
|
+
if (!state) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return state;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const clearUnhandledLink = useLatestCallback(() => {
|
|
83
|
+
setLastUnhandledLink(undefined);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
lastUnhandledLink,
|
|
88
|
+
getStateForRouteNamesChange,
|
|
89
|
+
clearUnhandledLink,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.ThemeContext = void 0;
|
|
7
|
-
var React = _interopRequireWildcard(require("react"));
|
|
8
|
-
var _DefaultTheme = require("./DefaultTheme");
|
|
9
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
10
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
11
|
-
const ThemeContext = /*#__PURE__*/React.createContext(_DefaultTheme.DefaultTheme);
|
|
12
|
-
exports.ThemeContext = ThemeContext;
|
|
13
|
-
ThemeContext.displayName = 'ThemeContext';
|
|
14
|
-
//# sourceMappingURL=ThemeContext.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["ThemeContext","React","createContext","DefaultTheme","displayName"],"sourceRoot":"../../../src","sources":["theming/ThemeContext.tsx"],"mappings":";;;;;;AAAA;AAGA;AAA8C;AAAA;AAEvC,MAAMA,YAAY,gBAAGC,KAAK,CAACC,aAAa,CAAQC,0BAAY,CAAC;AAAC;AAErEH,YAAY,CAACI,WAAW,GAAG,cAAc"}
|