navigation-stack 0.3.1 → 0.4.0

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 (253) hide show
  1. package/README.md +603 -163
  2. package/data-storage/package.json +6 -0
  3. package/karma.conf.cjs +21 -4
  4. package/lib/cjs/NavigationStack.js +73 -0
  5. package/lib/cjs/data-storage/DataStorage.js +71 -0
  6. package/lib/cjs/data-storage/LocationDataStorage.js +29 -0
  7. package/lib/cjs/data-storage/index.js +9 -0
  8. package/lib/cjs/environment/InMemoryEnvironment.js +15 -0
  9. package/lib/cjs/environment/WebBrowserEnvironment.js +15 -0
  10. package/lib/cjs/environment/data-storage/InMemoryDataStorage.js +27 -0
  11. package/lib/cjs/environment/data-storage/WebBrowserDataStorage.js +21 -0
  12. package/lib/cjs/environment/scroll-position/InMemoryScrollPosition.js +44 -0
  13. package/lib/cjs/environment/scroll-position/WebBrowserScrollPosition.js +60 -0
  14. package/lib/cjs/getLocationFromInternalLocation.js +14 -0
  15. package/lib/cjs/index.js +20 -16
  16. package/lib/cjs/navigationBlockers.js +25 -23
  17. package/lib/cjs/{normalizeInputLocation.js → parseInputLocation.js} +25 -9
  18. package/lib/cjs/{ActionTypes.js → redux/ActionTypes.js} +1 -1
  19. package/lib/cjs/redux/ActionTypesInternal.js +8 -0
  20. package/lib/cjs/{Actions.js → redux/Actions.js} +5 -4
  21. package/lib/cjs/redux/createMiddlewares.js +60 -0
  22. package/lib/cjs/redux/index.js +13 -0
  23. package/lib/cjs/redux/internalLocationReducer.js +14 -0
  24. package/lib/cjs/redux/middleware/createAddInputLocationBasePathMiddleware.js +32 -0
  25. package/lib/cjs/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +113 -0
  26. package/lib/cjs/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +94 -0
  27. package/lib/cjs/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +30 -0
  28. package/lib/cjs/redux/middleware/createUpdateInternalLocationMiddleware.js +73 -0
  29. package/lib/cjs/{middleware/navigationActionMiddleware.js → redux/middleware/navigationOperationMiddleware.js} +11 -8
  30. package/lib/cjs/{middleware/normalizeInputLocationMiddleware.js → redux/middleware/parseInputLocationMiddleware.js} +6 -4
  31. package/lib/cjs/redux/middleware/updateLocationMiddleware.js +34 -0
  32. package/lib/cjs/scroll-position/PageScrollPositionSetter.js +97 -0
  33. package/lib/cjs/scroll-position/ScrollPositionAutoSaver.js +130 -0
  34. package/lib/cjs/scroll-position/ScrollPositionRestoration.js +383 -0
  35. package/lib/cjs/scroll-position/ScrollPositionSaver.js +81 -0
  36. package/lib/cjs/scroll-position/ScrollPositionSetter.js +16 -0
  37. package/lib/cjs/scroll-position/constants.js +5 -0
  38. package/lib/cjs/scroll-position/index.js +7 -0
  39. package/lib/cjs/scroll-position/scheduleNextTick.js +11 -0
  40. package/lib/cjs/session/InMemorySession.js +22 -0
  41. package/lib/cjs/session/ServerSideRenderSession.js +17 -0
  42. package/lib/cjs/session/Session.js +196 -0
  43. package/lib/cjs/session/WebBrowserSession.js +20 -0
  44. package/lib/cjs/session/key/createSessionKey.js +23 -0
  45. package/lib/cjs/session/lifecycle/InMemorySessionLifecycle.js +19 -0
  46. package/lib/cjs/session/lifecycle/WebBrowserSessionLifecycle.js +128 -0
  47. package/lib/cjs/session/lifecycle/page-lifecycle/PageLifecycle.js +269 -0
  48. package/lib/cjs/session/lifecycle/page-lifecycle/PageLifecycleInstance.js +8 -0
  49. package/lib/cjs/session/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +33 -0
  50. package/lib/cjs/session/navigation/InMemoryNavigation.js +104 -0
  51. package/lib/cjs/session/navigation/ServerSideNavigation.js +61 -0
  52. package/lib/cjs/session/navigation/WebBrowserNavigation.js +221 -0
  53. package/lib/cjs/session/navigation/error/NavigationOutOfBoundsError.js +12 -0
  54. package/lib/cjs/session/navigation/error/ServerSideNavigationError.js +21 -0
  55. package/lib/cjs/session/navigation/operation/operations.js +11 -0
  56. package/lib/cjs/session/subscription/Subscription.js +81 -0
  57. package/lib/data-storage/index.d.ts +35 -0
  58. package/lib/esm/NavigationStack.js +66 -0
  59. package/lib/esm/data-storage/DataStorage.js +65 -0
  60. package/lib/esm/data-storage/LocationDataStorage.js +22 -0
  61. package/lib/esm/data-storage/index.js +2 -0
  62. package/lib/esm/environment/InMemoryEnvironment.js +8 -0
  63. package/lib/esm/environment/WebBrowserEnvironment.js +8 -0
  64. package/lib/esm/environment/data-storage/InMemoryDataStorage.js +21 -0
  65. package/lib/esm/environment/data-storage/WebBrowserDataStorage.js +15 -0
  66. package/lib/esm/environment/scroll-position/InMemoryScrollPosition.js +38 -0
  67. package/lib/esm/environment/scroll-position/WebBrowserScrollPosition.js +54 -0
  68. package/lib/esm/getLocationFromInternalLocation.js +9 -0
  69. package/lib/esm/index.js +10 -8
  70. package/lib/esm/navigationBlockers.js +25 -23
  71. package/lib/esm/{normalizeInputLocation.js → parseInputLocation.js} +24 -8
  72. package/lib/esm/{ActionTypes.js → redux/ActionTypes.js} +1 -1
  73. package/lib/esm/redux/ActionTypesInternal.js +3 -0
  74. package/lib/esm/{Actions.js → redux/Actions.js} +5 -4
  75. package/lib/esm/redux/createMiddlewares.js +54 -0
  76. package/lib/esm/redux/index.js +4 -0
  77. package/lib/esm/redux/internalLocationReducer.js +8 -0
  78. package/lib/esm/redux/middleware/createAddInputLocationBasePathMiddleware.js +27 -0
  79. package/lib/esm/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +108 -0
  80. package/lib/esm/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +88 -0
  81. package/lib/esm/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +25 -0
  82. package/lib/esm/redux/middleware/createUpdateInternalLocationMiddleware.js +68 -0
  83. package/lib/esm/{middleware/navigationActionMiddleware.js → redux/middleware/navigationOperationMiddleware.js} +10 -7
  84. package/lib/esm/{middleware/normalizeInputLocationMiddleware.js → redux/middleware/parseInputLocationMiddleware.js} +5 -3
  85. package/lib/esm/redux/middleware/updateLocationMiddleware.js +28 -0
  86. package/lib/esm/scroll-position/PageScrollPositionSetter.js +91 -0
  87. package/lib/esm/scroll-position/ScrollPositionAutoSaver.js +123 -0
  88. package/lib/esm/scroll-position/ScrollPositionRestoration.js +376 -0
  89. package/lib/esm/scroll-position/ScrollPositionSaver.js +74 -0
  90. package/lib/esm/scroll-position/ScrollPositionSetter.js +10 -0
  91. package/lib/esm/scroll-position/constants.js +1 -0
  92. package/lib/esm/scroll-position/index.js +1 -0
  93. package/lib/esm/scroll-position/scheduleNextTick.js +6 -0
  94. package/lib/esm/session/InMemorySession.js +15 -0
  95. package/lib/esm/session/ServerSideRenderSession.js +11 -0
  96. package/lib/esm/session/Session.js +189 -0
  97. package/lib/esm/session/WebBrowserSession.js +13 -0
  98. package/lib/esm/session/key/createSessionKey.js +18 -0
  99. package/lib/esm/session/lifecycle/InMemorySessionLifecycle.js +13 -0
  100. package/lib/esm/session/lifecycle/WebBrowserSessionLifecycle.js +120 -0
  101. package/lib/esm/session/lifecycle/page-lifecycle/PageLifecycle.js +263 -0
  102. package/lib/esm/session/lifecycle/page-lifecycle/PageLifecycleInstance.js +2 -0
  103. package/lib/esm/session/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +30 -0
  104. package/lib/esm/session/navigation/InMemoryNavigation.js +97 -0
  105. package/lib/esm/session/navigation/ServerSideNavigation.js +54 -0
  106. package/lib/esm/session/navigation/WebBrowserNavigation.js +213 -0
  107. package/lib/esm/session/navigation/error/NavigationOutOfBoundsError.js +6 -0
  108. package/lib/esm/session/navigation/error/ServerSideNavigationError.js +14 -0
  109. package/lib/esm/session/navigation/operation/operations.js +6 -0
  110. package/lib/esm/session/subscription/Subscription.js +75 -0
  111. package/lib/index.d.ts +178 -157
  112. package/lib/redux/index.d.ts +90 -0
  113. package/lib/scroll-position/index.d.ts +107 -0
  114. package/package.json +9 -5
  115. package/redux/package.json +6 -0
  116. package/scroll-position/package.json +6 -0
  117. package/src/NavigationStack.js +84 -0
  118. package/src/data-storage/DataStorage.js +69 -0
  119. package/src/data-storage/LocationDataStorage.js +23 -0
  120. package/src/data-storage/index.js +2 -0
  121. package/src/environment/InMemoryEnvironment.js +9 -0
  122. package/src/environment/WebBrowserEnvironment.js +9 -0
  123. package/src/environment/data-storage/InMemoryDataStorage.js +23 -0
  124. package/src/environment/data-storage/WebBrowserDataStorage.js +17 -0
  125. package/src/environment/scroll-position/InMemoryScrollPosition.js +45 -0
  126. package/src/environment/scroll-position/WebBrowserScrollPosition.js +72 -0
  127. package/src/getLocationFromInternalLocation.js +7 -0
  128. package/src/index.js +10 -8
  129. package/src/navigationBlockers.js +28 -27
  130. package/src/{normalizeInputLocation.js → parseInputLocation.js} +23 -8
  131. package/src/{ActionTypes.js → redux/ActionTypes.js} +1 -1
  132. package/src/redux/ActionTypesInternal.js +3 -0
  133. package/src/{Actions.js → redux/Actions.js} +4 -3
  134. package/src/redux/createMiddlewares.js +65 -0
  135. package/src/redux/index.js +4 -0
  136. package/src/redux/internalLocationReducer.js +9 -0
  137. package/src/redux/middleware/createAddInputLocationBasePathMiddleware.js +27 -0
  138. package/src/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +119 -0
  139. package/src/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +94 -0
  140. package/src/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +26 -0
  141. package/src/redux/middleware/createUpdateInternalLocationMiddleware.js +72 -0
  142. package/src/{middleware/navigationActionMiddleware.js → redux/middleware/navigationOperationMiddleware.js} +10 -3
  143. package/src/{middleware/normalizeInputLocationMiddleware.js → redux/middleware/parseInputLocationMiddleware.js} +5 -3
  144. package/src/redux/middleware/updateLocationMiddleware.js +28 -0
  145. package/src/scroll-position/PageScrollPositionSetter.js +110 -0
  146. package/src/scroll-position/ScrollPositionAutoSaver.js +151 -0
  147. package/src/scroll-position/ScrollPositionRestoration.js +506 -0
  148. package/src/scroll-position/ScrollPositionSaver.js +100 -0
  149. package/src/scroll-position/ScrollPositionSetter.js +16 -0
  150. package/src/scroll-position/constants.js +1 -0
  151. package/src/scroll-position/index.js +1 -0
  152. package/src/scroll-position/scheduleNextTick.js +6 -0
  153. package/src/session/InMemorySession.js +13 -0
  154. package/src/session/ServerSideRenderSession.js +9 -0
  155. package/src/session/Session.js +216 -0
  156. package/src/session/WebBrowserSession.js +13 -0
  157. package/src/session/key/createSessionKey.js +18 -0
  158. package/src/session/lifecycle/InMemorySessionLifecycle.js +13 -0
  159. package/src/session/lifecycle/WebBrowserSessionLifecycle.js +126 -0
  160. package/src/session/lifecycle/page-lifecycle/PageLifecycle.js +291 -0
  161. package/src/session/lifecycle/page-lifecycle/PageLifecycleInstance.js +3 -0
  162. package/src/session/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +32 -0
  163. package/src/session/navigation/InMemoryNavigation.js +78 -0
  164. package/src/session/navigation/ServerSideNavigation.js +43 -0
  165. package/src/session/navigation/WebBrowserNavigation.js +224 -0
  166. package/src/session/navigation/error/NavigationOutOfBoundsError.js +7 -0
  167. package/src/session/navigation/error/ServerSideNavigationError.js +18 -0
  168. package/src/session/navigation/operation/operations.js +6 -0
  169. package/src/session/subscription/Subscription.js +76 -0
  170. package/test/NavigationStack.test.js +296 -0
  171. package/test/{LocationDataStorage.test.js → data-storage/LocationDataStorage.test.js} +3 -3
  172. package/test/data-storage/index.test.js +8 -0
  173. package/test/index.js +12 -0
  174. package/test/index.test.js +8 -7
  175. package/test/{helpers.js → middlewareTestUtil.js} +9 -12
  176. package/test/{normalizeInputLocation.test.js → parseInputLocationMiddleware.test.js} +9 -9
  177. package/test/{Action.test.js → redux/Action.test.js} +7 -6
  178. package/test/{ActionTypes.test.js → redux/ActionTypes.test.js} +2 -2
  179. package/test/redux/createMiddlewares.test.js +96 -0
  180. package/test/redux/index.test.js +10 -0
  181. package/test/{locationReducer.test.js → redux/locationReducer.test.js} +4 -7
  182. package/test/redux/middleware/createAddInputLocationBasePathMiddleware.test.js +40 -0
  183. package/test/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.test.js +264 -0
  184. package/test/redux/middleware/createProgrammaticNavigationBlockerMiddleware.test.js +312 -0
  185. package/test/redux/middleware/createRemoveOutputLocationBasePathMiddleware.test.js +51 -0
  186. package/test/{middleware/navigationActionMiddleware.test.js → redux/middleware/navigationOperationMiddleware.test.js} +16 -12
  187. package/test/{middleware/normalizeInputLocationMiddleware.test.js → redux/middleware/parseInputLocationMiddleware.test.js} +4 -4
  188. package/test/scroll-position/ScrollPositionRestoration.test.js +418 -0
  189. package/test/scroll-position/addScrollableContainer.js +36 -0
  190. package/test/scroll-position/addScrollableContainerWithHyperlink.js +50 -0
  191. package/test/scroll-position/createApp.js +112 -0
  192. package/test/scroll-position/delay.js +9 -0
  193. package/test/scroll-position/mockPageLifecycle.js +17 -0
  194. package/test/scroll-position/runApp.js +24 -0
  195. package/test/scroll-position/withScrollableContainerAtIndexPage.js +62 -0
  196. package/test/session/InMemorySession.test.js +348 -0
  197. package/test/session/ServerSession.test.js +17 -9
  198. package/test/session/WebBrowserSession.test.js +265 -0
  199. package/test/testUtil.js +3 -0
  200. package/types/data-storage/index.d.ts +35 -0
  201. package/types/index.d.ts +178 -157
  202. package/types/redux/index.d.ts +90 -0
  203. package/types/scroll-position/index.d.ts +107 -0
  204. package/types/tsconfig.json +1 -1
  205. package/lib/cjs/LocationDataStorage.js +0 -61
  206. package/lib/cjs/addBeforeLocationChangeListener.js +0 -7
  207. package/lib/cjs/beforeLocationChangeListeners.js +0 -51
  208. package/lib/cjs/createMiddlewares.js +0 -47
  209. package/lib/cjs/middleware/createBasePathMiddleware.js +0 -24
  210. package/lib/cjs/middleware/createBeforeLocationChangeListenerMiddleware.js +0 -39
  211. package/lib/cjs/middleware/createLocationMiddleware.js +0 -56
  212. package/lib/cjs/middleware/createNavigationBlockerMiddleware.js +0 -161
  213. package/lib/cjs/middleware/createTransformLocationMiddleware.js +0 -38
  214. package/lib/cjs/onlyAllowedOnClientSide.js +0 -10
  215. package/lib/cjs/session/BrowserSession.js +0 -235
  216. package/lib/cjs/session/MemorySession.js +0 -223
  217. package/lib/cjs/session/ServerSession.js +0 -65
  218. package/lib/esm/LocationDataStorage.js +0 -54
  219. package/lib/esm/addBeforeLocationChangeListener.js +0 -2
  220. package/lib/esm/beforeLocationChangeListeners.js +0 -44
  221. package/lib/esm/createMiddlewares.js +0 -41
  222. package/lib/esm/middleware/createBasePathMiddleware.js +0 -19
  223. package/lib/esm/middleware/createBeforeLocationChangeListenerMiddleware.js +0 -34
  224. package/lib/esm/middleware/createLocationMiddleware.js +0 -50
  225. package/lib/esm/middleware/createNavigationBlockerMiddleware.js +0 -156
  226. package/lib/esm/middleware/createTransformLocationMiddleware.js +0 -33
  227. package/lib/esm/onlyAllowedOnClientSide.js +0 -5
  228. package/lib/esm/session/BrowserSession.js +0 -229
  229. package/lib/esm/session/MemorySession.js +0 -217
  230. package/lib/esm/session/ServerSession.js +0 -58
  231. package/src/LocationDataStorage.js +0 -60
  232. package/src/addBeforeLocationChangeListener.js +0 -2
  233. package/src/beforeLocationChangeListeners.js +0 -54
  234. package/src/createMiddlewares.js +0 -45
  235. package/src/middleware/createBasePathMiddleware.js +0 -20
  236. package/src/middleware/createBeforeLocationChangeListenerMiddleware.js +0 -40
  237. package/src/middleware/createLocationMiddleware.js +0 -55
  238. package/src/middleware/createNavigationBlockerMiddleware.js +0 -168
  239. package/src/middleware/createTransformLocationMiddleware.js +0 -29
  240. package/src/onlyAllowedOnClientSide.js +0 -5
  241. package/src/session/BrowserSession.js +0 -235
  242. package/src/session/MemorySession.js +0 -219
  243. package/src/session/ServerSession.js +0 -67
  244. package/test/createMiddlewares.test.js +0 -62
  245. package/test/middleware/createBasePathMiddleware.test.js +0 -67
  246. package/test/middleware/createBeforeLocationChangeListenerMiddleware.test.js +0 -141
  247. package/test/middleware/createNavigationBlockerMiddleware.test.js +0 -471
  248. package/test/middleware/createTransformLocationMiddleware.test.js +0 -44
  249. package/test/session/BrowserSession.test.js +0 -182
  250. package/test/session/MemorySession.test.js +0 -244
  251. /package/lib/cjs/{locationReducer.js → redux/locationReducer.js} +0 -0
  252. /package/lib/esm/{locationReducer.js → redux/locationReducer.js} +0 -0
  253. /package/src/{locationReducer.js → redux/locationReducer.js} +0 -0
@@ -0,0 +1,6 @@
1
+ {
2
+ "private": true,
3
+ "name": "navigation-stack/data-storage",
4
+ "main": "./../lib/cjs/data-storage/index.js",
5
+ "module": "./../lib/esm/data-storage/index.js"
6
+ }
package/karma.conf.cjs CHANGED
@@ -14,7 +14,7 @@ module.exports = (config) => {
14
14
  const { env } = process;
15
15
 
16
16
  config.set({
17
- frameworks: ['mocha', 'webpack', 'sinon-chai'],
17
+ frameworks: ['webpack', 'mocha', 'sinon-chai'],
18
18
 
19
19
  files: ['test/index.js', { pattern: 'test/**/*.test.js', watched: false }],
20
20
 
@@ -26,16 +26,32 @@ module.exports = (config) => {
26
26
  mode: 'development',
27
27
  module: {
28
28
  rules: [
29
- { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader' },
29
+ {
30
+ test: /\.js$/,
31
+ exclude: /node_modules/,
32
+ use: {
33
+ loader: 'babel-loader',
34
+ },
35
+ },
30
36
  ],
31
37
  },
32
38
  plugins: [
33
39
  new webpack.DefinePlugin({
34
40
  __DEV__: true,
35
41
  }),
42
+ new webpack.ProvidePlugin({
43
+ process: 'process/browser',
44
+ }),
36
45
  ],
37
46
  },
38
47
 
48
+ resolve: {
49
+ fallback: {
50
+ process: require.resolve('process/browser'),
51
+ util: require.resolve('util/'),
52
+ },
53
+ },
54
+
39
55
  webpackMiddleware: {
40
56
  noInfo: true,
41
57
  },
@@ -53,11 +69,12 @@ module.exports = (config) => {
53
69
 
54
70
  customLaunchers: {
55
71
  ChromeCi: {
56
- base: 'ChromeHeadless',
72
+ // base: 'ChromeHeadless',
73
+ base: 'Chrome',
57
74
  flags: ['--no-sandbox'],
58
75
  },
59
76
  },
60
77
 
61
- browsers: env.BROWSER ? env.BROWSER.split(',') : ['Chrome'],
78
+ browsers: env.BROWSER ? env.BROWSER.split(',') : ['Chrome', 'Firefox'],
62
79
  });
63
80
  };
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _redux = require("redux");
6
+ var _Actions = _interopRequireDefault(require("./redux/Actions"));
7
+ var _createMiddlewares = _interopRequireDefault(require("./redux/createMiddlewares"));
8
+ var _locationReducer = _interopRequireDefault(require("./redux/locationReducer"));
9
+ var _ScrollPositionRestoration = _interopRequireDefault(require("./scroll-position/ScrollPositionRestoration"));
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ class NavigationStack {
12
+ constructor(session, options) {
13
+ this._session = session;
14
+
15
+ // Create a Redux store.
16
+ this._store = (0, _redux.createStore)(_locationReducer.default, (0, _redux.applyMiddleware)(...(0, _createMiddlewares.default)(session, options)));
17
+
18
+ // Create `ScrollPositionRestoration`.
19
+ if (options && options.maintainScrollPosition) {
20
+ this._scrollPositionRestoration = new _ScrollPositionRestoration.default(session);
21
+ }
22
+ }
23
+ addScrollableContainer(scrollableContainerKey, scrollableContainer) {
24
+ if (!this._scrollPositionRestoration) {
25
+ throw new Error('`maintainScrollPosition: true` option not passed');
26
+ }
27
+ return this._scrollPositionRestoration.addScrollableContainer(scrollableContainerKey, scrollableContainer);
28
+ }
29
+ subscribe(listener) {
30
+ // Subscribe to any potential Redux state changes.
31
+ return this._store.subscribe(() => {
32
+ // Initially, calls the listener when setting the initial location.
33
+ // After that, calls it on any location change.
34
+ const location = this.current();
35
+ if (!this._latestLocation || location !== this._latestLocation) {
36
+ this._latestLocation = location;
37
+ listener(location);
38
+ }
39
+ });
40
+ }
41
+ init(initialLocation) {
42
+ if (this._latestLocation) {
43
+ throw new Error('Already initialized');
44
+ }
45
+ this._store.dispatch(_Actions.default.init(initialLocation));
46
+ this._latestLocation = this.current();
47
+ }
48
+ current() {
49
+ return this._store.getState();
50
+ }
51
+ push(location) {
52
+ this._store.dispatch(_Actions.default.push(location));
53
+ }
54
+ replace(location) {
55
+ this._store.dispatch(_Actions.default.replace(location));
56
+ }
57
+ shift(delta) {
58
+ this._store.dispatch(_Actions.default.shift(delta));
59
+ }
60
+ stop() {
61
+ if (this._scrollPositionRestoration) {
62
+ this._scrollPositionRestoration.stop();
63
+ }
64
+ this._store.dispatch(_Actions.default.stop());
65
+ }
66
+ locationRendered() {
67
+ if (this._scrollPositionRestoration) {
68
+ this._scrollPositionRestoration.locationRendered(this.current());
69
+ }
70
+ }
71
+ }
72
+ exports.default = NavigationStack;
73
+ module.exports = exports.default;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ class DataStorage {
6
+ constructor(session, {
7
+ namespace
8
+ }) {
9
+ if (!session.key) {
10
+ throw new Error('`DataStorage` requires a `session.key`');
11
+ }
12
+ this._sessionKey = session.key;
13
+ this._dataStorage = session.environment.dataStorage;
14
+ this._namespace = namespace;
15
+ }
16
+ get(key) {
17
+ const storageKey = this._getStorageKey(key);
18
+ try {
19
+ const value = this._dataStorage.get(storageKey);
20
+ // === null is probably sufficient.
21
+ if (value === null) {
22
+ return undefined;
23
+ }
24
+
25
+ // We want to catch JSON parse errors in case someone separately threw
26
+ // junk into sessionStorage under our namespace.
27
+ return JSON.parse(value);
28
+ } catch (error) {
29
+ // eslint-disable-next-line no-console
30
+ console.error('[navigation-stack] Could not read data from storage');
31
+
32
+ // Pretend that the entry doesn't exist.
33
+ return undefined;
34
+ }
35
+ }
36
+ set(key, value) {
37
+ const storageKey = this._getStorageKey(key);
38
+ if (value === undefined) {
39
+ try {
40
+ this._dataStorage.remove(storageKey);
41
+ } catch (error) {
42
+ // No need to handle errors here.
43
+ // eslint-disable-next-line no-console
44
+ console.error('[navigation-stack] Could not delete data from storage');
45
+ }
46
+ return;
47
+ }
48
+
49
+ // Unlike with read, we want to fail on invalid values here, since the
50
+ // value here is provided by the caller of this method.
51
+ const valueString = JSON.stringify(value);
52
+ try {
53
+ this._dataStorage.set(storageKey, valueString);
54
+ } catch (error) {
55
+ // No need to handle errors here either. If it didn't work, it didn't
56
+ // work. We make no guarantees about actually saving the value.
57
+ // eslint-disable-next-line no-console
58
+ console.error('[navigation-stack] Could not save data in storage');
59
+ }
60
+ }
61
+
62
+ // It could also implement a method that would clean up any data written so far,
63
+ // but so far it doesn't seem to be required by any real-world use case.
64
+ // cleanUp() {}
65
+
66
+ _getStorageKey(key) {
67
+ return `${this._sessionKey}|${this.namespace}|${key}`;
68
+ }
69
+ }
70
+ exports.default = DataStorage;
71
+ module.exports = exports.default;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _DataStorage = _interopRequireDefault(require("./DataStorage"));
6
+ var _getLocationUrl = _interopRequireDefault(require("../getLocationUrl"));
7
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
+ class LocationDataStorage {
9
+ constructor(session, {
10
+ namespace
11
+ }) {
12
+ this._storage = new _DataStorage.default(session, {
13
+ namespace
14
+ });
15
+ this._getFallbackLocationKey = _getLocationUrl.default;
16
+ }
17
+ get(location, key) {
18
+ return this._storage.get(this._getKey(location, key));
19
+ }
20
+ set(location, key, value) {
21
+ this._storage.set(this._getKey(location, key), value);
22
+ }
23
+ _getKey(location, key) {
24
+ const locationKey = location.key || this._getFallbackLocationKey(location);
25
+ return `${locationKey}|${key}`;
26
+ }
27
+ }
28
+ exports.default = LocationDataStorage;
29
+ module.exports = exports.default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.LocationDataStorage = exports.DataStorage = void 0;
5
+ var _DataStorage = _interopRequireDefault(require("./DataStorage"));
6
+ exports.DataStorage = _DataStorage.default;
7
+ var _LocationDataStorage = _interopRequireDefault(require("./LocationDataStorage"));
8
+ exports.LocationDataStorage = _LocationDataStorage.default;
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _InMemoryDataStorage = _interopRequireDefault(require("./data-storage/InMemoryDataStorage"));
6
+ var _InMemoryScrollPosition = _interopRequireDefault(require("./scroll-position/InMemoryScrollPosition"));
7
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
+ class InMemoryEnvironment {
9
+ constructor() {
10
+ this.dataStorage = new _InMemoryDataStorage.default();
11
+ this.scrollPosition = new _InMemoryScrollPosition.default();
12
+ }
13
+ }
14
+ exports.default = InMemoryEnvironment;
15
+ module.exports = exports.default;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _WebBrowserDataStorage = _interopRequireDefault(require("./data-storage/WebBrowserDataStorage"));
6
+ var _WebBrowserScrollPosition = _interopRequireDefault(require("./scroll-position/WebBrowserScrollPosition"));
7
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
+ class WebBrowserEnvironment {
9
+ constructor() {
10
+ this.dataStorage = new _WebBrowserDataStorage.default();
11
+ this.scrollPosition = new _WebBrowserScrollPosition.default();
12
+ }
13
+ }
14
+ exports.default = WebBrowserEnvironment;
15
+ module.exports = exports.default;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ class InMemoryDataStorage {
6
+ constructor() {
7
+ this._state = {};
8
+ }
9
+
10
+ // Returns either a `string` value or `null` if the key doesn't exist.
11
+ get(key) {
12
+ if (key in this._state) {
13
+ return this._state[key];
14
+ }
15
+ return null;
16
+ }
17
+ remove(key) {
18
+ if (key in this._state) {
19
+ delete this._state[key];
20
+ }
21
+ }
22
+ set(key, value) {
23
+ this._state[key] = value;
24
+ }
25
+ }
26
+ exports.default = InMemoryDataStorage;
27
+ module.exports = exports.default;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ class WebBrowserDataStorage {
6
+ // Returns either a `string` value or `null` if the key doesn't exist.
7
+ get(key) {
8
+ // `sessionStorage` persists across page reloads, and so does web browser navigation history.
9
+ return window.sessionStorage.getItem(key);
10
+ }
11
+ remove(key) {
12
+ // `sessionStorage` persists across page reloads, and so does web browser navigation history.
13
+ window.sessionStorage.removeItem(key);
14
+ }
15
+ set(key, value) {
16
+ // `sessionStorage` persists across page reloads, and so does web browser navigation history.
17
+ window.sessionStorage.setItem(key, value);
18
+ }
19
+ }
20
+ exports.default = WebBrowserDataStorage;
21
+ module.exports = exports.default;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ class InMemoryScrollPosition {
6
+ constructor() {
7
+ this.init();
8
+ }
9
+ getPageScrollPosition() {
10
+ return this._pageScrollPosition || [0, 0];
11
+ }
12
+ setPageScrollPosition(scrollPosition) {
13
+ this._pageScrollPosition = scrollPosition;
14
+ }
15
+
16
+ // eslint-disable-next-line no-unused-vars
17
+ setPageScrollPositionAtAnchor(anchor) {
18
+ this.setPageScrollPosition([0, 0]);
19
+ }
20
+ getScrollableContainerScrollPosition(key) {
21
+ return this._scrollableContainerScrollPositions[key] || [0, 0];
22
+ }
23
+ setScrollableContainerScrollPosition(key, scrollPosition) {
24
+ this._scrollableContainerScrollPositions[key] = scrollPosition;
25
+ }
26
+
27
+ // eslint-disable-next-line no-unused-vars
28
+ addPageScrollListener(listener) {
29
+ return () => {};
30
+ }
31
+
32
+ // eslint-disable-next-line no-unused-vars
33
+ addScrollableContainerScrollListener(scrollableContainerElement, listener) {
34
+ return () => {};
35
+ }
36
+ enableAutomaticScrollRestoration() {}
37
+ disableAutomaticScrollRestoration() {}
38
+ init() {
39
+ this._pageScrollPosition = undefined;
40
+ this._scrollableContainerScrollPositions = {};
41
+ }
42
+ }
43
+ exports.default = InMemoryScrollPosition;
44
+ module.exports = exports.default;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ class WebBrowserScrollPosition {
6
+ getPageScrollPosition() {
7
+ return [window.pageXOffset, window.pageYOffset];
8
+ }
9
+ setPageScrollPosition(scrollPosition) {
10
+ const [scrollX, scrollY] = scrollPosition;
11
+ window.scrollTo(scrollX, scrollY);
12
+ }
13
+ setPageScrollPositionAtAnchor(anchor) {
14
+ const anchorElement = document.getElementById(anchor) || document.getElementsByName(anchor)[0];
15
+ if (anchorElement) {
16
+ // By default it scrolls the element into view
17
+ // so that it's visible at the top of the window.
18
+ anchorElement.scrollIntoView();
19
+ } else {
20
+ this.setPageScrollPosition([0, 0]);
21
+ }
22
+ }
23
+ getScrollableContainerScrollPosition(scrollableContainerElement) {
24
+ return [scrollableContainerElement.scrollLeft, scrollableContainerElement.scrollTop];
25
+ }
26
+ setScrollableContainerScrollPosition(scrollableContainerElement, scrollPosition) {
27
+ const [scrollX, scrollY] = scrollPosition;
28
+ scrollableContainerElement.scrollLeft = scrollX;
29
+ scrollableContainerElement.scrollTop = scrollY;
30
+ }
31
+ addPageScrollListener(listener) {
32
+ // eslint-disable-next-line no-unused-vars
33
+ const scrollListener = event => {
34
+ listener();
35
+ };
36
+ window.addEventListener('scroll', scrollListener);
37
+ return () => {
38
+ window.removeEventListener('scroll', scrollListener);
39
+ };
40
+ }
41
+ addScrollableContainerScrollListener(scrollableContainerElement, listener) {
42
+ // eslint-disable-next-line no-unused-vars
43
+ const scrollListener = event => {
44
+ listener();
45
+ };
46
+ scrollableContainerElement.addEventListener('scroll', scrollListener);
47
+ return () => {
48
+ scrollableContainerElement.removeEventListener('scroll', scrollListener);
49
+ };
50
+ }
51
+ enableAutomaticScrollRestoration() {
52
+ window.history.scrollRestoration = 'auto';
53
+ }
54
+ disableAutomaticScrollRestoration() {
55
+ window.history.scrollRestoration = 'manual';
56
+ }
57
+ init() {}
58
+ }
59
+ exports.default = WebBrowserScrollPosition;
60
+ module.exports = exports.default;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = getLocationFromInternalLocation;
5
+ const _excluded = ["operation", "index", "delta"];
6
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
7
+ // Converts `LocationInternal` object to a publicly-visible `Location` object.
8
+ // It hides non-essential properties of location such as `operation`, `index`, `delta`.
9
+ function getLocationFromInternalLocation(internalLocation) {
10
+ // eslint-disable-next-line no-unused-vars
11
+ const location = _objectWithoutPropertiesLoose(internalLocation, _excluded);
12
+ return location;
13
+ }
14
+ module.exports = exports.default;
package/lib/cjs/index.js CHANGED
@@ -1,11 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.removeBasePath = exports.parseLocationUrl = exports.locationReducer = exports.getLocationUrl = exports.createMiddlewares = exports.addNavigationBlocker = exports.addBasePath = exports.ServerSession = exports.MemorySession = exports.LocationDataStorage = exports.BrowserSession = exports.Actions = exports.ActionTypes = void 0;
5
- var _Actions = _interopRequireDefault(require("./Actions"));
6
- exports.Actions = _Actions.default;
7
- var _ActionTypes = _interopRequireDefault(require("./ActionTypes"));
8
- exports.ActionTypes = _ActionTypes.default;
4
+ exports.removeBasePath = exports.parseLocationUrl = exports.parseInputLocation = exports.getLocationUrl = exports.addNavigationBlocker = exports.addBasePath = exports.WebBrowserSession = exports.Session = exports.ServerSideRenderSession = exports.ServerSideNavigationError = exports.NavigationStack = exports.NavigationOutOfBoundsError = exports.LocationDataStorage = exports.InMemorySession = exports.DataStorage = void 0;
9
5
  var _basePath = require("./basePath");
10
6
  exports.addBasePath = _basePath.addBasePath;
11
7
  exports.removeBasePath = _basePath.removeBasePath;
@@ -15,16 +11,24 @@ var _getLocationUrl = _interopRequireDefault(require("./getLocationUrl"));
15
11
  exports.getLocationUrl = _getLocationUrl.default;
16
12
  var _parseLocationUrl = _interopRequireDefault(require("./parseLocationUrl"));
17
13
  exports.parseLocationUrl = _parseLocationUrl.default;
18
- var _createMiddlewares = _interopRequireDefault(require("./createMiddlewares"));
19
- exports.createMiddlewares = _createMiddlewares.default;
20
- var _locationReducer = _interopRequireDefault(require("./locationReducer"));
21
- exports.locationReducer = _locationReducer.default;
22
- var _LocationDataStorage = _interopRequireDefault(require("./LocationDataStorage"));
14
+ var _parseInputLocation = _interopRequireDefault(require("./parseInputLocation"));
15
+ exports.parseInputLocation = _parseInputLocation.default;
16
+ var _NavigationStack = _interopRequireDefault(require("./NavigationStack"));
17
+ exports.NavigationStack = _NavigationStack.default;
18
+ var _DataStorage = _interopRequireDefault(require("./data-storage/DataStorage"));
19
+ exports.DataStorage = _DataStorage.default;
20
+ var _LocationDataStorage = _interopRequireDefault(require("./data-storage/LocationDataStorage"));
23
21
  exports.LocationDataStorage = _LocationDataStorage.default;
24
- var _BrowserSession = _interopRequireDefault(require("./session/BrowserSession"));
25
- exports.BrowserSession = _BrowserSession.default;
26
- var _MemorySession = _interopRequireDefault(require("./session/MemorySession"));
27
- exports.MemorySession = _MemorySession.default;
28
- var _ServerSession = _interopRequireDefault(require("./session/ServerSession"));
29
- exports.ServerSession = _ServerSession.default;
22
+ var _Session = _interopRequireDefault(require("./session/Session"));
23
+ exports.Session = _Session.default;
24
+ var _InMemorySession = _interopRequireDefault(require("./session/InMemorySession"));
25
+ exports.InMemorySession = _InMemorySession.default;
26
+ var _WebBrowserSession = _interopRequireDefault(require("./session/WebBrowserSession"));
27
+ exports.WebBrowserSession = _WebBrowserSession.default;
28
+ var _ServerSideRenderSession = _interopRequireDefault(require("./session/ServerSideRenderSession"));
29
+ exports.ServerSideRenderSession = _ServerSideRenderSession.default;
30
+ var _ServerSideNavigationError = _interopRequireDefault(require("./session/navigation/error/ServerSideNavigationError"));
31
+ exports.ServerSideNavigationError = _ServerSideNavigationError.default;
32
+ var _NavigationOutOfBoundsError = _interopRequireDefault(require("./session/navigation/error/NavigationOutOfBoundsError"));
33
+ exports.NavigationOutOfBoundsError = _NavigationOutOfBoundsError.default;
30
34
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -24,12 +24,12 @@ function removeNavigationBlockerFromTheList(blocker, session) {
24
24
  }
25
25
  }
26
26
  function removeAllNavigationBlockers(session) {
27
- if (getNavigationBlockers(session).some(blocker => blocker.beforeDestroy)) {
28
- if (!session._removeBeforeDestroyListener) {
29
- throw new Error('`_removeBeforeDestroyListener` property not found in the `session`');
27
+ if (getNavigationBlockers(session).some(blocker => blocker.beforeTermination)) {
28
+ if (!session._removeTerminationBlocker) {
29
+ throw new Error('`_removeTerminationBlocker` property not found in the `session`');
30
30
  }
31
- session._removeBeforeDestroyListener();
32
- session._removeBeforeDestroyListener = undefined;
31
+ session._removeTerminationBlocker();
32
+ session._removeTerminationBlocker = undefined;
33
33
  }
34
34
  session._navigationBlockersList = [];
35
35
  }
@@ -92,33 +92,33 @@ function runNavigationBlockers(navigationBlockers, toLocation) {
92
92
  }
93
93
 
94
94
  /* istanbul ignore next: not testable with Karma */
95
- function onBeforeDestroy(session) {
95
+ function terminationBlocker(session) {
96
96
  const result = runNavigationBlockers(getNavigationBlockers(session), null);
97
97
 
98
- // If no blocker returned anything, don't prevent the "unload" event.
98
+ // If no blocker returned anything, so don't prevent the navigation.
99
99
  if (!result) {
100
100
  return undefined;
101
101
  }
102
102
 
103
103
  // Web browsers don't allow displaying a custom modal in "beforeunload" phase.
104
104
  // They only allow displaying a standard one, with the default text.
105
- // Hence, "asynchronous" blockers should be ignored.
105
+ // Hence, "asynchronous" blockers should be ignored because web browsers won't wait for those to finish anyway.
106
106
  // https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
107
107
  if ((0, _isPromise.default)(result)) {
108
108
  return undefined;
109
109
  }
110
110
 
111
- // Prevent the "unload" event.
111
+ // Block the navigation.
112
112
  return true;
113
113
  }
114
114
  function addNavigationBlocker(session, blocker) {
115
- // All navigation blockers also run on `beforeDestroy` event.
115
+ // All navigation blockers also run on `beforeTermination` event.
116
116
  // If required, this could be a parameter of this function.
117
117
  // The rationale could be that adding a `beforeunload` listener
118
118
  // disables web page caching in some browsers like Firefox.
119
- const beforeDestroy = true;
119
+ const beforeTermination = true;
120
120
 
121
- // If it's the first "beforeDestroy" blocker, add the global `onBeforeDestroy` listener.
121
+ // If it's the first "beforeTermination" blocker, add a `terminationBlocker`.
122
122
  //
123
123
  // Sidenote: Add the "beforeunload" event listener only as needed, as its presence
124
124
  // prevents the page from being added to the page navigation cache:
@@ -128,27 +128,29 @@ function addNavigationBlocker(session, blocker) {
128
128
  // and this is bad for performance."
129
129
  //
130
130
  // https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
131
- if (beforeDestroy && !getNavigationBlockers(session).some(navigationBlocker => navigationBlocker.beforeDestroy)) {
132
- if (session._removeBeforeDestroyListener) {
133
- throw new Error('Unexpected `_removeBeforeDestroyListener` property found in the `session`');
131
+ if (beforeTermination && !getNavigationBlockers(session).some(navigationBlocker => navigationBlocker.beforeTermination)) {
132
+ if (session._removeTerminationBlocker) {
133
+ throw new Error('Unexpected `_removeTerminationBlocker` property found in the `session`');
134
134
  }
135
- session._removeBeforeDestroyListener = session.addBeforeDestroyListener(() => onBeforeDestroy(session));
135
+ session._removeTerminationBlocker = session.lifecycle.addTerminationBlocker(() => {
136
+ return terminationBlocker(session);
137
+ });
136
138
  }
137
139
  const newNavigationBlocker = {
138
140
  blocker,
139
- beforeDestroy
141
+ beforeTermination
140
142
  };
141
143
  addNavigationBlockerToTheList(newNavigationBlocker, session);
142
144
  return () => {
143
145
  removeNavigationBlockerFromTheList(newNavigationBlocker, session);
144
146
 
145
- // If it was the last "beforeDestroy" blocker, remove the global `onBeforeDestroy` listener.
146
- if (beforeDestroy && !getNavigationBlockers(session).some(navigationBlocker => navigationBlocker.beforeDestroy)) {
147
- if (!session._removeBeforeDestroyListener) {
148
- throw new Error('`_removeBeforeDestroyListener` property not found in the `session`');
147
+ // If it was the last "beforeTermination" blocker, remove navigation blocker.
148
+ if (beforeTermination && !getNavigationBlockers(session).some(navigationBlocker => navigationBlocker.beforeTermination)) {
149
+ if (!session._removeTerminationBlocker) {
150
+ throw new Error('`_removeTerminationBlocker` property not found in the `session`');
149
151
  }
150
- session._removeBeforeDestroyListener();
151
- session._removeBeforeDestroyListener = undefined;
152
+ session._removeTerminationBlocker();
153
+ session._removeTerminationBlocker = undefined;
152
154
  }
153
155
  };
154
156
  }
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.default = normalizeInputLocation;
4
+ exports.default = parseInputLocation;
5
5
  var _createSearchFromQuery = _interopRequireDefault(require("./createSearchFromQuery"));
6
6
  var _parseLocationUrl = _interopRequireDefault(require("./parseLocationUrl"));
7
7
  var _parseQueryFromSearch = _interopRequireDefault(require("./parseQueryFromSearch"));
8
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
- // * If `location` is a string, it parses it into a `NormalizedInputLocation`.
9
+ // * If `location` is a string, it parses it into a `LocationBase`.
10
10
  // * If `location` is an object, it ensures that `search` and `hash` properties aren't `undefined`,
11
- // i.e. it "ensures" that the `location` object can be used as a `NormalizedInputLocation`.
12
- function normalizeInputLocation(location) {
11
+ // i.e. it "ensures" that the `location` object can be used as a `LocationBase`.
12
+ function parseInputLocation(location) {
13
13
  if (typeof location === 'string') {
14
14
  return (0, _parseLocationUrl.default)(location);
15
15
  }
@@ -17,7 +17,13 @@ function normalizeInputLocation(location) {
17
17
  // Convert `query` property values to strings.
18
18
  if (location.query) {
19
19
  for (const key of Object.keys(location.query)) {
20
- location.query[key] = String(location.query[key]);
20
+ if (typeof location.query[key] !== 'string') {
21
+ location = Object.assign({}, location, {
22
+ query: Object.assign({}, location.query, {
23
+ [key]: String(location.query[key])
24
+ })
25
+ });
26
+ }
21
27
  }
22
28
  }
23
29
 
@@ -36,12 +42,22 @@ function normalizeInputLocation(location) {
36
42
  });
37
43
  }
38
44
 
39
- // Set default values on `search` and `hash`
40
- // if those properties are not present.
41
- return Object.assign({}, location, {
45
+ // Set default values for properties that're not present.
46
+ // Ignore unknown properties.
47
+ const {
48
+ state
49
+ } = location;
50
+ location = {
51
+ pathname: location.pathname,
42
52
  query: location.query || {},
43
53
  search: location.search || '',
44
54
  hash: location.hash || ''
45
- });
55
+ };
56
+ if (state) {
57
+ location.state = state;
58
+ }
59
+
60
+ // Return `location`.
61
+ return location;
46
62
  }
47
63
  module.exports = exports.default;