@react-navigation/native 7.0.0-alpha.4 → 7.0.0-alpha.6

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.
Files changed (157) hide show
  1. package/lib/commonjs/Link.js +13 -5
  2. package/lib/commonjs/Link.js.map +1 -1
  3. package/lib/commonjs/LinkingContext.js +7 -5
  4. package/lib/commonjs/LinkingContext.js.map +1 -1
  5. package/lib/commonjs/LocaleDirContext.js +3 -4
  6. package/lib/commonjs/LocaleDirContext.js.map +1 -1
  7. package/lib/commonjs/NavigationContainer.js +48 -14
  8. package/lib/commonjs/NavigationContainer.js.map +1 -1
  9. package/lib/commonjs/ServerContainer.js +3 -4
  10. package/lib/commonjs/ServerContainer.js.map +1 -1
  11. package/lib/commonjs/ServerContext.js +3 -4
  12. package/lib/commonjs/ServerContext.js.map +1 -1
  13. package/lib/commonjs/UnhandledLinkingContext.js +20 -0
  14. package/lib/commonjs/UnhandledLinkingContext.js.map +1 -0
  15. package/lib/commonjs/__stubs__/createStackNavigator.js +19 -0
  16. package/lib/commonjs/__stubs__/createStackNavigator.js.map +1 -0
  17. package/lib/commonjs/__stubs__/window.js +79 -0
  18. package/lib/commonjs/__stubs__/window.js.map +1 -0
  19. package/lib/commonjs/createMemoryHistory.js +4 -7
  20. package/lib/commonjs/createMemoryHistory.js.map +1 -1
  21. package/lib/commonjs/createStaticNavigation.js +2 -2
  22. package/lib/commonjs/createStaticNavigation.js.map +1 -1
  23. package/lib/commonjs/extractPathFromURL.js +1 -2
  24. package/lib/commonjs/extractPathFromURL.js.map +1 -1
  25. package/lib/commonjs/index.js +9 -1
  26. package/lib/commonjs/index.js.map +1 -1
  27. package/lib/commonjs/theming/DarkTheme.js +1 -2
  28. package/lib/commonjs/theming/DarkTheme.js.map +1 -1
  29. package/lib/commonjs/theming/DefaultTheme.js +1 -2
  30. package/lib/commonjs/theming/DefaultTheme.js.map +1 -1
  31. package/lib/commonjs/theming/ThemeContext.js +3 -4
  32. package/lib/commonjs/theming/ThemeContext.js.map +1 -1
  33. package/lib/commonjs/theming/ThemeProvider.js +2 -2
  34. package/lib/commonjs/theming/ThemeProvider.js.map +1 -1
  35. package/lib/commonjs/theming/fonts.js +1 -2
  36. package/lib/commonjs/theming/fonts.js.map +1 -1
  37. package/lib/commonjs/theming/useTheme.js +2 -2
  38. package/lib/commonjs/theming/useTheme.js.map +1 -1
  39. package/lib/commonjs/types.js.map +1 -1
  40. package/lib/commonjs/useBackButton.js.map +1 -1
  41. package/lib/commonjs/useBackButton.native.js +2 -2
  42. package/lib/commonjs/useBackButton.native.js.map +1 -1
  43. package/lib/commonjs/useDocumentTitle.js +5 -5
  44. package/lib/commonjs/useDocumentTitle.js.map +1 -1
  45. package/lib/commonjs/useDocumentTitle.native.js.map +1 -1
  46. package/lib/commonjs/useLinkProps.js +20 -23
  47. package/lib/commonjs/useLinkProps.js.map +1 -1
  48. package/lib/commonjs/useLinkTools.js +6 -6
  49. package/lib/commonjs/useLinkTools.js.map +1 -1
  50. package/lib/commonjs/useLinking.js +26 -13
  51. package/lib/commonjs/useLinking.js.map +1 -1
  52. package/lib/commonjs/useLinking.native.js +30 -23
  53. package/lib/commonjs/useLinking.native.js.map +1 -1
  54. package/lib/commonjs/useLocale.js +2 -2
  55. package/lib/commonjs/useLocale.js.map +1 -1
  56. package/lib/commonjs/useScrollToTop.js +4 -4
  57. package/lib/commonjs/useScrollToTop.js.map +1 -1
  58. package/lib/commonjs/useThenable.js +3 -2
  59. package/lib/commonjs/useThenable.js.map +1 -1
  60. package/lib/commonjs/useUnhandledLinking.js +74 -0
  61. package/lib/commonjs/useUnhandledLinking.js.map +1 -0
  62. package/lib/module/Link.js +11 -3
  63. package/lib/module/Link.js.map +1 -1
  64. package/lib/module/LinkingContext.js +4 -1
  65. package/lib/module/LinkingContext.js.map +1 -1
  66. package/lib/module/LocaleDirContext.js.map +1 -1
  67. package/lib/module/NavigationContainer.js +44 -10
  68. package/lib/module/NavigationContainer.js.map +1 -1
  69. package/lib/module/ServerContainer.js.map +1 -1
  70. package/lib/module/ServerContext.js.map +1 -1
  71. package/lib/module/UnhandledLinkingContext.js +12 -0
  72. package/lib/module/UnhandledLinkingContext.js.map +1 -0
  73. package/lib/module/__stubs__/createStackNavigator.js +11 -0
  74. package/lib/module/__stubs__/createStackNavigator.js.map +1 -0
  75. package/lib/module/__stubs__/window.js +73 -0
  76. package/lib/module/__stubs__/window.js.map +1 -0
  77. package/lib/module/createMemoryHistory.js +4 -7
  78. package/lib/module/createMemoryHistory.js.map +1 -1
  79. package/lib/module/createStaticNavigation.js.map +1 -1
  80. package/lib/module/extractPathFromURL.js +1 -2
  81. package/lib/module/extractPathFromURL.js.map +1 -1
  82. package/lib/module/index.js +1 -0
  83. package/lib/module/index.js.map +1 -1
  84. package/lib/module/theming/DarkTheme.js.map +1 -1
  85. package/lib/module/theming/DefaultTheme.js.map +1 -1
  86. package/lib/module/theming/ThemeContext.js.map +1 -1
  87. package/lib/module/theming/ThemeProvider.js.map +1 -1
  88. package/lib/module/theming/fonts.js.map +1 -1
  89. package/lib/module/theming/useTheme.js.map +1 -1
  90. package/lib/module/types.js.map +1 -1
  91. package/lib/module/useBackButton.js.map +1 -1
  92. package/lib/module/useBackButton.native.js.map +1 -1
  93. package/lib/module/useDocumentTitle.js +3 -3
  94. package/lib/module/useDocumentTitle.js.map +1 -1
  95. package/lib/module/useDocumentTitle.native.js.map +1 -1
  96. package/lib/module/useLinkProps.js +18 -21
  97. package/lib/module/useLinkProps.js.map +1 -1
  98. package/lib/module/useLinkTools.js +4 -4
  99. package/lib/module/useLinkTools.js.map +1 -1
  100. package/lib/module/useLinking.js +24 -11
  101. package/lib/module/useLinking.js.map +1 -1
  102. package/lib/module/useLinking.native.js +28 -21
  103. package/lib/module/useLinking.native.js.map +1 -1
  104. package/lib/module/useLocale.js.map +1 -1
  105. package/lib/module/useScrollToTop.js +2 -2
  106. package/lib/module/useScrollToTop.js.map +1 -1
  107. package/lib/module/useThenable.js +1 -0
  108. package/lib/module/useThenable.js.map +1 -1
  109. package/lib/module/useUnhandledLinking.js +67 -0
  110. package/lib/module/useUnhandledLinking.js.map +1 -0
  111. package/lib/typescript/src/Link.d.ts +3 -3
  112. package/lib/typescript/src/Link.d.ts.map +1 -1
  113. package/lib/typescript/src/LinkingContext.d.ts +2 -2
  114. package/lib/typescript/src/LinkingContext.d.ts.map +1 -1
  115. package/lib/typescript/src/NavigationContainer.d.ts +1 -1
  116. package/lib/typescript/src/NavigationContainer.d.ts.map +1 -1
  117. package/lib/typescript/src/ServerContainer.d.ts +1 -1
  118. package/lib/typescript/src/ServerContainer.d.ts.map +1 -1
  119. package/lib/typescript/src/UnhandledLinkingContext.d.ts +6 -0
  120. package/lib/typescript/src/UnhandledLinkingContext.d.ts.map +1 -0
  121. package/lib/typescript/src/{__mocks__ → __stubs__}/createStackNavigator.d.ts +5 -4
  122. package/lib/typescript/src/__stubs__/createStackNavigator.d.ts.map +1 -0
  123. package/lib/typescript/src/{__mocks__ → __stubs__}/window.d.ts +1 -1
  124. package/lib/typescript/src/{__mocks__ → __stubs__}/window.d.ts.map +1 -1
  125. package/lib/typescript/src/createStaticNavigation.d.ts +2 -2
  126. package/lib/typescript/src/createStaticNavigation.d.ts.map +1 -1
  127. package/lib/typescript/src/index.d.ts +1 -0
  128. package/lib/typescript/src/index.d.ts.map +1 -1
  129. package/lib/typescript/src/theming/ThemeProvider.d.ts +1 -1
  130. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
  131. package/lib/typescript/src/useLinkProps.d.ts +2 -2
  132. package/lib/typescript/src/useLinkProps.d.ts.map +1 -1
  133. package/lib/typescript/src/useLinking.d.ts +2 -2
  134. package/lib/typescript/src/useLinking.d.ts.map +1 -1
  135. package/lib/typescript/src/useLinking.native.d.ts +2 -2
  136. package/lib/typescript/src/useLinking.native.d.ts.map +1 -1
  137. package/lib/typescript/src/useThenable.d.ts.map +1 -1
  138. package/lib/typescript/src/useUnhandledLinking.d.ts +7 -0
  139. package/lib/typescript/src/useUnhandledLinking.d.ts.map +1 -0
  140. package/package.json +12 -12
  141. package/src/Link.tsx +11 -2
  142. package/src/LinkingContext.tsx +8 -3
  143. package/src/NavigationContainer.tsx +68 -20
  144. package/src/ServerContainer.tsx +1 -1
  145. package/src/UnhandledLinkingContext.tsx +18 -0
  146. package/src/{__mocks__ → __stubs__}/window.tsx +7 -5
  147. package/src/createStaticNavigation.tsx +2 -2
  148. package/src/index.tsx +1 -0
  149. package/src/useLinkProps.tsx +20 -19
  150. package/src/useLinkTools.tsx +3 -3
  151. package/src/useLinking.native.tsx +26 -20
  152. package/src/useLinking.tsx +33 -12
  153. package/src/useScrollToTop.tsx +4 -4
  154. package/src/useThenable.tsx +1 -0
  155. package/src/useUnhandledLinking.tsx +90 -0
  156. package/lib/typescript/src/__mocks__/createStackNavigator.d.ts.map +0 -1
  157. /package/src/{__mocks__ → __stubs__}/createStackNavigator.tsx +0 -0
@@ -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
- let linkingHandlers: Symbol[] = [];
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 && typeof url !== 'string') {
144
- return url.then((url) => {
145
- const state = getStateFromURL(url);
144
+ if (url != null) {
145
+ if (typeof url !== 'string') {
146
+ return url.then((url) => {
147
+ const state = getStateFromURL(url);
146
148
 
147
- return state;
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
- // Make sure that the routes in the state exist in the root navigator
177
- // Otherwise there's an error in the linking configuration
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,
@@ -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';
@@ -63,12 +63,13 @@ const findMatchingState = <T extends NavigationState>(
63
63
  export const series = (cb: () => Promise<void>) => {
64
64
  let queue = Promise.resolve();
65
65
  const callback = () => {
66
+ // eslint-disable-next-line promise/no-callback-in-promise
66
67
  queue = queue.then(cb);
67
68
  };
68
69
  return callback;
69
70
  };
70
71
 
71
- let linkingHandlers: Symbol[] = [];
72
+ const linkingHandlers: symbol[] = [];
72
73
 
73
74
  type Options = LinkingOptions<ParamListBase>;
74
75
 
@@ -80,7 +81,8 @@ export function useLinking(
80
81
  getStateFromPath = getStateFromPathDefault,
81
82
  getPathFromState = getPathFromStateDefault,
82
83
  getActionFromState = getActionFromStateDefault,
83
- }: Options
84
+ }: Options,
85
+ onUnhandledLinking: (lastUnhandledLining: string | undefined) => void
84
86
  ) {
85
87
  const independent = useNavigationIndependentTree();
86
88
 
@@ -139,6 +141,17 @@ export function useLinking(
139
141
  getActionFromStateRef.current = getActionFromState;
140
142
  });
141
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
+
142
155
  const server = React.useContext(ServerContext);
143
156
 
144
157
  const getInitialState = React.useCallback(() => {
@@ -154,6 +167,9 @@ export function useLinking(
154
167
  if (path) {
155
168
  value = getStateFromPathRef.current(path, configRef.current);
156
169
  }
170
+
171
+ // If the link were handled, it gets cleared in NavigationContainer
172
+ onUnhandledLinking(path);
157
173
  }
158
174
 
159
175
  const thenable = {
@@ -183,6 +199,8 @@ export function useLinking(
183
199
  return;
184
200
  }
185
201
 
202
+ const { location } = window;
203
+
186
204
  const path = location.pathname + location.search;
187
205
  const index = history.index;
188
206
 
@@ -206,14 +224,11 @@ export function useLinking(
206
224
  // We should only dispatch an action when going forward
207
225
  // Otherwise the action will likely add items to history, which would mess things up
208
226
  if (state) {
227
+ // If the link were handled, it gets cleared in NavigationContainer
228
+ onUnhandledLinking(path);
209
229
  // Make sure that the routes in the state exist in the root navigator
210
230
  // Otherwise there's an error in the linking configuration
211
- const rootState = navigation.getRootState();
212
-
213
- if (state.routes.some((r) => !rootState?.routeNames.includes(r.name))) {
214
- console.warn(
215
- "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."
216
- );
231
+ if (validateRoutesNotExistInRootState(state)) {
217
232
  return;
218
233
  }
219
234
 
@@ -248,7 +263,13 @@ export function useLinking(
248
263
  navigation.resetRoot(state);
249
264
  }
250
265
  });
251
- }, [enabled, history, ref]);
266
+ }, [
267
+ enabled,
268
+ history,
269
+ onUnhandledLinking,
270
+ ref,
271
+ validateRoutesNotExistInRootState,
272
+ ]);
252
273
 
253
274
  React.useEffect(() => {
254
275
  if (!enabled) {
@@ -1,6 +1,6 @@
1
1
  import {
2
- EventArg,
3
- NavigationProp,
2
+ type EventArg,
3
+ type NavigationProp,
4
4
  useNavigation,
5
5
  useRoute,
6
6
  } from '@react-navigation/core';
@@ -53,7 +53,7 @@ export function useScrollToTop(ref: React.RefObject<ScrollableWrapper>) {
53
53
  const route = useRoute();
54
54
 
55
55
  React.useEffect(() => {
56
- let tabNavigations: NavigationProp<ReactNavigation.RootParamList>[] = [];
56
+ const tabNavigations: NavigationProp<ReactNavigation.RootParamList>[] = [];
57
57
  let currentNavigation = navigation;
58
58
 
59
59
  // If the screen is nested inside multiple tab navigators, we should scroll to top for any of them
@@ -74,7 +74,7 @@ export function useScrollToTop(ref: React.RefObject<ScrollableWrapper>) {
74
74
  return tab.addListener(
75
75
  // We don't wanna import tab types here to avoid extra deps
76
76
  // in addition, there are multiple tab implementations
77
- // @ts-expect-error
77
+ // @ts-expect-error the `tabPress` event is only available when navigation type is tab
78
78
  'tabPress',
79
79
  (e: EventArg<'tabPress', true>) => {
80
80
  // We should scroll to top only when the screen is focused
@@ -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,90 @@
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
+ function extractNavigatorSpecificState(
14
+ _: NavigationState,
15
+ pathState: PartialState<NavigationState>,
16
+ depth: number
17
+ ) {
18
+ let partialPathState: PartialState<NavigationState> | undefined = pathState;
19
+
20
+ let currentDepth = depth;
21
+ while (currentDepth) {
22
+ if (!partialPathState) {
23
+ return undefined;
24
+ }
25
+ partialPathState =
26
+ partialPathState.routes[partialPathState.routes.length - 1].state;
27
+ currentDepth--;
28
+ }
29
+ return partialPathState;
30
+ }
31
+
32
+ export function useUnhandledLinking() {
33
+ const navigation = React.useContext(NavigationContext);
34
+ const linking = React.useContext(LinkingContext);
35
+ const { setLastUnhandledLink, lastUnhandledLink } = React.useContext(
36
+ UnhandledLinkingContext
37
+ );
38
+
39
+ const { options } = linking;
40
+
41
+ const getStateForRouteNamesChange = (
42
+ currentState: NavigationState
43
+ ): PartialState<NavigationState> | undefined => {
44
+ if (lastUnhandledLink == null) {
45
+ // noop, nothing to handle
46
+ return;
47
+ }
48
+
49
+ // at web, the path is already extracted
50
+ const path = lastUnhandledLink;
51
+ if (!lastUnhandledLink) {
52
+ return;
53
+ }
54
+
55
+ // First, we parse the URL to get the desired state
56
+ const getStateFromPathHelper =
57
+ options?.getStateFromPath ?? getStateFromPath;
58
+
59
+ const pathState = getStateFromPathHelper(path, options?.config);
60
+
61
+ if (!pathState) {
62
+ return;
63
+ }
64
+
65
+ let depth = 0;
66
+ let parent = navigation;
67
+ while (parent) {
68
+ depth++;
69
+ parent = parent.getParent();
70
+ }
71
+
72
+ const state = extractNavigatorSpecificState(currentState, pathState, depth);
73
+
74
+ if (!state) {
75
+ return;
76
+ }
77
+
78
+ return state;
79
+ };
80
+
81
+ const clearUnhandledLink = useLatestCallback(() => {
82
+ setLastUnhandledLink(undefined);
83
+ });
84
+
85
+ return {
86
+ lastUnhandledLink,
87
+ getStateForRouteNamesChange,
88
+ clearUnhandledLink,
89
+ };
90
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"createStackNavigator.d.ts","sourceRoot":"","sources":["../../../../src/__mocks__/createStackNavigator.tsx"],"names":[],"mappings":"AAOA,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAW/B,CAAC"}