@amazon-devices/react-navigation__native 7.0.1759135970 → 8.0.9000000000-rn-83

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 (232) hide show
  1. package/SystemBundles/c0d77be093c9724f49566be215c67240e6443c16760f772a745108ddaef15503.bundle +9117 -0
  2. package/SystemBundles/c0d77be093c9724f49566be215c67240e6443c16760f772a745108ddaef15503.map +3543 -0
  3. package/SystemModules/amzn__react-navigation__native-8.modules.txt +24 -0
  4. package/SystemModules/amzn__react-navigation__native-8.private.modules.txt +77 -0
  5. package/SystemModules/keplerscript-system-bundle-config.json +4 -4
  6. package/kepler-compatibility.json +2 -2
  7. package/lib/module/Link.js +31 -10
  8. package/lib/module/Link.js.map +1 -1
  9. package/lib/module/LinkingContext.js +7 -3
  10. package/lib/module/LinkingContext.js.map +1 -1
  11. package/lib/module/LocaleDirContext.js +6 -0
  12. package/lib/module/LocaleDirContext.js.map +1 -0
  13. package/lib/module/NavigationContainer.js +87 -59
  14. package/lib/module/NavigationContainer.js.map +1 -1
  15. package/lib/module/ServerContainer.js +20 -10
  16. package/lib/module/ServerContainer.js.map +1 -1
  17. package/lib/module/ServerContext.js +3 -2
  18. package/lib/module/ServerContext.js.map +1 -1
  19. package/lib/module/UnhandledLinkingContext.js +14 -0
  20. package/lib/module/UnhandledLinkingContext.js.map +1 -0
  21. package/lib/module/__stubs__/createStackNavigator.js +18 -0
  22. package/lib/module/__stubs__/createStackNavigator.js.map +1 -0
  23. package/lib/module/__stubs__/window.js +75 -0
  24. package/lib/module/__stubs__/window.js.map +1 -0
  25. package/lib/module/createMemoryHistory.js +19 -17
  26. package/lib/module/createMemoryHistory.js.map +1 -1
  27. package/lib/module/createStaticNavigation.js +54 -0
  28. package/lib/module/createStaticNavigation.js.map +1 -0
  29. package/lib/module/extractPathFromURL.js +6 -5
  30. package/lib/module/extractPathFromURL.js.map +1 -1
  31. package/lib/module/index.js +18 -13
  32. package/lib/module/index.js.map +1 -1
  33. package/lib/module/package.json +1 -0
  34. package/lib/module/theming/DarkTheme.js +6 -3
  35. package/lib/module/theming/DarkTheme.js.map +1 -1
  36. package/lib/module/theming/DefaultTheme.js +6 -3
  37. package/lib/module/theming/DefaultTheme.js.map +1 -1
  38. package/lib/module/theming/fonts.js +61 -0
  39. package/lib/module/theming/fonts.js.map +1 -0
  40. package/lib/module/types.js +2 -0
  41. package/lib/module/types.js.map +1 -1
  42. package/lib/module/useBackButton.js +3 -1
  43. package/lib/module/useBackButton.js.map +1 -1
  44. package/lib/module/useBackButton.native.js +3 -1
  45. package/lib/module/useBackButton.native.js.map +1 -1
  46. package/lib/module/useDocumentTitle.js +6 -4
  47. package/lib/module/useDocumentTitle.js.map +1 -1
  48. package/lib/module/useDocumentTitle.native.js +4 -2
  49. package/lib/module/useDocumentTitle.native.js.map +1 -1
  50. package/lib/module/useLinkBuilder.js +71 -40
  51. package/lib/module/useLinkBuilder.js.map +1 -1
  52. package/lib/module/useLinkProps.js +41 -36
  53. package/lib/module/useLinkProps.js.map +1 -1
  54. package/lib/module/useLinkTo.js +18 -28
  55. package/lib/module/useLinkTo.js.map +1 -1
  56. package/lib/module/useLinking.js +47 -19
  57. package/lib/module/useLinking.js.map +1 -1
  58. package/lib/module/useLinking.native.js +33 -28
  59. package/lib/module/useLinking.native.js.map +1 -1
  60. package/lib/module/useLocale.js +18 -0
  61. package/lib/module/useLocale.js.map +1 -0
  62. package/lib/module/useRoutePath.js +30 -0
  63. package/lib/module/useRoutePath.js.map +1 -0
  64. package/lib/module/useScrollToTop.js +11 -7
  65. package/lib/module/useScrollToTop.js.map +1 -1
  66. package/lib/module/useThenable.js +4 -1
  67. package/lib/module/useThenable.js.map +1 -1
  68. package/lib/typescript/package.json +1 -0
  69. package/lib/typescript/src/Link.d.ts +8 -10
  70. package/lib/typescript/src/Link.d.ts.map +1 -1
  71. package/lib/typescript/src/LinkingContext.d.ts +2 -3
  72. package/lib/typescript/src/LinkingContext.d.ts.map +1 -1
  73. package/lib/typescript/src/LocaleDirContext.d.ts +4 -0
  74. package/lib/typescript/src/LocaleDirContext.d.ts.map +1 -0
  75. package/lib/typescript/src/NavigationContainer.d.ts +36 -13
  76. package/lib/typescript/src/NavigationContainer.d.ts.map +1 -1
  77. package/lib/typescript/src/ServerContainer.d.ts +2 -3
  78. package/lib/typescript/src/ServerContainer.d.ts.map +1 -1
  79. package/lib/typescript/src/ServerContext.d.ts +1 -2
  80. package/lib/typescript/src/ServerContext.d.ts.map +1 -1
  81. package/lib/typescript/src/UnhandledLinkingContext.d.ts +6 -0
  82. package/lib/typescript/src/UnhandledLinkingContext.d.ts.map +1 -0
  83. package/lib/typescript/src/__stubs__/createStackNavigator.d.ts +13 -0
  84. package/lib/typescript/src/__stubs__/createStackNavigator.d.ts.map +1 -0
  85. package/lib/typescript/src/{__mocks__ → __stubs__}/window.d.ts +5 -6
  86. package/lib/typescript/src/__stubs__/window.d.ts.map +1 -0
  87. package/lib/typescript/src/createMemoryHistory.d.ts +1 -1
  88. package/lib/typescript/src/createMemoryHistory.d.ts.map +1 -1
  89. package/lib/typescript/src/createStaticNavigation.d.ts +34 -0
  90. package/lib/typescript/src/createStaticNavigation.d.ts.map +1 -0
  91. package/lib/typescript/src/extractPathFromURL.d.ts +1 -1
  92. package/lib/typescript/src/extractPathFromURL.d.ts.map +1 -1
  93. package/lib/typescript/src/index.d.ts +15 -12
  94. package/lib/typescript/src/index.d.ts.map +1 -1
  95. package/lib/typescript/src/theming/DarkTheme.d.ts +1 -2
  96. package/lib/typescript/src/theming/DarkTheme.d.ts.map +1 -1
  97. package/lib/typescript/src/theming/DefaultTheme.d.ts +1 -2
  98. package/lib/typescript/src/theming/DefaultTheme.d.ts.map +1 -1
  99. package/lib/typescript/src/theming/fonts.d.ts +53 -0
  100. package/lib/typescript/src/theming/fonts.d.ts.map +1 -0
  101. package/lib/typescript/src/types.d.ts +35 -3
  102. package/lib/typescript/src/types.d.ts.map +1 -1
  103. package/lib/typescript/src/useBackButton.d.ts +1 -2
  104. package/lib/typescript/src/useBackButton.d.ts.map +1 -1
  105. package/lib/typescript/src/useBackButton.native.d.ts +1 -1
  106. package/lib/typescript/src/useBackButton.native.d.ts.map +1 -1
  107. package/lib/typescript/src/useDocumentTitle.d.ts +1 -1
  108. package/lib/typescript/src/useDocumentTitle.d.ts.map +1 -1
  109. package/lib/typescript/src/useDocumentTitle.native.d.ts +1 -1
  110. package/lib/typescript/src/useDocumentTitle.native.d.ts.map +1 -1
  111. package/lib/typescript/src/useLinkBuilder.d.ts +97 -3
  112. package/lib/typescript/src/useLinkBuilder.d.ts.map +1 -1
  113. package/lib/typescript/src/useLinkProps.d.ts +23 -10
  114. package/lib/typescript/src/useLinkProps.d.ts.map +1 -1
  115. package/lib/typescript/src/useLinkTo.d.ts +6 -8
  116. package/lib/typescript/src/useLinkTo.d.ts.map +1 -1
  117. package/lib/typescript/src/useLinking.d.ts +5 -46
  118. package/lib/typescript/src/useLinking.d.ts.map +1 -1
  119. package/lib/typescript/src/useLinking.native.d.ts +11 -29
  120. package/lib/typescript/src/useLinking.native.d.ts.map +1 -1
  121. package/lib/typescript/src/useLocale.d.ts +7 -0
  122. package/lib/typescript/src/useLocale.d.ts.map +1 -0
  123. package/lib/typescript/src/useRoutePath.d.ts +7 -0
  124. package/lib/typescript/src/useRoutePath.d.ts.map +1 -0
  125. package/lib/typescript/src/useScrollToTop.d.ts +2 -2
  126. package/lib/typescript/src/useScrollToTop.d.ts.map +1 -1
  127. package/lib/typescript/src/useThenable.d.ts +1 -1
  128. package/lib/typescript/src/useThenable.d.ts.map +1 -1
  129. package/oss-attribution/attribution.txt +50 -0
  130. package/oss-attribution/licenseInfos.json +18 -0
  131. package/package.json +97 -1
  132. package/src/Link.tsx +36 -20
  133. package/src/LinkingContext.tsx +9 -5
  134. package/src/LocaleDirContext.tsx +7 -0
  135. package/src/NavigationContainer.tsx +128 -69
  136. package/src/ServerContainer.tsx +4 -3
  137. package/src/ServerContext.tsx +1 -3
  138. package/src/UnhandledLinkingContext.tsx +18 -0
  139. package/src/__stubs__/createStackNavigator.tsx +46 -0
  140. package/src/{__mocks__ → __stubs__}/window.tsx +8 -8
  141. package/src/createMemoryHistory.tsx +16 -11
  142. package/src/createStaticNavigation.tsx +109 -0
  143. package/src/extractPathFromURL.tsx +3 -3
  144. package/src/index.tsx +15 -12
  145. package/src/theming/DarkTheme.tsx +3 -3
  146. package/src/theming/DefaultTheme.tsx +3 -3
  147. package/src/theming/fonts.tsx +63 -0
  148. package/src/types.tsx +49 -3
  149. package/src/useBackButton.native.tsx +2 -2
  150. package/src/useBackButton.tsx +2 -2
  151. package/src/useDocumentTitle.native.tsx +2 -2
  152. package/src/useDocumentTitle.tsx +2 -2
  153. package/src/useLinkBuilder.tsx +100 -55
  154. package/src/useLinkProps.tsx +80 -50
  155. package/src/useLinkTo.tsx +13 -53
  156. package/src/useLinking.native.tsx +33 -31
  157. package/src/useLinking.tsx +70 -23
  158. package/src/useLocale.tsx +18 -0
  159. package/src/useRoutePath.tsx +34 -0
  160. package/src/useScrollToTop.tsx +16 -12
  161. package/src/useThenable.tsx +2 -1
  162. package/SystemBundles/8f36606502d3b658fa1ffc07fee4da0e39a8ce388742799c9ccdb66b39ef0362.bundle +0 -15196
  163. package/SystemBundles/8f36606502d3b658fa1ffc07fee4da0e39a8ce388742799c9ccdb66b39ef0362.map +0 -1
  164. package/SystemModules/amzn__react-navigation__native-7.modules.txt +0 -76
  165. package/SystemModules/amzn__react-navigation__native-7.private.modules.txt +0 -101
  166. package/THIRD_PARTY_NOTICES.txt +0 -24
  167. package/lib/commonjs/Link.js +0 -50
  168. package/lib/commonjs/Link.js.map +0 -1
  169. package/lib/commonjs/LinkingContext.js +0 -15
  170. package/lib/commonjs/LinkingContext.js.map +0 -1
  171. package/lib/commonjs/NavigationContainer.js +0 -109
  172. package/lib/commonjs/NavigationContainer.js.map +0 -1
  173. package/lib/commonjs/ServerContainer.js +0 -54
  174. package/lib/commonjs/ServerContainer.js.map +0 -1
  175. package/lib/commonjs/ServerContext.js +0 -12
  176. package/lib/commonjs/ServerContext.js.map +0 -1
  177. package/lib/commonjs/createMemoryHistory.js +0 -220
  178. package/lib/commonjs/createMemoryHistory.js.map +0 -1
  179. package/lib/commonjs/extractPathFromURL.js +0 -25
  180. package/lib/commonjs/extractPathFromURL.js.map +0 -1
  181. package/lib/commonjs/index.js +0 -129
  182. package/lib/commonjs/index.js.map +0 -1
  183. package/lib/commonjs/theming/DarkTheme.js +0 -19
  184. package/lib/commonjs/theming/DarkTheme.js.map +0 -1
  185. package/lib/commonjs/theming/DefaultTheme.js +0 -19
  186. package/lib/commonjs/theming/DefaultTheme.js.map +0 -1
  187. package/lib/commonjs/theming/ThemeContext.js +0 -15
  188. package/lib/commonjs/theming/ThemeContext.js.map +0 -1
  189. package/lib/commonjs/theming/ThemeProvider.js +0 -20
  190. package/lib/commonjs/theming/ThemeProvider.js.map +0 -1
  191. package/lib/commonjs/theming/useTheme.js +0 -16
  192. package/lib/commonjs/theming/useTheme.js.map +0 -1
  193. package/lib/commonjs/types.js +0 -6
  194. package/lib/commonjs/types.js.map +0 -1
  195. package/lib/commonjs/useBackButton.js +0 -11
  196. package/lib/commonjs/useBackButton.js.map +0 -1
  197. package/lib/commonjs/useBackButton.native.js +0 -27
  198. package/lib/commonjs/useBackButton.native.js.map +0 -1
  199. package/lib/commonjs/useDocumentTitle.js +0 -32
  200. package/lib/commonjs/useDocumentTitle.js.map +0 -1
  201. package/lib/commonjs/useDocumentTitle.native.js +0 -10
  202. package/lib/commonjs/useDocumentTitle.native.js.map +0 -1
  203. package/lib/commonjs/useLinkBuilder.js +0 -63
  204. package/lib/commonjs/useLinkBuilder.js.map +0 -1
  205. package/lib/commonjs/useLinkProps.js +0 -97
  206. package/lib/commonjs/useLinkProps.js.map +0 -1
  207. package/lib/commonjs/useLinkTo.js +0 -45
  208. package/lib/commonjs/useLinkTo.js.map +0 -1
  209. package/lib/commonjs/useLinking.js +0 -303
  210. package/lib/commonjs/useLinking.js.map +0 -1
  211. package/lib/commonjs/useLinking.native.js +0 -152
  212. package/lib/commonjs/useLinking.native.js.map +0 -1
  213. package/lib/commonjs/useScrollToTop.js +0 -95
  214. package/lib/commonjs/useScrollToTop.js.map +0 -1
  215. package/lib/commonjs/useThenable.js +0 -41
  216. package/lib/commonjs/useThenable.js.map +0 -1
  217. package/lib/module/theming/ThemeContext.js +0 -6
  218. package/lib/module/theming/ThemeContext.js.map +0 -1
  219. package/lib/module/theming/ThemeProvider.js +0 -11
  220. package/lib/module/theming/ThemeProvider.js.map +0 -1
  221. package/lib/module/theming/useTheme.js +0 -7
  222. package/lib/module/theming/useTheme.js.map +0 -1
  223. package/lib/typescript/src/__mocks__/window.d.ts.map +0 -1
  224. package/lib/typescript/src/theming/ThemeContext.d.ts +0 -5
  225. package/lib/typescript/src/theming/ThemeContext.d.ts.map +0 -1
  226. package/lib/typescript/src/theming/ThemeProvider.d.ts +0 -9
  227. package/lib/typescript/src/theming/ThemeProvider.d.ts.map +0 -1
  228. package/lib/typescript/src/theming/useTheme.d.ts +0 -2
  229. package/lib/typescript/src/theming/useTheme.d.ts.map +0 -1
  230. package/src/theming/ThemeContext.tsx +0 -10
  231. package/src/theming/ThemeProvider.tsx +0 -15
  232. package/src/theming/useTheme.tsx +0 -9
@@ -1,25 +1,38 @@
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 '@amazon-devices/react-navigation__core';
9
9
  import type { NavigationState, PartialState } from '@amazon-devices/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
- import LinkingContext from './LinkingContext';
14
- import useLinkTo, { To } from './useLinkTo';
13
+ import { LinkingContext } from './LinkingContext';
15
14
 
16
- type Props<ParamList extends ReactNavigation.RootParamList> = {
17
- to: To<ParamList>;
18
- action?: NavigationAction;
19
- };
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
+ };
20
33
 
21
34
  const getStateFromParams = (
22
- params: NavigatorScreenParams<ParamListBase, NavigationState> | undefined
35
+ params: NavigatorScreenParams<ParamListBase> | undefined
23
36
  ): PartialState<NavigationState> | NavigationState | undefined => {
24
37
  if (params?.state) {
25
38
  return params.state;
@@ -31,11 +44,11 @@ const getStateFromParams = (
31
44
  {
32
45
  name: params.screen,
33
46
  params: params.params,
34
- // @ts-expect-error
47
+ // @ts-expect-error this is fine 🔥
35
48
  state: params.screen
36
49
  ? getStateFromParams(
37
50
  params.params as
38
- | NavigatorScreenParams<ParamListBase, NavigationState>
51
+ | NavigatorScreenParams<ParamListBase>
39
52
  | undefined
40
53
  )
41
54
  : undefined,
@@ -50,16 +63,20 @@ const getStateFromParams = (
50
63
  /**
51
64
  * Hook to get props for an anchor tag so it can work with in page navigation.
52
65
  *
53
- * @param props.to Absolute path to screen (e.g. `/feeds/hot`).
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`).
54
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.
55
70
  */
56
- export default function useLinkProps<
57
- ParamList extends ReactNavigation.RootParamList
58
- >({ to, action }: Props<ParamList>) {
71
+ export function useLinkProps<ParamList extends ReactNavigation.RootParamList>({
72
+ screen,
73
+ params,
74
+ href,
75
+ action,
76
+ }: LinkProps<ParamList>) {
59
77
  const root = React.useContext(NavigationContainerRefContext);
60
78
  const navigation = React.useContext(NavigationHelpersContext);
61
79
  const { options } = React.useContext(LinkingContext);
62
- const linkTo = useLinkTo<ParamList>();
63
80
 
64
81
  const onPress = (
65
82
  e?: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
@@ -67,18 +84,30 @@ export default function useLinkProps<
67
84
  let shouldHandle = false;
68
85
 
69
86
  if (Platform.OS !== 'web' || !e) {
70
- shouldHandle = e ? !e.defaultPrevented : true;
71
- } else if (
72
- !e.defaultPrevented && // onPress prevented default
73
- // @ts-expect-error: these properties exist on web, but not in React Native
74
- !(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys
75
- // @ts-expect-error: these properties exist on web, but not in React Native
76
- (e.button == null || e.button === 0) && // ignore everything but left clicks
77
- // @ts-expect-error: these properties exist on web, but not in React Native
78
- [undefined, null, '', 'self'].includes(e.currentTarget?.target) // let browser handle "target=_blank" etc.
79
- ) {
80
- e.preventDefault();
87
+ e?.preventDefault?.();
81
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
+ }
82
111
  }
83
112
 
84
113
  if (shouldHandle) {
@@ -93,34 +122,35 @@ export default function useLinkProps<
93
122
  );
94
123
  }
95
124
  } else {
96
- linkTo(to);
125
+ // @ts-expect-error This is already type-checked by the prop types
126
+ navigation?.navigate(screen, params);
97
127
  }
98
128
  }
99
129
  };
100
130
 
101
131
  const getPathFromStateHelper = options?.getPathFromState ?? getPathFromState;
102
132
 
103
- const href =
104
- typeof to === 'string'
105
- ? to
106
- : getPathFromStateHelper(
107
- {
108
- routes: [
109
- {
110
- name: to.screen,
111
- // @ts-expect-error
112
- params: to.params,
113
- // @ts-expect-error
114
- state: getStateFromParams(to.params),
115
- },
116
- ],
117
- },
118
- options?.config
119
- );
120
-
121
133
  return {
122
- href,
123
- accessibilityRole: 'link' as const,
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,
124
154
  onPress,
125
155
  };
126
156
  }
package/src/useLinkTo.tsx CHANGED
@@ -1,70 +1,30 @@
1
- import {
2
- getActionFromState,
3
- getStateFromPath,
4
- NavigationContainerRefContext,
5
- } from '@amazon-devices/react-navigation__core';
1
+ import { NavigationContainerRefContext } from '@amazon-devices/react-navigation__core';
6
2
  import * as React from 'react';
7
3
 
8
- import LinkingContext from './LinkingContext';
4
+ import { useLinkBuilder } from './useLinkBuilder';
9
5
 
10
- export type To<
11
- ParamList extends ReactNavigation.RootParamList = ReactNavigation.RootParamList,
12
- RouteName extends keyof ParamList = keyof ParamList
13
- > =
14
- | string
15
- | (undefined extends ParamList[RouteName]
16
- ? {
17
- screen: Extract<RouteName, string>;
18
- params?: ParamList[RouteName];
19
- }
20
- : {
21
- screen: Extract<RouteName, string>;
22
- params: ParamList[RouteName];
23
- });
24
-
25
- export default function useLinkTo<
26
- ParamList extends ReactNavigation.RootParamList
27
- >() {
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() {
28
12
  const navigation = React.useContext(NavigationContainerRefContext);
29
- const linking = React.useContext(LinkingContext);
13
+ const { buildAction } = useLinkBuilder();
30
14
 
31
15
  const linkTo = React.useCallback(
32
- (to: To<ParamList>) => {
16
+ (href: string) => {
33
17
  if (navigation === undefined) {
34
18
  throw new Error(
35
19
  "Couldn't find a navigation object. Is your component inside NavigationContainer?"
36
20
  );
37
21
  }
38
22
 
39
- if (typeof to !== 'string') {
40
- // @ts-expect-error: This is fine
41
- navigation.navigate(to.screen, to.params);
42
- return;
43
- }
44
-
45
- if (!to.startsWith('/')) {
46
- throw new Error(`The path must start with '/' (${to}).`);
47
- }
48
-
49
- const { options } = linking;
50
-
51
- const state = options?.getStateFromPath
52
- ? options.getStateFromPath(to, options.config)
53
- : getStateFromPath(to, options?.config);
23
+ const action = buildAction(href);
54
24
 
55
- if (state) {
56
- const action = getActionFromState(state, options?.config);
57
-
58
- if (action !== undefined) {
59
- navigation.dispatch(action);
60
- } else {
61
- navigation.reset(state);
62
- }
63
- } else {
64
- throw new Error('Failed to parse the path to a navigation state.');
65
- }
25
+ navigation.dispatch(action);
66
26
  },
67
- [linking, navigation]
27
+ [buildAction, navigation]
68
28
  );
69
29
 
70
30
  return linkTo;
@@ -1,27 +1,25 @@
1
1
  import {
2
2
  getActionFromState as getActionFromStateDefault,
3
3
  getStateFromPath as getStateFromPathDefault,
4
- NavigationContainerRef,
5
- ParamListBase,
4
+ type NavigationContainerRef,
5
+ type ParamListBase,
6
+ useNavigationIndependentTree,
6
7
  } from '@amazon-devices/react-navigation__core';
7
8
  import * as React from 'react';
8
9
  import { Linking, Platform } from 'react-native';
9
10
 
10
- import extractPathFromURL from './extractPathFromURL';
11
+ import { extractPathFromURL } from './extractPathFromURL';
11
12
  import type { LinkingOptions } from './types';
12
13
 
13
14
  type ResultState = ReturnType<typeof getStateFromPathDefault>;
14
15
 
15
- type Options = LinkingOptions<ParamListBase> & {
16
- independent?: boolean;
17
- };
16
+ type Options = LinkingOptions<ParamListBase>;
18
17
 
19
- let linkingHandlers: Symbol[] = [];
18
+ const linkingHandlers: symbol[] = [];
20
19
 
21
- export default function useLinking(
22
- ref: React.RefObject<NavigationContainerRef<ParamListBase>>,
20
+ export function useLinking(
21
+ ref: React.RefObject<NavigationContainerRef<ParamListBase> | null>,
23
22
  {
24
- independent,
25
23
  enabled = true,
26
24
  prefixes,
27
25
  filter,
@@ -29,11 +27,11 @@ export default function useLinking(
29
27
  getInitialURL = () =>
30
28
  Promise.race([
31
29
  Linking.getInitialURL(),
32
- new Promise<undefined>((resolve) =>
30
+ new Promise<undefined>((resolve) => {
33
31
  // Timeout in 150ms if `getInitialState` doesn't resolve
34
32
  // Workaround for https://github.com/facebook/react-native/issues/25675
35
- setTimeout(resolve, 150)
36
- ),
33
+ setTimeout(resolve, 150);
34
+ }),
37
35
  ]),
38
36
  subscribe = (listener) => {
39
37
  const callback = ({ url }: { url: string }) => listener(url);
@@ -57,8 +55,11 @@ export default function useLinking(
57
55
  },
58
56
  getStateFromPath = getStateFromPathDefault,
59
57
  getActionFromState = getActionFromStateDefault,
60
- }: Options
58
+ }: Options,
59
+ onUnhandledLinking: (lastUnhandledLining: string | undefined) => void
61
60
  ) {
61
+ const independent = useNavigationIndependentTree();
62
+
62
63
  React.useEffect(() => {
63
64
  if (process.env.NODE_ENV === 'production') {
64
65
  return undefined;
@@ -140,12 +141,21 @@ export default 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);
148
+
149
+ if (typeof url === 'string') {
150
+ // If the link were handled, it gets cleared in NavigationContainer
151
+ onUnhandledLinking(extractPathFromURL(prefixes, url));
152
+ }
146
153
 
147
- return state;
148
- });
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 default 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,16 +183,8 @@ export default 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
178
- const rootState = navigation.getRootState();
179
-
180
- 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
- return;
185
- }
186
+ // If the link were handled, it gets cleared in NavigationContainer
187
+ onUnhandledLinking(extractPathFromURL(prefixes, url));
186
188
 
187
189
  const action = getActionFromStateRef.current(state, configRef.current);
188
190
 
@@ -207,7 +209,7 @@ export default function useLinking(
207
209
  };
208
210
 
209
211
  return subscribe(listener);
210
- }, [enabled, getStateFromURL, ref, subscribe]);
212
+ }, [enabled, getStateFromURL, onUnhandledLinking, prefixes, ref, subscribe]);
211
213
 
212
214
  return {
213
215
  getInitialState,
@@ -3,15 +3,16 @@ 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
+ useNavigationIndependentTree,
9
10
  } from '@amazon-devices/react-navigation__core';
10
11
  import isEqual from 'fast-deep-equal';
11
12
  import * as React from 'react';
12
13
 
13
- import createMemoryHistory from './createMemoryHistory';
14
- import ServerContext from './ServerContext';
14
+ import { createMemoryHistory } from './createMemoryHistory';
15
+ import { ServerContext } from './ServerContext';
15
16
  import type { LinkingOptions } from './types';
16
17
 
17
18
  type ResultState = ReturnType<typeof getStateFromPathDefault>;
@@ -62,28 +63,29 @@ const findMatchingState = <T extends NavigationState>(
62
63
  export const series = (cb: () => Promise<void>) => {
63
64
  let queue = Promise.resolve();
64
65
  const callback = () => {
66
+ // eslint-disable-next-line promise/no-callback-in-promise
65
67
  queue = queue.then(cb);
66
68
  };
67
69
  return callback;
68
70
  };
69
71
 
70
- let linkingHandlers: Symbol[] = [];
72
+ const linkingHandlers: symbol[] = [];
71
73
 
72
- type Options = LinkingOptions<ParamListBase> & {
73
- independent?: boolean;
74
- };
74
+ type Options = LinkingOptions<ParamListBase>;
75
75
 
76
- export default function useLinking(
77
- ref: React.RefObject<NavigationContainerRef<ParamListBase>>,
76
+ export function useLinking(
77
+ ref: React.RefObject<NavigationContainerRef<ParamListBase> | null>,
78
78
  {
79
- independent,
80
79
  enabled = true,
81
80
  config,
82
81
  getStateFromPath = getStateFromPathDefault,
83
82
  getPathFromState = getPathFromStateDefault,
84
83
  getActionFromState = getActionFromStateDefault,
85
- }: Options
84
+ }: Options,
85
+ onUnhandledLinking: (lastUnhandledLining: string | undefined) => void
86
86
  ) {
87
+ const independent = useNavigationIndependentTree();
88
+
87
89
  React.useEffect(() => {
88
90
  if (process.env.NODE_ENV === 'production') {
89
91
  return undefined;
@@ -139,6 +141,17 @@ export default 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 default 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 default 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 default 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 default 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) {
@@ -259,6 +280,8 @@ export default function useLinking(
259
280
  route: ReturnType<typeof findFocusedRoute>,
260
281
  state: NavigationState
261
282
  ): string => {
283
+ let path;
284
+
262
285
  // If the `route` object contains a `path`, use that path as long as `route.name` and `params` still match
263
286
  // This makes sure that we preserve the original URL for wildcard routes
264
287
  if (route?.path) {
@@ -275,12 +298,31 @@ export default function useLinking(
275
298
  focusedRoute.name === route.name &&
276
299
  isEqual(focusedRoute.params, route.params)
277
300
  ) {
278
- return route.path;
301
+ path = route.path;
279
302
  }
280
303
  }
281
304
  }
282
305
 
283
- return getPathFromStateRef.current(state, configRef.current);
306
+ if (path == null) {
307
+ path = getPathFromStateRef.current(state, configRef.current);
308
+ }
309
+
310
+ const previousRoute = previousStateRef.current
311
+ ? findFocusedRoute(previousStateRef.current)
312
+ : undefined;
313
+
314
+ // Preserve the hash if the route didn't change
315
+ if (
316
+ previousRoute &&
317
+ route &&
318
+ 'key' in previousRoute &&
319
+ 'key' in route &&
320
+ previousRoute.key === route.key
321
+ ) {
322
+ path = path + location.hash;
323
+ }
324
+
325
+ return path;
284
326
  };
285
327
 
286
328
  if (ref.current) {
@@ -357,7 +399,12 @@ export default function useLinking(
357
399
  const currentIndex = history.index;
358
400
 
359
401
  try {
360
- if (nextIndex !== -1 && nextIndex < currentIndex) {
402
+ if (
403
+ nextIndex !== -1 &&
404
+ nextIndex < currentIndex &&
405
+ // We should only go back if the entry exists and it's less than current index
406
+ history.get(nextIndex)
407
+ ) {
361
408
  // An existing entry for this path exists and it's less than current index, go back to that
362
409
  await history.go(nextIndex - currentIndex);
363
410
  } 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
+ }
@@ -0,0 +1,34 @@
1
+ import { getPathFromState, useStateForPath } from '@amazon-devices/react-navigation__core';
2
+ import * as React from 'react';
3
+
4
+ import { LinkingContext } from './LinkingContext';
5
+
6
+ /**
7
+ * Hook to get the path for the current route based on linking options.
8
+ *
9
+ * @returns Path for the current route.
10
+ */
11
+ export function useRoutePath() {
12
+ const { options } = React.useContext(LinkingContext);
13
+ const state = useStateForPath();
14
+
15
+ if (state === undefined) {
16
+ throw new Error(
17
+ "Couldn't find a state for the route object. Is your component inside a screen in a navigator?"
18
+ );
19
+ }
20
+
21
+ const getPathFromStateHelper = options?.getPathFromState ?? getPathFromState;
22
+
23
+ const path = React.useMemo(() => {
24
+ if (options?.enabled === false) {
25
+ return undefined;
26
+ }
27
+
28
+ const path = getPathFromStateHelper(state, options?.config);
29
+
30
+ return path;
31
+ }, [options?.enabled, options?.config, state, getPathFromStateHelper]);
32
+
33
+ return path;
34
+ }