@amazon-devices/react-navigation__native 8.0.9000000001 → 8.0.9000000002

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/kepler-compatibility.json +2 -1
  2. package/lib/module/index.js +0 -19
  3. package/package.json +1 -1
  4. package/src/index.tsx +1 -17
  5. package/lib/module/Link.js +0 -62
  6. package/lib/module/LinkingContext.js +0 -11
  7. package/lib/module/LocaleDirContext.js +0 -6
  8. package/lib/module/NavigationContainer.js +0 -128
  9. package/lib/module/ServerContainer.js +0 -55
  10. package/lib/module/ServerContext.js +0 -5
  11. package/lib/module/UnhandledLinkingContext.js +0 -14
  12. package/lib/module/__stubs__/createStackNavigator.js +0 -18
  13. package/lib/module/__stubs__/window.js +0 -75
  14. package/lib/module/createMemoryHistory.js +0 -216
  15. package/lib/module/createStaticNavigation.js +0 -54
  16. package/lib/module/extractPathFromURL.js +0 -19
  17. package/lib/module/theming/DarkTheme.js +0 -16
  18. package/lib/module/theming/DefaultTheme.js +0 -16
  19. package/lib/module/theming/fonts.js +0 -61
  20. package/lib/module/types.js +0 -4
  21. package/lib/module/useBackButton.js +0 -7
  22. package/lib/module/useBackButton.native.js +0 -21
  23. package/lib/module/useDocumentTitle.js +0 -26
  24. package/lib/module/useDocumentTitle.native.js +0 -6
  25. package/lib/module/useLinkBuilder.js +0 -85
  26. package/lib/module/useLinkProps.js +0 -93
  27. package/lib/module/useLinkTo.js +0 -26
  28. package/lib/module/useLinking.js +0 -320
  29. package/lib/module/useLinking.native.js +0 -148
  30. package/lib/module/useLocale.js +0 -18
  31. package/lib/module/useRoutePath.js +0 -30
  32. package/lib/module/useScrollToTop.js +0 -91
  33. package/lib/module/useThenable.js +0 -36
  34. package/src/Link.tsx +0 -69
  35. package/src/LinkingContext.tsx +0 -16
  36. package/src/LocaleDirContext.tsx +0 -7
  37. package/src/NavigationContainer.tsx +0 -211
  38. package/src/ServerContainer.tsx +0 -57
  39. package/src/ServerContext.tsx +0 -12
  40. package/src/UnhandledLinkingContext.tsx +0 -18
  41. package/src/__stubs__/createStackNavigator.tsx +0 -46
  42. package/src/__stubs__/window.tsx +0 -77
  43. package/src/createMemoryHistory.tsx +0 -229
  44. package/src/createStaticNavigation.tsx +0 -109
  45. package/src/extractPathFromURL.tsx +0 -29
  46. package/src/theming/DarkTheme.tsx +0 -15
  47. package/src/theming/DefaultTheme.tsx +0 -15
  48. package/src/theming/fonts.tsx +0 -63
  49. package/src/types.tsx +0 -191
  50. package/src/useBackButton.native.tsx +0 -33
  51. package/src/useBackButton.tsx +0 -11
  52. package/src/useDocumentTitle.native.tsx +0 -3
  53. package/src/useDocumentTitle.tsx +0 -41
  54. package/src/useLinkBuilder.tsx +0 -127
  55. package/src/useLinkProps.tsx +0 -156
  56. package/src/useLinkTo.tsx +0 -31
  57. package/src/useLinking.native.tsx +0 -217
  58. package/src/useLinking.tsx +0 -442
  59. package/src/useLocale.tsx +0 -18
  60. package/src/useRoutePath.tsx +0 -34
  61. package/src/useScrollToTop.tsx +0 -120
  62. package/src/useThenable.tsx +0 -42
@@ -2,6 +2,7 @@
2
2
  "versions": {
3
3
  "8.0.0": "/com.amazon.kepler.navigation__native_8@INavigation__Native_0",
4
4
  "8.0.9000000000": "/com.amazon.kepler.navigation__native_8@INavigation__Native_0",
5
- "8.0.9000000001": "/com.amazon.kepler.navigation__native_8@INavigation__Native_0"
5
+ "8.0.9000000001": "/com.amazon.kepler.navigation__native_8@INavigation__Native_0",
6
+ "8.0.9000000002": "/com.amazon.kepler.navigation__native_8@INavigation__Native_0"
6
7
  }
7
8
  }
@@ -1,20 +1 @@
1
- "use strict";
2
1
 
3
- export { createStaticNavigation } from "./createStaticNavigation.js";
4
- export { Link } from "./Link.js";
5
- export { LinkingContext } from "./LinkingContext.js";
6
- export { LocaleDirContext } from "./LocaleDirContext.js";
7
- export { NavigationContainer } from "./NavigationContainer.js";
8
- export { ServerContainer } from "./ServerContainer.js";
9
- export { DarkTheme } from "./theming/DarkTheme.js";
10
- export { DefaultTheme } from "./theming/DefaultTheme.js";
11
- export * from "./types.js";
12
- export { UnhandledLinkingContext as UNSTABLE_UnhandledLinkingContext } from "./UnhandledLinkingContext.js";
13
- export { useLinkBuilder } from "./useLinkBuilder.js";
14
- export { useLinkProps } from "./useLinkProps.js";
15
- export { useLinkTo } from "./useLinkTo.js";
16
- export { useLocale } from "./useLocale.js";
17
- export { useRoutePath } from "./useRoutePath.js";
18
- export { useScrollToTop } from "./useScrollToTop.js";
19
- export * from '@amazon-devices/react-navigation__core';
20
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name": "@amazon-devices/react-navigation__native", "description": "React Native integration for React Navigation", "version": "8.0.9000000001+7.1.22", "keywords": ["react-native", "react-navigation", "ios", "android"], "license": "See license in LICENSE", "repository": {"type": "git", "url": "https://github.com/react-navigation/react-navigation.git", "directory": "packages/native"}, "bugs": {"url": "https://github.com/react-navigation/react-navigation/issues"}, "homepage": "https://reactnavigation.org", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", "exports": {".": {"source": "./src/index.tsx", "types": "./lib/typescript/src/index.d.ts", "default": "./lib/module/index.js"}, "./package.json": "./package.json"}, "files": ["src", "lib", "!**/__tests__", "kepler-compatibility.json", "SystemModules", "SystemBundles", "oss-attribution", "kepler-transformed-package-info.json"], "sideEffects": false, "kepler": {"temporary-alias-for-package": {"name": "@react-navigation/native", "version": "7.0.14"}}, "publishConfig": {"access": "public"}, "scripts": {"clean": "del lib"}, "dependencies": {"@amazon-devices/react-navigation__routers": "^8.0.1", "@amazon-devices/react-navigation__core": "^8.0.1", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4"}, "devDependencies": {"@jest/globals": "^30.0.0", "@testing-library/react-native": "^13.2.0", "@types/react": "~19.0.10", "@types/react-dom": "~19.1.3", "del-cli": "^6.0.0", "react": "19.0.0", "react-dom": "19.0.0", "react-native": "0.79.3", "react-native-builder-bob": "^0.40.12", "react-test-renderer": "19.0.0", "typescript": "^5.8.3"}, "peerDependencies": {"react": ">= 18.2.0", "react-native": "*"}, "react-native-builder-bob": {"source": "src", "output": "lib", "targets": [["module", {"esm": true}], ["typescript", {"project": "tsconfig.build.json"}]]}}
1
+ {"name": "@amazon-devices/react-navigation__native", "version": "8.0.9000000002+7.1.22", "description": "React Native integration for React Navigation", "keywords": ["react-native", "react-navigation", "ios", "android"], "homepage": "https://reactnavigation.org", "bugs": {"url": "https://github.com/react-navigation/react-navigation/issues"}, "license": "See license in LICENSE", "files": ["src", "lib", "!**/__tests__", "kepler-compatibility.json", "SystemModules", "SystemBundles", "oss-attribution", "kepler-transformed-package-info.json"], "exports": {".": {"source": "./src/index.tsx", "types": "./lib/typescript/src/index.d.ts", "default": "./lib/module/index.js"}, "./package.json": "./package.json"}, "main": "./lib/module/index.js", "dependencies": {"@amazon-devices/react-navigation__core": "^8.0.1"}, "peerDependencies": {"react": ">= 18.2.0", "react-native": "*"}, "types": "./lib/typescript/src/index.d.ts"}
package/src/index.tsx CHANGED
@@ -1,17 +1 @@
1
- export { createStaticNavigation } from './createStaticNavigation';
2
- export { Link } from './Link';
3
- export { LinkingContext } from './LinkingContext';
4
- export { LocaleDirContext } from './LocaleDirContext';
5
- export { NavigationContainer } from './NavigationContainer';
6
- export { ServerContainer } from './ServerContainer';
7
- export { DarkTheme } from './theming/DarkTheme';
8
- export { DefaultTheme } from './theming/DefaultTheme';
9
- export * from './types';
10
- export { UnhandledLinkingContext as UNSTABLE_UnhandledLinkingContext } from './UnhandledLinkingContext';
11
- export { useLinkBuilder } from './useLinkBuilder';
12
- export { type LinkProps, useLinkProps } from './useLinkProps';
13
- export { useLinkTo } from './useLinkTo';
14
- export { useLocale } from './useLocale';
15
- export { useRoutePath } from './useRoutePath';
16
- export { useScrollToTop } from './useScrollToTop';
17
- export * from '@amazon-devices/react-navigation__core';
1
+
@@ -1,62 +0,0 @@
1
- "use strict";
2
-
3
- import { useTheme } from '@amazon-devices/react-navigation__core';
4
- import * as React from 'react';
5
- import { Platform, Text } from 'react-native';
6
- import { useLinkProps } from "./useLinkProps.js";
7
- /**
8
- * Component to render link to another screen using a path.
9
- * Uses an anchor tag on the web.
10
- *
11
- * @param props.screen Name of the screen to navigate to (e.g. `'Feeds'`).
12
- * @param props.params Params to pass to the screen to navigate to (e.g. `{ sort: 'hot' }`).
13
- * @param props.href Optional absolute path to use for the href (e.g. `/feeds/hot`).
14
- * @param props.action Optional action to use for in-page navigation. By default, the path is parsed to an action based on linking config.
15
- * @param props.children Child elements to render the content.
16
- */
17
- export function Link({
18
- screen,
19
- params,
20
- action,
21
- href,
22
- style,
23
- ...rest
24
- }) {
25
- const {
26
- colors,
27
- fonts
28
- } = useTheme();
29
- // @ts-expect-error: This is already type-checked by the prop types
30
- const props = useLinkProps({
31
- screen,
32
- params,
33
- action,
34
- href
35
- });
36
- const onPress = e => {
37
- if ('onPress' in rest) {
38
- rest.onPress?.(e);
39
- }
40
-
41
- // Let user prevent default behavior
42
- if (!e.defaultPrevented) {
43
- props.onPress(e);
44
- }
45
- };
46
- return /*#__PURE__*/React.createElement(Text, {
47
- ...props,
48
- ...rest,
49
- ...Platform.select({
50
- web: {
51
- onClick: onPress
52
- },
53
- default: {
54
- onPress
55
- }
56
- }),
57
- style: [{
58
- color: colors.primary
59
- }, fonts.regular, style]
60
- });
61
- }
62
- //# sourceMappingURL=Link.js.map
@@ -1,11 +0,0 @@
1
- "use strict";
2
-
3
- import * as React from 'react';
4
- const MISSING_CONTEXT_ERROR = "Couldn't find a LinkingContext context.";
5
- export const LinkingContext = /*#__PURE__*/React.createContext({
6
- get options() {
7
- throw new Error(MISSING_CONTEXT_ERROR);
8
- }
9
- });
10
- LinkingContext.displayName = 'LinkingContext';
11
- //# sourceMappingURL=LinkingContext.js.map
@@ -1,6 +0,0 @@
1
- "use strict";
2
-
3
- import * as React from 'react';
4
- export const LocaleDirContext = /*#__PURE__*/React.createContext('ltr');
5
- LocaleDirContext.displayName = 'LocaleDirContext';
6
- //# sourceMappingURL=LocaleDirContext.js.map
@@ -1,128 +0,0 @@
1
- "use strict";
2
-
3
- import { BaseNavigationContainer, getActionFromState, getPathFromState, getStateFromPath, ThemeProvider, validatePathConfig } from '@amazon-devices/react-navigation__core';
4
- import * as React from 'react';
5
- import { I18nManager } from 'react-native';
6
- import useLatestCallback from 'use-latest-callback';
7
- import { LinkingContext } from "./LinkingContext.js";
8
- import { LocaleDirContext } from "./LocaleDirContext.js";
9
- import { DefaultTheme } from "./theming/DefaultTheme.js";
10
- import { UnhandledLinkingContext } from "./UnhandledLinkingContext.js";
11
- import { useBackButton } from './useBackButton';
12
- import { useDocumentTitle } from './useDocumentTitle';
13
- import { useLinking } from './useLinking';
14
- import { useThenable } from "./useThenable.js";
15
- import { jsx as _jsx } from "react/jsx-runtime";
16
- globalThis.REACT_NAVIGATION_DEVTOOLS = new WeakMap();
17
- function NavigationContainerInner({
18
- direction = I18nManager.getConstants().isRTL ? 'rtl' : 'ltr',
19
- theme = DefaultTheme,
20
- linking,
21
- fallback = null,
22
- documentTitle,
23
- onReady,
24
- onStateChange,
25
- ...rest
26
- }, ref) {
27
- const isLinkingEnabled = linking ? linking.enabled !== false : false;
28
- if (linking?.config) {
29
- validatePathConfig(linking.config);
30
- }
31
- const refContainer = React.useRef(null);
32
- useBackButton(refContainer);
33
- useDocumentTitle(refContainer, documentTitle);
34
- const [lastUnhandledLink, setLastUnhandledLink] = React.useState();
35
- const {
36
- getInitialState
37
- } = useLinking(refContainer, {
38
- enabled: isLinkingEnabled,
39
- prefixes: [],
40
- ...linking
41
- }, setLastUnhandledLink);
42
- const linkingContext = React.useMemo(() => ({
43
- options: linking
44
- }), [linking]);
45
- const unhandledLinkingContext = React.useMemo(() => ({
46
- lastUnhandledLink,
47
- setLastUnhandledLink
48
- }), [lastUnhandledLink, setLastUnhandledLink]);
49
- const onReadyForLinkingHandling = useLatestCallback(() => {
50
- // If the screen path matches lastUnhandledLink, we do not track it
51
- const path = refContainer.current?.getCurrentRoute()?.path;
52
- setLastUnhandledLink(previousLastUnhandledLink => {
53
- if (previousLastUnhandledLink === path) {
54
- return undefined;
55
- }
56
- return previousLastUnhandledLink;
57
- });
58
- onReady?.();
59
- });
60
- const onStateChangeForLinkingHandling = useLatestCallback(state => {
61
- // If the screen path matches lastUnhandledLink, we do not track it
62
- const path = refContainer.current?.getCurrentRoute()?.path;
63
- setLastUnhandledLink(previousLastUnhandledLink => {
64
- if (previousLastUnhandledLink === path) {
65
- return undefined;
66
- }
67
- return previousLastUnhandledLink;
68
- });
69
- onStateChange?.(state);
70
- });
71
- // Add additional linking related info to the ref
72
- // This will be used by the devtools
73
- React.useEffect(() => {
74
- if (refContainer.current) {
75
- REACT_NAVIGATION_DEVTOOLS.set(refContainer.current, {
76
- get linking() {
77
- return {
78
- ...linking,
79
- enabled: isLinkingEnabled,
80
- prefixes: linking?.prefixes ?? [],
81
- getStateFromPath: linking?.getStateFromPath ?? getStateFromPath,
82
- getPathFromState: linking?.getPathFromState ?? getPathFromState,
83
- getActionFromState: linking?.getActionFromState ?? getActionFromState
84
- };
85
- }
86
- });
87
- }
88
- });
89
- const [isResolved, initialState] = useThenable(getInitialState);
90
-
91
- // FIXME
92
- // @ts-expect-error not sure why this is not working
93
- React.useImperativeHandle(ref, () => refContainer.current);
94
- const isLinkingReady = rest.initialState != null || !isLinkingEnabled || isResolved;
95
- if (!isLinkingReady) {
96
- return /*#__PURE__*/_jsx(LocaleDirContext.Provider, {
97
- value: direction,
98
- children: /*#__PURE__*/_jsx(ThemeProvider, {
99
- value: theme,
100
- children: fallback
101
- })
102
- });
103
- }
104
- return /*#__PURE__*/_jsx(LocaleDirContext.Provider, {
105
- value: direction,
106
- children: /*#__PURE__*/_jsx(UnhandledLinkingContext.Provider, {
107
- value: unhandledLinkingContext,
108
- children: /*#__PURE__*/_jsx(LinkingContext.Provider, {
109
- value: linkingContext,
110
- children: /*#__PURE__*/_jsx(BaseNavigationContainer, {
111
- ...rest,
112
- theme: theme,
113
- onReady: onReadyForLinkingHandling,
114
- onStateChange: onStateChangeForLinkingHandling,
115
- initialState: rest.initialState == null ? initialState : rest.initialState,
116
- ref: refContainer
117
- })
118
- })
119
- })
120
- });
121
- }
122
-
123
- /**
124
- * Container component that manages the navigation state.
125
- * This should be rendered at the root wrapping the whole app.
126
- */
127
- export const NavigationContainer = /*#__PURE__*/React.forwardRef(NavigationContainerInner);
128
- //# sourceMappingURL=NavigationContainer.js.map
@@ -1,55 +0,0 @@
1
- "use strict";
2
-
3
- import { CurrentRenderContext } from '@amazon-devices/react-navigation__core';
4
- import * as React from 'react';
5
- import { ServerContext } from "./ServerContext.js";
6
- import { jsx as _jsx } from "react/jsx-runtime";
7
- /**
8
- * Container component for server rendering.
9
- *
10
- * @param props.location Location object to base the initial URL for SSR.
11
- * @param props.children Child elements to render the content.
12
- * @param props.ref Ref object which contains helper methods.
13
- */
14
- export const ServerContainer = /*#__PURE__*/React.forwardRef(function ServerContainer({
15
- children,
16
- location
17
- }, ref) {
18
- React.useEffect(() => {
19
- console.error("'ServerContainer' should only be used on the server with 'react-dom/server' for SSR.");
20
- }, []);
21
-
22
- // eslint-disable-next-line @eslint-react/no-unstable-context-value
23
- const current = {};
24
- if (ref) {
25
- const value = {
26
- getCurrentOptions() {
27
- return current.options;
28
- }
29
- };
30
-
31
- // We write to the `ref` during render instead of `React.useImperativeHandle`
32
- // This is because `useImperativeHandle` will update the ref after 'commit',
33
- // and there's no 'commit' phase during SSR.
34
- // Mutating ref during render is unsafe in concurrent mode, but we don't care about it for SSR.
35
- if (typeof ref === 'function') {
36
- ref(value);
37
- } else {
38
- ref.current = value;
39
- }
40
- }
41
- return (
42
- /*#__PURE__*/
43
- // eslint-disable-next-line @eslint-react/no-unstable-context-value
44
- _jsx(ServerContext.Provider, {
45
- value: {
46
- location
47
- },
48
- children: /*#__PURE__*/_jsx(CurrentRenderContext.Provider, {
49
- value: current,
50
- children: children
51
- })
52
- })
53
- );
54
- });
55
- //# sourceMappingURL=ServerContainer.js.map
@@ -1,5 +0,0 @@
1
- "use strict";
2
-
3
- import * as React from 'react';
4
- export const ServerContext = /*#__PURE__*/React.createContext(undefined);
5
- //# sourceMappingURL=ServerContext.js.map
@@ -1,14 +0,0 @@
1
- "use strict";
2
-
3
- import * as React from 'react';
4
- const MISSING_CONTEXT_ERROR = "Couldn't find an UnhandledLinkingContext context.";
5
- export const UnhandledLinkingContext = /*#__PURE__*/React.createContext({
6
- get lastUnhandledLink() {
7
- throw new Error(MISSING_CONTEXT_ERROR);
8
- },
9
- get setLastUnhandledLink() {
10
- throw new Error(MISSING_CONTEXT_ERROR);
11
- }
12
- });
13
- UnhandledLinkingContext.displayName = 'UnhandledLinkingContext';
14
- //# sourceMappingURL=UnhandledLinkingContext.js.map
@@ -1,18 +0,0 @@
1
- "use strict";
2
-
3
- import { createNavigatorFactory, StackRouter, useNavigationBuilder } from '@amazon-devices/react-navigation__core';
4
- import { jsx as _jsx } from "react/jsx-runtime";
5
- const StackNavigator = props => {
6
- const {
7
- state,
8
- descriptors,
9
- NavigationContent
10
- } = useNavigationBuilder(StackRouter, props);
11
- return /*#__PURE__*/_jsx(NavigationContent, {
12
- children: descriptors[state.routes[state.index].key].render()
13
- });
14
- };
15
- export function createStackNavigator() {
16
- return createNavigatorFactory(StackNavigator)();
17
- }
18
- //# sourceMappingURL=createStackNavigator.js.map
@@ -1,75 +0,0 @@
1
- "use strict";
2
-
3
- let location = new URL('', 'http://example.com');
4
- let listeners = [];
5
- let entries = [{
6
- state: null,
7
- href: location.href
8
- }];
9
- let index = 0;
10
- let currentState = null;
11
- const history = {
12
- get state() {
13
- return currentState;
14
- },
15
- pushState(state, _, path) {
16
- location = new URL(path, location.origin);
17
- currentState = state;
18
- entries = entries.slice(0, index + 1);
19
- entries.push({
20
- state,
21
- href: location.href
22
- });
23
- index = entries.length - 1;
24
- },
25
- replaceState(state, _, path) {
26
- location = new URL(path, location.origin);
27
- currentState = state;
28
- entries[index] = {
29
- state,
30
- href: location.href
31
- };
32
- },
33
- go(n) {
34
- setTimeout(() => {
35
- if (n > 0 && n < entries.length - index || n < 0 && Math.abs(n) <= index) {
36
- index += n;
37
- const entry = entries[index];
38
- location = new URL(entry.href);
39
- currentState = entry.state;
40
- listeners.forEach(cb => cb());
41
- }
42
- }, 0);
43
- },
44
- back() {
45
- this.go(-1);
46
- },
47
- forward() {
48
- this.go(1);
49
- }
50
- };
51
- const addEventListener = (type, listener) => {
52
- if (type === 'popstate') {
53
- listeners.push(listener);
54
- }
55
- };
56
- const removeEventListener = (type, listener) => {
57
- if (type === 'popstate') {
58
- listeners = listeners.filter(cb => cb !== listener);
59
- }
60
- };
61
- export const window = {
62
- document: {
63
- title: ''
64
- },
65
- get location() {
66
- return location;
67
- },
68
- history,
69
- addEventListener,
70
- removeEventListener,
71
- get window() {
72
- return window;
73
- }
74
- };
75
- //# sourceMappingURL=window.js.map
@@ -1,216 +0,0 @@
1
- "use strict";
2
-
3
- import { nanoid } from 'nanoid/non-secure';
4
- export function createMemoryHistory() {
5
- let index = 0;
6
- let items = [];
7
-
8
- // Pending callbacks for `history.go(n)`
9
- // We might modify the callback stored if it was interrupted, so we have a ref to identify it
10
- const pending = [];
11
- const interrupt = () => {
12
- // If another history operation was performed we need to interrupt existing ones
13
- // This makes sure that calls such as `history.replace` after `history.go` don't happen
14
- // Since otherwise it won't be correct if something else has changed
15
- pending.forEach(it => {
16
- const cb = it.cb;
17
- it.cb = () => cb(true);
18
- });
19
- };
20
- const history = {
21
- get index() {
22
- // We store an id in the state instead of an index
23
- // Index could get out of sync with in-memory values if page reloads
24
- const id = window.history.state?.id;
25
- if (id) {
26
- const index = items.findIndex(item => item.id === id);
27
- return index > -1 ? index : 0;
28
- }
29
- return 0;
30
- },
31
- get(index) {
32
- return items[index];
33
- },
34
- backIndex({
35
- path
36
- }) {
37
- // We need to find the index from the element before current to get closest path to go back to
38
- for (let i = index - 1; i >= 0; i--) {
39
- const item = items[i];
40
- if (item.path === path) {
41
- return i;
42
- }
43
- }
44
- return -1;
45
- },
46
- push({
47
- path,
48
- state
49
- }) {
50
- interrupt();
51
- const id = nanoid();
52
-
53
- // When a new entry is pushed, all the existing entries after index will be inaccessible
54
- // So we remove any existing entries after the current index to clean them up
55
- items = items.slice(0, index + 1);
56
- items.push({
57
- path,
58
- state,
59
- id
60
- });
61
- index = items.length - 1;
62
-
63
- // We pass empty string for title because it's ignored in all browsers except safari
64
- // We don't store state object in history.state because:
65
- // - browsers have limits on how big it can be, and we don't control the size
66
- // - while not recommended, there could be non-serializable data in state
67
- window.history.pushState({
68
- id
69
- }, '', path);
70
- },
71
- replace({
72
- path,
73
- state
74
- }) {
75
- interrupt();
76
- const id = window.history.state?.id ?? nanoid();
77
-
78
- // Need to keep the hash part of the path if there was no previous history entry
79
- // or the previous history entry had the same path
80
- let pathWithHash = path;
81
- const hash = pathWithHash.includes('#') ? '' : location.hash;
82
- if (!items.length || items.findIndex(item => item.id === id) < 0) {
83
- // There are two scenarios for creating an array with only one history record:
84
- // - When loaded id not found in the items array, this function by default will replace
85
- // the first item. We need to keep only the new updated object, otherwise it will break
86
- // the page when navigating forward in history.
87
- // - This is the first time any state modifications are done
88
- // So we need to push the entry as there's nothing to replace
89
-
90
- pathWithHash = pathWithHash + hash;
91
- items = [{
92
- path: pathWithHash,
93
- state,
94
- id
95
- }];
96
- index = 0;
97
- } else {
98
- if (items[index].path === path) {
99
- pathWithHash = pathWithHash + hash;
100
- }
101
- items[index] = {
102
- path,
103
- state,
104
- id
105
- };
106
- }
107
- window.history.replaceState({
108
- id
109
- }, '', pathWithHash);
110
- },
111
- // `history.go(n)` is asynchronous, there are couple of things to keep in mind:
112
- // - it won't do anything if we can't go `n` steps, the `popstate` event won't fire.
113
- // - each `history.go(n)` call will trigger a separate `popstate` event with correct location.
114
- // - the `popstate` event fires before the next frame after calling `history.go(n)`.
115
- // This method differs from `history.go(n)` in the sense that it'll go back as many steps it can.
116
- go(n) {
117
- interrupt();
118
-
119
- // To guard against unexpected navigation out of the app we will assume that browser history is only as deep as the length of our memory
120
- // history. If we don't have an item to navigate to then update our index and navigate as far as we can without taking the user out of the app.
121
- const nextIndex = index + n;
122
- const lastItemIndex = items.length - 1;
123
- if (n < 0 && !items[nextIndex]) {
124
- // Attempted to navigate beyond the first index. Negating the current index will align the browser history with the first item.
125
- n = -index;
126
- index = 0;
127
- } else if (n > 0 && nextIndex > lastItemIndex) {
128
- // Attempted to navigate past the last index. Calculate how many indices away from the last index and go there.
129
- n = lastItemIndex - index;
130
- index = lastItemIndex;
131
- } else {
132
- index = nextIndex;
133
- }
134
- if (n === 0) {
135
- return;
136
- }
137
-
138
- // When we call `history.go`, `popstate` will fire when there's history to go back to
139
- // So we need to somehow handle following cases:
140
- // - There's history to go back, `history.go` is called, and `popstate` fires
141
- // - `history.go` is called multiple times, we need to resolve on respective `popstate`
142
- // - No history to go back, but `history.go` was called, browser has no API to detect it
143
- return new Promise((resolve, reject) => {
144
- const done = interrupted => {
145
- clearTimeout(timer);
146
- if (interrupted) {
147
- reject(new Error('History was changed during navigation.'));
148
- return;
149
- }
150
-
151
- // There seems to be a bug in Chrome regarding updating the title
152
- // If we set a title just before calling `history.go`, the title gets lost
153
- // However the value of `document.title` is still what we set it to
154
- // It's just not displayed in the tab bar
155
- // To update the tab bar, we need to reset the title to something else first (e.g. '')
156
- // And set the title to what it was before so it gets applied
157
- // It won't work without setting it to empty string coz otherwise title isn't changing
158
- // Which means that the browser won't do anything after setting the title
159
- const {
160
- title
161
- } = window.document;
162
- window.document.title = '';
163
- window.document.title = title;
164
- resolve();
165
- };
166
- pending.push({
167
- ref: done,
168
- cb: done
169
- });
170
-
171
- // If navigation didn't happen within 100ms, assume that it won't happen
172
- // This may not be accurate, but hopefully it won't take so much time
173
- // In Chrome, navigation seems to happen instantly in next microtask
174
- // But on Firefox, it seems to take much longer, around 50ms from our testing
175
- // We're using a hacky timeout since there doesn't seem to be way to know for sure
176
- const timer = setTimeout(() => {
177
- const foundIndex = pending.findIndex(it => it.ref === done);
178
- if (foundIndex > -1) {
179
- pending[foundIndex].cb();
180
- pending.splice(foundIndex, 1);
181
- }
182
- index = this.index;
183
- }, 100);
184
- const onPopState = () => {
185
- // Fix createMemoryHistory.index variable's value
186
- // as it may go out of sync when navigating in the browser.
187
- index = this.index;
188
- const last = pending.pop();
189
- window.removeEventListener('popstate', onPopState);
190
- last?.cb();
191
- };
192
- window.addEventListener('popstate', onPopState);
193
- window.history.go(n);
194
- });
195
- },
196
- // The `popstate` event is triggered when history changes, except `pushState` and `replaceState`
197
- // If we call `history.go(n)` ourselves, we don't want it to trigger the listener
198
- // Here we normalize it so that only external changes (e.g. user pressing back/forward) trigger the listener
199
- listen(listener) {
200
- const onPopState = () => {
201
- // Fix createMemoryHistory.index variable's value
202
- // as it may go out of sync when navigating in the browser.
203
- index = this.index;
204
- if (pending.length) {
205
- // This was triggered by `history.go(n)`, we shouldn't call the listener
206
- return;
207
- }
208
- listener();
209
- };
210
- window.addEventListener('popstate', onPopState);
211
- return () => window.removeEventListener('popstate', onPopState);
212
- }
213
- };
214
- return history;
215
- }
216
- //# sourceMappingURL=createMemoryHistory.js.map