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,3 @@
1
+ export function shouldWarn(about) {
2
+ console.warn.expected.push(about); // eslint-disable-line no-console
3
+ }
@@ -0,0 +1,35 @@
1
+ // TypeScript Version: 3.0
2
+
3
+ import { Session } from '../index.d.js';
4
+
5
+ export {};
6
+
7
+ export type GenericValue =
8
+ | string
9
+ | number
10
+ | boolean
11
+ | Record<string, unknown>
12
+ | null
13
+ | undefined;
14
+
15
+ export class DataStorage<
16
+ Key extends string = string,
17
+ Value extends GenericValue = GenericValue,
18
+ > {
19
+ constructor(session: Session, options: { namespace: string });
20
+
21
+ get(key: Key): Value;
22
+
23
+ set(key: Key, value: Value): void;
24
+ }
25
+
26
+ export class LocationDataStorage<
27
+ Key extends string = string,
28
+ Value extends GenericValue = GenericValue,
29
+ > {
30
+ constructor(session: Session, options: { namespace: string });
31
+
32
+ get(location: Location, key: Key): Value;
33
+
34
+ set(location: Location, key: Key, value: Value): void;
35
+ }
package/types/index.d.ts CHANGED
@@ -11,11 +11,7 @@ export type InputLocationQuery = Record<
11
11
  string | number | boolean | null | undefined
12
12
  >;
13
13
 
14
- export interface Location<TState = any> {
15
- /**
16
- * See the README on the `action` property of `location`.
17
- */
18
- action: 'PUSH' | 'REPLACE' | 'SHIFT' | 'INIT';
14
+ export interface LocationBase {
19
15
  /**
20
16
  * the path name; as on window.location e.g. '/foo'
21
17
  */
@@ -32,61 +28,52 @@ export interface Location<TState = any> {
32
28
  * the location hash; as on window.location e.g. '#qux'
33
29
  */
34
30
  hash: string;
31
+ }
32
+
33
+ export interface Location extends LocationBase {
35
34
  /**
36
35
  * a unique key identifying the current history entry
37
36
  */
38
37
  key: string;
38
+ }
39
+
40
+ type PushOrReplaceOperation = 'PUSH' | 'REPLACE';
41
+
42
+ export interface LocationInternal extends Location {
43
+ /**
44
+ * `navigation-stack` operation.
45
+ */
46
+ operation: PushOrReplaceOperation | 'SHIFT' | 'INIT';
39
47
  /**
40
48
  * the current index of the history entry, starting at 0 for the initial
41
- * entry; this increments on FarceActions.push but not on
42
- * FarceActions.replace
49
+ * entry; this increments on `.push()` but not on `.replace()`
43
50
  */
44
51
  index: number;
45
52
  /**
46
53
  * the difference between the current index and the index of the previous location
47
54
  */
48
55
  delta: number;
49
- /**
50
- * any additional location state that the application might explicitly define and store
51
- */
52
- state: TState;
53
56
  }
54
57
 
55
58
  /**
56
59
  * Location descriptor object used in #push and #replace.
57
60
  */
58
61
  export interface InputLocationObject {
59
- pathname: Location['pathname'];
60
- search?: Location['search'];
62
+ pathname: LocationBase['pathname'];
63
+ search?: LocationBase['search'];
61
64
  query?: InputLocationQuery;
62
- hash?: Location['hash'];
63
- state?: Location['state'];
64
- }
65
-
66
- export interface LocationBase {
67
- pathname: Location['pathname'];
68
- search: Location['search'];
69
- query: Query;
70
- hash: Location['hash'];
71
- state?: Location['state'];
72
- }
73
-
74
- export interface NavigationLocation extends LocationBase {
75
- action: 'PUSH' | 'REPLACE';
65
+ hash?: LocationBase['hash'];
76
66
  }
77
67
 
78
68
  /**
79
- * Location descriptor string:
80
- * store.dispatch(FarceActions.push('/foo?bar=baz#qux'));
69
+ * Location input string: "/foo?bar=baz#qux"
81
70
  *
82
- * Equivalent location descriptor object:
83
- * store.dispatch(FarceActions.push({
84
- * pathname: '/foo',
85
- * search: '?bar=baz',
86
- * hash: '#qux',
87
- * }));
88
- *
89
- * https://github.com/4Catalyzer/farce#locations-and-location-descriptors
71
+ * Equivalent location input object:
72
+ * {
73
+ * pathname: '/foo',
74
+ * search: '?bar=baz',
75
+ * hash: '#qux'
76
+ * }
90
77
  */
91
78
  export type InputLocationString = string;
92
79
 
@@ -99,10 +86,6 @@ export interface InputLocationTypes {
99
86
 
100
87
  export type InputLocation = InputLocationTypes[keyof InputLocationTypes];
101
88
 
102
- export interface CreateMiddlewaresOptions {
103
- basePath?: string;
104
- }
105
-
106
89
  export type NavigationBlockerSyncResult = boolean | undefined;
107
90
  export type NavigationBlockerResult =
108
91
  | NavigationBlockerSyncResult
@@ -112,13 +95,13 @@ export type NavigationBlockerResult =
112
95
  * Navigation blocker function receives a `location` to which the application (or the user) is attempting to navigate.
113
96
  *
114
97
  * * The `location` argument is `null` when the web browser tab is about to be closed.
115
- * * The `location` argument is of type `NavigationLocation` when a `.push()` or `.replace()` action is blocked.
98
+ * * The `location` argument is of type `LocationBase` when a `.push()` or `.replace()` navigation is blocked.
116
99
  * * The `location` argument is of type `Location` when blocking a navigation that was initiated outside of the application code.
117
100
  * For example, when the user clicks "Back" or "Forward" button in a web browser.
118
101
  */
119
- export interface NavigationBlocker {
120
- (location: Location | NavigationLocation | null): NavigationBlockerResult;
121
- }
102
+ export type NavigationBlocker = (
103
+ location: Location | LocationBase | null,
104
+ ) => NavigationBlockerResult;
122
105
 
123
106
  // I dunno why did they use an `interface` here.
124
107
  export interface BeforeLocationChangeListener {
@@ -137,166 +120,204 @@ export function removeBasePath<L extends InputLocation>(
137
120
  export function getLocationUrl(location: InputLocationObject): string;
138
121
  export function parseLocationUrl(locationUrl: string): LocationBase;
139
122
 
140
- export function createMiddlewares(
141
- session: SessionBase,
142
- options?: CreateMiddlewaresOptions,
143
- ): Middleware[];
123
+ export function parseInputLocation(location: InputLocation): LocationBase;
144
124
 
145
125
  export function addNavigationBlocker(
146
- session: SessionBase,
126
+ session: Session,
147
127
  blocker: NavigationBlocker,
148
128
  ): () => void;
149
129
 
150
- export function addBeforeLocationChangeListener(
151
- session: SessionBase,
152
- listener: BeforeLocationChangeListener,
153
- ): () => void;
154
-
155
- export const ActionTypes: {
156
- INIT: '@@navigation-stack/INIT';
157
- PUSH: '@@navigation-stack/PUSH';
158
- REPLACE: '@@navigation-stack/REPLACE';
159
- NAVIGATE: '@@navigation-stack/NAVIGATE';
160
- SHIFT: '@@navigation-stack/SHIFT';
161
- UPDATE: '@@navigation-stack/UPDATE';
162
- DISPOSE: '@@navigation-stack/DISPOSE';
163
- };
164
-
165
- export interface InitAction {
166
- type: (typeof ActionTypes)['INIT'];
130
+ export interface NavigationStackOptions {
131
+ basePath?: string;
132
+ maintainScrollPosition?: boolean;
167
133
  }
168
134
 
169
- export interface PushAction {
170
- type: (typeof ActionTypes)['PUSH'];
171
- payload: InputLocation;
172
- }
135
+ export class NavigationStack<ScrollableContainer = any, Anchor = any> {
136
+ constructor(
137
+ session: Session<ScrollableContainer, Anchor>,
138
+ options?: NavigationStackOptions,
139
+ );
173
140
 
174
- export interface ReplaceAction {
175
- type: (typeof ActionTypes)['REPLACE'];
176
- payload: InputLocation;
177
- }
141
+ addScrollableContainer(
142
+ scrollableContainerKey: string,
143
+ scrollableContainer: ScrollableContainer,
144
+ ): () => void;
145
+
146
+ subscribe(listener: (location: Location) => void): () => void;
147
+
148
+ current(): Location;
178
149
 
179
- export interface RewindAction {
180
- type: (typeof ActionTypes)['SHIFT'];
181
- payload: number;
150
+ init(initialLocation?: InputLocation): void;
151
+
152
+ push(location: InputLocation): void;
153
+
154
+ replace(location: InputLocation): void;
155
+
156
+ shift(delta: number): void;
157
+
158
+ locationRendered(): void;
159
+
160
+ stop(): void;
182
161
  }
183
162
 
184
- export interface DisposeAction {
185
- type: (typeof ActionTypes)['DISPOSE'];
163
+ export type SessionTerminationBlocker = () => boolean | undefined;
164
+
165
+ interface SessionExecutionStatusListenerParameters {
166
+ running: boolean;
186
167
  }
187
168
 
188
- export type Action =
189
- | InitAction
190
- | PushAction
191
- | ReplaceAction
192
- | RewindAction
193
- | DisposeAction;
169
+ export type SessionExecutionStatusListener = (
170
+ parameters: SessionExecutionStatusListenerParameters,
171
+ ) => void;
194
172
 
195
- export const Actions: {
196
- init(): InitAction;
197
- push(location: InputLocation): PushAction;
198
- replace(location: InputLocation): ReplaceAction;
199
- shift(delta: number): RewindAction;
200
- dispose(): DisposeAction;
201
- };
173
+ export type ScrollListener = () => void;
202
174
 
203
- type BeforeDestroyListener = () => boolean | undefined;
175
+ export class ServerSideNavigationError extends Error {
176
+ constructor(location: LocationBase);
204
177
 
205
- interface SessionNavigation {
206
- init(): void;
178
+ location: LocationBase;
179
+ }
207
180
 
208
- // Subscribes to changes in location,
209
- // excluding ones that happened as a result of calling `.navigate()`.
210
- subscribe(listener: (location: Location) => void): () => void;
181
+ export class NavigationOutOfBoundsError extends Error {
182
+ constructor(index: number);
211
183
 
212
- navigate(location: NavigationLocation): Location;
184
+ index: number;
185
+ }
213
186
 
214
- shift(delta: number): void;
187
+ export class Navigation {
188
+ // Subscribes to "location change" events.
189
+ subscribe(listener: (location: LocationInternal) => void): () => void;
190
+
191
+ init(
192
+ initialLocation: LocationBase,
193
+ parameters: Pick<
194
+ LocationInternal,
195
+ 'operation' | 'key' | 'index' | 'delta'
196
+ >,
197
+ ): LocationInternal | undefined;
198
+
199
+ navigate(
200
+ location: LocationBase,
201
+ parameters: Pick<
202
+ LocationInternal,
203
+ 'operation' | 'key' | 'index' | 'delta'
204
+ >,
205
+ ): LocationInternal | undefined;
206
+
207
+ shift(
208
+ parameters: Pick<LocationInternal, 'operation' | 'index' | 'delta'>,
209
+ ): LocationInternal | undefined;
210
+
211
+ getInitialLocation(): InputLocation | undefined;
215
212
  }
216
213
 
217
- interface SessionDataStorage {
214
+ export interface EnvironmentDataStorage {
218
215
  get(key: string): string | null;
219
216
  remove(key: string): void;
220
217
  set(key: string, value: string): void;
221
218
  }
222
219
 
223
- export interface Session {
224
- navigation: SessionNavigation;
225
- dataStorage: SessionDataStorage;
226
- addBeforeDestroyListener(listener: BeforeDestroyListener): void;
220
+ export interface SessionLifecycle {
221
+ addTerminationBlocker(blocker: SessionTerminationBlocker): () => void;
222
+ addExecutionStatusListener(
223
+ listener: SessionExecutionStatusListener,
224
+ ): () => void;
225
+ }
226
+
227
+ // Manages scroll position in an environment such as a web browser.
228
+ export interface EnvironmentScrollPosition<ScrollableContainer, Anchor> {
229
+ // Gets numeric scroll position of a page.
230
+ getPageScrollPosition(): [number, number];
231
+ // Sets numeric scroll position of a page.
232
+ setPageScrollPosition(scrollPosition: [number, number]): void;
233
+ // Sets scroll position of a page to be at an "anchor".
234
+ setPageScrollPositionAtAnchor(anchor: Anchor): void;
235
+ // Gets numeric scroll position of a scrollable element.
236
+ getScrollableContainerScrollPosition(
237
+ scrollableContainer: ScrollableContainer,
238
+ ): [number, number];
239
+ // Sets numeric scroll position of a scrollable element.
240
+ setScrollableContainerScrollPosition(
241
+ scrollableContainer: ScrollableContainer,
242
+ scrollPosition: [number, number],
243
+ ): void;
244
+ // Adds "on scroll" listeners.
245
+ addPageScrollListener(listener: ScrollListener): () => void;
246
+ addScrollableContainerScrollListener(listener: ScrollListener): () => void;
247
+ // These methods could be used to disable environment's automatic scroll position restoration feature,
248
+ // such as the one present in web browsers, so that the code could control it manually.
249
+ enableAutomaticScrollRestoration(): void;
250
+ disableAutomaticScrollRestoration(): void;
251
+ // `init()` is called every time when a new page is rendered.
252
+ init(): void;
253
+ }
227
254
 
228
- // These're internal variables that're manually set under the hood.
229
- // _beforeLocationChangeListenersList?: Array<BeforeLocationChangeListener>;
230
- // _navigationBlockersList?: Array<NavigationBlocker>;
231
- // _removeBeforeDestroyListener?: () => void;
232
- // _navigationBlockersEvaluationStatus?: { cancelled?: boolean };
255
+ export interface Environment<ScrollableContainer, Anchor> {
256
+ dataStorage: EnvironmentDataStorage;
257
+ scrollPosition: EnvironmentScrollPosition<ScrollableContainer, Anchor>;
233
258
  }
234
259
 
235
- // This is just a copy-paste of the `session` interface above.
236
- declare abstract class SessionBase implements Session {
237
- navigation: SessionNavigation;
260
+ export interface Session<ScrollableContainer = any, Anchor = any> {
261
+ // `key` should be unique within `environment.dataStorage`.
262
+ // For example, `BrowserEnvironment` uses `window.sessionStorage`
263
+ // that is shared across different sessions within a given web browser tab,
264
+ // hence the uniqueness requirement.
265
+ key: string;
238
266
 
239
- dataStorage: SessionDataStorage;
267
+ // Private varibles. Not public API.
268
+ environment: Environment<ScrollableContainer, Anchor>;
240
269
 
241
- addBeforeDestroyListener(listener: BeforeDestroyListener): void;
270
+ lifecycle: SessionLifecycle;
242
271
 
243
- // These're internal variables that're manually set under the hood.
244
- // _beforeLocationChangeListenersList?: Array<BeforeLocationChangeListener>;
245
- // _navigationBlockersList?: Array<NavigationBlocker>;
246
- // _removeBeforeDestroyListener?: () => void;
247
- // _navigationBlockersEvaluationStatus?: { cancelled?: boolean };
248
- }
272
+ subscribe(listener: (location: LocationInternal) => void): () => void;
249
273
 
250
- export class BrowserSession extends SessionBase {}
274
+ start(initialLocation?: LocationBase): void;
251
275
 
252
- export interface MemorySessionOptions {
253
- save?: (data: string) => void;
254
- load?: () => string | undefined | null;
255
- }
276
+ stop(): void;
256
277
 
257
- export class ServerSession extends SessionBase {
258
- constructor(initialLocation: InputLocation);
259
- }
278
+ navigate(operation: PushOrReplaceOperation, location: LocationBase): void;
260
279
 
261
- export class MemorySession extends SessionBase {
262
- constructor(initialLocation: InputLocation, options?: MemorySessionOptions);
280
+ shift(delta: number): void;
263
281
  }
264
282
 
265
- export const locationReducer: Reducer<Location, Action>;
283
+ // This is just a copy-paste of the `session` interface above.
284
+ declare abstract class SessionBaseClass<
285
+ ScrollableContainer = any,
286
+ Anchor = any,
287
+ > implements Session<ScrollableContainer, Anchor>
288
+ {
289
+ constructor(parameters: { navigation: Navigation });
290
+
291
+ // `key` should be unique within `environment.dataStorage`.
292
+ // For example, `BrowserEnvironment` uses `window.sessionStorage`
293
+ // that is shared across different sessions within a given web browser tab,
294
+ // hence the uniqueness requirement.
295
+ key: string;
266
296
 
267
- export class LocationDataStorage {
268
- constructor(session: Session, options: { namespace: string });
297
+ // Private varibles. Not public API.
298
+ environment: Environment<ScrollableContainer, Anchor>;
269
299
 
270
- get(location: Location, key: string): any;
300
+ lifecycle: SessionLifecycle;
271
301
 
272
- set(location: Location, key: string, value: any): void;
273
- }
302
+ subscribe(listener: (location: LocationInternal) => void): () => void;
274
303
 
275
- // The following types are copy-pasted from `redux`.
304
+ start(initialLocation?: LocationBase): void;
276
305
 
277
- interface ReduxAction<T = any> {
278
- type: T;
279
- }
306
+ stop(): void;
280
307
 
281
- interface AnyAction extends ReduxAction {
282
- // Allows any extra properties to be defined in an action.
283
- [extraProps: string]: any;
284
- }
308
+ navigate(operation: PushOrReplaceOperation, location: LocationBase): void;
285
309
 
286
- interface Dispatch<A extends Action = AnyAction> {
287
- <T extends A>(action: T): T;
310
+ shift(delta: number): void;
288
311
  }
289
312
 
290
- interface MiddlewareAPI<D extends Dispatch = Dispatch, S = any> {
291
- dispatch: D;
292
- getState(): S;
313
+ export class WebBrowserSession extends SessionBaseClass<HTMLElement, string> {
314
+ constructor();
293
315
  }
294
316
 
295
- interface Middleware<S = any, D extends Dispatch = Dispatch> {
296
- (api: MiddlewareAPI<D, S>): (next: Dispatch) => (action: any) => any;
317
+ export class ServerSideRenderSession extends SessionBaseClass<string, string> {
318
+ constructor();
297
319
  }
298
320
 
299
- type Reducer<S = any, A extends Action = AnyAction> = (
300
- state: S | undefined,
301
- action: A,
302
- ) => S;
321
+ export class InMemorySession extends SessionBaseClass<string, string> {
322
+ constructor();
323
+ }
@@ -0,0 +1,90 @@
1
+ import { InputLocation, Session } from '../index.d.js';
2
+
3
+ export interface CreateMiddlewaresOptions {
4
+ basePath?: string;
5
+ }
6
+
7
+ export function createMiddlewares(
8
+ session: Session,
9
+ options?: CreateMiddlewaresOptions,
10
+ ): Middleware[];
11
+
12
+ export const ActionTypes: {
13
+ INIT: '@@navigation-stack/INIT';
14
+ PUSH: '@@navigation-stack/PUSH';
15
+ REPLACE: '@@navigation-stack/REPLACE';
16
+ NAVIGATE: '@@navigation-stack/NAVIGATE';
17
+ SHIFT: '@@navigation-stack/SHIFT';
18
+ UPDATE: '@@navigation-stack/UPDATE';
19
+ STOP: '@@navigation-stack/STOP';
20
+ };
21
+
22
+ export interface InitAction {
23
+ type: (typeof ActionTypes)['INIT'];
24
+ payload?: InputLocation;
25
+ }
26
+
27
+ export interface PushAction {
28
+ type: (typeof ActionTypes)['PUSH'];
29
+ payload: InputLocation;
30
+ }
31
+
32
+ export interface ReplaceAction {
33
+ type: (typeof ActionTypes)['REPLACE'];
34
+ payload: InputLocation;
35
+ }
36
+
37
+ export interface ShiftAction {
38
+ type: (typeof ActionTypes)['SHIFT'];
39
+ payload: number;
40
+ }
41
+
42
+ export interface DisposeAction {
43
+ type: (typeof ActionTypes)['STOP'];
44
+ }
45
+
46
+ export type Action =
47
+ | InitAction
48
+ | PushAction
49
+ | ReplaceAction
50
+ | ShiftAction
51
+ | DisposeAction;
52
+
53
+ export const Actions: {
54
+ init(initialLocation?: InputLocation): InitAction;
55
+ push(location: InputLocation): PushAction;
56
+ replace(location: InputLocation): ReplaceAction;
57
+ shift(delta: number): ShiftAction;
58
+ stop(): DisposeAction;
59
+ };
60
+
61
+ export const locationReducer: Reducer<Location, Action>;
62
+
63
+ // The following types are copy-pasted from `redux`.
64
+
65
+ interface ReduxAction<T = any> {
66
+ type: T;
67
+ }
68
+
69
+ interface AnyAction extends ReduxAction {
70
+ // Allows any extra properties to be defined in an action.
71
+ [extraProps: string]: any;
72
+ }
73
+
74
+ interface Dispatch<A extends Action = AnyAction> {
75
+ <T extends A>(action: T): T;
76
+ }
77
+
78
+ interface MiddlewareAPI<D extends Dispatch = Dispatch, S = any> {
79
+ dispatch: D;
80
+ getState(): S;
81
+ }
82
+
83
+ interface Middleware<S = any, D extends Dispatch = Dispatch> {
84
+ (api: MiddlewareAPI<D, S>): (next: Dispatch) => (action: any) => any;
85
+ }
86
+
87
+ type Reducer<S = any, A extends Action = AnyAction> = (
88
+ state: S | undefined,
89
+ action: A,
90
+ ) => S;
@@ -0,0 +1,107 @@
1
+ // TypeScript Version: 3.0
2
+
3
+ import { EnvironmentScrollPosition, Location, Session } from '../index.d.js';
4
+
5
+ export { EnvironmentScrollPosition, Location, Session } from '../index.d.js';
6
+
7
+ export {};
8
+
9
+ export class ScrollPositionRestoration<
10
+ ScrollableContainer = any,
11
+ Anchor = any,
12
+ > {
13
+ constructor(
14
+ session: Session<ScrollableContainer, Anchor>,
15
+
16
+ // `_options` are currently only used in tests.
17
+ _options?: {
18
+ // `_options._shouldUpdatePageScrollPositionForLocation`
19
+ // isn't used in real life and is not part of the public API.
20
+ // It's only used in tests.
21
+ _shouldUpdatePageScrollPositionForLocation?: (
22
+ location: Location,
23
+ prevLocation: Location | undefined,
24
+ ) => boolean;
25
+
26
+ // `_options._getPageScrollPositionForLocation`
27
+ // isn't used in real life and is not part of the public API.
28
+ // It's only used in tests.
29
+ _getPageScrollPositionForLocation?: (
30
+ location: Location,
31
+ prevLocation: Location | undefined,
32
+ ) => boolean;
33
+
34
+ // Using this option, a developer could theoretically provide their own implementation
35
+ // of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
36
+ // This could be part of the public API if anyone provided a sensible real-world use case for it.
37
+ _pageScrollPositionSetter: ScrollPositionSetter<
38
+ ScrollableContainer,
39
+ Anchor
40
+ >;
41
+ },
42
+ );
43
+
44
+ addScrollableContainer(
45
+ scrollableContainerKey: string,
46
+ scrollableContainer: ScrollableContainer,
47
+
48
+ // `_options` are currently only used in tests.
49
+ _options?: {
50
+ // `_options._shouldUpdateScrollPositionForLocation`
51
+ // isn't used in real life and is not part of the public API.
52
+ // It's only used in tests.
53
+ _shouldUpdateScrollPositionForLocation?: (
54
+ location: Location,
55
+ prevLocation: Location | undefined,
56
+ ) => boolean;
57
+
58
+ // `_options._getScrollPositionForLocation`
59
+ // isn't used in real life and is not part of the public API.
60
+ // It's only used in tests.
61
+ _getScrollPositionForLocation?: (
62
+ location: Location,
63
+ prevLocation: Location | undefined,
64
+ ) => boolean;
65
+
66
+ // Using this option, a developer could theoretically provide their own implementation
67
+ // of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
68
+ // This could be part of the public API if anyone provided a sensible real-world use case for it.
69
+ _scrollPositionSetter: ScrollPositionSetter<ScrollableContainer, Anchor>;
70
+ },
71
+ ): () => void;
72
+
73
+ locationRendered: (location: Location) => void;
74
+
75
+ stop(): void;
76
+
77
+ // `_enableSavingScrollPosition()` and `_disableSavingScrollPosition()`
78
+ // aren't used in real life and are not part of the public API.
79
+ // They're only used in tests.
80
+ _enableSavingScrollPosition(): void;
81
+
82
+ // `_enableSavingScrollPosition()` and `_disableSavingScrollPosition()`
83
+ // aren't used in real life and are not part of the public API.
84
+ // They're only used in tests.
85
+ _disableSavingScrollPosition(): void;
86
+ }
87
+
88
+ // Theoretically, a developer could pass their own `ScrollPositionSetter` implementation
89
+ // when calling `.addScrollableContainer()` or
90
+ export interface ScrollPositionSetter<ScrollableContainer, Anchor> {
91
+ // Sets scroll position of a page or a scrollable element.
92
+ // Returns a `Promise` that resolves when it has finished setting the scroll position.
93
+ set(
94
+ // When setting page scroll position, `scrollableContainer` is `undefined`.
95
+ // When setting scrollable element scroll position, `scrollableContainer` is the scrollable element.
96
+ scrollableContainer: ScrollableContainer,
97
+ // When setting page scroll position, it could be either an anchor or numeric coordinates.
98
+ // When setting scrollable element scroll position, it could only be numeric coordinates.
99
+ scrollPositionOrAnchor: Anchor | [number, number],
100
+ // `scrollPosition` provides the API for setting scroll position according to the environment.
101
+ // For example, `WebBrowserScrollPosition` provides the methods for setting scroll position in a web browser.
102
+ scrollPosition: EnvironmentScrollPosition<ScrollableContainer, Anchor>,
103
+ ): Promise<void>;
104
+
105
+ // Cancels any pending (or in-progress) setting of scroll position.
106
+ cancel(): void;
107
+ }