navigation-stack 0.5.3 → 0.6.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.
- 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
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import InMemoryEnvironment from '../../src/environment/InMemoryEnvironment';
|
|
1
2
|
import parseInputLocation from '../../src/parseInputLocation';
|
|
2
|
-
import
|
|
3
|
+
import Session from '../../src/session/Session';
|
|
3
4
|
|
|
4
|
-
describe('
|
|
5
|
+
describe('Session (InMemoryEnvironment)', () => {
|
|
5
6
|
it('should parse the initial location', () => {
|
|
6
|
-
const session = new
|
|
7
|
+
const session = new Session(InMemoryEnvironment);
|
|
7
8
|
|
|
8
9
|
let location;
|
|
9
10
|
session.subscribe((newLocation) => {
|
|
@@ -28,7 +29,7 @@ describe('InMemorySession', () => {
|
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
it('should support basic navigation', () => {
|
|
31
|
-
const session = new
|
|
32
|
+
const session = new Session(InMemoryEnvironment);
|
|
32
33
|
|
|
33
34
|
let location;
|
|
34
35
|
session.subscribe((newLocation) => {
|
|
@@ -124,7 +125,7 @@ describe('InMemorySession', () => {
|
|
|
124
125
|
});
|
|
125
126
|
|
|
126
127
|
it('should support subscribing and unsubscribing', () => {
|
|
127
|
-
const session = new
|
|
128
|
+
const session = new Session(InMemoryEnvironment);
|
|
128
129
|
session.start(parseInputLocation('/initial'));
|
|
129
130
|
session.navigate('push', { pathname: '/new' });
|
|
130
131
|
session.navigate('push', { pathname: '/new-2' });
|
|
@@ -151,7 +152,7 @@ describe('InMemorySession', () => {
|
|
|
151
152
|
});
|
|
152
153
|
|
|
153
154
|
it('should respect stack bounds', () => {
|
|
154
|
-
const session = new
|
|
155
|
+
const session = new Session(InMemoryEnvironment);
|
|
155
156
|
session.start(parseInputLocation('/initial'));
|
|
156
157
|
session.navigate('push', { pathname: '/new' });
|
|
157
158
|
session.navigate('push', { pathname: '/new-2' });
|
|
@@ -205,7 +206,7 @@ describe('InMemorySession', () => {
|
|
|
205
206
|
});
|
|
206
207
|
|
|
207
208
|
it('should not reset forward entries on replace', () => {
|
|
208
|
-
const session = new
|
|
209
|
+
const session = new Session(InMemoryEnvironment);
|
|
209
210
|
session.start(parseInputLocation('/initial'));
|
|
210
211
|
session.navigate('push', { pathname: '/new' });
|
|
211
212
|
session.navigate('push', { pathname: '/new-2' });
|
|
@@ -228,7 +229,7 @@ describe('InMemorySession', () => {
|
|
|
228
229
|
});
|
|
229
230
|
|
|
230
231
|
it('should reset forward entries on push', () => {
|
|
231
|
-
const session = new
|
|
232
|
+
const session = new Session(InMemoryEnvironment);
|
|
232
233
|
|
|
233
234
|
session.start(parseInputLocation('/initial'));
|
|
234
235
|
session.navigate('push', { pathname: '/new' });
|
|
@@ -249,7 +250,7 @@ describe('InMemorySession', () => {
|
|
|
249
250
|
});
|
|
250
251
|
|
|
251
252
|
it('should remove all subscriptions on stop', () => {
|
|
252
|
-
const session = new
|
|
253
|
+
const session = new Session(InMemoryEnvironment);
|
|
253
254
|
|
|
254
255
|
session.start(parseInputLocation('/initial'));
|
|
255
256
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import ServerSideRenderEnvironment from '../../src/environment/ServerSideRenderEnvironment';
|
|
1
2
|
import parseInputLocation from '../../src/parseInputLocation';
|
|
2
|
-
import
|
|
3
|
+
import Session from '../../src/session/Session';
|
|
3
4
|
|
|
4
|
-
describe('
|
|
5
|
+
describe('Session (ServerSideRenderEnvironment)', () => {
|
|
5
6
|
it('should parse the initial location', () => {
|
|
6
|
-
const session = new
|
|
7
|
+
const session = new Session(ServerSideRenderEnvironment);
|
|
7
8
|
|
|
8
9
|
let location;
|
|
9
10
|
session.subscribe((newLocation) => {
|
|
@@ -24,7 +25,7 @@ describe('ServerSideRenderSession', () => {
|
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
it('should support subscriptions', () => {
|
|
27
|
-
const session = new
|
|
28
|
+
const session = new Session(ServerSideRenderEnvironment);
|
|
28
29
|
// eslint-disable-next-line no-unused-vars
|
|
29
30
|
expect(() => session.subscribe((location) => {})).to.not.throw();
|
|
30
31
|
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import delay from 'delay';
|
|
2
2
|
|
|
3
|
+
import WebBrowserEnvironment from '../../src/environment/WebBrowserEnvironment';
|
|
3
4
|
import parseInputLocation from '../../src/parseInputLocation';
|
|
4
|
-
import
|
|
5
|
+
import Session from '../../src/session/Session';
|
|
5
6
|
|
|
6
|
-
describe('
|
|
7
|
+
describe('Session.stop() (WebBrowserEnvironment)', () => {
|
|
7
8
|
const sandbox = sinon.createSandbox();
|
|
8
9
|
|
|
9
10
|
afterEach(() => {
|
|
@@ -16,7 +17,7 @@ describe('WebBrowserSession.stop()', () => {
|
|
|
16
17
|
sandbox.spy(window, 'addEventListener');
|
|
17
18
|
sandbox.spy(window, 'removeEventListener');
|
|
18
19
|
|
|
19
|
-
const session = new
|
|
20
|
+
const session = new Session(WebBrowserEnvironment);
|
|
20
21
|
|
|
21
22
|
session.subscribe(() => {});
|
|
22
23
|
|
|
@@ -40,7 +41,7 @@ describe('WebBrowserSession.stop()', () => {
|
|
|
40
41
|
});
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
describe('
|
|
44
|
+
describe('Session (WebBrowserEnvironment)', () => {
|
|
44
45
|
let session;
|
|
45
46
|
|
|
46
47
|
afterEach(() => {
|
|
@@ -52,7 +53,7 @@ describe('WebBrowserSession', () => {
|
|
|
52
53
|
|
|
53
54
|
it('should parse the initial location', () => {
|
|
54
55
|
window.history.replaceState(null, null, '/initial?bar=baz#qux');
|
|
55
|
-
session = new
|
|
56
|
+
session = new Session(WebBrowserEnvironment);
|
|
56
57
|
|
|
57
58
|
let location;
|
|
58
59
|
session.subscribe((newLocation) => {
|
|
@@ -75,7 +76,7 @@ describe('WebBrowserSession', () => {
|
|
|
75
76
|
});
|
|
76
77
|
|
|
77
78
|
it('should require initialization', () => {
|
|
78
|
-
session = new
|
|
79
|
+
session = new Session(WebBrowserEnvironment);
|
|
79
80
|
|
|
80
81
|
expect(() =>
|
|
81
82
|
session.navigate('push', {
|
|
@@ -89,7 +90,7 @@ describe('WebBrowserSession', () => {
|
|
|
89
90
|
it('should support basic navigation', async () => {
|
|
90
91
|
window.history.replaceState(null, null, '/initial');
|
|
91
92
|
|
|
92
|
-
session = new
|
|
93
|
+
session = new Session(WebBrowserEnvironment);
|
|
93
94
|
|
|
94
95
|
let location;
|
|
95
96
|
session.subscribe((newLocation) => {
|
|
@@ -178,7 +179,7 @@ describe('WebBrowserSession', () => {
|
|
|
178
179
|
index: 2,
|
|
179
180
|
delta: 0,
|
|
180
181
|
});
|
|
181
|
-
await delay(
|
|
182
|
+
await delay(100);
|
|
182
183
|
|
|
183
184
|
expect(window.location.pathname).to.equal('/new-3');
|
|
184
185
|
|
|
@@ -192,7 +193,7 @@ describe('WebBrowserSession', () => {
|
|
|
192
193
|
listener.resetHistory();
|
|
193
194
|
|
|
194
195
|
session.shift(-1);
|
|
195
|
-
await delay(
|
|
196
|
+
await delay(100);
|
|
196
197
|
|
|
197
198
|
expect(window.location).to.include({
|
|
198
199
|
pathname: '/new',
|
|
@@ -213,7 +214,7 @@ describe('WebBrowserSession', () => {
|
|
|
213
214
|
listener.resetHistory();
|
|
214
215
|
|
|
215
216
|
window.history.back();
|
|
216
|
-
await delay(
|
|
217
|
+
await delay(100);
|
|
217
218
|
|
|
218
219
|
expect(window.location.pathname).to.equal('/initial');
|
|
219
220
|
|
|
@@ -229,7 +230,7 @@ describe('WebBrowserSession', () => {
|
|
|
229
230
|
|
|
230
231
|
it('should support subscribing and unsubscribing', async () => {
|
|
231
232
|
window.history.replaceState(null, null, '/');
|
|
232
|
-
session = new
|
|
233
|
+
session = new Session(WebBrowserEnvironment);
|
|
233
234
|
session.start(parseInputLocation(window.location));
|
|
234
235
|
session.navigate('push', {
|
|
235
236
|
pathname: '/new',
|
|
@@ -246,7 +247,7 @@ describe('WebBrowserSession', () => {
|
|
|
246
247
|
const unsubscribe = session.subscribe(listener);
|
|
247
248
|
|
|
248
249
|
session.shift(-1);
|
|
249
|
-
await delay(
|
|
250
|
+
await delay(100);
|
|
250
251
|
|
|
251
252
|
expect(listener).to.have.been.calledOnce();
|
|
252
253
|
expect(listener.firstCall.args[0]).to.include({
|
|
@@ -258,8 +259,57 @@ describe('WebBrowserSession', () => {
|
|
|
258
259
|
unsubscribe();
|
|
259
260
|
|
|
260
261
|
session.shift(-1);
|
|
261
|
-
await delay(
|
|
262
|
+
await delay(100);
|
|
262
263
|
|
|
263
264
|
expect(listener).not.to.have.been.called();
|
|
264
265
|
});
|
|
265
266
|
});
|
|
267
|
+
|
|
268
|
+
describe('Session (WebBrowserEnvironment) (restart)', () => {
|
|
269
|
+
it('should restart a previously-started session', async () => {
|
|
270
|
+
window.history.replaceState(null, null, '/initial');
|
|
271
|
+
|
|
272
|
+
let currentLocation;
|
|
273
|
+
const locationListener = (location) => {
|
|
274
|
+
currentLocation = location;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const session = new Session(WebBrowserEnvironment);
|
|
278
|
+
session.subscribe(locationListener);
|
|
279
|
+
session.start();
|
|
280
|
+
session.navigate('push', parseInputLocation('/new'));
|
|
281
|
+
session.stop();
|
|
282
|
+
|
|
283
|
+
const latestLocationIndex = currentLocation.index;
|
|
284
|
+
expect(latestLocationIndex > 0).to.equal(true);
|
|
285
|
+
|
|
286
|
+
// Simulate the user refreshing the page in a web browser.
|
|
287
|
+
// In such case, `window.history` will be retained
|
|
288
|
+
// but every javascript variable will be recreated from scratch.
|
|
289
|
+
const newSession = new Session(WebBrowserEnvironment);
|
|
290
|
+
newSession.subscribe(locationListener);
|
|
291
|
+
newSession.start();
|
|
292
|
+
|
|
293
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
294
|
+
expect(newSession._subscription._latest.operation).to.equal('init');
|
|
295
|
+
|
|
296
|
+
expect(currentLocation.pathname).to.equal('/new');
|
|
297
|
+
expect(currentLocation.index).to.equal(latestLocationIndex);
|
|
298
|
+
|
|
299
|
+
newSession.shift(-1);
|
|
300
|
+
|
|
301
|
+
await delay(100);
|
|
302
|
+
|
|
303
|
+
expect(currentLocation.pathname).to.equal('/initial');
|
|
304
|
+
expect(currentLocation.index).to.equal(latestLocationIndex - 1);
|
|
305
|
+
|
|
306
|
+
newSession.shift(1);
|
|
307
|
+
|
|
308
|
+
await delay(100);
|
|
309
|
+
|
|
310
|
+
expect(currentLocation.pathname).to.equal('/new');
|
|
311
|
+
expect(currentLocation.index).to.equal(latestLocationIndex);
|
|
312
|
+
|
|
313
|
+
newSession.stop();
|
|
314
|
+
});
|
|
315
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// With such `import`, tests wouldn't work and would throw an error:
|
|
2
|
+
// "console.warn.restore is not a function".
|
|
3
|
+
// It could or could not be related to using `karma` test runner.
|
|
4
|
+
//
|
|
5
|
+
// import sinon from 'sinon';
|
|
6
|
+
|
|
7
|
+
export default function shouldWarn(about) {
|
|
8
|
+
console.warn.expected.push(about); // eslint-disable-line no-console
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function stubWarn() {
|
|
12
|
+
/* eslint-disable no-console */
|
|
13
|
+
sinon.stub(console, 'warn').callsFake((message) => {
|
|
14
|
+
let expected = false;
|
|
15
|
+
|
|
16
|
+
console.warn.expected.forEach((about) => {
|
|
17
|
+
if (message.includes(about)) {
|
|
18
|
+
console.warn.warned[about] = true;
|
|
19
|
+
expected = true;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (expected) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.warn.threw = true;
|
|
28
|
+
throw new Error(message);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.warn.expected = [];
|
|
32
|
+
console.warn.warned = Object.create(null);
|
|
33
|
+
console.warn.threw = false;
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
const { expected, warned, threw } = console.warn;
|
|
37
|
+
console.warn.restore();
|
|
38
|
+
|
|
39
|
+
if (!threw && expected.length) {
|
|
40
|
+
expect(warned).to.have.keys(expected);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
/* eslint-enable no-console */
|
|
44
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import stringifyQuery from '../src/stringifyQuery';
|
|
2
|
+
|
|
3
|
+
describe('stringifyQuery', () => {
|
|
4
|
+
it('stringify', () => {
|
|
5
|
+
expect(stringifyQuery({ foo: 'bar' })).to.equal('foo=bar');
|
|
6
|
+
expect(
|
|
7
|
+
stringifyQuery({
|
|
8
|
+
foo: 'bar',
|
|
9
|
+
bar: 'baz',
|
|
10
|
+
}),
|
|
11
|
+
).to.equal('foo=bar&bar=baz');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('different types', () => {
|
|
15
|
+
expect(stringifyQuery({})).to.equal('');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('primitive types', () => {
|
|
19
|
+
expect(stringifyQuery({ a: 'string' })).to.equal('a=string');
|
|
20
|
+
expect(stringifyQuery({ a: true, b: false })).to.equal('a=true&b=false');
|
|
21
|
+
expect(stringifyQuery({ a: 0, b: 1n })).to.equal('a=0&b=1');
|
|
22
|
+
expect(stringifyQuery({ a: null, b: undefined })).to.equal('a');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('URI encode', () => {
|
|
26
|
+
expect(stringifyQuery({ 'foo bar': 'baz faz' })).to.equal(
|
|
27
|
+
'foo%20bar=baz%20faz',
|
|
28
|
+
);
|
|
29
|
+
expect(stringifyQuery({ 'foo bar': "baz'faz" })).to.equal(
|
|
30
|
+
'foo%20bar=baz%27faz',
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('handle array value', () => {
|
|
35
|
+
expect(() => {
|
|
36
|
+
stringifyQuery({
|
|
37
|
+
abc: 'abc',
|
|
38
|
+
foo: ['bar', 'baz'],
|
|
39
|
+
});
|
|
40
|
+
}).to.throw('Array values are not supported');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should not encode undefined values', () => {
|
|
44
|
+
expect(
|
|
45
|
+
stringifyQuery({
|
|
46
|
+
abc: undefined,
|
|
47
|
+
foo: 'baz',
|
|
48
|
+
}),
|
|
49
|
+
).to.equal('foo=baz');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should encode null values as just a key', () => {
|
|
53
|
+
expect(
|
|
54
|
+
stringifyQuery({
|
|
55
|
+
'x y z': null,
|
|
56
|
+
'abc': null,
|
|
57
|
+
'foo': 'baz',
|
|
58
|
+
}),
|
|
59
|
+
).to.equal('x%20y%20z&abc&foo=baz');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('encoding', () => {
|
|
63
|
+
expect(stringifyQuery({ foo: "'bar'" })).to.equal('foo=%27bar%27');
|
|
64
|
+
});
|
|
65
|
+
});
|
package/types/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
|
}
|