navigation-stack 0.5.3 → 0.6.1
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.
- package/CHANGELOG.md +16 -0
- package/README.md +144 -282
- package/karma.conf.cjs +1 -1
- package/lib/cjs/NavigationStack.js +138 -49
- package/lib/cjs/data-storage/DataStorage.js +7 -6
- package/lib/cjs/environment/InMemoryEnvironment.js +6 -0
- package/lib/cjs/{session/ServerSideRenderSession.js → environment/ServerSideRenderEnvironment.js} +5 -6
- package/lib/cjs/environment/WebBrowserEnvironment.js +6 -0
- package/lib/cjs/environment/log/InMemoryLog.js +23 -0
- package/lib/cjs/environment/log/WebBrowserLog.js +22 -0
- package/lib/cjs/{session → environment}/navigation/InMemoryNavigation.js +16 -5
- package/lib/cjs/{session → environment}/navigation/ServerSideNavigation.js +16 -7
- package/lib/cjs/{session → environment}/navigation/WebBrowserNavigation.js +48 -8
- package/lib/cjs/{session/navigation/error/ServerSideNavigationError.js → environment/navigation/error/ServerSideRedirectError.js} +2 -2
- package/lib/cjs/environment/scroll-position/WebBrowserScrollPosition.js +15 -0
- package/lib/cjs/getLocationBaseFromLocation.js +14 -0
- package/lib/cjs/getLocationUrl.js +3 -5
- package/lib/cjs/index.js +10 -16
- package/lib/cjs/navigationBlockers.js +34 -32
- package/lib/cjs/navigationBlockersEvaluation.js +150 -0
- package/lib/cjs/parseInputLocation.js +2 -2
- package/lib/cjs/parseQueryFromSearch.js +3 -6
- package/lib/cjs/parseQueryString.js +77 -0
- package/lib/cjs/scroll-position/ScrollPositionAutoSaver.js +7 -6
- package/lib/cjs/scroll-position/ScrollPositionRestoration.js +31 -27
- package/lib/cjs/scroll-position/ScrollPositionSaver.js +6 -4
- package/lib/cjs/session/Session.js +61 -26
- package/lib/cjs/session/subscription/Subscription.js +36 -18
- package/lib/cjs/stringifyQuery.js +66 -0
- package/lib/cjs/stringifyQueryAsSearch.js +14 -0
- package/lib/esm/NavigationStack.js +138 -49
- package/lib/esm/data-storage/DataStorage.js +7 -6
- package/lib/esm/environment/InMemoryEnvironment.js +6 -0
- package/lib/esm/environment/ServerSideRenderEnvironment.js +10 -0
- package/lib/esm/environment/WebBrowserEnvironment.js +6 -0
- package/lib/esm/environment/log/InMemoryLog.js +17 -0
- package/lib/esm/environment/log/WebBrowserLog.js +16 -0
- package/lib/esm/{session → environment}/navigation/InMemoryNavigation.js +16 -5
- package/lib/esm/{session → environment}/navigation/ServerSideNavigation.js +16 -7
- package/lib/esm/{session → environment}/navigation/WebBrowserNavigation.js +48 -8
- package/lib/esm/{session/navigation/error/ServerSideNavigationError.js → environment/navigation/error/ServerSideRedirectError.js} +1 -1
- package/lib/esm/environment/scroll-position/WebBrowserScrollPosition.js +15 -0
- package/lib/esm/getLocationBaseFromLocation.js +9 -0
- package/lib/esm/getLocationUrl.js +2 -5
- package/lib/esm/index.js +5 -8
- package/lib/esm/navigationBlockers.js +34 -32
- package/lib/esm/navigationBlockersEvaluation.js +145 -0
- package/lib/esm/parseInputLocation.js +2 -2
- package/lib/esm/parseQueryFromSearch.js +2 -6
- package/lib/esm/parseQueryString.js +72 -0
- package/lib/esm/scroll-position/ScrollPositionAutoSaver.js +7 -6
- package/lib/esm/scroll-position/ScrollPositionRestoration.js +31 -27
- package/lib/esm/scroll-position/ScrollPositionSaver.js +6 -4
- package/lib/esm/session/Session.js +61 -26
- package/lib/esm/session/subscription/Subscription.js +36 -18
- package/lib/esm/stringifyQuery.js +61 -0
- package/lib/esm/stringifyQueryAsSearch.js +8 -0
- package/lib/index.d.ts +180 -34
- package/package.json +4 -7
- package/src/NavigationStack.js +166 -56
- package/src/data-storage/DataStorage.js +9 -6
- package/src/environment/InMemoryEnvironment.js +6 -0
- package/src/environment/ServerSideRenderEnvironment.js +10 -0
- package/src/environment/WebBrowserEnvironment.js +6 -0
- package/src/environment/log/InMemoryLog.js +20 -0
- package/src/environment/log/WebBrowserLog.js +18 -0
- package/src/{session → environment}/navigation/InMemoryNavigation.js +16 -5
- package/src/{session → environment}/navigation/ServerSideNavigation.js +16 -7
- package/src/{session → environment}/navigation/WebBrowserNavigation.js +48 -8
- package/src/{session/navigation/error/ServerSideNavigationError.js → environment/navigation/error/ServerSideRedirectError.js} +1 -1
- package/src/environment/scroll-position/WebBrowserScrollPosition.js +15 -0
- package/src/getLocationBaseFromLocation.js +7 -0
- package/src/getLocationUrl.js +2 -5
- package/src/index.js +10 -13
- package/src/navigationBlockers.js +55 -34
- package/src/navigationBlockersEvaluation.js +161 -0
- package/src/parseInputLocation.js +2 -2
- package/src/parseQueryFromSearch.js +2 -6
- package/src/parseQueryString.js +81 -0
- package/src/scroll-position/ScrollPositionAutoSaver.js +10 -6
- package/src/scroll-position/ScrollPositionRestoration.js +36 -30
- package/src/scroll-position/ScrollPositionSaver.js +6 -4
- package/src/scroll-position/index.js +1 -1
- package/src/session/Session.js +68 -24
- package/src/session/subscription/Subscription.js +36 -11
- package/src/stringifyQuery.js +71 -0
- package/src/stringifyQueryAsSearch.js +9 -0
- package/test/NavigationStack.addBasePath.test.js +50 -0
- package/test/{redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.test.js → NavigationStack.blockNonProgrammaticNavigationIfRequired.test.js} +51 -63
- package/test/{redux/middleware/createProgrammaticNavigationBlockerMiddleware.test.js → NavigationStack.blockProgrammaticNavigationIfRequired.test.js} +98 -78
- package/test/NavigationStack.general.test.js +68 -0
- package/test/NavigationStack.parseInputLocation.test.js +52 -0
- package/test/NavigationStack.removeBasePath.test.js +69 -0
- package/test/NavigationStack.test.js +97 -29
- package/test/data-storage/LocationDataStorage.test.js +3 -2
- package/test/index.js +7 -31
- package/test/index.test.js +4 -5
- package/test/parseQueryFromSearch.test.js +19 -0
- package/test/parseQueryString.test.js +18 -0
- package/test/scroll-position/ScrollPositionRestoration.test.js +34 -13
- package/test/scroll-position/createApp.js +8 -8
- package/test/scroll-position/withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration.js +4 -4
- package/test/session/{InMemorySession.test.js → Session.InMemoryEnvironment.test.js} +10 -9
- package/test/session/{ServerSession.test.js → Session.ServerSideRenderEnvironment.test.js} +5 -4
- package/test/session/{WebBrowserSession.test.js → Session.WebBrowserEnvironment.test.js} +63 -13
- package/test/shouldWarn.js +44 -0
- package/test/stringifyQuery.test.js +65 -0
- package/types/index.d.ts +180 -34
- package/types/tsconfig.json +0 -1
- package/data-storage/package.json +0 -7
- package/lib/cjs/createSearchFromQuery.js +0 -13
- package/lib/cjs/debug.js +0 -12
- package/lib/cjs/redux/ActionTypes.js +0 -14
- package/lib/cjs/redux/ActionTypesInternal.js +0 -8
- package/lib/cjs/redux/Actions.js +0 -28
- package/lib/cjs/redux/createMiddlewares.js +0 -60
- package/lib/cjs/redux/index.js +0 -13
- package/lib/cjs/redux/internalLocationReducer.js +0 -14
- package/lib/cjs/redux/locationReducer.js +0 -13
- package/lib/cjs/redux/middleware/createAddInputLocationBasePathMiddleware.js +0 -32
- package/lib/cjs/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +0 -113
- package/lib/cjs/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +0 -94
- package/lib/cjs/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +0 -30
- package/lib/cjs/redux/middleware/createUpdateInternalLocationMiddleware.js +0 -73
- package/lib/cjs/redux/middleware/navigationOperationMiddleware.js +0 -40
- package/lib/cjs/redux/middleware/parseInputLocationMiddleware.js +0 -29
- package/lib/cjs/redux/middleware/updateLocationMiddleware.js +0 -34
- package/lib/cjs/session/InMemorySession.js +0 -22
- package/lib/cjs/session/WebBrowserSession.js +0 -20
- package/lib/data-storage/index.d.ts +0 -35
- package/lib/esm/createSearchFromQuery.js +0 -8
- package/lib/esm/debug.js +0 -7
- package/lib/esm/redux/ActionTypes.js +0 -9
- package/lib/esm/redux/ActionTypesInternal.js +0 -3
- package/lib/esm/redux/Actions.js +0 -22
- package/lib/esm/redux/createMiddlewares.js +0 -54
- package/lib/esm/redux/index.js +0 -4
- package/lib/esm/redux/internalLocationReducer.js +0 -8
- package/lib/esm/redux/locationReducer.js +0 -7
- package/lib/esm/redux/middleware/createAddInputLocationBasePathMiddleware.js +0 -27
- package/lib/esm/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +0 -108
- package/lib/esm/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +0 -88
- package/lib/esm/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +0 -25
- package/lib/esm/redux/middleware/createUpdateInternalLocationMiddleware.js +0 -68
- package/lib/esm/redux/middleware/navigationOperationMiddleware.js +0 -35
- package/lib/esm/redux/middleware/parseInputLocationMiddleware.js +0 -24
- package/lib/esm/redux/middleware/updateLocationMiddleware.js +0 -28
- package/lib/esm/session/InMemorySession.js +0 -15
- package/lib/esm/session/ServerSideRenderSession.js +0 -11
- package/lib/esm/session/WebBrowserSession.js +0 -13
- package/lib/redux/index.d.ts +0 -90
- package/lib/scroll-position/index.d.ts +0 -107
- package/redux/package.json +0 -7
- package/scroll-position/package.json +0 -7
- package/src/createSearchFromQuery.js +0 -9
- package/src/debug.js +0 -8
- package/src/redux/ActionTypes.js +0 -9
- package/src/redux/ActionTypesInternal.js +0 -3
- package/src/redux/Actions.js +0 -27
- package/src/redux/createMiddlewares.js +0 -65
- package/src/redux/index.js +0 -4
- package/src/redux/internalLocationReducer.js +0 -9
- package/src/redux/locationReducer.js +0 -8
- package/src/redux/middleware/createAddInputLocationBasePathMiddleware.js +0 -27
- package/src/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +0 -119
- package/src/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +0 -94
- package/src/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +0 -26
- package/src/redux/middleware/createUpdateInternalLocationMiddleware.js +0 -72
- package/src/redux/middleware/navigationOperationMiddleware.js +0 -34
- package/src/redux/middleware/parseInputLocationMiddleware.js +0 -23
- package/src/redux/middleware/updateLocationMiddleware.js +0 -28
- package/src/session/InMemorySession.js +0 -13
- package/src/session/ServerSideRenderSession.js +0 -9
- package/src/session/WebBrowserSession.js +0 -13
- package/test/middlewareTestUtil.js +0 -31
- package/test/redux/Action.test.js +0 -73
- package/test/redux/ActionTypes.test.js +0 -13
- package/test/redux/createMiddlewares.test.js +0 -96
- package/test/redux/index.test.js +0 -10
- package/test/redux/locationReducer.test.js +0 -39
- package/test/redux/middleware/createAddInputLocationBasePathMiddleware.test.js +0 -40
- package/test/redux/middleware/createRemoveOutputLocationBasePathMiddleware.test.js +0 -51
- package/test/redux/middleware/navigationOperationMiddleware.test.js +0 -78
- package/test/redux/middleware/parseInputLocationMiddleware.test.js +0 -62
- package/test/testUtil.js +0 -3
- package/types/data-storage/index.d.ts +0 -35
- package/types/redux/index.d.ts +0 -90
- package/types/scroll-position/index.d.ts +0 -107
- /package/lib/cjs/{session → environment}/lifecycle/InMemorySessionLifecycle.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/WebBrowserSessionLifecycle.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/page-lifecycle/PageLifecycle.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/page-lifecycle/PageLifecycleInstance.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +0 -0
- /package/lib/cjs/{session → environment}/navigation/error/NavigationOutOfBoundsError.js +0 -0
- /package/lib/cjs/{session → environment}/navigation/operation/operations.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/InMemorySessionLifecycle.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/WebBrowserSessionLifecycle.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/page-lifecycle/PageLifecycle.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/page-lifecycle/PageLifecycleInstance.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +0 -0
- /package/lib/esm/{session → environment}/navigation/error/NavigationOutOfBoundsError.js +0 -0
- /package/lib/esm/{session → environment}/navigation/operation/operations.js +0 -0
- /package/src/{session → environment}/lifecycle/InMemorySessionLifecycle.js +0 -0
- /package/src/{session → environment}/lifecycle/WebBrowserSessionLifecycle.js +0 -0
- /package/src/{session → environment}/lifecycle/page-lifecycle/PageLifecycle.js +0 -0
- /package/src/{session → environment}/lifecycle/page-lifecycle/PageLifecycleInstance.js +0 -0
- /package/src/{session → environment}/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +0 -0
- /package/src/{session → environment}/navigation/error/NavigationOutOfBoundsError.js +0 -0
- /package/src/{session → environment}/navigation/operation/operations.js +0 -0
- /package/test/{parseInputLocationMiddleware.test.js → parseInputLocation.test.js} +0 -0
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// TypeScript Version: 3.0
|
|
2
|
-
|
|
3
1
|
export {};
|
|
4
2
|
|
|
5
3
|
export type Query = Record<string, string>;
|
|
@@ -97,11 +95,11 @@ export type NavigationBlockerResult =
|
|
|
97
95
|
*
|
|
98
96
|
* * The `location` argument is `null` when the web browser tab is about to be closed.
|
|
99
97
|
* * The `location` argument is of type `LocationBase` when a `.push()` or `.replace()` navigation is blocked.
|
|
100
|
-
* * The `location` argument is of type `
|
|
98
|
+
* * The `location` argument is of type `LocationBase` when blocking a navigation that was initiated outside of the application code.
|
|
101
99
|
* For example, when the user clicks "Back" or "Forward" button in a web browser.
|
|
102
100
|
*/
|
|
103
101
|
export type NavigationBlocker = (
|
|
104
|
-
location:
|
|
102
|
+
location: LocationBase | null,
|
|
105
103
|
) => NavigationBlockerResult;
|
|
106
104
|
|
|
107
105
|
// I dunno why did they use an `interface` here.
|
|
@@ -123,20 +121,18 @@ export function parseLocationUrl(locationUrl: string): LocationBase;
|
|
|
123
121
|
|
|
124
122
|
export function parseInputLocation(location: InputLocation): LocationBase;
|
|
125
123
|
|
|
126
|
-
export
|
|
127
|
-
session: Session,
|
|
128
|
-
blocker: NavigationBlocker,
|
|
129
|
-
): () => void;
|
|
130
|
-
|
|
131
|
-
export interface NavigationStackOptions {
|
|
124
|
+
export interface NavigationStackOptions<ScrollableContainer, Anchor> {
|
|
132
125
|
basePath?: string;
|
|
133
|
-
|
|
126
|
+
manageScrollPosition?: boolean;
|
|
127
|
+
scrollPositionSetter?: Constructor<
|
|
128
|
+
ScrollPositionSetter<ScrollableContainer, Anchor>
|
|
129
|
+
>;
|
|
134
130
|
}
|
|
135
131
|
|
|
136
132
|
export class NavigationStack<ScrollableContainer = any, Anchor = any> {
|
|
137
133
|
constructor(
|
|
138
|
-
|
|
139
|
-
options?: NavigationStackOptions,
|
|
134
|
+
environment: Constructor<Environment<ScrollableContainer, Anchor>>,
|
|
135
|
+
options?: NavigationStackOptions<ScrollableContainer, Anchor>,
|
|
140
136
|
);
|
|
141
137
|
|
|
142
138
|
addScrollableContainer(
|
|
@@ -144,6 +140,10 @@ export class NavigationStack<ScrollableContainer = any, Anchor = any> {
|
|
|
144
140
|
scrollableContainer: ScrollableContainer,
|
|
145
141
|
): () => void;
|
|
146
142
|
|
|
143
|
+
addNavigationBlocker(blocker: NavigationBlocker): () => void;
|
|
144
|
+
|
|
145
|
+
dataStorage: LocationDataStorage;
|
|
146
|
+
|
|
147
147
|
subscribe(listener: (location: Location) => void): () => void;
|
|
148
148
|
|
|
149
149
|
current(): Location;
|
|
@@ -156,7 +156,7 @@ export class NavigationStack<ScrollableContainer = any, Anchor = any> {
|
|
|
156
156
|
|
|
157
157
|
shift(delta: number): void;
|
|
158
158
|
|
|
159
|
-
locationRendered(): Promise<void>;
|
|
159
|
+
locationRendered(location: Location): Promise<void>;
|
|
160
160
|
|
|
161
161
|
stop(): void;
|
|
162
162
|
}
|
|
@@ -173,7 +173,7 @@ export type SessionExecutionStatusListener = (
|
|
|
173
173
|
|
|
174
174
|
export type ScrollListener = () => void;
|
|
175
175
|
|
|
176
|
-
export class
|
|
176
|
+
export class ServerSideRedirectError extends Error {
|
|
177
177
|
constructor(location: LocationBase);
|
|
178
178
|
|
|
179
179
|
location: LocationBase;
|
|
@@ -185,9 +185,11 @@ export class NavigationOutOfBoundsError extends Error {
|
|
|
185
185
|
index: number;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
export class
|
|
189
|
-
// Subscribes to "
|
|
190
|
-
|
|
188
|
+
export class EnvironmentNavigation {
|
|
189
|
+
// Subscribes to "asynchronous" changes of the current location.
|
|
190
|
+
subscribeToAsyncrhonousLocationUpdates(
|
|
191
|
+
listener: (location: LocationInternal) => void,
|
|
192
|
+
): () => void;
|
|
191
193
|
|
|
192
194
|
init(
|
|
193
195
|
initialLocation: LocationBase,
|
|
@@ -218,13 +220,19 @@ export interface EnvironmentDataStorage {
|
|
|
218
220
|
set(key: string, value: string): void;
|
|
219
221
|
}
|
|
220
222
|
|
|
221
|
-
export interface
|
|
223
|
+
export interface EnvironmentLifecycle {
|
|
222
224
|
addTerminationBlocker(blocker: SessionTerminationBlocker): () => void;
|
|
223
225
|
addExecutionStatusListener(
|
|
224
226
|
listener: SessionExecutionStatusListener,
|
|
225
227
|
): () => void;
|
|
226
228
|
}
|
|
227
229
|
|
|
230
|
+
export interface EnvironmentLog {
|
|
231
|
+
debug(...args: any[]): void;
|
|
232
|
+
warn(...args: any[]): void;
|
|
233
|
+
error(...args: any[]): void;
|
|
234
|
+
}
|
|
235
|
+
|
|
228
236
|
// Manages scroll position in an environment such as a web browser.
|
|
229
237
|
export interface EnvironmentScrollPosition<ScrollableContainer, Anchor> {
|
|
230
238
|
// Gets numeric scroll position of a page.
|
|
@@ -255,10 +263,13 @@ export interface EnvironmentScrollPosition<ScrollableContainer, Anchor> {
|
|
|
255
263
|
|
|
256
264
|
export interface Environment<ScrollableContainer, Anchor> {
|
|
257
265
|
dataStorage: EnvironmentDataStorage;
|
|
266
|
+
log: EnvironmentLog;
|
|
267
|
+
lifecycle: EnvironmentLifecycle;
|
|
268
|
+
navigation: EnvironmentNavigation;
|
|
258
269
|
scrollPosition: EnvironmentScrollPosition<ScrollableContainer, Anchor>;
|
|
259
270
|
}
|
|
260
271
|
|
|
261
|
-
|
|
272
|
+
interface Session<ScrollableContainer = any, Anchor = any> {
|
|
262
273
|
// `key` should be unique within `environment.dataStorage`.
|
|
263
274
|
// For example, `BrowserEnvironment` uses `window.sessionStorage`
|
|
264
275
|
// that is shared across different sessions within a given web browser tab,
|
|
@@ -268,7 +279,7 @@ export interface Session<ScrollableContainer = any, Anchor = any> {
|
|
|
268
279
|
// Private varibles. Not public API.
|
|
269
280
|
environment: Environment<ScrollableContainer, Anchor>;
|
|
270
281
|
|
|
271
|
-
lifecycle:
|
|
282
|
+
lifecycle: EnvironmentLifecycle;
|
|
272
283
|
|
|
273
284
|
subscribe(listener: (location: LocationInternal) => void): () => void;
|
|
274
285
|
|
|
@@ -282,12 +293,12 @@ export interface Session<ScrollableContainer = any, Anchor = any> {
|
|
|
282
293
|
}
|
|
283
294
|
|
|
284
295
|
// This is just a copy-paste of the `session` interface above.
|
|
285
|
-
declare abstract class
|
|
286
|
-
ScrollableContainer
|
|
287
|
-
Anchor = any,
|
|
288
|
-
> implements Session<ScrollableContainer, Anchor>
|
|
296
|
+
declare abstract class SessionClass<ScrollableContainer = any, Anchor = any>
|
|
297
|
+
implements Session<ScrollableContainer, Anchor>
|
|
289
298
|
{
|
|
290
|
-
constructor(
|
|
299
|
+
constructor(
|
|
300
|
+
environmentClass: Constructor<Environment<ScrollableContainer, Anchor>>,
|
|
301
|
+
);
|
|
291
302
|
|
|
292
303
|
// `key` should be unique within `environment.dataStorage`.
|
|
293
304
|
// For example, `BrowserEnvironment` uses `window.sessionStorage`
|
|
@@ -295,10 +306,11 @@ declare abstract class SessionBaseClass<
|
|
|
295
306
|
// hence the uniqueness requirement.
|
|
296
307
|
key: string;
|
|
297
308
|
|
|
298
|
-
// Private
|
|
309
|
+
// Private varible. Not public API.
|
|
299
310
|
environment: Environment<ScrollableContainer, Anchor>;
|
|
300
311
|
|
|
301
|
-
|
|
312
|
+
// Private varible. Not public API.
|
|
313
|
+
lifecycle: EnvironmentLifecycle;
|
|
302
314
|
|
|
303
315
|
subscribe(listener: (location: LocationInternal) => void): () => void;
|
|
304
316
|
|
|
@@ -311,14 +323,148 @@ declare abstract class SessionBaseClass<
|
|
|
311
323
|
shift(delta: number): void;
|
|
312
324
|
}
|
|
313
325
|
|
|
314
|
-
|
|
315
|
-
|
|
326
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
327
|
+
export interface WebBrowserEnvironment
|
|
328
|
+
extends Environment<HTMLElement, string> {}
|
|
329
|
+
|
|
330
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
331
|
+
export interface ServerSideRenderEnvironment
|
|
332
|
+
extends Environment<string, string> {}
|
|
333
|
+
|
|
334
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
335
|
+
export interface InMemoryEnvironment extends Environment<string, string> {}
|
|
336
|
+
|
|
337
|
+
// Theoretically, a developer could pass their own `ScrollPositionSetter` implementation
|
|
338
|
+
// when calling `.addScrollableContainer()` or
|
|
339
|
+
export interface ScrollPositionSetter<ScrollableContainer, Anchor> {
|
|
340
|
+
// Sets scroll position of a page or a scrollable element.
|
|
341
|
+
// Returns a `Promise` that resolves when it has finished setting the scroll position.
|
|
342
|
+
set(
|
|
343
|
+
// This is the scrollable container whose scroll position should be set.
|
|
344
|
+
// * When setting page scroll position, `scrollableContainer` is `undefined`.
|
|
345
|
+
// * When setting scrollable element scroll position, `scrollableContainer` is the scrollable element.
|
|
346
|
+
scrollableContainer: ScrollableContainer,
|
|
347
|
+
// This is the scroll position to set.
|
|
348
|
+
// * When setting page scroll position, it could be either an anchor or numeric coordinates.
|
|
349
|
+
// * When setting scrollable element scroll position, it could only be numeric coordinates.
|
|
350
|
+
scrollPositionOrAnchor: Anchor | [number, number],
|
|
351
|
+
// `scrollPosition` provides various "helper" methods for setting scroll position according to the environment.
|
|
352
|
+
// For example, in the context of a `WebBrowserEnvironment`, it provides the methods for setting scroll position in a web browser.
|
|
353
|
+
scrollPositionHelper: EnvironmentScrollPosition<
|
|
354
|
+
ScrollableContainer,
|
|
355
|
+
Anchor
|
|
356
|
+
>,
|
|
357
|
+
): Promise<void>;
|
|
358
|
+
|
|
359
|
+
// Cancels any pending (or in-progress) setting of scroll position.
|
|
360
|
+
cancel(): void;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// https://stackoverflow.com/questions/39392853/is-there-a-type-for-class-in-typescript-and-does-any-include-it
|
|
364
|
+
export type Constructor<T = any> = new (...args: any[]) => T;
|
|
365
|
+
|
|
366
|
+
export type DataStorageValue =
|
|
367
|
+
| string
|
|
368
|
+
| number
|
|
369
|
+
| boolean
|
|
370
|
+
| Record<string, unknown>
|
|
371
|
+
| null
|
|
372
|
+
| undefined;
|
|
373
|
+
|
|
374
|
+
declare class DataStorage<
|
|
375
|
+
Key extends string = string,
|
|
376
|
+
Value extends DataStorageValue = DataStorageValue,
|
|
377
|
+
> {
|
|
378
|
+
constructor(session: Session, options: { namespace: string });
|
|
379
|
+
|
|
380
|
+
get(key: Key): Value | undefined;
|
|
381
|
+
|
|
382
|
+
set(key: Key, value: Value | undefined): void;
|
|
316
383
|
}
|
|
317
384
|
|
|
318
|
-
|
|
319
|
-
|
|
385
|
+
declare class LocationDataStorage<
|
|
386
|
+
Key extends string = string,
|
|
387
|
+
Value extends DataStorageValue = DataStorageValue,
|
|
388
|
+
> {
|
|
389
|
+
constructor(session: Session, options: { namespace: string });
|
|
390
|
+
|
|
391
|
+
get(location: Location, key: Key): Value;
|
|
392
|
+
|
|
393
|
+
set(location: Location, key: Key, value: Value): void;
|
|
320
394
|
}
|
|
321
395
|
|
|
322
|
-
export class
|
|
323
|
-
|
|
396
|
+
export class ScrollPositionRestoration<
|
|
397
|
+
ScrollableContainer = any,
|
|
398
|
+
Anchor = any,
|
|
399
|
+
> {
|
|
400
|
+
constructor(
|
|
401
|
+
session: Session<ScrollableContainer, Anchor>,
|
|
402
|
+
|
|
403
|
+
options?: {
|
|
404
|
+
// Using this option, a developer could provide their own implementation of setting
|
|
405
|
+
// a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
|
|
406
|
+
// When specified, it applies to both page and any scrollable containers.
|
|
407
|
+
scrollPositionSetter: ScrollPositionSetter<ScrollableContainer, Anchor>;
|
|
408
|
+
|
|
409
|
+
shouldChangePageScrollPositionOnLocationChange?: (
|
|
410
|
+
prevLocation: Location | undefined,
|
|
411
|
+
newLocation: Location,
|
|
412
|
+
) => boolean;
|
|
413
|
+
|
|
414
|
+
// `options._getSavedPageScrollPositionOnLocationChange`
|
|
415
|
+
// isn't used in real life and is not part of the public API.
|
|
416
|
+
// It's only used in tests.
|
|
417
|
+
_getSavedPageScrollPositionOnLocationChange?: (
|
|
418
|
+
location: Location,
|
|
419
|
+
prevLocation: Location | undefined,
|
|
420
|
+
) => [number, number] | undefined;
|
|
421
|
+
|
|
422
|
+
// Using this option, a developer could theoretically provide their own implementation
|
|
423
|
+
// of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
|
|
424
|
+
// This could be part of the public API if anyone provided a sensible real-world use case for it.
|
|
425
|
+
_pageScrollPositionSetter?: ScrollPositionSetter<
|
|
426
|
+
ScrollableContainer,
|
|
427
|
+
Anchor
|
|
428
|
+
>;
|
|
429
|
+
},
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
addScrollableContainer(
|
|
433
|
+
scrollableContainerKey: string,
|
|
434
|
+
scrollableContainer: ScrollableContainer,
|
|
435
|
+
|
|
436
|
+
options?: {
|
|
437
|
+
shouldChangeScrollPositionOnLocationChange?: (
|
|
438
|
+
prevLocation: Location | undefined,
|
|
439
|
+
newLocation: Location,
|
|
440
|
+
) => boolean;
|
|
441
|
+
|
|
442
|
+
// `_options._getSavedScrollPositionOnLocationChange`
|
|
443
|
+
// isn't used in real life and is not part of the public API.
|
|
444
|
+
// It's only used in tests.
|
|
445
|
+
_getSavedScrollPositionOnLocationChange?: (
|
|
446
|
+
location: Location,
|
|
447
|
+
prevLocation: Location | undefined,
|
|
448
|
+
) => [number, number] | undefined;
|
|
449
|
+
|
|
450
|
+
// Using this option, a developer could theoretically provide their own implementation
|
|
451
|
+
// of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
|
|
452
|
+
// This could be part of the public API if anyone provided a sensible real-world use case for it.
|
|
453
|
+
_scrollPositionSetter: ScrollPositionSetter<ScrollableContainer, Anchor>;
|
|
454
|
+
},
|
|
455
|
+
): () => void;
|
|
456
|
+
|
|
457
|
+
locationRendered: (location: Location) => Promise<void>;
|
|
458
|
+
|
|
459
|
+
stop(): void;
|
|
460
|
+
|
|
461
|
+
// `_enableSavingScrollPosition()` and `_disableSavingScrollPosition()`
|
|
462
|
+
// aren't used in real life and are not part of the public API.
|
|
463
|
+
// They're only used in tests.
|
|
464
|
+
_enableSavingScrollPosition(): void;
|
|
465
|
+
|
|
466
|
+
// `_enableSavingScrollPosition()` and `_disableSavingScrollPosition()`
|
|
467
|
+
// aren't used in real life and are not part of the public API.
|
|
468
|
+
// They're only used in tests.
|
|
469
|
+
_disableSavingScrollPosition(): void;
|
|
324
470
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "navigation-stack",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "Navigation in a Single-Page Application",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"history",
|
|
7
7
|
"browser",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "rimraf lib && 4c build --types false src && npm run build:pick && npm run build:types",
|
|
27
27
|
"build:pick": "cherry-pick --cjs-dir cjs --esm-dir esm --cwd lib ../src",
|
|
28
|
-
"build:types": "cpy types/*.d.ts lib
|
|
28
|
+
"build:types": "cpy types/*.d.ts lib",
|
|
29
29
|
"format": "4c format --prettier-ignore .eslintignore .",
|
|
30
30
|
"lint": "4c lint --prettier-ignore .eslintignore .",
|
|
31
31
|
"prepublishOnly": "npm run build",
|
|
@@ -44,10 +44,7 @@
|
|
|
44
44
|
"*": "yarn 4c lint --fix --prettier-ignore .eslintignore"
|
|
45
45
|
},
|
|
46
46
|
"prettier": "@4c/prettier-config",
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"query-string": "^5.1.1",
|
|
49
|
-
"redux": "^5.0.1"
|
|
50
|
-
},
|
|
47
|
+
"dependencies": {},
|
|
51
48
|
"devDependencies": {
|
|
52
49
|
"@4c/babel-preset": "^9.1.0",
|
|
53
50
|
"@4c/cli": "^3.0.1",
|
package/src/NavigationStack.js
CHANGED
|
@@ -1,40 +1,102 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { addBasePath, removeBasePath } from './basePath';
|
|
2
|
+
import LocationDataStorage from './data-storage/LocationDataStorage';
|
|
3
|
+
import getLocationFromInternalLocation from './getLocationFromInternalLocation';
|
|
4
|
+
import isPromise from './isPromise';
|
|
5
|
+
import {
|
|
6
|
+
addNavigationBlocker,
|
|
7
|
+
removeAllNavigationBlockers,
|
|
8
|
+
} from './navigationBlockers';
|
|
9
|
+
import {
|
|
10
|
+
blockNonProgrammaticNavigationIfRequired,
|
|
11
|
+
blockProgrammaticNavigationIfRequired,
|
|
12
|
+
} from './navigationBlockersEvaluation';
|
|
13
|
+
import parseInputLocation from './parseInputLocation';
|
|
6
14
|
import ScrollPositionRestoration from './scroll-position/ScrollPositionRestoration';
|
|
7
|
-
|
|
8
|
-
function getCreateMiddlewaresOptions(navigationStackOptions) {
|
|
9
|
-
if (!navigationStackOptions) {
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
|
-
// eslint-disable-next-line no-unused-vars
|
|
13
|
-
const { maintainScrollPosition, ...restOptions } = navigationStackOptions;
|
|
14
|
-
return restOptions;
|
|
15
|
-
}
|
|
15
|
+
import Session from './session/Session';
|
|
16
16
|
|
|
17
17
|
export default class NavigationStack {
|
|
18
|
-
constructor(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
constructor(
|
|
19
|
+
Environment,
|
|
20
|
+
{ basePath, manageScrollPosition, scrollPositionSetter } = {},
|
|
21
|
+
) {
|
|
22
|
+
// Create a session.
|
|
23
|
+
this._session = new Session(Environment);
|
|
24
|
+
|
|
25
|
+
// Base path, if used.
|
|
26
|
+
this._basePath = basePath;
|
|
27
|
+
|
|
28
|
+
// Create location data storage.
|
|
29
|
+
this.dataStorage = new LocationDataStorage(this._session, {
|
|
30
|
+
namespace: 'navigation-stack',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Allows temporarily ignoring location update events when set to `true`.
|
|
34
|
+
this._ignoreLocationUpdates = false;
|
|
35
|
+
|
|
36
|
+
// Subscribe to location updates.
|
|
37
|
+
// * Ignores location updates if `_ignoreLocationUpdates` flag is temporarily set.
|
|
38
|
+
// * Runs navigation blockers to see if the location update should be reverted.
|
|
39
|
+
// * Updates `this._location` if the update wasn't ignored or blocked.
|
|
40
|
+
this._unsubscribe = this._session.subscribe((location) => {
|
|
41
|
+
// If this location update shouldn't be temporarily ignored.
|
|
42
|
+
if (!this._ignoreLocationUpdates) {
|
|
43
|
+
// Remove `basePath` from `location`.
|
|
44
|
+
location = removeBasePath(location, this._basePath);
|
|
45
|
+
|
|
46
|
+
// See if the location update should've been blocked.
|
|
47
|
+
// If it should've, it will automatically "rewind" it.
|
|
48
|
+
const result = blockNonProgrammaticNavigationIfRequired(
|
|
49
|
+
location,
|
|
50
|
+
this._session,
|
|
51
|
+
this._doAndIgnoreLocationUpdates,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const onResult = (blocked) => {
|
|
55
|
+
if (!blocked) {
|
|
56
|
+
// Update `this._location`.
|
|
57
|
+
// Since it's gonna be returned from the public `this.current()` method,
|
|
58
|
+
// convert it from `LocationInternal` to `Location`.
|
|
59
|
+
this._location = getLocationFromInternalLocation(location);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (isPromise(result)) {
|
|
64
|
+
result.then(onResult);
|
|
65
|
+
} else {
|
|
66
|
+
onResult(result);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
28
70
|
|
|
29
71
|
// Create `ScrollPositionRestoration`.
|
|
30
|
-
if (
|
|
31
|
-
this._scrollPositionRestoration = new ScrollPositionRestoration(
|
|
72
|
+
if (manageScrollPosition) {
|
|
73
|
+
this._scrollPositionRestoration = new ScrollPositionRestoration(
|
|
74
|
+
this._session,
|
|
75
|
+
// Custom `ScrollPositionSetter`.
|
|
76
|
+
{ scrollPositionSetter },
|
|
77
|
+
);
|
|
32
78
|
}
|
|
33
79
|
}
|
|
34
80
|
|
|
81
|
+
// Subscribes to any changes of the current location.
|
|
82
|
+
// The first subscriber is always the `NavigationStack` itself
|
|
83
|
+
// because its listener is what drives the actual navigation.
|
|
84
|
+
// Any additional application-specific listeners could be added, if required.
|
|
85
|
+
subscribe(listener) {
|
|
86
|
+
// `NavigationStack.subscribe()` is simply a proxy to `Session.subscribe()`
|
|
87
|
+
// with the only convenience feature that it "normalizes" the `location` argument.
|
|
88
|
+
return this._session.subscribe((locationInternal) => {
|
|
89
|
+
listener(getLocationFromInternalLocation(locationInternal));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
addNavigationBlocker(blocker) {
|
|
94
|
+
return addNavigationBlocker(this._session, blocker);
|
|
95
|
+
}
|
|
96
|
+
|
|
35
97
|
addScrollableContainer(scrollableContainerKey, scrollableContainer) {
|
|
36
98
|
if (!this._scrollPositionRestoration) {
|
|
37
|
-
throw new Error('`
|
|
99
|
+
throw new Error('`manageScrollPosition: true` option not passed');
|
|
38
100
|
}
|
|
39
101
|
return this._scrollPositionRestoration.addScrollableContainer(
|
|
40
102
|
scrollableContainerKey,
|
|
@@ -42,59 +104,107 @@ export default class NavigationStack {
|
|
|
42
104
|
);
|
|
43
105
|
}
|
|
44
106
|
|
|
45
|
-
subscribe(listener) {
|
|
46
|
-
// Subscribe to any potential Redux state changes.
|
|
47
|
-
return this._store.subscribe(() => {
|
|
48
|
-
// Initially, calls the listener when setting the initial location.
|
|
49
|
-
// After that, calls it on any location change.
|
|
50
|
-
const location = this.current();
|
|
51
|
-
if (!this._latestLocation || location !== this._latestLocation) {
|
|
52
|
-
this._latestLocation = location;
|
|
53
|
-
listener(location);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
107
|
init(initialLocation) {
|
|
59
|
-
if (this.
|
|
108
|
+
if (this._location) {
|
|
60
109
|
throw new Error('Already initialized');
|
|
61
110
|
}
|
|
62
111
|
|
|
63
|
-
this.
|
|
64
|
-
|
|
112
|
+
this._session.start(
|
|
113
|
+
initialLocation && this._parseInputLocation(initialLocation),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
if (this._scrollPositionRestoration) {
|
|
117
|
+
this._scrollPositionRestoration.start();
|
|
118
|
+
}
|
|
65
119
|
}
|
|
66
120
|
|
|
67
121
|
current() {
|
|
68
|
-
|
|
122
|
+
// TypeScript definition of the `.current()` method tells that it always returns
|
|
123
|
+
// some non-`undefined` location.
|
|
124
|
+
// But `this._location` is `undefined` until `.init(initialLocation?)` is called.
|
|
125
|
+
// To work around that limitation, it simply throws if `.current()` is called before `.init()`.
|
|
126
|
+
if (!this._location) {
|
|
127
|
+
throw new Error('Not initialized');
|
|
128
|
+
}
|
|
129
|
+
return this._location;
|
|
69
130
|
}
|
|
70
131
|
|
|
71
132
|
push(location) {
|
|
72
|
-
this.
|
|
133
|
+
this._navigate('push', location);
|
|
73
134
|
}
|
|
74
135
|
|
|
75
136
|
replace(location) {
|
|
76
|
-
this.
|
|
137
|
+
this._navigate('replace', location);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_navigate(operation, location) {
|
|
141
|
+
const toLocation = this._parseInputLocation(location);
|
|
142
|
+
|
|
143
|
+
const result = blockProgrammaticNavigationIfRequired(
|
|
144
|
+
toLocation,
|
|
145
|
+
this._session,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const onResult = (blocked) => {
|
|
149
|
+
if (!blocked) {
|
|
150
|
+
this._session.navigate(operation, toLocation);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
if (isPromise(result)) {
|
|
155
|
+
result.then(onResult);
|
|
156
|
+
} else {
|
|
157
|
+
onResult(result);
|
|
158
|
+
}
|
|
77
159
|
}
|
|
78
160
|
|
|
79
161
|
shift(delta) {
|
|
80
|
-
this.
|
|
162
|
+
this._session.shift(delta);
|
|
81
163
|
}
|
|
82
164
|
|
|
83
165
|
stop() {
|
|
166
|
+
if (!this._unsubscribe) {
|
|
167
|
+
throw new Error('Already stopped');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this._unsubscribe();
|
|
171
|
+
this._unsubscribe = undefined;
|
|
172
|
+
|
|
173
|
+
// Even if it calls `unsubscribe()` function above, any other subscriptions
|
|
174
|
+
// would still stay. We're not talking about `navigationStack.subscribe()`
|
|
175
|
+
// subscriptions because those don't really matter in terms of cleaning them up:
|
|
176
|
+
// those're just Redux store subscriptions that don't have any side effects.
|
|
177
|
+
// Subscriptions we're talking here are `Session`'s own subscription
|
|
178
|
+
// via `session.subscribe()` and any hypothetical manual `session.subscribe()`
|
|
179
|
+
// calls that could be made by the application code for whatever purpose.
|
|
180
|
+
// Both of those should be cleared.
|
|
181
|
+
// To work around that, `.stop()` function removes all subscriptions.
|
|
182
|
+
this._session.stop();
|
|
183
|
+
|
|
184
|
+
removeAllNavigationBlockers(this._session);
|
|
185
|
+
|
|
84
186
|
if (this._scrollPositionRestoration) {
|
|
85
187
|
this._scrollPositionRestoration.stop();
|
|
86
188
|
}
|
|
87
|
-
this._store.dispatch(Actions.stop());
|
|
88
189
|
}
|
|
89
190
|
|
|
90
|
-
locationRendered() {
|
|
91
|
-
if (this._scrollPositionRestoration) {
|
|
92
|
-
|
|
93
|
-
if (!location) {
|
|
94
|
-
throw new Error('Not initialized');
|
|
95
|
-
}
|
|
96
|
-
return this._scrollPositionRestoration.locationRendered(location);
|
|
191
|
+
locationRendered(location) {
|
|
192
|
+
if (!this._scrollPositionRestoration) {
|
|
193
|
+
throw new Error('`manageScrollPosition: true` option not passed');
|
|
97
194
|
}
|
|
98
|
-
return
|
|
195
|
+
return this._scrollPositionRestoration.locationRendered(location);
|
|
99
196
|
}
|
|
197
|
+
|
|
198
|
+
_parseInputLocation(inputLocation) {
|
|
199
|
+
// Parse input location (string or incomplete object) to a proper `location` object.
|
|
200
|
+
// Add `basePath` to `location`.
|
|
201
|
+
return addBasePath(parseInputLocation(inputLocation), this._basePath);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Allows temporarily ignoring location update events.
|
|
205
|
+
_doAndIgnoreLocationUpdates = (func) => {
|
|
206
|
+
this._ignoreLocationUpdates = true;
|
|
207
|
+
func();
|
|
208
|
+
this._ignoreLocationUpdates = false;
|
|
209
|
+
};
|
|
100
210
|
}
|
|
@@ -4,6 +4,7 @@ export default class DataStorage {
|
|
|
4
4
|
throw new Error('`DataStorage` requires a `session.key`');
|
|
5
5
|
}
|
|
6
6
|
this._sessionKey = session.key;
|
|
7
|
+
this._log = session.environment.log;
|
|
7
8
|
this._dataStorage = session.environment.dataStorage;
|
|
8
9
|
this._namespace = namespace;
|
|
9
10
|
}
|
|
@@ -22,8 +23,8 @@ export default class DataStorage {
|
|
|
22
23
|
// junk into sessionStorage under our namespace.
|
|
23
24
|
return JSON.parse(value);
|
|
24
25
|
} catch (error) {
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
this._log.error('[navigation-stack] Could not read data from storage');
|
|
27
|
+
this._log.error(error);
|
|
27
28
|
|
|
28
29
|
// Pretend that the entry doesn't exist.
|
|
29
30
|
return undefined;
|
|
@@ -38,8 +39,10 @@ export default class DataStorage {
|
|
|
38
39
|
this._dataStorage.remove(storageKey);
|
|
39
40
|
} catch (error) {
|
|
40
41
|
// No need to handle errors here.
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
this._log.error(
|
|
43
|
+
'[navigation-stack] Could not delete data from storage',
|
|
44
|
+
);
|
|
45
|
+
this._log.error(error);
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
return;
|
|
@@ -54,8 +57,8 @@ export default class DataStorage {
|
|
|
54
57
|
} catch (error) {
|
|
55
58
|
// No need to handle errors here either. If it didn't work, it didn't
|
|
56
59
|
// work. We make no guarantees about actually saving the value.
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
this._log.error('[navigation-stack] Could not save data in storage');
|
|
61
|
+
this._log.error(error);
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import InMemoryDataStorage from './data-storage/InMemoryDataStorage';
|
|
2
|
+
import InMemorySessionLifecycle from './lifecycle/InMemorySessionLifecycle';
|
|
3
|
+
import InMemoryLog from './log/InMemoryLog';
|
|
4
|
+
import InMemoryNavigation from './navigation/InMemoryNavigation';
|
|
2
5
|
import InMemoryScrollPosition from './scroll-position/InMemoryScrollPosition';
|
|
3
6
|
|
|
4
7
|
export default class InMemoryEnvironment {
|
|
5
8
|
constructor() {
|
|
6
9
|
this.dataStorage = new InMemoryDataStorage();
|
|
10
|
+
this.log = new InMemoryLog();
|
|
11
|
+
this.lifecycle = new InMemorySessionLifecycle();
|
|
12
|
+
this.navigation = new InMemoryNavigation();
|
|
7
13
|
this.scrollPosition = new InMemoryScrollPosition();
|
|
8
14
|
}
|
|
9
15
|
}
|