@tanstack/router-core 0.0.1-beta.2 → 0.0.1-beta.201
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/LICENSE +21 -0
- package/build/cjs/defer.js +39 -0
- package/build/cjs/defer.js.map +1 -0
- package/build/cjs/fileRoute.js +29 -0
- package/build/cjs/fileRoute.js.map +1 -0
- package/build/cjs/index.js +89 -0
- package/build/cjs/{packages/router-core/src/index.js.map → index.js.map} +1 -1
- package/build/cjs/{packages/router-core/src/path.js → path.js} +45 -56
- package/build/cjs/path.js.map +1 -0
- package/build/cjs/{packages/router-core/src/qss.js → qss.js} +10 -15
- package/build/cjs/qss.js.map +1 -0
- package/build/cjs/route.js +114 -0
- package/build/cjs/route.js.map +1 -0
- package/build/cjs/router.js +1277 -0
- package/build/cjs/router.js.map +1 -0
- package/build/cjs/scroll-restoration.js +139 -0
- package/build/cjs/scroll-restoration.js.map +1 -0
- package/build/cjs/{packages/router-core/src/searchParams.js → searchParams.js} +32 -19
- package/build/cjs/searchParams.js.map +1 -0
- package/build/cjs/utils.js +132 -0
- package/build/cjs/utils.js.map +1 -0
- package/build/esm/index.js +1565 -2106
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +59 -49
- package/build/stats-react.json +219 -241
- package/build/types/defer.d.ts +19 -0
- package/build/types/fileRoute.d.ts +35 -0
- package/build/types/index.d.ts +13 -611
- package/build/types/link.d.ts +96 -0
- package/build/types/path.d.ts +16 -0
- package/build/types/qss.d.ts +2 -0
- package/build/types/route.d.ts +261 -0
- package/build/types/routeInfo.d.ts +22 -0
- package/build/types/router.d.ts +265 -0
- package/build/types/scroll-restoration.d.ts +6 -0
- package/build/types/searchParams.d.ts +5 -0
- package/build/types/utils.d.ts +51 -0
- package/build/umd/index.development.js +1917 -2070
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +23 -2
- package/build/umd/index.production.js.map +1 -1
- package/package.json +13 -7
- package/src/defer.ts +55 -0
- package/src/fileRoute.ts +156 -0
- package/src/index.ts +5 -11
- package/src/link.ts +149 -123
- package/src/path.ts +37 -17
- package/src/qss.ts +1 -1
- package/src/route.ts +861 -231
- package/src/routeInfo.ts +47 -205
- package/src/router.ts +1818 -952
- package/src/scroll-restoration.ts +179 -0
- package/src/searchParams.ts +31 -9
- package/src/utils.ts +106 -43
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -33
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
- package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -33
- package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js.map +0 -1
- package/build/cjs/node_modules/history/index.js +0 -815
- package/build/cjs/node_modules/history/index.js.map +0 -1
- package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +0 -30
- package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +0 -1
- package/build/cjs/packages/router-core/src/index.js +0 -58
- package/build/cjs/packages/router-core/src/path.js.map +0 -1
- package/build/cjs/packages/router-core/src/qss.js.map +0 -1
- package/build/cjs/packages/router-core/src/route.js +0 -161
- package/build/cjs/packages/router-core/src/route.js.map +0 -1
- package/build/cjs/packages/router-core/src/routeConfig.js +0 -69
- package/build/cjs/packages/router-core/src/routeConfig.js.map +0 -1
- package/build/cjs/packages/router-core/src/routeMatch.js +0 -266
- package/build/cjs/packages/router-core/src/routeMatch.js.map +0 -1
- package/build/cjs/packages/router-core/src/router.js +0 -789
- package/build/cjs/packages/router-core/src/router.js.map +0 -1
- package/build/cjs/packages/router-core/src/searchParams.js.map +0 -1
- package/build/cjs/packages/router-core/src/utils.js +0 -118
- package/build/cjs/packages/router-core/src/utils.js.map +0 -1
- package/src/frameworks.ts +0 -12
- package/src/routeConfig.ts +0 -495
- package/src/routeMatch.ts +0 -374
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* router-core
|
|
2
|
+
* @tanstack/router-core/src/index.ts
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) TanStack
|
|
5
5
|
*
|
|
@@ -14,921 +14,423 @@
|
|
|
14
14
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.RouterCore = {}));
|
|
15
15
|
})(this, (function (exports) { 'use strict';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return target;
|
|
30
|
-
};
|
|
31
|
-
return _extends$1.apply(this, arguments);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Actions represent the type of change to a location value.
|
|
36
|
-
*
|
|
37
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#action
|
|
38
|
-
*/
|
|
39
|
-
var Action;
|
|
40
|
-
|
|
41
|
-
(function (Action) {
|
|
42
|
-
/**
|
|
43
|
-
* A POP indicates a change to an arbitrary index in the history stack, such
|
|
44
|
-
* as a back or forward navigation. It does not describe the direction of the
|
|
45
|
-
* navigation, only that the current index changed.
|
|
46
|
-
*
|
|
47
|
-
* Note: This is the default action for newly created history objects.
|
|
48
|
-
*/
|
|
49
|
-
Action["Pop"] = "POP";
|
|
50
|
-
/**
|
|
51
|
-
* A PUSH indicates a new entry being added to the history stack, such as when
|
|
52
|
-
* a link is clicked and a new page loads. When this happens, all subsequent
|
|
53
|
-
* entries in the stack are lost.
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
Action["Push"] = "PUSH";
|
|
57
|
-
/**
|
|
58
|
-
* A REPLACE indicates the entry at the current index in the history stack
|
|
59
|
-
* being replaced by a new one.
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
Action["Replace"] = "REPLACE";
|
|
63
|
-
})(Action || (Action = {}));
|
|
64
|
-
|
|
65
|
-
var readOnly = function (obj) {
|
|
66
|
-
return Object.freeze(obj);
|
|
67
|
-
} ;
|
|
68
|
-
|
|
69
|
-
function warning$1(cond, message) {
|
|
70
|
-
if (!cond) {
|
|
71
|
-
// eslint-disable-next-line no-console
|
|
72
|
-
if (typeof console !== 'undefined') console.warn(message);
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
// Welcome to debugging history!
|
|
76
|
-
//
|
|
77
|
-
// This error is thrown as a convenience so you can more easily
|
|
78
|
-
// find the source for a warning that appears in the console by
|
|
79
|
-
// enabling "pause on exceptions" in your JavaScript debugger.
|
|
80
|
-
throw new Error(message); // eslint-disable-next-line no-empty
|
|
81
|
-
} catch (e) {}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
var BeforeUnloadEventType = 'beforeunload';
|
|
86
|
-
var HashChangeEventType = 'hashchange';
|
|
87
|
-
var PopStateEventType = 'popstate';
|
|
88
|
-
/**
|
|
89
|
-
* Browser history stores the location in regular URLs. This is the standard for
|
|
90
|
-
* most web apps, but it requires some configuration on the server to ensure you
|
|
91
|
-
* serve the same app at multiple URLs.
|
|
92
|
-
*
|
|
93
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createbrowserhistory
|
|
17
|
+
/**
|
|
18
|
+
* @tanstack/history/src/index.ts
|
|
19
|
+
*
|
|
20
|
+
* Copyright (c) TanStack
|
|
21
|
+
*
|
|
22
|
+
* This source code is licensed under the MIT license found in the
|
|
23
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
24
|
+
*
|
|
25
|
+
* @license MIT
|
|
94
26
|
*/
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
var nextAction = Action.Pop;
|
|
129
|
-
|
|
130
|
-
var _getIndexAndLocation = getIndexAndLocation(),
|
|
131
|
-
nextIndex = _getIndexAndLocation[0],
|
|
132
|
-
nextLocation = _getIndexAndLocation[1];
|
|
133
|
-
|
|
134
|
-
if (blockers.length) {
|
|
135
|
-
if (nextIndex != null) {
|
|
136
|
-
var delta = index - nextIndex;
|
|
137
|
-
|
|
138
|
-
if (delta) {
|
|
139
|
-
// Revert the POP
|
|
140
|
-
blockedPopTx = {
|
|
141
|
-
action: nextAction,
|
|
142
|
-
location: nextLocation,
|
|
143
|
-
retry: function retry() {
|
|
144
|
-
go(delta * -1);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
go(delta);
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
// Trying to POP to a location with no index. We did not create
|
|
151
|
-
// this location, so we can't effectively block the navigation.
|
|
152
|
-
warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
|
|
153
|
-
// detail and link to it here so people can understand better what
|
|
154
|
-
// is going on and how to avoid it.
|
|
155
|
-
"You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation.") ;
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
applyTx(nextAction);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
window.addEventListener(PopStateEventType, handlePop);
|
|
164
|
-
var action = Action.Pop;
|
|
165
|
-
|
|
166
|
-
var _getIndexAndLocation2 = getIndexAndLocation(),
|
|
167
|
-
index = _getIndexAndLocation2[0],
|
|
168
|
-
location = _getIndexAndLocation2[1];
|
|
169
|
-
|
|
170
|
-
var listeners = createEvents();
|
|
171
|
-
var blockers = createEvents();
|
|
172
|
-
|
|
173
|
-
if (index == null) {
|
|
174
|
-
index = 0;
|
|
175
|
-
globalHistory.replaceState(_extends$1({}, globalHistory.state, {
|
|
176
|
-
idx: index
|
|
177
|
-
}), '');
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function createHref(to) {
|
|
181
|
-
return typeof to === 'string' ? to : createPath(to);
|
|
182
|
-
} // state defaults to `null` because `window.history.state` does
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
function getNextLocation(to, state) {
|
|
186
|
-
if (state === void 0) {
|
|
187
|
-
state = null;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return readOnly(_extends$1({
|
|
191
|
-
pathname: location.pathname,
|
|
192
|
-
hash: '',
|
|
193
|
-
search: ''
|
|
194
|
-
}, typeof to === 'string' ? parsePath(to) : to, {
|
|
195
|
-
state: state,
|
|
196
|
-
key: createKey()
|
|
197
|
-
}));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function getHistoryStateAndUrl(nextLocation, index) {
|
|
201
|
-
return [{
|
|
202
|
-
usr: nextLocation.state,
|
|
203
|
-
key: nextLocation.key,
|
|
204
|
-
idx: index
|
|
205
|
-
}, createHref(nextLocation)];
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function allowTx(action, location, retry) {
|
|
209
|
-
return !blockers.length || (blockers.call({
|
|
210
|
-
action: action,
|
|
211
|
-
location: location,
|
|
212
|
-
retry: retry
|
|
213
|
-
}), false);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function applyTx(nextAction) {
|
|
217
|
-
action = nextAction;
|
|
218
|
-
|
|
219
|
-
var _getIndexAndLocation3 = getIndexAndLocation();
|
|
220
|
-
|
|
221
|
-
index = _getIndexAndLocation3[0];
|
|
222
|
-
location = _getIndexAndLocation3[1];
|
|
223
|
-
listeners.call({
|
|
224
|
-
action: action,
|
|
225
|
-
location: location
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function push(to, state) {
|
|
230
|
-
var nextAction = Action.Push;
|
|
231
|
-
var nextLocation = getNextLocation(to, state);
|
|
232
|
-
|
|
233
|
-
function retry() {
|
|
234
|
-
push(to, state);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
238
|
-
var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1),
|
|
239
|
-
historyState = _getHistoryStateAndUr[0],
|
|
240
|
-
url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading
|
|
241
|
-
// try...catch because iOS limits us to 100 pushState calls :/
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
try {
|
|
245
|
-
globalHistory.pushState(historyState, '', url);
|
|
246
|
-
} catch (error) {
|
|
247
|
-
// They are going to lose state here, but there is no real
|
|
248
|
-
// way to warn them about it since the page will refresh...
|
|
249
|
-
window.location.assign(url);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
applyTx(nextAction);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function replace(to, state) {
|
|
257
|
-
var nextAction = Action.Replace;
|
|
258
|
-
var nextLocation = getNextLocation(to, state);
|
|
259
|
-
|
|
260
|
-
function retry() {
|
|
261
|
-
replace(to, state);
|
|
27
|
+
// While the public API was clearly inspired by the "history" npm package,
|
|
28
|
+
// This implementation attempts to be more lightweight by
|
|
29
|
+
// making assumptions about the way TanStack Router works
|
|
30
|
+
|
|
31
|
+
const pushStateEvent = 'pushstate';
|
|
32
|
+
const popStateEvent = 'popstate';
|
|
33
|
+
const beforeUnloadEvent = 'beforeunload';
|
|
34
|
+
const beforeUnloadListener = event => {
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
return event.returnValue = '';
|
|
38
|
+
};
|
|
39
|
+
const stopBlocking = () => {
|
|
40
|
+
removeEventListener(beforeUnloadEvent, beforeUnloadListener, {
|
|
41
|
+
capture: true
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
function createHistory(opts) {
|
|
45
|
+
let location = opts.getLocation();
|
|
46
|
+
let subscribers = new Set();
|
|
47
|
+
let blockers = [];
|
|
48
|
+
let queue = [];
|
|
49
|
+
const onUpdate = () => {
|
|
50
|
+
location = opts.getLocation();
|
|
51
|
+
subscribers.forEach(subscriber => subscriber());
|
|
52
|
+
};
|
|
53
|
+
const tryUnblock = () => {
|
|
54
|
+
if (blockers.length) {
|
|
55
|
+
blockers[0]?.(tryUnblock, () => {
|
|
56
|
+
blockers = [];
|
|
57
|
+
stopBlocking();
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
262
60
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index),
|
|
266
|
-
historyState = _getHistoryStateAndUr2[0],
|
|
267
|
-
url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
globalHistory.replaceState(historyState, '', url);
|
|
271
|
-
applyTx(nextAction);
|
|
61
|
+
while (queue.length) {
|
|
62
|
+
queue.shift()?.();
|
|
272
63
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
get action() {
|
|
281
|
-
return action;
|
|
282
|
-
},
|
|
283
|
-
|
|
64
|
+
onUpdate();
|
|
65
|
+
};
|
|
66
|
+
const queueTask = task => {
|
|
67
|
+
queue.push(task);
|
|
68
|
+
tryUnblock();
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
284
71
|
get location() {
|
|
285
72
|
return location;
|
|
286
73
|
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
74
|
+
subscribe: cb => {
|
|
75
|
+
subscribers.add(cb);
|
|
76
|
+
return () => {
|
|
77
|
+
subscribers.delete(cb);
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
push: (path, state) => {
|
|
81
|
+
state = assignKey(state);
|
|
82
|
+
queueTask(() => {
|
|
83
|
+
opts.pushState(path, state, onUpdate);
|
|
84
|
+
});
|
|
294
85
|
},
|
|
295
|
-
|
|
296
|
-
|
|
86
|
+
replace: (path, state) => {
|
|
87
|
+
state = assignKey(state);
|
|
88
|
+
queueTask(() => {
|
|
89
|
+
opts.replaceState(path, state, onUpdate);
|
|
90
|
+
});
|
|
297
91
|
},
|
|
298
|
-
|
|
299
|
-
|
|
92
|
+
go: index => {
|
|
93
|
+
queueTask(() => {
|
|
94
|
+
opts.go(index);
|
|
95
|
+
});
|
|
300
96
|
},
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
97
|
+
back: () => {
|
|
98
|
+
queueTask(() => {
|
|
99
|
+
opts.back();
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
forward: () => {
|
|
103
|
+
queueTask(() => {
|
|
104
|
+
opts.forward();
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
createHref: str => opts.createHref(str),
|
|
108
|
+
block: cb => {
|
|
109
|
+
blockers.push(cb);
|
|
304
110
|
if (blockers.length === 1) {
|
|
305
|
-
|
|
111
|
+
addEventListener(beforeUnloadEvent, beforeUnloadListener, {
|
|
112
|
+
capture: true
|
|
113
|
+
});
|
|
306
114
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
unblock(); // Remove the beforeunload listener so the document may
|
|
310
|
-
// still be salvageable in the pagehide event.
|
|
311
|
-
// See https://html.spec.whatwg.org/#unloading-documents
|
|
312
|
-
|
|
115
|
+
return () => {
|
|
116
|
+
blockers = blockers.filter(b => b !== cb);
|
|
313
117
|
if (!blockers.length) {
|
|
314
|
-
|
|
118
|
+
stopBlocking();
|
|
315
119
|
}
|
|
316
120
|
};
|
|
317
|
-
}
|
|
121
|
+
},
|
|
122
|
+
flush: () => opts.flush?.(),
|
|
123
|
+
destroy: () => opts.destroy?.(),
|
|
124
|
+
update: onUpdate
|
|
318
125
|
};
|
|
319
|
-
return history;
|
|
320
126
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
* some reason, either because you do cannot configure it or the URL space is
|
|
325
|
-
* reserved for something else.
|
|
326
|
-
*
|
|
327
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createhashhistory
|
|
328
|
-
*/
|
|
329
|
-
|
|
330
|
-
function createHashHistory(options) {
|
|
331
|
-
if (options === void 0) {
|
|
332
|
-
options = {};
|
|
127
|
+
function assignKey(state) {
|
|
128
|
+
if (!state) {
|
|
129
|
+
state = {};
|
|
333
130
|
}
|
|
131
|
+
state.key = createRandomKey();
|
|
132
|
+
return state;
|
|
133
|
+
}
|
|
334
134
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (delta) {
|
|
377
|
-
// Revert the POP
|
|
378
|
-
blockedPopTx = {
|
|
379
|
-
action: nextAction,
|
|
380
|
-
location: nextLocation,
|
|
381
|
-
retry: function retry() {
|
|
382
|
-
go(delta * -1);
|
|
383
|
-
}
|
|
384
|
-
};
|
|
385
|
-
go(delta);
|
|
386
|
-
}
|
|
387
|
-
} else {
|
|
388
|
-
// Trying to POP to a location with no index. We did not create
|
|
389
|
-
// this location, so we can't effectively block the navigation.
|
|
390
|
-
warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
|
|
391
|
-
// detail and link to it here so people can understand better
|
|
392
|
-
// what is going on and how to avoid it.
|
|
393
|
-
"You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation.") ;
|
|
394
|
-
}
|
|
395
|
-
} else {
|
|
396
|
-
applyTx(nextAction);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
135
|
+
/**
|
|
136
|
+
* Creates a history object that can be used to interact with the browser's
|
|
137
|
+
* navigation. This is a lightweight API wrapping the browser's native methods.
|
|
138
|
+
* It is designed to work with TanStack Router, but could be used as a standalone API as well.
|
|
139
|
+
* IMPORTANT: This API implements history throttling via a microtask to prevent
|
|
140
|
+
* excessive calls to the history API. In some browsers, calling history.pushState or
|
|
141
|
+
* history.replaceState in quick succession can cause the browser to ignore subsequent
|
|
142
|
+
* calls. This API smooths out those differences and ensures that your application
|
|
143
|
+
* state will *eventually* match the browser state. In most cases, this is not a problem,
|
|
144
|
+
* but if you need to ensure that the browser state is up to date, you can use the
|
|
145
|
+
* `history.flush` method to immediately flush all pending state changes to the browser URL.
|
|
146
|
+
* @param opts
|
|
147
|
+
* @param opts.getHref A function that returns the current href (path + search + hash)
|
|
148
|
+
* @param opts.createHref A function that takes a path and returns a href (path + search + hash)
|
|
149
|
+
* @returns A history instance
|
|
150
|
+
*/
|
|
151
|
+
function createBrowserHistory(opts) {
|
|
152
|
+
const getHref = opts?.getHref ?? (() => `${window.location.pathname}${window.location.search}${window.location.hash}`);
|
|
153
|
+
const createHref = opts?.createHref ?? (path => path);
|
|
154
|
+
let currentLocation = parseLocation(getHref(), window.history.state);
|
|
155
|
+
const getLocation = () => currentLocation;
|
|
156
|
+
let next;
|
|
157
|
+
|
|
158
|
+
// Because we are proactively updating the location
|
|
159
|
+
// in memory before actually updating the browser history,
|
|
160
|
+
// we need to track when we are doing this so we don't
|
|
161
|
+
// notify subscribers twice on the last update.
|
|
162
|
+
let tracking = true;
|
|
163
|
+
|
|
164
|
+
// We need to track the current scheduled update to prevent
|
|
165
|
+
// multiple updates from being scheduled at the same time.
|
|
166
|
+
let scheduled;
|
|
167
|
+
|
|
168
|
+
// This function is a wrapper to prevent any of the callback's
|
|
169
|
+
// side effects from causing a subscriber notification
|
|
170
|
+
const untrack = fn => {
|
|
171
|
+
tracking = false;
|
|
172
|
+
fn();
|
|
173
|
+
tracking = true;
|
|
174
|
+
};
|
|
400
175
|
|
|
401
|
-
|
|
402
|
-
|
|
176
|
+
// This function flushes the next update to the browser history
|
|
177
|
+
const flush = () => {
|
|
178
|
+
// Do not notify subscribers about this push/replace call
|
|
179
|
+
untrack(() => {
|
|
180
|
+
if (!next) return;
|
|
181
|
+
window.history[next.isPush ? 'pushState' : 'replaceState'](next.state, '', next.href);
|
|
182
|
+
// Reset the nextIsPush flag and clear the scheduled update
|
|
183
|
+
next = undefined;
|
|
184
|
+
scheduled = undefined;
|
|
185
|
+
});
|
|
186
|
+
};
|
|
403
187
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
188
|
+
// This function queues up a call to update the browser history
|
|
189
|
+
const queueHistoryAction = (type, path, state, onUpdate) => {
|
|
190
|
+
const href = createHref(path);
|
|
407
191
|
|
|
192
|
+
// Update the location in memory
|
|
193
|
+
currentLocation = parseLocation(href, state);
|
|
408
194
|
|
|
409
|
-
|
|
410
|
-
|
|
195
|
+
// Keep track of the next location we need to flush to the URL
|
|
196
|
+
next = {
|
|
197
|
+
href,
|
|
198
|
+
state,
|
|
199
|
+
isPush: next?.isPush || type === 'push'
|
|
200
|
+
};
|
|
201
|
+
// Notify subscribers
|
|
202
|
+
onUpdate();
|
|
203
|
+
if (!scheduled) {
|
|
204
|
+
// Schedule an update to the browser history
|
|
205
|
+
scheduled = Promise.resolve().then(() => flush());
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const onPushPop = () => {
|
|
209
|
+
currentLocation = parseLocation(getHref(), window.history.state);
|
|
210
|
+
history.update();
|
|
211
|
+
};
|
|
212
|
+
var originalPushState = window.history.pushState;
|
|
213
|
+
var originalReplaceState = window.history.replaceState;
|
|
214
|
+
const history = createHistory({
|
|
215
|
+
getLocation,
|
|
216
|
+
pushState: (path, state, onUpdate) => queueHistoryAction('push', path, state, onUpdate),
|
|
217
|
+
replaceState: (path, state, onUpdate) => queueHistoryAction('replace', path, state, onUpdate),
|
|
218
|
+
back: () => window.history.back(),
|
|
219
|
+
forward: () => window.history.forward(),
|
|
220
|
+
go: n => window.history.go(n),
|
|
221
|
+
createHref: path => createHref(path),
|
|
222
|
+
flush,
|
|
223
|
+
destroy: () => {
|
|
224
|
+
window.history.pushState = originalPushState;
|
|
225
|
+
window.history.replaceState = originalReplaceState;
|
|
226
|
+
window.removeEventListener(pushStateEvent, onPushPop);
|
|
227
|
+
window.removeEventListener(popStateEvent, onPushPop);
|
|
411
228
|
}
|
|
412
229
|
});
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
230
|
+
window.addEventListener(pushStateEvent, onPushPop);
|
|
231
|
+
window.addEventListener(popStateEvent, onPushPop);
|
|
232
|
+
window.history.pushState = function () {
|
|
233
|
+
let res = originalPushState.apply(window.history, arguments);
|
|
234
|
+
if (tracking) history.update();
|
|
235
|
+
return res;
|
|
236
|
+
};
|
|
237
|
+
window.history.replaceState = function () {
|
|
238
|
+
let res = originalReplaceState.apply(window.history, arguments);
|
|
239
|
+
if (tracking) history.update();
|
|
240
|
+
return res;
|
|
241
|
+
};
|
|
242
|
+
return history;
|
|
243
|
+
}
|
|
244
|
+
function createHashHistory() {
|
|
245
|
+
return createBrowserHistory({
|
|
246
|
+
getHref: () => window.location.hash.substring(1),
|
|
247
|
+
createHref: path => `#${path}`
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function createMemoryHistory(opts = {
|
|
251
|
+
initialEntries: ['/']
|
|
252
|
+
}) {
|
|
253
|
+
const entries = opts.initialEntries;
|
|
254
|
+
let index = opts.initialIndex ?? entries.length - 1;
|
|
255
|
+
let currentState = {
|
|
256
|
+
key: createRandomKey()
|
|
257
|
+
};
|
|
258
|
+
const getLocation = () => parseLocation(entries[index], currentState);
|
|
259
|
+
return createHistory({
|
|
260
|
+
getLocation,
|
|
261
|
+
pushState: (path, state) => {
|
|
262
|
+
currentState = state;
|
|
263
|
+
entries.push(path);
|
|
264
|
+
index++;
|
|
265
|
+
},
|
|
266
|
+
replaceState: (path, state) => {
|
|
267
|
+
currentState = state;
|
|
268
|
+
entries[index] = path;
|
|
269
|
+
},
|
|
270
|
+
back: () => {
|
|
271
|
+
index--;
|
|
272
|
+
},
|
|
273
|
+
forward: () => {
|
|
274
|
+
index = Math.min(index + 1, entries.length - 1);
|
|
275
|
+
},
|
|
276
|
+
go: n => window.history.go(n),
|
|
277
|
+
createHref: path => path
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function parseLocation(href, state) {
|
|
281
|
+
let hashIndex = href.indexOf('#');
|
|
282
|
+
let searchIndex = href.indexOf('?');
|
|
283
|
+
return {
|
|
284
|
+
href,
|
|
285
|
+
pathname: href.substring(0, hashIndex > 0 ? searchIndex > 0 ? Math.min(hashIndex, searchIndex) : hashIndex : searchIndex > 0 ? searchIndex : href.length),
|
|
286
|
+
hash: hashIndex > -1 ? href.substring(hashIndex) : '',
|
|
287
|
+
search: searchIndex > -1 ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex) : '',
|
|
288
|
+
state: state || {}
|
|
289
|
+
};
|
|
290
|
+
}
|
|
428
291
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
292
|
+
// Thanks co-pilot!
|
|
293
|
+
function createRandomKey() {
|
|
294
|
+
return (Math.random() + 1).toString(36).substring(7);
|
|
295
|
+
}
|
|
432
296
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
297
|
+
var prefix = 'Invariant failed';
|
|
298
|
+
function invariant(condition, message) {
|
|
299
|
+
if (condition) {
|
|
300
|
+
return;
|
|
437
301
|
}
|
|
302
|
+
var provided = typeof message === 'function' ? message() : message;
|
|
303
|
+
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
304
|
+
throw new Error(value);
|
|
305
|
+
}
|
|
438
306
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
return getBaseHref() + '#' + (typeof to === 'string' ? to : createPath(to));
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function getNextLocation(to, state) {
|
|
447
|
-
if (state === void 0) {
|
|
448
|
-
state = null;
|
|
307
|
+
function warning(condition, message) {
|
|
308
|
+
{
|
|
309
|
+
if (condition) {
|
|
310
|
+
return;
|
|
449
311
|
}
|
|
450
312
|
|
|
451
|
-
|
|
452
|
-
pathname: location.pathname,
|
|
453
|
-
hash: '',
|
|
454
|
-
search: ''
|
|
455
|
-
}, typeof to === 'string' ? parsePath(to) : to, {
|
|
456
|
-
state: state,
|
|
457
|
-
key: createKey()
|
|
458
|
-
}));
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
function getHistoryStateAndUrl(nextLocation, index) {
|
|
462
|
-
return [{
|
|
463
|
-
usr: nextLocation.state,
|
|
464
|
-
key: nextLocation.key,
|
|
465
|
-
idx: index
|
|
466
|
-
}, createHref(nextLocation)];
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
function allowTx(action, location, retry) {
|
|
470
|
-
return !blockers.length || (blockers.call({
|
|
471
|
-
action: action,
|
|
472
|
-
location: location,
|
|
473
|
-
retry: retry
|
|
474
|
-
}), false);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function applyTx(nextAction) {
|
|
478
|
-
action = nextAction;
|
|
313
|
+
var text = "Warning: " + message;
|
|
479
314
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
index = _getIndexAndLocation7[0];
|
|
483
|
-
location = _getIndexAndLocation7[1];
|
|
484
|
-
listeners.call({
|
|
485
|
-
action: action,
|
|
486
|
-
location: location
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
function push(to, state) {
|
|
491
|
-
var nextAction = Action.Push;
|
|
492
|
-
var nextLocation = getNextLocation(to, state);
|
|
493
|
-
|
|
494
|
-
function retry() {
|
|
495
|
-
push(to, state);
|
|
315
|
+
if (typeof console !== 'undefined') {
|
|
316
|
+
console.warn(text);
|
|
496
317
|
}
|
|
497
318
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1),
|
|
502
|
-
historyState = _getHistoryStateAndUr3[0],
|
|
503
|
-
url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading
|
|
504
|
-
// try...catch because iOS limits us to 100 pushState calls :/
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
try {
|
|
508
|
-
globalHistory.pushState(historyState, '', url);
|
|
509
|
-
} catch (error) {
|
|
510
|
-
// They are going to lose state here, but there is no real
|
|
511
|
-
// way to warn them about it since the page will refresh...
|
|
512
|
-
window.location.assign(url);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
applyTx(nextAction);
|
|
516
|
-
}
|
|
319
|
+
try {
|
|
320
|
+
throw Error(text);
|
|
321
|
+
} catch (x) {}
|
|
517
322
|
}
|
|
323
|
+
}
|
|
518
324
|
|
|
519
|
-
|
|
520
|
-
var nextAction = Action.Replace;
|
|
521
|
-
var nextLocation = getNextLocation(to, state);
|
|
522
|
-
|
|
523
|
-
function retry() {
|
|
524
|
-
replace(to, state);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.replace(" + JSON.stringify(to) + ")") ;
|
|
325
|
+
// export type Expand<T> = T
|
|
528
326
|
|
|
529
|
-
|
|
530
|
-
var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index),
|
|
531
|
-
historyState = _getHistoryStateAndUr4[0],
|
|
532
|
-
url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading
|
|
327
|
+
// type Compute<T> = { [K in keyof T]: T[K] } | never
|
|
533
328
|
|
|
329
|
+
// type AllKeys<T> = T extends any ? keyof T : never
|
|
534
330
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
331
|
+
// export type MergeUnion<T, Keys extends keyof T = keyof T> = Compute<
|
|
332
|
+
// {
|
|
333
|
+
// [K in Keys]: T[Keys]
|
|
334
|
+
// } & {
|
|
335
|
+
// [K in AllKeys<T>]?: T extends any
|
|
336
|
+
// ? K extends keyof T
|
|
337
|
+
// ? T[K]
|
|
338
|
+
// : never
|
|
339
|
+
// : never
|
|
340
|
+
// }
|
|
341
|
+
// >
|
|
342
|
+
function last(arr) {
|
|
343
|
+
return arr[arr.length - 1];
|
|
344
|
+
}
|
|
345
|
+
function isFunction(d) {
|
|
346
|
+
return typeof d === 'function';
|
|
347
|
+
}
|
|
348
|
+
function functionalUpdate(updater, previous) {
|
|
349
|
+
if (isFunction(updater)) {
|
|
350
|
+
return updater(previous);
|
|
538
351
|
}
|
|
352
|
+
return updater;
|
|
353
|
+
}
|
|
354
|
+
function pick(parent, keys) {
|
|
355
|
+
return keys.reduce((obj, key) => {
|
|
356
|
+
obj[key] = parent[key];
|
|
357
|
+
return obj;
|
|
358
|
+
}, {});
|
|
359
|
+
}
|
|
539
360
|
|
|
540
|
-
|
|
541
|
-
|
|
361
|
+
/**
|
|
362
|
+
* This function returns `a` if `b` is deeply equal.
|
|
363
|
+
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
|
364
|
+
* This can be used for structural sharing between immutable JSON values for example.
|
|
365
|
+
* Do not use this with signals
|
|
366
|
+
*/
|
|
367
|
+
function replaceEqualDeep(prev, _next) {
|
|
368
|
+
if (prev === _next) {
|
|
369
|
+
return prev;
|
|
542
370
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
go: go,
|
|
557
|
-
back: function back() {
|
|
558
|
-
go(-1);
|
|
559
|
-
},
|
|
560
|
-
forward: function forward() {
|
|
561
|
-
go(1);
|
|
562
|
-
},
|
|
563
|
-
listen: function listen(listener) {
|
|
564
|
-
return listeners.push(listener);
|
|
565
|
-
},
|
|
566
|
-
block: function block(blocker) {
|
|
567
|
-
var unblock = blockers.push(blocker);
|
|
568
|
-
|
|
569
|
-
if (blockers.length === 1) {
|
|
570
|
-
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
|
|
371
|
+
const next = _next;
|
|
372
|
+
const array = Array.isArray(prev) && Array.isArray(next);
|
|
373
|
+
if (array || isPlainObject(prev) && isPlainObject(next)) {
|
|
374
|
+
const prevSize = array ? prev.length : Object.keys(prev).length;
|
|
375
|
+
const nextItems = array ? next : Object.keys(next);
|
|
376
|
+
const nextSize = nextItems.length;
|
|
377
|
+
const copy = array ? [] : {};
|
|
378
|
+
let equalItems = 0;
|
|
379
|
+
for (let i = 0; i < nextSize; i++) {
|
|
380
|
+
const key = array ? i : nextItems[i];
|
|
381
|
+
copy[key] = replaceEqualDeep(prev[key], next[key]);
|
|
382
|
+
if (copy[key] === prev[key]) {
|
|
383
|
+
equalItems++;
|
|
571
384
|
}
|
|
572
|
-
|
|
573
|
-
return function () {
|
|
574
|
-
unblock(); // Remove the beforeunload listener so the document may
|
|
575
|
-
// still be salvageable in the pagehide event.
|
|
576
|
-
// See https://html.spec.whatwg.org/#unloading-documents
|
|
577
|
-
|
|
578
|
-
if (!blockers.length) {
|
|
579
|
-
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
385
|
}
|
|
583
|
-
|
|
584
|
-
|
|
386
|
+
return prevSize === nextSize && equalItems === prevSize ? prev : copy;
|
|
387
|
+
}
|
|
388
|
+
return next;
|
|
585
389
|
}
|
|
586
|
-
/**
|
|
587
|
-
* Memory history stores the current location in memory. It is designed for use
|
|
588
|
-
* in stateful non-browser environments like tests and React Native.
|
|
589
|
-
*
|
|
590
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#creatememoryhistory
|
|
591
|
-
*/
|
|
592
390
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
391
|
+
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
|
392
|
+
function isPlainObject(o) {
|
|
393
|
+
if (!hasObjectPrototype(o)) {
|
|
394
|
+
return false;
|
|
596
395
|
}
|
|
597
396
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
var entries = initialEntries.map(function (entry) {
|
|
603
|
-
var location = readOnly(_extends$1({
|
|
604
|
-
pathname: '/',
|
|
605
|
-
search: '',
|
|
606
|
-
hash: '',
|
|
607
|
-
state: null,
|
|
608
|
-
key: createKey()
|
|
609
|
-
}, typeof entry === 'string' ? parsePath(entry) : entry));
|
|
610
|
-
warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + JSON.stringify(entry) + ")") ;
|
|
611
|
-
return location;
|
|
612
|
-
});
|
|
613
|
-
var index = clamp(initialIndex == null ? entries.length - 1 : initialIndex, 0, entries.length - 1);
|
|
614
|
-
var action = Action.Pop;
|
|
615
|
-
var location = entries[index];
|
|
616
|
-
var listeners = createEvents();
|
|
617
|
-
var blockers = createEvents();
|
|
618
|
-
|
|
619
|
-
function createHref(to) {
|
|
620
|
-
return typeof to === 'string' ? to : createPath(to);
|
|
397
|
+
// If has modified constructor
|
|
398
|
+
const ctor = o.constructor;
|
|
399
|
+
if (typeof ctor === 'undefined') {
|
|
400
|
+
return true;
|
|
621
401
|
}
|
|
622
402
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
return readOnly(_extends$1({
|
|
629
|
-
pathname: location.pathname,
|
|
630
|
-
search: '',
|
|
631
|
-
hash: ''
|
|
632
|
-
}, typeof to === 'string' ? parsePath(to) : to, {
|
|
633
|
-
state: state,
|
|
634
|
-
key: createKey()
|
|
635
|
-
}));
|
|
403
|
+
// If has modified prototype
|
|
404
|
+
const prot = ctor.prototype;
|
|
405
|
+
if (!hasObjectPrototype(prot)) {
|
|
406
|
+
return false;
|
|
636
407
|
}
|
|
637
408
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
location: location,
|
|
642
|
-
retry: retry
|
|
643
|
-
}), false);
|
|
409
|
+
// If constructor does not have an Object-specific method
|
|
410
|
+
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
|
411
|
+
return false;
|
|
644
412
|
}
|
|
645
413
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
414
|
+
// Most likely a plain Object
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
function hasObjectPrototype(o) {
|
|
418
|
+
return Object.prototype.toString.call(o) === '[object Object]';
|
|
419
|
+
}
|
|
420
|
+
function partialDeepEqual(a, b) {
|
|
421
|
+
if (a === b) {
|
|
422
|
+
return true;
|
|
653
423
|
}
|
|
654
|
-
|
|
655
|
-
function push(to, state) {
|
|
656
|
-
var nextAction = Action.Push;
|
|
657
|
-
var nextLocation = getNextLocation(to, state);
|
|
658
|
-
|
|
659
|
-
function retry() {
|
|
660
|
-
push(to, state);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.push(" + JSON.stringify(to) + ")") ;
|
|
664
|
-
|
|
665
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
666
|
-
index += 1;
|
|
667
|
-
entries.splice(index, entries.length, nextLocation);
|
|
668
|
-
applyTx(nextAction, nextLocation);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
function replace(to, state) {
|
|
673
|
-
var nextAction = Action.Replace;
|
|
674
|
-
var nextLocation = getNextLocation(to, state);
|
|
675
|
-
|
|
676
|
-
function retry() {
|
|
677
|
-
replace(to, state);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.replace(" + JSON.stringify(to) + ")") ;
|
|
681
|
-
|
|
682
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
683
|
-
entries[index] = nextLocation;
|
|
684
|
-
applyTx(nextAction, nextLocation);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
function go(delta) {
|
|
689
|
-
var nextIndex = clamp(index + delta, 0, entries.length - 1);
|
|
690
|
-
var nextAction = Action.Pop;
|
|
691
|
-
var nextLocation = entries[nextIndex];
|
|
692
|
-
|
|
693
|
-
function retry() {
|
|
694
|
-
go(delta);
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
698
|
-
index = nextIndex;
|
|
699
|
-
applyTx(nextAction, nextLocation);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
var history = {
|
|
704
|
-
get index() {
|
|
705
|
-
return index;
|
|
706
|
-
},
|
|
707
|
-
|
|
708
|
-
get action() {
|
|
709
|
-
return action;
|
|
710
|
-
},
|
|
711
|
-
|
|
712
|
-
get location() {
|
|
713
|
-
return location;
|
|
714
|
-
},
|
|
715
|
-
|
|
716
|
-
createHref: createHref,
|
|
717
|
-
push: push,
|
|
718
|
-
replace: replace,
|
|
719
|
-
go: go,
|
|
720
|
-
back: function back() {
|
|
721
|
-
go(-1);
|
|
722
|
-
},
|
|
723
|
-
forward: function forward() {
|
|
724
|
-
go(1);
|
|
725
|
-
},
|
|
726
|
-
listen: function listen(listener) {
|
|
727
|
-
return listeners.push(listener);
|
|
728
|
-
},
|
|
729
|
-
block: function block(blocker) {
|
|
730
|
-
return blockers.push(blocker);
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
return history;
|
|
734
|
-
} ////////////////////////////////////////////////////////////////////////////////
|
|
735
|
-
// UTILS
|
|
736
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
737
|
-
|
|
738
|
-
function clamp(n, lowerBound, upperBound) {
|
|
739
|
-
return Math.min(Math.max(n, lowerBound), upperBound);
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
function promptBeforeUnload(event) {
|
|
743
|
-
// Cancel the event.
|
|
744
|
-
event.preventDefault(); // Chrome (and legacy IE) requires returnValue to be set.
|
|
745
|
-
|
|
746
|
-
event.returnValue = '';
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
function createEvents() {
|
|
750
|
-
var handlers = [];
|
|
751
|
-
return {
|
|
752
|
-
get length() {
|
|
753
|
-
return handlers.length;
|
|
754
|
-
},
|
|
755
|
-
|
|
756
|
-
push: function push(fn) {
|
|
757
|
-
handlers.push(fn);
|
|
758
|
-
return function () {
|
|
759
|
-
handlers = handlers.filter(function (handler) {
|
|
760
|
-
return handler !== fn;
|
|
761
|
-
});
|
|
762
|
-
};
|
|
763
|
-
},
|
|
764
|
-
call: function call(arg) {
|
|
765
|
-
handlers.forEach(function (fn) {
|
|
766
|
-
return fn && fn(arg);
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
function createKey() {
|
|
773
|
-
return Math.random().toString(36).substr(2, 8);
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Creates a string URL path from the given pathname, search, and hash components.
|
|
777
|
-
*
|
|
778
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createpath
|
|
779
|
-
*/
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
function createPath(_ref) {
|
|
783
|
-
var _ref$pathname = _ref.pathname,
|
|
784
|
-
pathname = _ref$pathname === void 0 ? '/' : _ref$pathname,
|
|
785
|
-
_ref$search = _ref.search,
|
|
786
|
-
search = _ref$search === void 0 ? '' : _ref$search,
|
|
787
|
-
_ref$hash = _ref.hash,
|
|
788
|
-
hash = _ref$hash === void 0 ? '' : _ref$hash;
|
|
789
|
-
if (search && search !== '?') pathname += search.charAt(0) === '?' ? search : '?' + search;
|
|
790
|
-
if (hash && hash !== '#') pathname += hash.charAt(0) === '#' ? hash : '#' + hash;
|
|
791
|
-
return pathname;
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Parses a string URL path into its separate pathname, search, and hash components.
|
|
795
|
-
*
|
|
796
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#parsepath
|
|
797
|
-
*/
|
|
798
|
-
|
|
799
|
-
function parsePath(path) {
|
|
800
|
-
var parsedPath = {};
|
|
801
|
-
|
|
802
|
-
if (path) {
|
|
803
|
-
var hashIndex = path.indexOf('#');
|
|
804
|
-
|
|
805
|
-
if (hashIndex >= 0) {
|
|
806
|
-
parsedPath.hash = path.substr(hashIndex);
|
|
807
|
-
path = path.substr(0, hashIndex);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
var searchIndex = path.indexOf('?');
|
|
811
|
-
|
|
812
|
-
if (searchIndex >= 0) {
|
|
813
|
-
parsedPath.search = path.substr(searchIndex);
|
|
814
|
-
path = path.substr(0, searchIndex);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
if (path) {
|
|
818
|
-
parsedPath.pathname = path;
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
return parsedPath;
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
var prefix = 'Invariant failed';
|
|
826
|
-
function invariant(condition, message) {
|
|
827
|
-
if (condition) {
|
|
828
|
-
return;
|
|
829
|
-
}
|
|
830
|
-
var provided = typeof message === 'function' ? message() : message;
|
|
831
|
-
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
832
|
-
throw new Error(value);
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
// type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
836
|
-
// k: infer I,
|
|
837
|
-
// ) => any
|
|
838
|
-
// ? I
|
|
839
|
-
// : never
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* This function returns `a` if `b` is deeply equal.
|
|
843
|
-
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
|
844
|
-
* This can be used for structural sharing between JSON values for example.
|
|
845
|
-
*/
|
|
846
|
-
function replaceEqualDeep(prev, next) {
|
|
847
|
-
if (prev === next) {
|
|
848
|
-
return prev;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
const array = Array.isArray(prev) && Array.isArray(next);
|
|
852
|
-
|
|
853
|
-
if (array || isPlainObject(prev) && isPlainObject(next)) {
|
|
854
|
-
const aSize = array ? prev.length : Object.keys(prev).length;
|
|
855
|
-
const bItems = array ? next : Object.keys(next);
|
|
856
|
-
const bSize = bItems.length;
|
|
857
|
-
const copy = array ? [] : {};
|
|
858
|
-
let equalItems = 0;
|
|
859
|
-
|
|
860
|
-
for (let i = 0; i < bSize; i++) {
|
|
861
|
-
const key = array ? i : bItems[i];
|
|
862
|
-
copy[key] = replaceEqualDeep(prev[key], next[key]);
|
|
863
|
-
|
|
864
|
-
if (copy[key] === prev[key]) {
|
|
865
|
-
equalItems++;
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
return aSize === bSize && equalItems === aSize ? prev : copy;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
return next;
|
|
873
|
-
} // Copied from: https://github.com/jonschlinkert/is-plain-object
|
|
874
|
-
|
|
875
|
-
function isPlainObject(o) {
|
|
876
|
-
if (!hasObjectPrototype(o)) {
|
|
877
|
-
return false;
|
|
878
|
-
} // If has modified constructor
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
const ctor = o.constructor;
|
|
882
|
-
|
|
883
|
-
if (typeof ctor === 'undefined') {
|
|
884
|
-
return true;
|
|
885
|
-
} // If has modified prototype
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
const prot = ctor.prototype;
|
|
889
|
-
|
|
890
|
-
if (!hasObjectPrototype(prot)) {
|
|
891
|
-
return false;
|
|
892
|
-
} // If constructor does not have an Object-specific method
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
|
424
|
+
if (typeof a !== typeof b) {
|
|
896
425
|
return false;
|
|
897
|
-
} // Most likely a plain Object
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
return true;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
function hasObjectPrototype(o) {
|
|
904
|
-
return Object.prototype.toString.call(o) === '[object Object]';
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
function last(arr) {
|
|
908
|
-
return arr[arr.length - 1];
|
|
909
|
-
}
|
|
910
|
-
function warning(cond, message) {
|
|
911
|
-
if (cond) {
|
|
912
|
-
if (typeof console !== 'undefined') console.warn(message);
|
|
913
|
-
|
|
914
|
-
try {
|
|
915
|
-
throw new Error(message);
|
|
916
|
-
} catch (_unused) {}
|
|
917
426
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
function isFunction(d) {
|
|
923
|
-
return typeof d === 'function';
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
function functionalUpdate(updater, previous) {
|
|
927
|
-
if (isFunction(updater)) {
|
|
928
|
-
return updater(previous);
|
|
427
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
428
|
+
return !Object.keys(b).some(key => !partialDeepEqual(a[key], b[key]));
|
|
929
429
|
}
|
|
930
|
-
|
|
931
|
-
|
|
430
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
431
|
+
return a.length === b.length && a.every((item, index) => partialDeepEqual(item, b[index]));
|
|
432
|
+
}
|
|
433
|
+
return false;
|
|
932
434
|
}
|
|
933
435
|
|
|
934
436
|
function joinPaths(paths) {
|
|
@@ -948,8 +450,8 @@
|
|
|
948
450
|
return trimPathRight(trimPathLeft(path));
|
|
949
451
|
}
|
|
950
452
|
function resolvePath(basepath, base, to) {
|
|
951
|
-
base = base.replace(new RegExp(
|
|
952
|
-
to = to.replace(new RegExp(
|
|
453
|
+
base = base.replace(new RegExp(`^${basepath}`), '/');
|
|
454
|
+
to = to.replace(new RegExp(`^${basepath}`), '/');
|
|
953
455
|
let baseSegments = parsePathname(base);
|
|
954
456
|
const toSegments = parsePathname(to);
|
|
955
457
|
toSegments.forEach((toSegment, index) => {
|
|
@@ -962,13 +464,10 @@
|
|
|
962
464
|
baseSegments.push(toSegment);
|
|
963
465
|
} else ;
|
|
964
466
|
} else if (toSegment.value === '..') {
|
|
965
|
-
var _last;
|
|
966
|
-
|
|
967
467
|
// Extra trailing slash? pop it off
|
|
968
|
-
if (baseSegments.length > 1 &&
|
|
468
|
+
if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
|
|
969
469
|
baseSegments.pop();
|
|
970
470
|
}
|
|
971
|
-
|
|
972
471
|
baseSegments.pop();
|
|
973
472
|
} else if (toSegment.value === '.') {
|
|
974
473
|
return;
|
|
@@ -983,10 +482,8 @@
|
|
|
983
482
|
if (!pathname) {
|
|
984
483
|
return [];
|
|
985
484
|
}
|
|
986
|
-
|
|
987
485
|
pathname = cleanPath(pathname);
|
|
988
486
|
const segments = [];
|
|
989
|
-
|
|
990
487
|
if (pathname.slice(0, 1) === '/') {
|
|
991
488
|
pathname = pathname.substring(1);
|
|
992
489
|
segments.push({
|
|
@@ -994,34 +491,30 @@
|
|
|
994
491
|
value: '/'
|
|
995
492
|
});
|
|
996
493
|
}
|
|
997
|
-
|
|
998
494
|
if (!pathname) {
|
|
999
495
|
return segments;
|
|
1000
|
-
}
|
|
1001
|
-
|
|
496
|
+
}
|
|
1002
497
|
|
|
498
|
+
// Remove empty segments and '.' segments
|
|
1003
499
|
const split = pathname.split('/').filter(Boolean);
|
|
1004
500
|
segments.push(...split.map(part => {
|
|
1005
|
-
if (part
|
|
501
|
+
if (part === '$' || part === '*') {
|
|
1006
502
|
return {
|
|
1007
503
|
type: 'wildcard',
|
|
1008
504
|
value: part
|
|
1009
505
|
};
|
|
1010
506
|
}
|
|
1011
|
-
|
|
1012
|
-
if (part.charAt(0) === ':') {
|
|
507
|
+
if (part.charAt(0) === '$') {
|
|
1013
508
|
return {
|
|
1014
509
|
type: 'param',
|
|
1015
510
|
value: part
|
|
1016
511
|
};
|
|
1017
512
|
}
|
|
1018
|
-
|
|
1019
513
|
return {
|
|
1020
514
|
type: 'pathname',
|
|
1021
515
|
value: part
|
|
1022
516
|
};
|
|
1023
517
|
}));
|
|
1024
|
-
|
|
1025
518
|
if (pathname.slice(-1) === '/') {
|
|
1026
519
|
pathname = pathname.substring(1);
|
|
1027
520
|
segments.push({
|
|
@@ -1029,66 +522,70 @@
|
|
|
1029
522
|
value: '/'
|
|
1030
523
|
});
|
|
1031
524
|
}
|
|
1032
|
-
|
|
1033
525
|
return segments;
|
|
1034
526
|
}
|
|
1035
|
-
function interpolatePath(path, params,
|
|
527
|
+
function interpolatePath(path, params, leaveWildcards = false) {
|
|
1036
528
|
const interpolatedPathSegments = parsePathname(path);
|
|
1037
529
|
return joinPaths(interpolatedPathSegments.map(segment => {
|
|
1038
|
-
if (segment.
|
|
1039
|
-
|
|
530
|
+
if (segment.type === 'wildcard') {
|
|
531
|
+
const value = params[segment.value];
|
|
532
|
+
if (leaveWildcards) return `${segment.value}${value ?? ''}`;
|
|
533
|
+
return value;
|
|
1040
534
|
}
|
|
1041
|
-
|
|
1042
535
|
if (segment.type === 'param') {
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
return (_segment$value$substr = params[segment.value.substring(1)]) != null ? _segment$value$substr : '';
|
|
536
|
+
return params[segment.value.substring(1)] ?? '';
|
|
1046
537
|
}
|
|
1047
|
-
|
|
1048
538
|
return segment.value;
|
|
1049
539
|
}));
|
|
1050
540
|
}
|
|
1051
|
-
function matchPathname(currentPathname, matchLocation) {
|
|
1052
|
-
const pathParams = matchByPath(currentPathname, matchLocation);
|
|
541
|
+
function matchPathname(basepath, currentPathname, matchLocation) {
|
|
542
|
+
const pathParams = matchByPath(basepath, currentPathname, matchLocation);
|
|
543
|
+
// const searchMatched = matchBySearch(location.search, matchLocation)
|
|
1053
544
|
|
|
1054
545
|
if (matchLocation.to && !pathParams) {
|
|
1055
546
|
return;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
// }
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
return pathParams != null ? pathParams : {};
|
|
547
|
+
}
|
|
548
|
+
return pathParams ?? {};
|
|
1062
549
|
}
|
|
1063
|
-
function matchByPath(from, matchLocation) {
|
|
1064
|
-
|
|
1065
|
-
|
|
550
|
+
function matchByPath(basepath, from, matchLocation) {
|
|
551
|
+
// Remove the base path from the pathname
|
|
552
|
+
from = basepath != '/' ? from.substring(basepath.length) : from;
|
|
553
|
+
// Default to to $ (wildcard)
|
|
554
|
+
const to = `${matchLocation.to ?? '$'}`;
|
|
555
|
+
// Parse the from and to
|
|
1066
556
|
const baseSegments = parsePathname(from);
|
|
1067
|
-
const routeSegments = parsePathname(
|
|
557
|
+
const routeSegments = parsePathname(to);
|
|
558
|
+
if (!from.startsWith('/')) {
|
|
559
|
+
baseSegments.unshift({
|
|
560
|
+
type: 'pathname',
|
|
561
|
+
value: '/'
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
if (!to.startsWith('/')) {
|
|
565
|
+
routeSegments.unshift({
|
|
566
|
+
type: 'pathname',
|
|
567
|
+
value: '/'
|
|
568
|
+
});
|
|
569
|
+
}
|
|
1068
570
|
const params = {};
|
|
1069
|
-
|
|
1070
571
|
let isMatch = (() => {
|
|
1071
572
|
for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
|
|
1072
573
|
const baseSegment = baseSegments[i];
|
|
1073
574
|
const routeSegment = routeSegments[i];
|
|
1074
|
-
const
|
|
1075
|
-
const
|
|
1076
|
-
|
|
575
|
+
const isLastBaseSegment = i >= baseSegments.length - 1;
|
|
576
|
+
const isLastRouteSegment = i >= routeSegments.length - 1;
|
|
1077
577
|
if (routeSegment) {
|
|
1078
578
|
if (routeSegment.type === 'wildcard') {
|
|
1079
|
-
if (baseSegment
|
|
579
|
+
if (baseSegment?.value) {
|
|
1080
580
|
params['*'] = joinPaths(baseSegments.slice(i).map(d => d.value));
|
|
1081
581
|
return true;
|
|
1082
582
|
}
|
|
1083
|
-
|
|
1084
583
|
return false;
|
|
1085
584
|
}
|
|
1086
|
-
|
|
1087
585
|
if (routeSegment.type === 'pathname') {
|
|
1088
|
-
if (routeSegment.value === '/' && !
|
|
586
|
+
if (routeSegment.value === '/' && !baseSegment?.value) {
|
|
1089
587
|
return true;
|
|
1090
588
|
}
|
|
1091
|
-
|
|
1092
589
|
if (baseSegment) {
|
|
1093
590
|
if (matchLocation.caseSensitive) {
|
|
1094
591
|
if (routeSegment.value !== baseSegment.value) {
|
|
@@ -1099,41 +596,36 @@
|
|
|
1099
596
|
}
|
|
1100
597
|
}
|
|
1101
598
|
}
|
|
1102
|
-
|
|
1103
599
|
if (!baseSegment) {
|
|
1104
600
|
return false;
|
|
1105
601
|
}
|
|
1106
|
-
|
|
1107
602
|
if (routeSegment.type === 'param') {
|
|
1108
|
-
if (
|
|
603
|
+
if (baseSegment?.value === '/') {
|
|
1109
604
|
return false;
|
|
1110
605
|
}
|
|
1111
|
-
|
|
1112
|
-
if (!baseSegment.value.startsWith(':')) {
|
|
606
|
+
if (baseSegment.value.charAt(0) !== '$') {
|
|
1113
607
|
params[routeSegment.value.substring(1)] = baseSegment.value;
|
|
1114
608
|
}
|
|
1115
609
|
}
|
|
1116
610
|
}
|
|
1117
|
-
|
|
1118
|
-
if (isLastRouteSegment && !isLastBaseSegment) {
|
|
611
|
+
if (!isLastBaseSegment && isLastRouteSegment) {
|
|
1119
612
|
return !!matchLocation.fuzzy;
|
|
1120
613
|
}
|
|
1121
614
|
}
|
|
1122
|
-
|
|
1123
615
|
return true;
|
|
1124
616
|
})();
|
|
1125
|
-
|
|
1126
617
|
return isMatch ? params : undefined;
|
|
1127
618
|
}
|
|
1128
619
|
|
|
1129
620
|
// @ts-nocheck
|
|
621
|
+
|
|
1130
622
|
// qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
|
|
623
|
+
|
|
1131
624
|
function encode(obj, pfx) {
|
|
1132
625
|
var k,
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
626
|
+
i,
|
|
627
|
+
tmp,
|
|
628
|
+
str = '';
|
|
1137
629
|
for (k in obj) {
|
|
1138
630
|
if ((tmp = obj[k]) !== void 0) {
|
|
1139
631
|
if (Array.isArray(tmp)) {
|
|
@@ -1147,1335 +639,1690 @@
|
|
|
1147
639
|
}
|
|
1148
640
|
}
|
|
1149
641
|
}
|
|
1150
|
-
|
|
1151
642
|
return (pfx || '') + str;
|
|
1152
643
|
}
|
|
1153
|
-
|
|
1154
644
|
function toValue(mix) {
|
|
1155
645
|
if (!mix) return '';
|
|
1156
646
|
var str = decodeURIComponent(mix);
|
|
1157
647
|
if (str === 'false') return false;
|
|
1158
648
|
if (str === 'true') return true;
|
|
1159
|
-
return +str * 0 === 0 ? +str : str;
|
|
649
|
+
return +str * 0 === 0 && +str + '' === str ? +str : str;
|
|
1160
650
|
}
|
|
1161
|
-
|
|
1162
651
|
function decode(str) {
|
|
1163
652
|
var tmp,
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
653
|
+
k,
|
|
654
|
+
out = {},
|
|
655
|
+
arr = str.split('&');
|
|
1168
656
|
while (tmp = arr.shift()) {
|
|
1169
657
|
tmp = tmp.split('=');
|
|
1170
658
|
k = tmp.shift();
|
|
1171
|
-
|
|
1172
659
|
if (out[k] !== void 0) {
|
|
1173
660
|
out[k] = [].concat(out[k], toValue(tmp.shift()));
|
|
1174
661
|
} else {
|
|
1175
662
|
out[k] = toValue(tmp.shift());
|
|
1176
663
|
}
|
|
1177
664
|
}
|
|
1178
|
-
|
|
1179
665
|
return out;
|
|
1180
666
|
}
|
|
1181
667
|
|
|
1182
|
-
|
|
1183
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
1184
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
1185
|
-
var source = arguments[i];
|
|
1186
|
-
|
|
1187
|
-
for (var key in source) {
|
|
1188
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1189
|
-
target[key] = source[key];
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
return target;
|
|
1195
|
-
};
|
|
1196
|
-
return _extends.apply(this, arguments);
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
function createRoute(routeConfig, options, parent, router) {
|
|
1200
|
-
const {
|
|
1201
|
-
id,
|
|
1202
|
-
routeId,
|
|
1203
|
-
path: routePath,
|
|
1204
|
-
fullPath
|
|
1205
|
-
} = routeConfig;
|
|
1206
|
-
|
|
1207
|
-
const action = router.state.actions[id] || (() => {
|
|
1208
|
-
router.state.actions[id] = {
|
|
1209
|
-
pending: [],
|
|
1210
|
-
submit: async (submission, actionOpts) => {
|
|
1211
|
-
var _actionOpts$invalidat;
|
|
1212
|
-
|
|
1213
|
-
if (!route) {
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
const invalidate = (_actionOpts$invalidat = actionOpts == null ? void 0 : actionOpts.invalidate) != null ? _actionOpts$invalidat : true;
|
|
1218
|
-
const actionState = {
|
|
1219
|
-
submittedAt: Date.now(),
|
|
1220
|
-
status: 'pending',
|
|
1221
|
-
submission
|
|
1222
|
-
};
|
|
1223
|
-
action.current = actionState;
|
|
1224
|
-
action.latest = actionState;
|
|
1225
|
-
action.pending.push(actionState);
|
|
1226
|
-
router.state = _extends({}, router.state, {
|
|
1227
|
-
currentAction: actionState,
|
|
1228
|
-
latestAction: actionState
|
|
1229
|
-
});
|
|
1230
|
-
router.notify();
|
|
1231
|
-
|
|
1232
|
-
try {
|
|
1233
|
-
const res = await (route.options.action == null ? void 0 : route.options.action(submission));
|
|
1234
|
-
actionState.data = res;
|
|
668
|
+
const rootRouteId = '__root__';
|
|
1235
669
|
|
|
1236
|
-
|
|
1237
|
-
router.invalidateRoute({
|
|
1238
|
-
to: '.',
|
|
1239
|
-
fromCurrent: true
|
|
1240
|
-
});
|
|
1241
|
-
await router.reload();
|
|
1242
|
-
}
|
|
670
|
+
// The parse type here allows a zod schema to be passed directly to the validator
|
|
1243
671
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
actionState.status = 'error';
|
|
1250
|
-
} finally {
|
|
1251
|
-
action.pending = action.pending.filter(d => d !== actionState);
|
|
1252
|
-
router.removeActionQueue.push({
|
|
1253
|
-
action,
|
|
1254
|
-
actionState
|
|
1255
|
-
});
|
|
1256
|
-
router.notify();
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
};
|
|
1260
|
-
return router.state.actions[id];
|
|
1261
|
-
})();
|
|
672
|
+
// T extends Record<PropertyKey, infer U>
|
|
673
|
+
// ? {
|
|
674
|
+
// [K in keyof T]: UseLoaderResultPromise<T[K]>
|
|
675
|
+
// }
|
|
676
|
+
// : UseLoaderResultPromise<T>
|
|
1262
677
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
return;
|
|
1269
|
-
}
|
|
678
|
+
// export type UseLoaderResultPromise<T> = T extends Promise<infer U>
|
|
679
|
+
// ? StreamedPromise<U>
|
|
680
|
+
// : T
|
|
681
|
+
class Route {
|
|
682
|
+
// Set up in this.init()
|
|
1270
683
|
|
|
1271
|
-
|
|
1272
|
-
loadedAt: Date.now(),
|
|
1273
|
-
loaderContext
|
|
1274
|
-
};
|
|
1275
|
-
loader.current = loaderState;
|
|
1276
|
-
loader.latest = loaderState;
|
|
1277
|
-
loader.pending.push(loaderState); // router.state = {
|
|
1278
|
-
// ...router.state,
|
|
1279
|
-
// currentAction: loaderState,
|
|
1280
|
-
// latestAction: loaderState,
|
|
1281
|
-
// }
|
|
684
|
+
// customId!: TCustomId
|
|
1282
685
|
|
|
1283
|
-
|
|
686
|
+
// Optional
|
|
1284
687
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
688
|
+
constructor(options) {
|
|
689
|
+
this.options = options || {};
|
|
690
|
+
this.isRoot = !options?.getParentRoute;
|
|
691
|
+
Route.__onInit(this);
|
|
692
|
+
}
|
|
693
|
+
init = opts => {
|
|
694
|
+
this.originalIndex = opts.originalIndex;
|
|
695
|
+
this.router = opts.router;
|
|
696
|
+
const options = this.options;
|
|
697
|
+
const isRoot = !options?.path && !options?.id;
|
|
698
|
+
this.parentRoute = this.options?.getParentRoute?.();
|
|
699
|
+
if (isRoot) {
|
|
700
|
+
this.path = rootRouteId;
|
|
701
|
+
} else {
|
|
702
|
+
invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
|
|
703
|
+
}
|
|
704
|
+
let path = isRoot ? rootRouteId : options.path;
|
|
1289
705
|
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
})();
|
|
706
|
+
// If the path is anything other than an index path, trim it up
|
|
707
|
+
if (path && path !== '/') {
|
|
708
|
+
path = trimPath(path);
|
|
709
|
+
}
|
|
710
|
+
const customId = options?.id || path;
|
|
1296
711
|
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
fullPath,
|
|
1302
|
-
options,
|
|
1303
|
-
router,
|
|
1304
|
-
childRoutes: undefined,
|
|
1305
|
-
parentRoute: parent,
|
|
1306
|
-
action,
|
|
1307
|
-
loader: loader,
|
|
1308
|
-
buildLink: options => {
|
|
1309
|
-
return router.buildLink(_extends({}, options, {
|
|
1310
|
-
from: fullPath
|
|
1311
|
-
}));
|
|
1312
|
-
},
|
|
1313
|
-
navigate: options => {
|
|
1314
|
-
return router.navigate(_extends({}, options, {
|
|
1315
|
-
from: fullPath
|
|
1316
|
-
}));
|
|
1317
|
-
},
|
|
1318
|
-
matchRoute: (matchLocation, opts) => {
|
|
1319
|
-
return router.matchRoute(_extends({}, matchLocation, {
|
|
1320
|
-
from: fullPath
|
|
1321
|
-
}), opts);
|
|
712
|
+
// Strip the parentId prefix from the first level of children
|
|
713
|
+
let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
|
|
714
|
+
if (path === rootRouteId) {
|
|
715
|
+
path = '/';
|
|
1322
716
|
}
|
|
717
|
+
if (id !== rootRouteId) {
|
|
718
|
+
id = joinPaths(['/', id]);
|
|
719
|
+
}
|
|
720
|
+
const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
|
|
721
|
+
this.path = path;
|
|
722
|
+
this.id = id;
|
|
723
|
+
// this.customId = customId as TCustomId
|
|
724
|
+
this.fullPath = fullPath;
|
|
725
|
+
this.to = fullPath;
|
|
726
|
+
};
|
|
727
|
+
addChildren = children => {
|
|
728
|
+
this.children = children;
|
|
729
|
+
return this;
|
|
730
|
+
};
|
|
731
|
+
update = options => {
|
|
732
|
+
Object.assign(this.options, options);
|
|
733
|
+
return this;
|
|
734
|
+
};
|
|
735
|
+
static __onInit = route => {
|
|
736
|
+
// This is a dummy static method that should get
|
|
737
|
+
// replaced by a framework specific implementation if necessary
|
|
1323
738
|
};
|
|
1324
|
-
router.options.createRoute == null ? void 0 : router.options.createRoute({
|
|
1325
|
-
router,
|
|
1326
|
-
route
|
|
1327
|
-
});
|
|
1328
|
-
return route;
|
|
1329
739
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
match.loaderData = replaceEqualDeep(match.loaderData, _extends({}, parent.loaderData, match.routeLoaderData));
|
|
1336
|
-
}
|
|
1337
|
-
});
|
|
740
|
+
class RouterContext {
|
|
741
|
+
constructor() {}
|
|
742
|
+
createRootRoute = options => {
|
|
743
|
+
return new RootRoute(options);
|
|
744
|
+
};
|
|
1338
745
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
if (options === void 0) {
|
|
1343
|
-
options = {};
|
|
746
|
+
class RootRoute extends Route {
|
|
747
|
+
constructor(options) {
|
|
748
|
+
super(options);
|
|
1344
749
|
}
|
|
750
|
+
}
|
|
751
|
+
function createRouteMask(opts) {
|
|
752
|
+
return opts;
|
|
753
|
+
}
|
|
1345
754
|
|
|
1346
|
-
|
|
1347
|
-
|
|
755
|
+
class FileRoute {
|
|
756
|
+
constructor(path) {
|
|
757
|
+
this.path = path;
|
|
1348
758
|
}
|
|
759
|
+
createRoute = options => {
|
|
760
|
+
const route = new Route(options);
|
|
761
|
+
route.isRoot = false;
|
|
762
|
+
return route;
|
|
763
|
+
};
|
|
764
|
+
}
|
|
1349
765
|
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
if (path === rootRouteId) {
|
|
1369
|
-
path = '/';
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
if (id !== rootRouteId) {
|
|
1373
|
-
id = joinPaths(['/', id]);
|
|
766
|
+
/**
|
|
767
|
+
* @tanstack/store/src/index.ts
|
|
768
|
+
*
|
|
769
|
+
* Copyright (c) TanStack
|
|
770
|
+
*
|
|
771
|
+
* This source code is licensed under the MIT license found in the
|
|
772
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
773
|
+
*
|
|
774
|
+
* @license MIT
|
|
775
|
+
*/
|
|
776
|
+
class Store {
|
|
777
|
+
listeners = new Set();
|
|
778
|
+
_batching = false;
|
|
779
|
+
_flushing = 0;
|
|
780
|
+
_nextPriority = null;
|
|
781
|
+
constructor(initialState, options) {
|
|
782
|
+
this.state = initialState;
|
|
783
|
+
this.options = options;
|
|
1374
784
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
options: options,
|
|
1383
|
-
children,
|
|
1384
|
-
createChildren: cb => createRouteConfig(options, cb(childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath)), false, parentId, parentPath),
|
|
1385
|
-
addChildren: children => createRouteConfig(options, children, false, parentId, parentPath),
|
|
1386
|
-
createRoute: childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath)
|
|
785
|
+
subscribe = listener => {
|
|
786
|
+
this.listeners.add(listener);
|
|
787
|
+
const unsub = this.options?.onSubscribe?.(listener, this);
|
|
788
|
+
return () => {
|
|
789
|
+
this.listeners.delete(listener);
|
|
790
|
+
unsub?.();
|
|
791
|
+
};
|
|
1387
792
|
};
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
routeLoaderData: {},
|
|
1399
|
-
loaderData: {},
|
|
1400
|
-
isPending: false,
|
|
1401
|
-
isFetching: false,
|
|
1402
|
-
isInvalid: false,
|
|
1403
|
-
invalidAt: Infinity,
|
|
1404
|
-
getIsInvalid: () => {
|
|
1405
|
-
const now = Date.now();
|
|
1406
|
-
return routeMatch.isInvalid || routeMatch.invalidAt < now;
|
|
1407
|
-
},
|
|
1408
|
-
__: {
|
|
1409
|
-
abortController: new AbortController(),
|
|
1410
|
-
latestId: '',
|
|
1411
|
-
resolve: () => {},
|
|
1412
|
-
notify: () => {
|
|
1413
|
-
routeMatch.__.resolve();
|
|
1414
|
-
|
|
1415
|
-
routeMatch.router.notify();
|
|
1416
|
-
},
|
|
1417
|
-
startPending: () => {
|
|
1418
|
-
var _routeMatch$options$p, _routeMatch$options$p2;
|
|
1419
|
-
|
|
1420
|
-
const pendingMs = (_routeMatch$options$p = routeMatch.options.pendingMs) != null ? _routeMatch$options$p : router.options.defaultPendingMs;
|
|
1421
|
-
const pendingMinMs = (_routeMatch$options$p2 = routeMatch.options.pendingMinMs) != null ? _routeMatch$options$p2 : router.options.defaultPendingMinMs;
|
|
1422
|
-
|
|
1423
|
-
if (routeMatch.__.pendingTimeout || routeMatch.status !== 'loading' || typeof pendingMs === 'undefined') {
|
|
1424
|
-
return;
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
routeMatch.__.pendingTimeout = setTimeout(() => {
|
|
1428
|
-
routeMatch.isPending = true;
|
|
1429
|
-
|
|
1430
|
-
routeMatch.__.resolve();
|
|
1431
|
-
|
|
1432
|
-
if (typeof pendingMinMs !== 'undefined') {
|
|
1433
|
-
routeMatch.__.pendingMinPromise = new Promise(r => routeMatch.__.pendingMinTimeout = setTimeout(r, pendingMinMs));
|
|
1434
|
-
}
|
|
1435
|
-
}, pendingMs);
|
|
1436
|
-
},
|
|
1437
|
-
cancelPending: () => {
|
|
1438
|
-
routeMatch.isPending = false;
|
|
1439
|
-
clearTimeout(routeMatch.__.pendingTimeout);
|
|
1440
|
-
clearTimeout(routeMatch.__.pendingMinTimeout);
|
|
1441
|
-
delete routeMatch.__.pendingMinPromise;
|
|
1442
|
-
},
|
|
1443
|
-
// setParentMatch: (parentMatch?: RouteMatch) => {
|
|
1444
|
-
// routeMatch.parentMatch = parentMatch
|
|
1445
|
-
// },
|
|
1446
|
-
// addChildMatch: (childMatch: RouteMatch) => {
|
|
1447
|
-
// if (
|
|
1448
|
-
// routeMatch.childMatches.find((d) => d.matchId === childMatch.matchId)
|
|
1449
|
-
// ) {
|
|
1450
|
-
// return
|
|
1451
|
-
// }
|
|
1452
|
-
// routeMatch.childMatches.push(childMatch)
|
|
1453
|
-
// },
|
|
1454
|
-
validate: () => {
|
|
1455
|
-
var _routeMatch$parentMat, _routeMatch$parentMat2;
|
|
1456
|
-
|
|
1457
|
-
// Validate the search params and stabilize them
|
|
1458
|
-
const parentSearch = (_routeMatch$parentMat = (_routeMatch$parentMat2 = routeMatch.parentMatch) == null ? void 0 : _routeMatch$parentMat2.search) != null ? _routeMatch$parentMat : router.location.search;
|
|
1459
|
-
|
|
1460
|
-
try {
|
|
1461
|
-
const prevSearch = routeMatch.routeSearch;
|
|
1462
|
-
const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
|
|
1463
|
-
let nextSearch = replaceEqualDeep(prevSearch, validator == null ? void 0 : validator(parentSearch)); // Invalidate route matches when search param stability changes
|
|
1464
|
-
|
|
1465
|
-
if (prevSearch !== nextSearch) {
|
|
1466
|
-
routeMatch.isInvalid = true;
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
routeMatch.routeSearch = nextSearch;
|
|
1470
|
-
routeMatch.search = replaceEqualDeep(parentSearch, _extends({}, parentSearch, nextSearch));
|
|
1471
|
-
} catch (err) {
|
|
1472
|
-
console.error(err);
|
|
1473
|
-
const error = new Error('Invalid search params found', {
|
|
1474
|
-
cause: err
|
|
1475
|
-
});
|
|
1476
|
-
error.code = 'INVALID_SEARCH_PARAMS';
|
|
1477
|
-
routeMatch.status = 'error';
|
|
1478
|
-
routeMatch.error = error; // Do not proceed with loading the route
|
|
1479
|
-
|
|
1480
|
-
return;
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
},
|
|
1484
|
-
cancel: () => {
|
|
1485
|
-
var _routeMatch$__$abortC;
|
|
1486
|
-
|
|
1487
|
-
(_routeMatch$__$abortC = routeMatch.__.abortController) == null ? void 0 : _routeMatch$__$abortC.abort();
|
|
1488
|
-
|
|
1489
|
-
routeMatch.__.cancelPending();
|
|
1490
|
-
},
|
|
1491
|
-
invalidate: () => {
|
|
1492
|
-
routeMatch.isInvalid = true;
|
|
1493
|
-
},
|
|
1494
|
-
hasLoaders: () => {
|
|
1495
|
-
return !!(route.options.loader || elementTypes.some(d => typeof route.options[d] === 'function'));
|
|
1496
|
-
},
|
|
1497
|
-
load: async loaderOpts => {
|
|
1498
|
-
const now = Date.now();
|
|
1499
|
-
const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0; // If this is a preload, add it to the preload cache
|
|
1500
|
-
|
|
1501
|
-
if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
|
|
1502
|
-
// If the match is currently active, don't preload it
|
|
1503
|
-
if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
|
|
1504
|
-
return;
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
router.matchCache[routeMatch.matchId] = {
|
|
1508
|
-
gc: now + loaderOpts.gcMaxAge,
|
|
1509
|
-
match: routeMatch
|
|
1510
|
-
};
|
|
1511
|
-
} // If the match is invalid, errored or idle, trigger it to load
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
|
|
1515
|
-
const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
|
|
1516
|
-
routeMatch.fetch({
|
|
1517
|
-
maxAge
|
|
1518
|
-
});
|
|
1519
|
-
}
|
|
1520
|
-
},
|
|
1521
|
-
fetch: async opts => {
|
|
1522
|
-
const id = '' + Date.now() + Math.random();
|
|
1523
|
-
routeMatch.__.latestId = id; // If the match was in an error state, set it
|
|
1524
|
-
// to a loading state again. Otherwise, keep it
|
|
1525
|
-
// as loading or resolved
|
|
1526
|
-
|
|
1527
|
-
if (routeMatch.status === 'idle') {
|
|
1528
|
-
routeMatch.status = 'loading';
|
|
1529
|
-
} // We started loading the route, so it's no longer invalid
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
routeMatch.isInvalid = false;
|
|
1533
|
-
routeMatch.__.loadPromise = new Promise(async resolve => {
|
|
1534
|
-
// We are now fetching, even if it's in the background of a
|
|
1535
|
-
// resolved state
|
|
1536
|
-
routeMatch.isFetching = true;
|
|
1537
|
-
routeMatch.__.resolve = resolve;
|
|
1538
|
-
|
|
1539
|
-
const loaderPromise = (async () => {
|
|
1540
|
-
// Load the elements and data in parallel
|
|
1541
|
-
routeMatch.__.elementsPromise = (async () => {
|
|
1542
|
-
// then run all element and data loaders in parallel
|
|
1543
|
-
// For each element type, potentially load it asynchronously
|
|
1544
|
-
await Promise.all(elementTypes.map(async type => {
|
|
1545
|
-
const routeElement = routeMatch.options[type];
|
|
1546
|
-
|
|
1547
|
-
if (routeMatch.__[type]) {
|
|
1548
|
-
return;
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
routeMatch.__[type] = await router.options.createElement(routeElement);
|
|
1552
|
-
}));
|
|
1553
|
-
})();
|
|
1554
|
-
|
|
1555
|
-
routeMatch.__.dataPromise = Promise.resolve().then(async () => {
|
|
1556
|
-
try {
|
|
1557
|
-
var _ref, _ref2, _opts$maxAge;
|
|
1558
|
-
|
|
1559
|
-
if (routeMatch.options.loader) {
|
|
1560
|
-
const data = await routeMatch.options.loader({
|
|
1561
|
-
params: routeMatch.params,
|
|
1562
|
-
search: routeMatch.routeSearch,
|
|
1563
|
-
signal: routeMatch.__.abortController.signal
|
|
1564
|
-
});
|
|
1565
|
-
|
|
1566
|
-
if (id !== routeMatch.__.latestId) {
|
|
1567
|
-
return routeMatch.__.loaderPromise;
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
routeMatch.routeLoaderData = replaceEqualDeep(routeMatch.routeLoaderData, data);
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
routeMatch.error = undefined;
|
|
1574
|
-
routeMatch.status = 'success';
|
|
1575
|
-
routeMatch.updatedAt = Date.now();
|
|
1576
|
-
routeMatch.invalidAt = routeMatch.updatedAt + ((_ref = (_ref2 = (_opts$maxAge = opts == null ? void 0 : opts.maxAge) != null ? _opts$maxAge : routeMatch.options.loaderMaxAge) != null ? _ref2 : router.options.defaultLoaderMaxAge) != null ? _ref : 0);
|
|
1577
|
-
} catch (err) {
|
|
1578
|
-
if (id !== routeMatch.__.latestId) {
|
|
1579
|
-
return routeMatch.__.loaderPromise;
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
{
|
|
1583
|
-
console.error(err);
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
routeMatch.error = err;
|
|
1587
|
-
routeMatch.status = 'error';
|
|
1588
|
-
routeMatch.updatedAt = Date.now();
|
|
1589
|
-
}
|
|
1590
|
-
});
|
|
1591
|
-
|
|
1592
|
-
try {
|
|
1593
|
-
await Promise.all([routeMatch.__.elementsPromise, routeMatch.__.dataPromise]);
|
|
1594
|
-
|
|
1595
|
-
if (id !== routeMatch.__.latestId) {
|
|
1596
|
-
return routeMatch.__.loaderPromise;
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
if (routeMatch.__.pendingMinPromise) {
|
|
1600
|
-
await routeMatch.__.pendingMinPromise;
|
|
1601
|
-
delete routeMatch.__.pendingMinPromise;
|
|
1602
|
-
}
|
|
1603
|
-
} finally {
|
|
1604
|
-
if (id !== routeMatch.__.latestId) {
|
|
1605
|
-
return routeMatch.__.loaderPromise;
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
routeMatch.__.cancelPending();
|
|
1609
|
-
|
|
1610
|
-
routeMatch.isPending = false;
|
|
1611
|
-
routeMatch.isFetching = false;
|
|
1612
|
-
|
|
1613
|
-
routeMatch.__.notify();
|
|
1614
|
-
}
|
|
1615
|
-
})();
|
|
1616
|
-
|
|
1617
|
-
routeMatch.__.loaderPromise = loaderPromise;
|
|
1618
|
-
await loaderPromise;
|
|
1619
|
-
|
|
1620
|
-
if (id !== routeMatch.__.latestId) {
|
|
1621
|
-
return routeMatch.__.loaderPromise;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
delete routeMatch.__.loaderPromise;
|
|
1625
|
-
});
|
|
1626
|
-
return await routeMatch.__.loadPromise;
|
|
793
|
+
setState = (updater, opts) => {
|
|
794
|
+
const previous = this.state;
|
|
795
|
+
this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
|
|
796
|
+
const priority = opts?.priority ?? this.options?.defaultPriority ?? 'high';
|
|
797
|
+
if (this._nextPriority === null) {
|
|
798
|
+
this._nextPriority = priority;
|
|
799
|
+
} else if (this._nextPriority === 'high') {
|
|
800
|
+
this._nextPriority = priority;
|
|
801
|
+
} else {
|
|
802
|
+
this._nextPriority = this.options?.defaultPriority ?? 'high';
|
|
1627
803
|
}
|
|
1628
|
-
});
|
|
1629
804
|
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
805
|
+
// Always run onUpdate, regardless of batching
|
|
806
|
+
this.options?.onUpdate?.({
|
|
807
|
+
priority: this._nextPriority
|
|
808
|
+
});
|
|
1633
809
|
|
|
1634
|
-
|
|
810
|
+
// Attempt to flush
|
|
811
|
+
this._flush();
|
|
812
|
+
};
|
|
813
|
+
_flush = () => {
|
|
814
|
+
if (this._batching) return;
|
|
815
|
+
const flushId = ++this._flushing;
|
|
816
|
+
this.listeners.forEach(listener => {
|
|
817
|
+
if (this._flushing !== flushId) return;
|
|
818
|
+
listener({
|
|
819
|
+
priority: this._nextPriority ?? 'high'
|
|
820
|
+
});
|
|
821
|
+
});
|
|
822
|
+
};
|
|
823
|
+
batch = cb => {
|
|
824
|
+
if (this._batching) return cb();
|
|
825
|
+
this._batching = true;
|
|
826
|
+
cb();
|
|
827
|
+
this._batching = false;
|
|
828
|
+
this._flush();
|
|
829
|
+
};
|
|
1635
830
|
}
|
|
1636
831
|
|
|
1637
832
|
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
1638
|
-
const defaultStringifySearch = stringifySearchWith(JSON.stringify);
|
|
833
|
+
const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
|
|
1639
834
|
function parseSearchWith(parser) {
|
|
1640
835
|
return searchStr => {
|
|
1641
836
|
if (searchStr.substring(0, 1) === '?') {
|
|
1642
837
|
searchStr = searchStr.substring(1);
|
|
1643
838
|
}
|
|
839
|
+
let query = decode(searchStr);
|
|
1644
840
|
|
|
1645
|
-
|
|
1646
|
-
|
|
841
|
+
// Try to parse any query params that might be json
|
|
1647
842
|
for (let key in query) {
|
|
1648
843
|
const value = query[key];
|
|
1649
|
-
|
|
1650
844
|
if (typeof value === 'string') {
|
|
1651
845
|
try {
|
|
1652
846
|
query[key] = parser(value);
|
|
1653
|
-
} catch (err) {
|
|
847
|
+
} catch (err) {
|
|
848
|
+
//
|
|
1654
849
|
}
|
|
1655
850
|
}
|
|
1656
851
|
}
|
|
1657
|
-
|
|
1658
852
|
return query;
|
|
1659
853
|
};
|
|
1660
854
|
}
|
|
1661
|
-
function stringifySearchWith(stringify) {
|
|
855
|
+
function stringifySearchWith(stringify, parser) {
|
|
856
|
+
function stringifyValue(val) {
|
|
857
|
+
if (typeof val === 'object' && val !== null) {
|
|
858
|
+
try {
|
|
859
|
+
return stringify(val);
|
|
860
|
+
} catch (err) {
|
|
861
|
+
// silent
|
|
862
|
+
}
|
|
863
|
+
} else if (typeof val === 'string' && typeof parser === 'function') {
|
|
864
|
+
try {
|
|
865
|
+
// Check if it's a valid parseable string.
|
|
866
|
+
// If it is, then stringify it again.
|
|
867
|
+
parser(val);
|
|
868
|
+
return stringify(val);
|
|
869
|
+
} catch (err) {
|
|
870
|
+
// silent
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return val;
|
|
874
|
+
}
|
|
1662
875
|
return search => {
|
|
1663
|
-
search =
|
|
1664
|
-
|
|
876
|
+
search = {
|
|
877
|
+
...search
|
|
878
|
+
};
|
|
1665
879
|
if (search) {
|
|
1666
880
|
Object.keys(search).forEach(key => {
|
|
1667
881
|
const val = search[key];
|
|
1668
|
-
|
|
1669
882
|
if (typeof val === 'undefined' || val === undefined) {
|
|
1670
883
|
delete search[key];
|
|
1671
|
-
} else
|
|
1672
|
-
|
|
1673
|
-
search[key] = stringify(val);
|
|
1674
|
-
} catch (err) {// silent
|
|
1675
|
-
}
|
|
884
|
+
} else {
|
|
885
|
+
search[key] = stringifyValue(val);
|
|
1676
886
|
}
|
|
1677
887
|
});
|
|
1678
888
|
}
|
|
1679
|
-
|
|
1680
889
|
const searchStr = encode(search).toString();
|
|
1681
|
-
return searchStr ?
|
|
890
|
+
return searchStr ? `?${searchStr}` : '';
|
|
1682
891
|
};
|
|
1683
892
|
}
|
|
1684
893
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
const
|
|
1688
|
-
|
|
1689
|
-
const
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
894
|
+
//
|
|
895
|
+
|
|
896
|
+
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
897
|
+
const visibilityChangeEvent = 'visibilitychange';
|
|
898
|
+
const focusEvent = 'focus';
|
|
899
|
+
const preloadWarning = 'Error preloading route! ☝️';
|
|
900
|
+
class Router {
|
|
901
|
+
#unsubHistory;
|
|
902
|
+
resetNextScroll = false;
|
|
903
|
+
tempLocationKey = `${Math.round(Math.random() * 10000000)}`;
|
|
904
|
+
// nextTemporaryLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
905
|
+
|
|
906
|
+
constructor(options) {
|
|
907
|
+
this.options = {
|
|
908
|
+
defaultPreloadDelay: 50,
|
|
909
|
+
context: undefined,
|
|
910
|
+
...options,
|
|
911
|
+
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
912
|
+
parseSearch: options?.parseSearch ?? defaultParseSearch
|
|
913
|
+
// fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn,
|
|
914
|
+
};
|
|
1705
915
|
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
916
|
+
this.__store = new Store(getInitialRouterState(), {
|
|
917
|
+
onUpdate: () => {
|
|
918
|
+
const prev = this.state;
|
|
919
|
+
const next = this.__store.state;
|
|
920
|
+
const matchesByIdChanged = prev.matchesById !== next.matchesById;
|
|
921
|
+
let matchesChanged;
|
|
922
|
+
let pendingMatchesChanged;
|
|
923
|
+
if (!matchesByIdChanged) {
|
|
924
|
+
matchesChanged = prev.matchIds.length !== next.matchIds.length || prev.matchIds.some((d, i) => d !== next.matchIds[i]);
|
|
925
|
+
pendingMatchesChanged = prev.pendingMatchIds.length !== next.pendingMatchIds.length || prev.pendingMatchIds.some((d, i) => d !== next.pendingMatchIds[i]);
|
|
926
|
+
}
|
|
927
|
+
if (matchesByIdChanged || matchesChanged) {
|
|
928
|
+
next.matches = next.matchIds.map(id => {
|
|
929
|
+
return next.matchesById[id];
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
if (matchesByIdChanged || pendingMatchesChanged) {
|
|
933
|
+
next.pendingMatches = next.pendingMatchIds.map(id => {
|
|
934
|
+
return next.matchesById[id];
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
if (matchesByIdChanged || matchesChanged || pendingMatchesChanged) {
|
|
938
|
+
const hasPendingComponent = next.pendingMatches.some(d => {
|
|
939
|
+
const route = this.getRoute(d.routeId);
|
|
940
|
+
return !!route?.options.pendingComponent;
|
|
941
|
+
});
|
|
942
|
+
next.renderedMatchIds = hasPendingComponent ? next.pendingMatchIds : next.matchIds;
|
|
943
|
+
next.renderedMatches = next.renderedMatchIds.map(id => {
|
|
944
|
+
return next.matchesById[id];
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
next.isFetching = [...next.matches, ...next.pendingMatches].some(d => d.isFetching);
|
|
948
|
+
this.state = next;
|
|
949
|
+
},
|
|
950
|
+
defaultPriority: 'low'
|
|
951
|
+
});
|
|
952
|
+
this.state = this.__store.state;
|
|
953
|
+
this.update(options);
|
|
954
|
+
const nextLocation = this.buildLocation({
|
|
955
|
+
search: true,
|
|
956
|
+
params: true,
|
|
957
|
+
hash: true,
|
|
958
|
+
state: true
|
|
959
|
+
});
|
|
960
|
+
if (this.state.location.href !== nextLocation.href) {
|
|
961
|
+
this.#commitLocation({
|
|
962
|
+
...nextLocation,
|
|
963
|
+
replace: true
|
|
1746
964
|
});
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
subscribers = new Set();
|
|
968
|
+
subscribe = (eventType, fn) => {
|
|
969
|
+
const listener = {
|
|
970
|
+
eventType,
|
|
971
|
+
fn
|
|
972
|
+
};
|
|
973
|
+
this.subscribers.add(listener);
|
|
974
|
+
return () => {
|
|
975
|
+
this.subscribers.delete(listener);
|
|
976
|
+
};
|
|
977
|
+
};
|
|
978
|
+
#emit = routerEvent => {
|
|
979
|
+
this.subscribers.forEach(listener => {
|
|
980
|
+
if (listener.eventType === routerEvent.type) {
|
|
981
|
+
listener.fn(routerEvent);
|
|
1763
982
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
983
|
+
});
|
|
984
|
+
};
|
|
985
|
+
reset = () => {
|
|
986
|
+
this.__store.setState(s => Object.assign(s, getInitialRouterState()));
|
|
987
|
+
};
|
|
988
|
+
mount = () => {
|
|
989
|
+
// addEventListener does not exist in React Native, but window does
|
|
990
|
+
// In the future, we might need to invert control here for more adapters
|
|
991
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
992
|
+
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
993
|
+
window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
|
|
994
|
+
window.addEventListener(focusEvent, this.#onFocus, false);
|
|
995
|
+
}
|
|
996
|
+
this.safeLoad();
|
|
997
|
+
return () => {
|
|
998
|
+
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
999
|
+
window.removeEventListener(visibilityChangeEvent, this.#onFocus);
|
|
1000
|
+
window.removeEventListener(focusEvent, this.#onFocus);
|
|
1774
1001
|
}
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
};
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
} = router.options;
|
|
1792
|
-
router.basepath = cleanPath("/" + (basepath != null ? basepath : ''));
|
|
1793
|
-
|
|
1794
|
-
if (routeConfig) {
|
|
1795
|
-
router.routesById = {};
|
|
1796
|
-
router.routeTree = router.__.buildRouteTree(routeConfig);
|
|
1002
|
+
};
|
|
1003
|
+
};
|
|
1004
|
+
#onFocus = () => {
|
|
1005
|
+
if (this.options.reloadOnWindowFocus ?? true) {
|
|
1006
|
+
this.invalidate({
|
|
1007
|
+
__fromFocus: true
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
update = opts => {
|
|
1012
|
+
this.options = {
|
|
1013
|
+
...this.options,
|
|
1014
|
+
...opts,
|
|
1015
|
+
context: {
|
|
1016
|
+
...this.options.context,
|
|
1017
|
+
...opts?.context
|
|
1797
1018
|
}
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1019
|
+
};
|
|
1020
|
+
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
1021
|
+
if (this.#unsubHistory) {
|
|
1022
|
+
this.#unsubHistory();
|
|
1023
|
+
}
|
|
1024
|
+
this.history = this.options.history ?? (isServer ? createMemoryHistory() : createBrowserHistory());
|
|
1025
|
+
const parsedLocation = this.#parseLocation();
|
|
1026
|
+
this.__store.setState(s => ({
|
|
1027
|
+
...s,
|
|
1028
|
+
resolvedLocation: parsedLocation,
|
|
1029
|
+
location: parsedLocation
|
|
1030
|
+
}));
|
|
1031
|
+
this.#unsubHistory = this.history.subscribe(() => {
|
|
1032
|
+
this.safeLoad({
|
|
1033
|
+
next: this.#parseLocation(this.state.location)
|
|
1034
|
+
});
|
|
1805
1035
|
});
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1036
|
+
}
|
|
1037
|
+
const {
|
|
1038
|
+
basepath,
|
|
1039
|
+
routeTree
|
|
1040
|
+
} = this.options;
|
|
1041
|
+
this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
|
|
1042
|
+
if (routeTree && routeTree !== this.routeTree) {
|
|
1043
|
+
this.#processRoutes(routeTree);
|
|
1044
|
+
}
|
|
1045
|
+
return this;
|
|
1046
|
+
};
|
|
1047
|
+
cancelMatches = () => {
|
|
1048
|
+
this.state.matches.forEach(match => {
|
|
1049
|
+
this.cancelMatch(match.id);
|
|
1050
|
+
});
|
|
1051
|
+
};
|
|
1052
|
+
cancelMatch = id => {
|
|
1053
|
+
this.getRouteMatch(id)?.abortController?.abort();
|
|
1054
|
+
};
|
|
1055
|
+
safeLoad = async opts => {
|
|
1056
|
+
try {
|
|
1057
|
+
return this.load(opts);
|
|
1058
|
+
} catch (err) {
|
|
1059
|
+
// Don't do anything
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
latestLoadPromise = Promise.resolve();
|
|
1063
|
+
load = async opts => {
|
|
1064
|
+
const promise = new Promise(async (resolve, reject) => {
|
|
1065
|
+
const prevLocation = this.state.resolvedLocation;
|
|
1066
|
+
const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
|
|
1067
|
+
let latestPromise;
|
|
1068
|
+
const checkLatest = () => {
|
|
1069
|
+
return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
|
|
1070
|
+
};
|
|
1816
1071
|
|
|
1817
|
-
|
|
1818
|
-
let {
|
|
1819
|
-
action,
|
|
1820
|
-
actionState
|
|
1821
|
-
} = _ref;
|
|
1072
|
+
// Cancel any pending matches
|
|
1822
1073
|
|
|
1823
|
-
|
|
1824
|
-
|
|
1074
|
+
let pendingMatches;
|
|
1075
|
+
this.#emit({
|
|
1076
|
+
type: 'onBeforeLoad',
|
|
1077
|
+
from: prevLocation,
|
|
1078
|
+
to: opts?.next ?? this.state.location,
|
|
1079
|
+
pathChanged: pathDidChange
|
|
1080
|
+
});
|
|
1081
|
+
this.__store.batch(() => {
|
|
1082
|
+
if (opts?.next) {
|
|
1083
|
+
// Ingest the new location
|
|
1084
|
+
this.__store.setState(s => ({
|
|
1085
|
+
...s,
|
|
1086
|
+
location: opts.next
|
|
1087
|
+
}));
|
|
1825
1088
|
}
|
|
1826
1089
|
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1090
|
+
// Match the routes
|
|
1091
|
+
pendingMatches = this.matchRoutes(this.state.location.pathname, this.state.location.search, {
|
|
1092
|
+
throwOnError: opts?.throwOnError,
|
|
1093
|
+
debug: true
|
|
1094
|
+
});
|
|
1095
|
+
this.__store.setState(s => ({
|
|
1096
|
+
...s,
|
|
1097
|
+
status: 'pending',
|
|
1098
|
+
pendingMatchIds: pendingMatches.map(d => d.id),
|
|
1099
|
+
matchesById: this.#mergeMatches(s.matchesById, pendingMatches)
|
|
1100
|
+
}));
|
|
1830
1101
|
});
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1102
|
+
try {
|
|
1103
|
+
// Load the matches
|
|
1104
|
+
try {
|
|
1105
|
+
await this.loadMatches(pendingMatches.map(d => d.id));
|
|
1106
|
+
} catch (err) {
|
|
1107
|
+
// swallow this error, since we'll display the
|
|
1108
|
+
// errors on the route components
|
|
1109
|
+
}
|
|
1834
1110
|
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1111
|
+
// Only apply the latest transition
|
|
1112
|
+
if (latestPromise = checkLatest()) {
|
|
1113
|
+
return latestPromise;
|
|
1114
|
+
}
|
|
1115
|
+
const exitingMatchIds = this.state.matchIds.filter(id => !this.state.pendingMatchIds.includes(id));
|
|
1116
|
+
const enteringMatchIds = this.state.pendingMatchIds.filter(id => !this.state.matchIds.includes(id));
|
|
1117
|
+
const stayingMatchIds = this.state.matchIds.filter(id => this.state.pendingMatchIds.includes(id));
|
|
1118
|
+
this.__store.setState(s => ({
|
|
1119
|
+
...s,
|
|
1120
|
+
status: 'idle',
|
|
1121
|
+
resolvedLocation: s.location,
|
|
1122
|
+
matchIds: s.pendingMatchIds,
|
|
1123
|
+
pendingMatchIds: []
|
|
1124
|
+
}));
|
|
1125
|
+
[[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matchIds, hook]) => {
|
|
1126
|
+
matchIds.forEach(id => {
|
|
1127
|
+
const match = this.getRouteMatch(id);
|
|
1128
|
+
const route = this.getRoute(match.routeId);
|
|
1129
|
+
route.options[hook]?.(match);
|
|
1130
|
+
});
|
|
1131
|
+
});
|
|
1132
|
+
this.#emit({
|
|
1133
|
+
type: 'onLoad',
|
|
1134
|
+
from: prevLocation,
|
|
1135
|
+
to: this.state.location,
|
|
1136
|
+
pathChanged: pathDidChange
|
|
1137
|
+
});
|
|
1138
|
+
resolve();
|
|
1139
|
+
} catch (err) {
|
|
1140
|
+
// Only apply the latest transition
|
|
1141
|
+
if (latestPromise = checkLatest()) {
|
|
1142
|
+
return latestPromise;
|
|
1143
|
+
}
|
|
1144
|
+
reject(err);
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
this.latestLoadPromise = promise;
|
|
1148
|
+
this.latestLoadPromise.then(() => {
|
|
1149
|
+
this.cleanMatches();
|
|
1150
|
+
});
|
|
1151
|
+
return this.latestLoadPromise;
|
|
1152
|
+
};
|
|
1153
|
+
#mergeMatches = (prevMatchesById, nextMatches) => {
|
|
1154
|
+
let matchesById = {
|
|
1155
|
+
...prevMatchesById
|
|
1156
|
+
};
|
|
1157
|
+
nextMatches.forEach(match => {
|
|
1158
|
+
if (!matchesById[match.id]) {
|
|
1159
|
+
matchesById[match.id] = match;
|
|
1160
|
+
}
|
|
1161
|
+
matchesById[match.id] = {
|
|
1162
|
+
...matchesById[match.id],
|
|
1163
|
+
...match
|
|
1164
|
+
};
|
|
1165
|
+
});
|
|
1166
|
+
return matchesById;
|
|
1167
|
+
};
|
|
1168
|
+
getRoute = id => {
|
|
1169
|
+
const route = this.routesById[id];
|
|
1170
|
+
invariant(route, `Route with id "${id}" not found`);
|
|
1171
|
+
return route;
|
|
1172
|
+
};
|
|
1173
|
+
preloadRoute = async (navigateOpts = this.state.location) => {
|
|
1174
|
+
let next = this.buildLocation(navigateOpts);
|
|
1175
|
+
const matches = this.matchRoutes(next.pathname, next.search, {
|
|
1176
|
+
throwOnError: true
|
|
1177
|
+
});
|
|
1178
|
+
this.__store.setState(s => {
|
|
1179
|
+
return {
|
|
1180
|
+
...s,
|
|
1181
|
+
matchesById: this.#mergeMatches(s.matchesById, matches)
|
|
1182
|
+
};
|
|
1183
|
+
});
|
|
1184
|
+
await this.loadMatches(matches.map(d => d.id), {
|
|
1185
|
+
preload: true,
|
|
1186
|
+
maxAge: navigateOpts.maxAge
|
|
1187
|
+
});
|
|
1188
|
+
return [last(matches), matches];
|
|
1189
|
+
};
|
|
1190
|
+
cleanMatches = () => {
|
|
1191
|
+
const now = Date.now();
|
|
1192
|
+
const outdatedMatchIds = Object.values(this.state.matchesById).filter(match => {
|
|
1193
|
+
const route = this.getRoute(match.routeId);
|
|
1194
|
+
return !this.state.matchIds.includes(match.id) && !this.state.pendingMatchIds.includes(match.id) && (match.preloadMaxAge > -1 ? match.updatedAt + match.preloadMaxAge < now : true) && (route.options.gcMaxAge ? match.updatedAt + route.options.gcMaxAge < now : true);
|
|
1195
|
+
}).map(d => d.id);
|
|
1196
|
+
if (outdatedMatchIds.length) {
|
|
1197
|
+
this.__store.setState(s => {
|
|
1198
|
+
const matchesById = {
|
|
1199
|
+
...s.matchesById
|
|
1200
|
+
};
|
|
1201
|
+
outdatedMatchIds.forEach(id => {
|
|
1202
|
+
delete matchesById[id];
|
|
1203
|
+
});
|
|
1204
|
+
return {
|
|
1205
|
+
...s,
|
|
1206
|
+
matchesById
|
|
1207
|
+
};
|
|
1844
1208
|
});
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
matchRoutes = (pathname, locationSearch, opts) => {
|
|
1212
|
+
let routeParams = {};
|
|
1213
|
+
let foundRoute = this.flatRoutes.find(route => {
|
|
1214
|
+
const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
|
|
1215
|
+
to: route.fullPath,
|
|
1216
|
+
caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive
|
|
1849
1217
|
});
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
return router.navigationPromise;
|
|
1218
|
+
if (matchedParams) {
|
|
1219
|
+
routeParams = matchedParams;
|
|
1220
|
+
return true;
|
|
1854
1221
|
}
|
|
1222
|
+
return false;
|
|
1223
|
+
});
|
|
1224
|
+
let routeCursor = foundRoute || this.routesById['__root__'];
|
|
1225
|
+
let matchedRoutes = [routeCursor];
|
|
1226
|
+
// let includingLayouts = true
|
|
1227
|
+
while (routeCursor?.parentRoute) {
|
|
1228
|
+
routeCursor = routeCursor.parentRoute;
|
|
1229
|
+
if (routeCursor) matchedRoutes.unshift(routeCursor);
|
|
1230
|
+
}
|
|
1855
1231
|
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1232
|
+
// Existing matches are matches that are already loaded along with
|
|
1233
|
+
// pending matches that are still loading
|
|
1234
|
+
|
|
1235
|
+
const parseErrors = matchedRoutes.map(route => {
|
|
1236
|
+
let parsedParamsError;
|
|
1237
|
+
if (route.options.parseParams) {
|
|
1238
|
+
try {
|
|
1239
|
+
const parsedParams = route.options.parseParams(routeParams);
|
|
1240
|
+
// Add the parsed params to the accumulated params bag
|
|
1241
|
+
Object.assign(routeParams, parsedParams);
|
|
1242
|
+
} catch (err) {
|
|
1243
|
+
parsedParamsError = new PathParamError(err.message, {
|
|
1244
|
+
cause: err
|
|
1245
|
+
});
|
|
1246
|
+
if (opts?.throwOnError) {
|
|
1247
|
+
throw parsedParamsError;
|
|
1248
|
+
}
|
|
1249
|
+
return parsedParamsError;
|
|
1864
1250
|
}
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
d.error = undefined;
|
|
1251
|
+
}
|
|
1252
|
+
return;
|
|
1253
|
+
});
|
|
1254
|
+
const matches = matchedRoutes.map((route, index) => {
|
|
1255
|
+
const interpolatedPath = interpolatePath(route.path, routeParams);
|
|
1256
|
+
const loaderContext = route.options.loaderContext ? route.options.loaderContext({
|
|
1257
|
+
search: locationSearch
|
|
1258
|
+
}) : undefined;
|
|
1259
|
+
const matchId = JSON.stringify([interpolatePath(route.id, routeParams, true), loaderContext].filter(d => d !== undefined), (key, value) => {
|
|
1260
|
+
if (typeof value === 'function') {
|
|
1261
|
+
console.info(route);
|
|
1262
|
+
invariant(false, `Cannot return functions and other non-serializable values from routeOptions.loaderContext! Please use routeOptions.beforeLoad to do this. Route info is logged above 👆`);
|
|
1878
1263
|
}
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
if (gc > 0) {
|
|
1883
|
-
router.matchCache[d.matchId] = {
|
|
1884
|
-
gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
|
|
1885
|
-
match: d
|
|
1886
|
-
};
|
|
1264
|
+
if (typeof value === 'object' && value !== null) {
|
|
1265
|
+
return Object.fromEntries(Object.keys(value).sort().map(key => [key, value[key]]));
|
|
1887
1266
|
}
|
|
1888
|
-
|
|
1889
|
-
staying.forEach(d => {
|
|
1890
|
-
d.options.onTransition == null ? void 0 : d.options.onTransition({
|
|
1891
|
-
params: d.params,
|
|
1892
|
-
search: d.routeSearch
|
|
1893
|
-
});
|
|
1894
|
-
});
|
|
1895
|
-
const entering = matches.filter(d => {
|
|
1896
|
-
return !previousMatches.find(dd => dd.matchId === d.matchId);
|
|
1897
|
-
});
|
|
1898
|
-
entering.forEach(d => {
|
|
1899
|
-
d.__.onExit = d.options.onMatch == null ? void 0 : d.options.onMatch({
|
|
1900
|
-
params: d.params,
|
|
1901
|
-
search: d.search
|
|
1902
|
-
});
|
|
1903
|
-
delete router.matchCache[d.matchId];
|
|
1267
|
+
return value;
|
|
1904
1268
|
});
|
|
1905
1269
|
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1270
|
+
// Waste not, want not. If we already have a match for this route,
|
|
1271
|
+
// reuse it. This is important for layout routes, which might stick
|
|
1272
|
+
// around between navigation actions that only change leaf routes.
|
|
1273
|
+
const existingMatch = this.getRouteMatch(matchId);
|
|
1274
|
+
if (existingMatch) {
|
|
1275
|
+
return {
|
|
1276
|
+
...existingMatch
|
|
1277
|
+
};
|
|
1909
1278
|
}
|
|
1910
1279
|
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1280
|
+
// Create a fresh route match
|
|
1281
|
+
const hasLoaders = !!(route.options.loader || componentTypes.some(d => route.options[d]?.preload));
|
|
1282
|
+
const routeMatch = {
|
|
1283
|
+
id: matchId,
|
|
1284
|
+
loaderContext,
|
|
1285
|
+
routeId: route.id,
|
|
1286
|
+
params: routeParams,
|
|
1287
|
+
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
1288
|
+
updatedAt: Date.now(),
|
|
1289
|
+
maxAge: -1,
|
|
1290
|
+
preloadMaxAge: -1,
|
|
1291
|
+
routeSearch: {},
|
|
1292
|
+
search: {},
|
|
1293
|
+
status: hasLoaders ? 'pending' : 'success',
|
|
1294
|
+
isFetching: false,
|
|
1295
|
+
invalid: false,
|
|
1296
|
+
error: undefined,
|
|
1297
|
+
paramsError: parseErrors[index],
|
|
1298
|
+
searchError: undefined,
|
|
1299
|
+
loaderData: undefined,
|
|
1300
|
+
loadPromise: Promise.resolve(),
|
|
1301
|
+
context: undefined,
|
|
1302
|
+
abortController: new AbortController(),
|
|
1303
|
+
fetchedAt: 0
|
|
1304
|
+
};
|
|
1305
|
+
return routeMatch;
|
|
1306
|
+
});
|
|
1915
1307
|
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1308
|
+
// Take each match and resolve its search params and context
|
|
1309
|
+
// This has to happen after the matches are created or found
|
|
1310
|
+
// so that we can use the parent match's search params and context
|
|
1311
|
+
matches.forEach((match, i) => {
|
|
1312
|
+
const parentMatch = matches[i - 1];
|
|
1313
|
+
const route = this.getRoute(match.routeId);
|
|
1314
|
+
const searchInfo = (() => {
|
|
1315
|
+
// Validate the search params and stabilize them
|
|
1316
|
+
const parentSearchInfo = {
|
|
1317
|
+
search: parentMatch?.search ?? locationSearch,
|
|
1318
|
+
routeSearch: parentMatch?.routeSearch ?? locationSearch
|
|
1319
|
+
};
|
|
1320
|
+
try {
|
|
1321
|
+
const validator = typeof route.options.validateSearch === 'object' ? route.options.validateSearch.parse : route.options.validateSearch;
|
|
1322
|
+
let routeSearch = validator?.(parentSearchInfo.search) ?? {};
|
|
1323
|
+
let search = {
|
|
1324
|
+
...parentSearchInfo.search,
|
|
1325
|
+
...routeSearch
|
|
1326
|
+
};
|
|
1327
|
+
routeSearch = replaceEqualDeep(match.routeSearch, routeSearch);
|
|
1328
|
+
search = replaceEqualDeep(match.search, search);
|
|
1329
|
+
return {
|
|
1330
|
+
routeSearch,
|
|
1331
|
+
search,
|
|
1332
|
+
searchDidChange: match.routeSearch !== routeSearch
|
|
1333
|
+
};
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
match.searchError = new SearchParamError(err.message, {
|
|
1336
|
+
cause: err
|
|
1337
|
+
});
|
|
1338
|
+
if (opts?.throwOnError) {
|
|
1339
|
+
throw match.searchError;
|
|
1340
|
+
}
|
|
1341
|
+
return parentSearchInfo;
|
|
1342
|
+
}
|
|
1343
|
+
})();
|
|
1344
|
+
Object.assign(match, searchInfo);
|
|
1345
|
+
});
|
|
1346
|
+
return matches;
|
|
1347
|
+
};
|
|
1348
|
+
loadMatches = async (matchIds, opts) => {
|
|
1349
|
+
const getFreshMatches = () => matchIds.map(d => this.getRouteMatch(d));
|
|
1350
|
+
if (!opts?.preload) {
|
|
1351
|
+
getFreshMatches().forEach(match => {
|
|
1352
|
+
// Update each match with its latest route data
|
|
1353
|
+
this.setRouteMatch(match.id, s => ({
|
|
1354
|
+
...s,
|
|
1355
|
+
routeSearch: match.routeSearch,
|
|
1356
|
+
search: match.search,
|
|
1357
|
+
context: match.context,
|
|
1358
|
+
error: match.error,
|
|
1359
|
+
paramsError: match.paramsError,
|
|
1360
|
+
searchError: match.searchError,
|
|
1361
|
+
params: match.params,
|
|
1362
|
+
preloadMaxAge: 0
|
|
1363
|
+
}));
|
|
1941
1364
|
});
|
|
1942
|
-
}
|
|
1943
|
-
|
|
1944
|
-
if (navigateOpts === void 0) {
|
|
1945
|
-
navigateOpts = router.location;
|
|
1946
|
-
}
|
|
1365
|
+
}
|
|
1366
|
+
let firstBadMatchIndex;
|
|
1947
1367
|
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1368
|
+
// Check each match middleware to see if the route can be accessed
|
|
1369
|
+
try {
|
|
1370
|
+
for (const [index, match] of getFreshMatches().entries()) {
|
|
1371
|
+
const parentMatch = getFreshMatches()[index - 1];
|
|
1372
|
+
const route = this.getRoute(match.routeId);
|
|
1373
|
+
const handleError = (err, code) => {
|
|
1374
|
+
err.routerCode = code;
|
|
1375
|
+
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
1376
|
+
if (isRedirect(err)) {
|
|
1377
|
+
throw err;
|
|
1378
|
+
}
|
|
1379
|
+
try {
|
|
1380
|
+
route.options.onError?.(err);
|
|
1381
|
+
} catch (errorHandlerErr) {
|
|
1382
|
+
err = errorHandlerErr;
|
|
1383
|
+
if (isRedirect(errorHandlerErr)) {
|
|
1384
|
+
throw errorHandlerErr;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
this.setRouteMatch(match.id, s => ({
|
|
1388
|
+
...s,
|
|
1389
|
+
error: err,
|
|
1390
|
+
status: 'error',
|
|
1391
|
+
updatedAt: Date.now()
|
|
1392
|
+
}));
|
|
1393
|
+
};
|
|
1394
|
+
if (match.paramsError) {
|
|
1395
|
+
handleError(match.paramsError, 'PARSE_PARAMS');
|
|
1396
|
+
}
|
|
1397
|
+
if (match.searchError) {
|
|
1398
|
+
handleError(match.searchError, 'VALIDATE_SEARCH');
|
|
1399
|
+
}
|
|
1400
|
+
let didError = false;
|
|
1401
|
+
const parentContext = parentMatch?.context ?? this?.options.context ?? {};
|
|
1402
|
+
try {
|
|
1403
|
+
const beforeLoadContext = (await route.options.beforeLoad?.({
|
|
1404
|
+
abortController: match.abortController,
|
|
1405
|
+
params: match.params,
|
|
1406
|
+
preload: !!opts?.preload,
|
|
1407
|
+
context: {
|
|
1408
|
+
...parentContext,
|
|
1409
|
+
...match.loaderContext
|
|
1410
|
+
}
|
|
1411
|
+
})) ?? {};
|
|
1412
|
+
const context = {
|
|
1413
|
+
...parentContext,
|
|
1414
|
+
...match.loaderContext,
|
|
1415
|
+
...beforeLoadContext
|
|
1416
|
+
};
|
|
1417
|
+
this.setRouteMatch(match.id, s => ({
|
|
1418
|
+
...s,
|
|
1419
|
+
context: replaceEqualDeep(s.context, context)
|
|
1420
|
+
}));
|
|
1421
|
+
} catch (err) {
|
|
1422
|
+
handleError(err, 'BEFORE_LOAD');
|
|
1423
|
+
didError = true;
|
|
1424
|
+
}
|
|
1957
1425
|
|
|
1958
|
-
|
|
1959
|
-
|
|
1426
|
+
// If we errored, do not run the next matches' middleware
|
|
1427
|
+
if (didError) {
|
|
1428
|
+
break;
|
|
1429
|
+
}
|
|
1960
1430
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
});
|
|
1966
|
-
await router.loadMatches(matches, {
|
|
1967
|
-
preload: true,
|
|
1968
|
-
maxAge: (_ref4 = (_ref5 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref5 : router.options.defaultLoaderMaxAge) != null ? _ref4 : 0,
|
|
1969
|
-
gcMaxAge: (_ref6 = (_ref7 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0
|
|
1970
|
-
});
|
|
1971
|
-
return matches;
|
|
1972
|
-
},
|
|
1973
|
-
matchRoutes: (pathname, opts) => {
|
|
1974
|
-
var _router$state$pending3, _router$state$pending4;
|
|
1975
|
-
|
|
1976
|
-
router.cleanMatchCache();
|
|
1977
|
-
const matches = [];
|
|
1978
|
-
|
|
1979
|
-
if (!router.routeTree) {
|
|
1980
|
-
return matches;
|
|
1431
|
+
} catch (err) {
|
|
1432
|
+
if (isRedirect(err)) {
|
|
1433
|
+
if (!opts?.preload) this.navigate(err);
|
|
1434
|
+
return;
|
|
1981
1435
|
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
const
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1436
|
+
throw err;
|
|
1437
|
+
}
|
|
1438
|
+
const validResolvedMatches = getFreshMatches().slice(0, firstBadMatchIndex);
|
|
1439
|
+
const matchPromises = [];
|
|
1440
|
+
validResolvedMatches.forEach((match, index) => {
|
|
1441
|
+
matchPromises.push((async () => {
|
|
1442
|
+
const parentMatchPromise = matchPromises[index - 1];
|
|
1443
|
+
const route = this.getRoute(match.routeId);
|
|
1444
|
+
if (match.isFetching || match.status === 'success' && !isMatchInvalid(match, {
|
|
1445
|
+
preload: opts?.preload
|
|
1446
|
+
})) {
|
|
1447
|
+
return this.getRouteMatch(match.id)?.loadPromise;
|
|
1448
|
+
}
|
|
1449
|
+
const fetchedAt = Date.now();
|
|
1450
|
+
const checkLatest = () => {
|
|
1451
|
+
const latest = this.getRouteMatch(match.id);
|
|
1452
|
+
return latest && latest.fetchedAt !== fetchedAt ? latest.loadPromise : undefined;
|
|
1453
|
+
};
|
|
1454
|
+
const handleIfRedirect = err => {
|
|
1455
|
+
if (isRedirect(err)) {
|
|
1456
|
+
if (!opts?.preload) {
|
|
1457
|
+
this.navigate(err);
|
|
1999
1458
|
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
try {
|
|
2012
|
-
var _route$options$parseP;
|
|
2013
|
-
|
|
2014
|
-
parsedParams = (_route$options$parseP = route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) != null ? _route$options$parseP : matchParams;
|
|
2015
|
-
} catch (err) {
|
|
2016
|
-
if (opts != null && opts.strictParseParams) {
|
|
2017
|
-
throw err;
|
|
2018
|
-
}
|
|
1459
|
+
return true;
|
|
1460
|
+
}
|
|
1461
|
+
return false;
|
|
1462
|
+
};
|
|
1463
|
+
const load = async () => {
|
|
1464
|
+
let latestPromise;
|
|
1465
|
+
try {
|
|
1466
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
1467
|
+
const component = route.options[type];
|
|
1468
|
+
if (component?.preload) {
|
|
1469
|
+
await component.preload();
|
|
2019
1470
|
}
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
1471
|
+
}));
|
|
1472
|
+
const loaderPromise = route.options.loader?.({
|
|
1473
|
+
params: match.params,
|
|
1474
|
+
preload: !!opts?.preload,
|
|
1475
|
+
parentMatchPromise,
|
|
1476
|
+
abortController: match.abortController,
|
|
1477
|
+
context: match.context
|
|
1478
|
+
});
|
|
1479
|
+
const [_, loader] = await Promise.all([componentsPromise, loaderPromise]);
|
|
1480
|
+
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1481
|
+
this.setRouteMatchData(match.id, () => loader, opts);
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1484
|
+
if (handleIfRedirect(error)) return;
|
|
1485
|
+
try {
|
|
1486
|
+
route.options.onError?.(error);
|
|
1487
|
+
} catch (onErrorError) {
|
|
1488
|
+
error = onErrorError;
|
|
1489
|
+
if (handleIfRedirect(onErrorError)) return;
|
|
2026
1490
|
}
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
1491
|
+
this.setRouteMatch(match.id, s => ({
|
|
1492
|
+
...s,
|
|
1493
|
+
error,
|
|
1494
|
+
status: 'error',
|
|
1495
|
+
isFetching: false,
|
|
1496
|
+
updatedAt: Date.now()
|
|
1497
|
+
}));
|
|
1498
|
+
}
|
|
2031
1499
|
};
|
|
1500
|
+
let loadPromise;
|
|
1501
|
+
this.__store.batch(() => {
|
|
1502
|
+
this.setRouteMatch(match.id, s => ({
|
|
1503
|
+
...s,
|
|
1504
|
+
// status: s.status !== 'success' ? 'pending' : s.status,
|
|
1505
|
+
isFetching: true,
|
|
1506
|
+
fetchedAt,
|
|
1507
|
+
invalid: false
|
|
1508
|
+
}));
|
|
1509
|
+
loadPromise = load();
|
|
1510
|
+
this.setRouteMatch(match.id, s => ({
|
|
1511
|
+
...s,
|
|
1512
|
+
loadPromise
|
|
1513
|
+
}));
|
|
1514
|
+
});
|
|
1515
|
+
await loadPromise;
|
|
1516
|
+
})());
|
|
1517
|
+
});
|
|
1518
|
+
await Promise.all(matchPromises);
|
|
1519
|
+
};
|
|
1520
|
+
resolvePath = (from, path) => {
|
|
1521
|
+
return resolvePath(this.basepath, from, cleanPath(path));
|
|
1522
|
+
};
|
|
1523
|
+
navigate = async ({
|
|
1524
|
+
from,
|
|
1525
|
+
to = '',
|
|
1526
|
+
...rest
|
|
1527
|
+
}) => {
|
|
1528
|
+
// If this link simply reloads the current route,
|
|
1529
|
+
// make sure it has a new key so it will trigger a data refresh
|
|
1530
|
+
|
|
1531
|
+
// If this `to` is a valid external URL, return
|
|
1532
|
+
// null for LinkUtils
|
|
1533
|
+
const toString = String(to);
|
|
1534
|
+
const fromString = typeof from === 'undefined' ? from : String(from);
|
|
1535
|
+
let isExternal;
|
|
1536
|
+
try {
|
|
1537
|
+
new URL(`${toString}`);
|
|
1538
|
+
isExternal = true;
|
|
1539
|
+
} catch (e) {}
|
|
1540
|
+
invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
|
|
1541
|
+
return this.#buildAndCommitLocation({
|
|
1542
|
+
...rest,
|
|
1543
|
+
from: fromString,
|
|
1544
|
+
to: toString
|
|
1545
|
+
});
|
|
1546
|
+
};
|
|
1547
|
+
matchRoute = (location, opts) => {
|
|
1548
|
+
location = {
|
|
1549
|
+
...location,
|
|
1550
|
+
to: location.to ? this.resolvePath(location.from ?? '', location.to) : undefined
|
|
1551
|
+
};
|
|
1552
|
+
const next = this.buildLocation(location);
|
|
1553
|
+
if (opts?.pending && this.state.status !== 'pending') {
|
|
1554
|
+
return false;
|
|
1555
|
+
}
|
|
1556
|
+
const baseLocation = opts?.pending ? this.state.location : this.state.resolvedLocation;
|
|
1557
|
+
if (!baseLocation) {
|
|
1558
|
+
return false;
|
|
1559
|
+
}
|
|
1560
|
+
const match = matchPathname(this.basepath, baseLocation.pathname, {
|
|
1561
|
+
...opts,
|
|
1562
|
+
to: next.pathname
|
|
1563
|
+
});
|
|
1564
|
+
if (!match) {
|
|
1565
|
+
return false;
|
|
1566
|
+
}
|
|
1567
|
+
if (opts?.includeSearch ?? true) {
|
|
1568
|
+
return partialDeepEqual(baseLocation.search, next.search) ? match : false;
|
|
1569
|
+
}
|
|
1570
|
+
return match;
|
|
1571
|
+
};
|
|
1572
|
+
buildLink = dest => {
|
|
1573
|
+
// If this link simply reloads the current route,
|
|
1574
|
+
// make sure it has a new key so it will trigger a data refresh
|
|
1575
|
+
|
|
1576
|
+
// If this `to` is a valid external URL, return
|
|
1577
|
+
// null for LinkUtils
|
|
1578
|
+
|
|
1579
|
+
const {
|
|
1580
|
+
to,
|
|
1581
|
+
preload: userPreload,
|
|
1582
|
+
preloadDelay: userPreloadDelay,
|
|
1583
|
+
activeOptions,
|
|
1584
|
+
disabled,
|
|
1585
|
+
target,
|
|
1586
|
+
replace,
|
|
1587
|
+
resetScroll
|
|
1588
|
+
} = dest;
|
|
1589
|
+
try {
|
|
1590
|
+
new URL(`${to}`);
|
|
1591
|
+
return {
|
|
1592
|
+
type: 'external',
|
|
1593
|
+
href: to
|
|
1594
|
+
};
|
|
1595
|
+
} catch (e) {}
|
|
1596
|
+
const nextOpts = dest;
|
|
1597
|
+
const next = this.buildLocation(nextOpts);
|
|
1598
|
+
const preload = userPreload ?? this.options.defaultPreload;
|
|
1599
|
+
const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
|
|
1600
|
+
|
|
1601
|
+
// Compare path/hash for matches
|
|
1602
|
+
const currentPathSplit = this.state.location.pathname.split('/');
|
|
1603
|
+
const nextPathSplit = next.pathname.split('/');
|
|
1604
|
+
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1605
|
+
// Combine the matches based on user options
|
|
1606
|
+
const pathTest = activeOptions?.exact ? this.state.location.pathname === next.pathname : pathIsFuzzyEqual;
|
|
1607
|
+
const hashTest = activeOptions?.includeHash ? this.state.location.hash === next.hash : true;
|
|
1608
|
+
const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(this.state.location.search, next.search) : true;
|
|
1609
|
+
|
|
1610
|
+
// The final "active" test
|
|
1611
|
+
const isActive = pathTest && hashTest && searchTest;
|
|
1612
|
+
|
|
1613
|
+
// The click handler
|
|
1614
|
+
const handleClick = e => {
|
|
1615
|
+
if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
|
|
1616
|
+
e.preventDefault();
|
|
1617
|
+
|
|
1618
|
+
// All is well? Navigate!
|
|
1619
|
+
this.#commitLocation({
|
|
1620
|
+
...next,
|
|
1621
|
+
replace,
|
|
1622
|
+
resetScroll
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
};
|
|
2032
1626
|
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
1627
|
+
// The click handler
|
|
1628
|
+
const handleFocus = e => {
|
|
1629
|
+
if (preload) {
|
|
1630
|
+
this.preloadRoute(nextOpts).catch(err => {
|
|
1631
|
+
console.warn(err);
|
|
1632
|
+
console.warn(preloadWarning);
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
};
|
|
1636
|
+
const handleTouchStart = e => {
|
|
1637
|
+
this.preloadRoute(nextOpts).catch(err => {
|
|
1638
|
+
console.warn(err);
|
|
1639
|
+
console.warn(preloadWarning);
|
|
1640
|
+
});
|
|
1641
|
+
};
|
|
1642
|
+
const handleEnter = e => {
|
|
1643
|
+
const target = e.target || {};
|
|
1644
|
+
if (preload) {
|
|
1645
|
+
if (target.preloadTimeout) {
|
|
2036
1646
|
return;
|
|
2037
1647
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
const matchId = interpolatePath(foundRoute.routeId, params, true);
|
|
2044
|
-
const match = existingMatches.find(d => d.matchId === matchId) || ((_router$matchCache$ma = router.matchCache[matchId]) == null ? void 0 : _router$matchCache$ma.match) || createRouteMatch(router, foundRoute, {
|
|
2045
|
-
matchId,
|
|
2046
|
-
params,
|
|
2047
|
-
pathname: joinPaths([pathname, interpolatedPath])
|
|
1648
|
+
target.preloadTimeout = setTimeout(() => {
|
|
1649
|
+
target.preloadTimeout = null;
|
|
1650
|
+
this.preloadRoute(nextOpts).catch(err => {
|
|
1651
|
+
console.warn(err);
|
|
1652
|
+
console.warn(preloadWarning);
|
|
2048
1653
|
});
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
1654
|
+
}, preloadDelay);
|
|
1655
|
+
}
|
|
1656
|
+
};
|
|
1657
|
+
const handleLeave = e => {
|
|
1658
|
+
const target = e.target || {};
|
|
1659
|
+
if (target.preloadTimeout) {
|
|
1660
|
+
clearTimeout(target.preloadTimeout);
|
|
1661
|
+
target.preloadTimeout = null;
|
|
1662
|
+
}
|
|
1663
|
+
};
|
|
1664
|
+
return {
|
|
1665
|
+
type: 'internal',
|
|
1666
|
+
next,
|
|
1667
|
+
handleFocus,
|
|
1668
|
+
handleClick,
|
|
1669
|
+
handleEnter,
|
|
1670
|
+
handleLeave,
|
|
1671
|
+
handleTouchStart,
|
|
1672
|
+
isActive,
|
|
1673
|
+
disabled
|
|
1674
|
+
};
|
|
1675
|
+
};
|
|
1676
|
+
dehydrate = () => {
|
|
1677
|
+
return {
|
|
1678
|
+
state: {
|
|
1679
|
+
matchIds: this.state.matchIds,
|
|
1680
|
+
dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'preloadMaxAge', 'maxAge', 'id', 'loaderData', 'status', 'updatedAt']))
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
};
|
|
1684
|
+
hydrate = async __do_not_use_server_ctx => {
|
|
1685
|
+
let _ctx = __do_not_use_server_ctx;
|
|
1686
|
+
// Client hydrates from window
|
|
1687
|
+
if (typeof document !== 'undefined') {
|
|
1688
|
+
_ctx = window.__TSR_DEHYDRATED__;
|
|
1689
|
+
}
|
|
1690
|
+
invariant(_ctx, 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?');
|
|
1691
|
+
const ctx = _ctx;
|
|
1692
|
+
this.dehydratedData = ctx.payload;
|
|
1693
|
+
this.options.hydrate?.(ctx.payload);
|
|
1694
|
+
const dehydratedState = ctx.router.state;
|
|
1695
|
+
let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
|
|
1696
|
+
const dehydratedMatch = dehydratedState.dehydratedMatches.find(d => d.id === match.id);
|
|
1697
|
+
invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
|
|
1698
|
+
if (dehydratedMatch) {
|
|
1699
|
+
return {
|
|
1700
|
+
...match,
|
|
1701
|
+
...dehydratedMatch
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
return match;
|
|
1705
|
+
});
|
|
1706
|
+
this.__store.setState(s => {
|
|
1707
|
+
return {
|
|
1708
|
+
...s,
|
|
1709
|
+
matchIds: dehydratedState.matchIds,
|
|
1710
|
+
matches,
|
|
1711
|
+
matchesById: this.#mergeMatches(s.matchesById, matches)
|
|
2056
1712
|
};
|
|
1713
|
+
});
|
|
1714
|
+
};
|
|
1715
|
+
injectedHtml = [];
|
|
1716
|
+
injectHtml = async html => {
|
|
1717
|
+
this.injectedHtml.push(html);
|
|
1718
|
+
};
|
|
1719
|
+
dehydrateData = (key, getData) => {
|
|
1720
|
+
if (typeof document === 'undefined') {
|
|
1721
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
1722
|
+
this.injectHtml(async () => {
|
|
1723
|
+
const id = `__TSR_DEHYDRATED__${strKey}`;
|
|
1724
|
+
const data = typeof getData === 'function' ? await getData() : getData;
|
|
1725
|
+
return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
|
|
1726
|
+
;(() => {
|
|
1727
|
+
var el = document.getElementById('${id}')
|
|
1728
|
+
el.parentElement.removeChild(el)
|
|
1729
|
+
})()
|
|
1730
|
+
</script>`;
|
|
1731
|
+
});
|
|
1732
|
+
return () => this.hydrateData(key);
|
|
1733
|
+
}
|
|
1734
|
+
return () => undefined;
|
|
1735
|
+
};
|
|
1736
|
+
hydrateData = key => {
|
|
1737
|
+
if (typeof document !== 'undefined') {
|
|
1738
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
1739
|
+
return window[`__TSR_DEHYDRATED__${strKey}`];
|
|
1740
|
+
}
|
|
1741
|
+
return undefined;
|
|
1742
|
+
};
|
|
2057
1743
|
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
const matchPromises = resolvedMatches.map(async match => {
|
|
2064
|
-
// Validate the match (loads search params etc)
|
|
2065
|
-
match.__.validate();
|
|
2066
|
-
|
|
2067
|
-
match.load(loaderOpts);
|
|
2068
|
-
|
|
2069
|
-
if (match.status === 'loading') {
|
|
2070
|
-
// If requested, start the pending timers
|
|
2071
|
-
if (loaderOpts != null && loaderOpts.withPending) match.__.startPending(); // Wait for the first sign of activity from the match
|
|
2072
|
-
// This might be completion, error, or a pending state
|
|
1744
|
+
// resolveMatchPromise = (matchId: string, key: string, value: any) => {
|
|
1745
|
+
// this.state.matches
|
|
1746
|
+
// .find((d) => d.id === matchId)
|
|
1747
|
+
// ?.__promisesByKey[key]?.resolve(value)
|
|
1748
|
+
// }
|
|
2073
1749
|
|
|
2074
|
-
|
|
1750
|
+
#processRoutes = routeTree => {
|
|
1751
|
+
this.routeTree = routeTree;
|
|
1752
|
+
this.routesById = {};
|
|
1753
|
+
this.routesByPath = {};
|
|
1754
|
+
this.flatRoutes = [];
|
|
1755
|
+
const recurseRoutes = routes => {
|
|
1756
|
+
routes.forEach((route, i) => {
|
|
1757
|
+
route.init({
|
|
1758
|
+
originalIndex: i,
|
|
1759
|
+
router: this
|
|
1760
|
+
});
|
|
1761
|
+
const existingRoute = this.routesById[route.id];
|
|
1762
|
+
invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
|
|
1763
|
+
this.routesById[route.id] = route;
|
|
1764
|
+
if (!route.isRoot && route.path) {
|
|
1765
|
+
const trimmedFullPath = trimPathRight(route.fullPath);
|
|
1766
|
+
if (!this.routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
|
|
1767
|
+
this.routesByPath[trimmedFullPath] = route;
|
|
1768
|
+
}
|
|
2075
1769
|
}
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
},
|
|
2080
|
-
invalidateRoute: opts => {
|
|
2081
|
-
var _router$state$pending5, _router$state$pending6;
|
|
2082
|
-
|
|
2083
|
-
const next = router.buildNext(opts);
|
|
2084
|
-
const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
|
|
2085
|
-
[...router.state.matches, ...((_router$state$pending5 = (_router$state$pending6 = router.state.pending) == null ? void 0 : _router$state$pending6.matches) != null ? _router$state$pending5 : [])].forEach(match => {
|
|
2086
|
-
if (unloadedMatchIds.includes(match.matchId)) {
|
|
2087
|
-
match.invalidate();
|
|
1770
|
+
const children = route.children;
|
|
1771
|
+
if (children?.length) {
|
|
1772
|
+
recurseRoutes(children);
|
|
2088
1773
|
}
|
|
2089
1774
|
});
|
|
2090
|
-
}
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
1775
|
+
};
|
|
1776
|
+
recurseRoutes([routeTree]);
|
|
1777
|
+
this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
|
|
1778
|
+
const trimmed = trimPath(d.fullPath);
|
|
1779
|
+
const parsed = parsePathname(trimmed);
|
|
1780
|
+
while (parsed.length > 1 && parsed[0]?.value === '/') {
|
|
1781
|
+
parsed.shift();
|
|
1782
|
+
}
|
|
1783
|
+
const score = parsed.map(d => {
|
|
1784
|
+
if (d.type === 'param') {
|
|
1785
|
+
return 0.5;
|
|
1786
|
+
}
|
|
1787
|
+
if (d.type === 'wildcard') {
|
|
1788
|
+
return 0.25;
|
|
1789
|
+
}
|
|
1790
|
+
return 1;
|
|
2105
1791
|
});
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
1792
|
+
return {
|
|
1793
|
+
child: d,
|
|
1794
|
+
trimmed,
|
|
1795
|
+
parsed,
|
|
1796
|
+
index: i,
|
|
1797
|
+
score
|
|
1798
|
+
};
|
|
1799
|
+
}).sort((a, b) => {
|
|
1800
|
+
let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
|
|
1801
|
+
if (isIndex !== 0) return isIndex;
|
|
1802
|
+
const length = Math.min(a.score.length, b.score.length);
|
|
1803
|
+
|
|
1804
|
+
// Sort by length of score
|
|
1805
|
+
if (a.score.length !== b.score.length) {
|
|
1806
|
+
return b.score.length - a.score.length;
|
|
1807
|
+
}
|
|
2110
1808
|
|
|
2111
|
-
|
|
2112
|
-
|
|
1809
|
+
// Sort by min available score
|
|
1810
|
+
for (let i = 0; i < length; i++) {
|
|
1811
|
+
if (a.score[i] !== b.score[i]) {
|
|
1812
|
+
return b.score[i] - a.score[i];
|
|
2113
1813
|
}
|
|
2114
|
-
|
|
2115
|
-
return !!matchPathname(router.state.pending.location.pathname, _extends({}, opts, {
|
|
2116
|
-
to: next.pathname
|
|
2117
|
-
}));
|
|
2118
1814
|
}
|
|
2119
1815
|
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
from,
|
|
2127
|
-
to = '.',
|
|
2128
|
-
search,
|
|
2129
|
-
hash,
|
|
2130
|
-
replace,
|
|
2131
|
-
params
|
|
2132
|
-
} = _ref8;
|
|
2133
|
-
// If this link simply reloads the current route,
|
|
2134
|
-
// make sure it has a new key so it will trigger a data refresh
|
|
2135
|
-
// If this `to` is a valid external URL, return
|
|
2136
|
-
// null for LinkUtils
|
|
2137
|
-
const toString = String(to);
|
|
2138
|
-
const fromString = String(from);
|
|
2139
|
-
let isExternal;
|
|
2140
|
-
|
|
2141
|
-
try {
|
|
2142
|
-
new URL("" + toString);
|
|
2143
|
-
isExternal = true;
|
|
2144
|
-
} catch (e) {}
|
|
2145
|
-
|
|
2146
|
-
invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
|
|
2147
|
-
return router.__.navigate({
|
|
2148
|
-
from: fromString,
|
|
2149
|
-
to: toString,
|
|
2150
|
-
search,
|
|
2151
|
-
hash,
|
|
2152
|
-
replace,
|
|
2153
|
-
params
|
|
2154
|
-
});
|
|
2155
|
-
},
|
|
2156
|
-
buildLink: _ref9 => {
|
|
2157
|
-
var _preload, _ref10;
|
|
1816
|
+
// Sort by min available parsed value
|
|
1817
|
+
for (let i = 0; i < length; i++) {
|
|
1818
|
+
if (a.parsed[i].value !== b.parsed[i].value) {
|
|
1819
|
+
return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
2158
1822
|
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
params,
|
|
2164
|
-
hash,
|
|
2165
|
-
target,
|
|
2166
|
-
replace,
|
|
2167
|
-
activeOptions,
|
|
2168
|
-
preload,
|
|
2169
|
-
preloadMaxAge: userPreloadMaxAge,
|
|
2170
|
-
preloadGcMaxAge: userPreloadGcMaxAge,
|
|
2171
|
-
preloadDelay: userPreloadDelay,
|
|
2172
|
-
disabled
|
|
2173
|
-
} = _ref9;
|
|
2174
|
-
|
|
2175
|
-
// If this link simply reloads the current route,
|
|
2176
|
-
// make sure it has a new key so it will trigger a data refresh
|
|
2177
|
-
// If this `to` is a valid external URL, return
|
|
2178
|
-
// null for LinkUtils
|
|
2179
|
-
try {
|
|
2180
|
-
new URL("" + to);
|
|
2181
|
-
return {
|
|
2182
|
-
type: 'external',
|
|
2183
|
-
href: to
|
|
2184
|
-
};
|
|
2185
|
-
} catch (e) {}
|
|
1823
|
+
// Sort by length of trimmed full path
|
|
1824
|
+
if (a.trimmed !== b.trimmed) {
|
|
1825
|
+
return a.trimmed > b.trimmed ? 1 : -1;
|
|
1826
|
+
}
|
|
2186
1827
|
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
1828
|
+
// Sort by original index
|
|
1829
|
+
return a.index - b.index;
|
|
1830
|
+
}).map((d, i) => {
|
|
1831
|
+
d.child.rank = i;
|
|
1832
|
+
return d.child;
|
|
1833
|
+
});
|
|
1834
|
+
};
|
|
1835
|
+
#parseLocation = previousLocation => {
|
|
1836
|
+
const parse = ({
|
|
1837
|
+
pathname,
|
|
1838
|
+
search,
|
|
1839
|
+
hash,
|
|
1840
|
+
state
|
|
1841
|
+
}) => {
|
|
1842
|
+
const parsedSearch = this.options.parseSearch(search);
|
|
1843
|
+
return {
|
|
1844
|
+
pathname: pathname,
|
|
1845
|
+
searchStr: search,
|
|
1846
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
1847
|
+
hash: hash.split('#').reverse()[0] ?? '',
|
|
1848
|
+
href: `${pathname}${search}${hash}`,
|
|
1849
|
+
state: replaceEqualDeep(previousLocation?.state, state)
|
|
1850
|
+
};
|
|
1851
|
+
};
|
|
1852
|
+
const location = parse(this.history.location);
|
|
1853
|
+
let {
|
|
1854
|
+
__tempLocation,
|
|
1855
|
+
__tempKey
|
|
1856
|
+
} = location.state;
|
|
1857
|
+
if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
|
|
1858
|
+
// Sync up the location keys
|
|
1859
|
+
const parsedTempLocation = parse(__tempLocation);
|
|
1860
|
+
parsedTempLocation.state.key = location.state.key;
|
|
1861
|
+
delete parsedTempLocation.state.__tempLocation;
|
|
1862
|
+
return {
|
|
1863
|
+
...parsedTempLocation,
|
|
1864
|
+
maskedLocation: location
|
|
1865
|
+
};
|
|
1866
|
+
}
|
|
1867
|
+
return location;
|
|
1868
|
+
};
|
|
1869
|
+
buildLocation = (opts = {}) => {
|
|
1870
|
+
const build = (dest = {}, matches) => {
|
|
1871
|
+
const from = this.state.location;
|
|
1872
|
+
const fromPathname = dest.from ?? from.pathname;
|
|
1873
|
+
let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? ''}`);
|
|
1874
|
+
const fromMatches = this.matchRoutes(fromPathname, from.search);
|
|
1875
|
+
const prevParams = {
|
|
1876
|
+
...last(fromMatches)?.params
|
|
1877
|
+
};
|
|
1878
|
+
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
1879
|
+
if (nextParams) {
|
|
1880
|
+
matches?.map(d => this.getRoute(d.routeId).options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
1881
|
+
nextParams = {
|
|
1882
|
+
...nextParams,
|
|
1883
|
+
...fn(nextParams)
|
|
1884
|
+
};
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
1888
|
+
const preSearchFilters = matches?.map(match => this.getRoute(match.routeId).options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1889
|
+
const postSearchFilters = matches?.map(match => this.getRoute(match.routeId).options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1890
|
+
|
|
1891
|
+
// Pre filters first
|
|
1892
|
+
const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
|
|
1893
|
+
|
|
1894
|
+
// Then the link/navigate function
|
|
1895
|
+
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
1896
|
+
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
1897
|
+
: preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
1898
|
+
: {};
|
|
1899
|
+
|
|
1900
|
+
// Then post filters
|
|
1901
|
+
const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1902
|
+
const search = replaceEqualDeep(from.search, postFilteredSearch);
|
|
1903
|
+
const searchStr = this.options.stringifySearch(search);
|
|
1904
|
+
const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
|
|
1905
|
+
const hashStr = hash ? `#${hash}` : '';
|
|
1906
|
+
let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
|
|
1907
|
+
nextState = replaceEqualDeep(from.state, nextState);
|
|
1908
|
+
return {
|
|
1909
|
+
pathname,
|
|
2190
1910
|
search,
|
|
2191
|
-
|
|
1911
|
+
searchStr,
|
|
1912
|
+
state: nextState,
|
|
2192
1913
|
hash,
|
|
2193
|
-
|
|
1914
|
+
href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
|
|
1915
|
+
unmaskOnReload: dest.unmaskOnReload
|
|
2194
1916
|
};
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
|
|
2206
|
-
const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true; // The final "active" test
|
|
2207
|
-
|
|
2208
|
-
const isActive = pathTest && hashTest; // The click handler
|
|
2209
|
-
|
|
2210
|
-
const handleClick = e => {
|
|
2211
|
-
if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
|
|
2212
|
-
e.preventDefault();
|
|
2213
|
-
|
|
2214
|
-
if (pathIsEqual && !search && !hash) {
|
|
2215
|
-
router.invalidateRoute(nextOpts);
|
|
2216
|
-
} // All is well? Navigate!)
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
router.__.navigate(nextOpts);
|
|
2220
|
-
}
|
|
2221
|
-
}; // The click handler
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
const handleFocus = e => {
|
|
2225
|
-
if (preload) {
|
|
2226
|
-
router.preloadRoute(nextOpts, {
|
|
2227
|
-
maxAge: userPreloadMaxAge,
|
|
2228
|
-
gcMaxAge: userPreloadGcMaxAge
|
|
1917
|
+
};
|
|
1918
|
+
const buildWithMatches = (dest = {}, maskedDest) => {
|
|
1919
|
+
let next = build(dest);
|
|
1920
|
+
let maskedNext = maskedDest ? build(maskedDest) : undefined;
|
|
1921
|
+
if (!maskedNext) {
|
|
1922
|
+
let params = {};
|
|
1923
|
+
let foundMask = this.options.routeMasks?.find(d => {
|
|
1924
|
+
const match = matchPathname(this.basepath, next.pathname, {
|
|
1925
|
+
to: d.from,
|
|
1926
|
+
fuzzy: false
|
|
2229
1927
|
});
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
const handleEnter = e => {
|
|
2234
|
-
const target = e.target || {};
|
|
2235
|
-
|
|
2236
|
-
if (preload) {
|
|
2237
|
-
if (target.preloadTimeout) {
|
|
2238
|
-
return;
|
|
1928
|
+
if (match) {
|
|
1929
|
+
params = match;
|
|
1930
|
+
return true;
|
|
2239
1931
|
}
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
1932
|
+
return false;
|
|
1933
|
+
});
|
|
1934
|
+
if (foundMask) {
|
|
1935
|
+
foundMask = {
|
|
1936
|
+
...foundMask,
|
|
1937
|
+
from: interpolatePath(foundMask.from, params)
|
|
1938
|
+
};
|
|
1939
|
+
maskedDest = foundMask;
|
|
1940
|
+
maskedNext = build(maskedDest);
|
|
2248
1941
|
}
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
|
-
const
|
|
2252
|
-
|
|
1942
|
+
}
|
|
1943
|
+
const nextMatches = this.matchRoutes(next.pathname, next.search);
|
|
1944
|
+
const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
|
|
1945
|
+
const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
|
|
1946
|
+
const final = build(dest, nextMatches);
|
|
1947
|
+
if (maskedFinal) {
|
|
1948
|
+
final.maskedLocation = maskedFinal;
|
|
1949
|
+
}
|
|
1950
|
+
return final;
|
|
1951
|
+
};
|
|
1952
|
+
if (opts.mask) {
|
|
1953
|
+
return buildWithMatches(opts, {
|
|
1954
|
+
...pick(opts, ['from']),
|
|
1955
|
+
...opts.mask
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
return buildWithMatches(opts);
|
|
1959
|
+
};
|
|
1960
|
+
#buildAndCommitLocation = ({
|
|
1961
|
+
replace,
|
|
1962
|
+
resetScroll,
|
|
1963
|
+
...rest
|
|
1964
|
+
} = {}) => {
|
|
1965
|
+
const location = this.buildLocation(rest);
|
|
1966
|
+
return this.#commitLocation({
|
|
1967
|
+
...location,
|
|
1968
|
+
replace,
|
|
1969
|
+
resetScroll
|
|
1970
|
+
});
|
|
1971
|
+
};
|
|
1972
|
+
#commitLocation = async next => {
|
|
1973
|
+
if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
|
|
1974
|
+
const isSameUrl = this.state.location.href === next.href;
|
|
2253
1975
|
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
1976
|
+
// If the next urls are the same and we're not replacing,
|
|
1977
|
+
// do nothing
|
|
1978
|
+
if (isSameUrl && !next.replace) {
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
let {
|
|
1982
|
+
maskedLocation,
|
|
1983
|
+
...nextHistory
|
|
1984
|
+
} = next;
|
|
1985
|
+
if (maskedLocation) {
|
|
1986
|
+
nextHistory = {
|
|
1987
|
+
...maskedLocation,
|
|
1988
|
+
state: {
|
|
1989
|
+
...maskedLocation.state,
|
|
1990
|
+
__tempKey: undefined,
|
|
1991
|
+
__tempLocation: {
|
|
1992
|
+
...nextHistory,
|
|
1993
|
+
search: nextHistory.searchStr,
|
|
1994
|
+
state: {
|
|
1995
|
+
...nextHistory.state,
|
|
1996
|
+
__tempKey: undefined,
|
|
1997
|
+
__tempLocation: undefined,
|
|
1998
|
+
key: undefined
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2257
2001
|
}
|
|
2258
2002
|
};
|
|
2259
|
-
|
|
2003
|
+
if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
|
|
2004
|
+
nextHistory.state.__tempKey = this.tempLocationKey;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
|
|
2008
|
+
this.resetNextScroll = next.resetScroll ?? true;
|
|
2009
|
+
return this.latestLoadPromise;
|
|
2010
|
+
};
|
|
2011
|
+
getRouteMatch = id => {
|
|
2012
|
+
return this.state.matchesById[id];
|
|
2013
|
+
};
|
|
2014
|
+
setRouteMatch = (id, updater) => {
|
|
2015
|
+
this.__store.setState(prev => {
|
|
2016
|
+
if (!prev.matchesById[id]) {
|
|
2017
|
+
return prev;
|
|
2018
|
+
}
|
|
2260
2019
|
return {
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
handleLeave,
|
|
2267
|
-
isActive,
|
|
2268
|
-
disabled
|
|
2020
|
+
...prev,
|
|
2021
|
+
matchesById: {
|
|
2022
|
+
...prev.matchesById,
|
|
2023
|
+
[id]: updater(prev.matchesById[id])
|
|
2024
|
+
}
|
|
2269
2025
|
};
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2026
|
+
});
|
|
2027
|
+
};
|
|
2028
|
+
setRouteMatchData = (id, updater, opts) => {
|
|
2029
|
+
const match = this.getRouteMatch(id);
|
|
2030
|
+
if (!match) return;
|
|
2031
|
+
const route = this.getRoute(match.routeId);
|
|
2032
|
+
const updatedAt = opts?.updatedAt ?? Date.now();
|
|
2033
|
+
const preloadMaxAge = opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000;
|
|
2034
|
+
const maxAge = opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? -1;
|
|
2035
|
+
this.setRouteMatch(id, s => ({
|
|
2036
|
+
...s,
|
|
2037
|
+
error: undefined,
|
|
2038
|
+
status: 'success',
|
|
2039
|
+
isFetching: false,
|
|
2040
|
+
updatedAt: updatedAt,
|
|
2041
|
+
loaderData: functionalUpdate(updater, s.loaderData),
|
|
2042
|
+
preloadMaxAge,
|
|
2043
|
+
maxAge
|
|
2044
|
+
}));
|
|
2045
|
+
};
|
|
2046
|
+
invalidate = async opts => {
|
|
2047
|
+
if (opts?.matchId) {
|
|
2048
|
+
this.setRouteMatch(opts.matchId, s => ({
|
|
2049
|
+
...s,
|
|
2050
|
+
invalid: true
|
|
2291
2051
|
}));
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
// pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
|
|
2300
|
-
// pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
|
|
2301
|
-
// }
|
|
2302
|
-
|
|
2303
|
-
const existingRoute = router.routesById[route.routeId];
|
|
2304
|
-
|
|
2305
|
-
if (existingRoute) {
|
|
2306
|
-
{
|
|
2307
|
-
console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
|
|
2308
|
-
}
|
|
2309
|
-
|
|
2310
|
-
throw new Error();
|
|
2311
|
-
}
|
|
2312
|
-
router.routesById[route.routeId] = route;
|
|
2313
|
-
const children = routeConfig.children;
|
|
2314
|
-
route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
|
|
2315
|
-
return route;
|
|
2316
|
-
});
|
|
2317
|
-
};
|
|
2318
|
-
|
|
2319
|
-
const routes = recurseRoutes([rootRouteConfig]);
|
|
2320
|
-
return routes[0];
|
|
2321
|
-
},
|
|
2322
|
-
parseLocation: (location, previousLocation) => {
|
|
2323
|
-
var _location$hash$split$;
|
|
2324
|
-
|
|
2325
|
-
const parsedSearch = router.options.parseSearch(location.search);
|
|
2326
|
-
return {
|
|
2327
|
-
pathname: location.pathname,
|
|
2328
|
-
searchStr: location.search,
|
|
2329
|
-
search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
|
|
2330
|
-
hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
|
|
2331
|
-
href: "" + location.pathname + location.search + location.hash,
|
|
2332
|
-
state: location.state,
|
|
2333
|
-
key: location.key
|
|
2334
|
-
};
|
|
2335
|
-
},
|
|
2336
|
-
navigate: location => {
|
|
2337
|
-
const next = router.buildNext(location);
|
|
2338
|
-
return router.__.commitLocation(next, location.replace);
|
|
2339
|
-
},
|
|
2340
|
-
buildLocation: function buildLocation(dest) {
|
|
2341
|
-
var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
|
|
2342
|
-
|
|
2343
|
-
if (dest === void 0) {
|
|
2344
|
-
dest = {};
|
|
2345
|
-
}
|
|
2346
|
-
|
|
2347
|
-
// const resolvedFrom: Location = {
|
|
2348
|
-
// ...router.location,
|
|
2349
|
-
const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
|
|
2350
|
-
|
|
2351
|
-
let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
|
|
2352
|
-
|
|
2353
|
-
const fromMatches = router.matchRoutes(router.location.pathname, {
|
|
2354
|
-
strictParseParams: true
|
|
2052
|
+
const matchIndex = this.state.matches.findIndex(d => d.id === opts.matchId);
|
|
2053
|
+
const childMatch = this.state.matches[matchIndex + 1];
|
|
2054
|
+
if (childMatch) {
|
|
2055
|
+
return this.invalidate({
|
|
2056
|
+
matchId: childMatch.id,
|
|
2057
|
+
reload: false,
|
|
2058
|
+
__fromFocus: opts.__fromFocus
|
|
2355
2059
|
});
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2060
|
+
}
|
|
2061
|
+
} else {
|
|
2062
|
+
this.__store.batch(() => {
|
|
2063
|
+
Object.values(this.state.matchesById).forEach(match => {
|
|
2064
|
+
const route = this.getRoute(match.routeId);
|
|
2065
|
+
const shouldInvalidate = opts?.__fromFocus ? route.options.reloadOnWindowFocus ?? true : true;
|
|
2066
|
+
if (shouldInvalidate) {
|
|
2067
|
+
this.setRouteMatch(match.id, s => ({
|
|
2068
|
+
...s,
|
|
2069
|
+
invalid: true
|
|
2070
|
+
}));
|
|
2071
|
+
}
|
|
2072
|
+
});
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
if (opts?.reload ?? true) {
|
|
2076
|
+
return this.load();
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2369
2080
|
|
|
2370
|
-
|
|
2081
|
+
// Detect if we're in the DOM
|
|
2082
|
+
const isServer = typeof window === 'undefined' || !window.document.createElement;
|
|
2083
|
+
function getInitialRouterState() {
|
|
2084
|
+
return {
|
|
2085
|
+
status: 'idle',
|
|
2086
|
+
isFetching: false,
|
|
2087
|
+
resolvedLocation: null,
|
|
2088
|
+
location: null,
|
|
2089
|
+
matchesById: {},
|
|
2090
|
+
matchIds: [],
|
|
2091
|
+
pendingMatchIds: [],
|
|
2092
|
+
matches: [],
|
|
2093
|
+
pendingMatches: [],
|
|
2094
|
+
renderedMatchIds: [],
|
|
2095
|
+
renderedMatches: [],
|
|
2096
|
+
lastUpdated: Date.now()
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
function isCtrlEvent(e) {
|
|
2100
|
+
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
2101
|
+
}
|
|
2102
|
+
function redirect(opts) {
|
|
2103
|
+
opts.isRedirect = true;
|
|
2104
|
+
return opts;
|
|
2105
|
+
}
|
|
2106
|
+
function isRedirect(obj) {
|
|
2107
|
+
return !!obj?.isRedirect;
|
|
2108
|
+
}
|
|
2109
|
+
class SearchParamError extends Error {}
|
|
2110
|
+
class PathParamError extends Error {}
|
|
2111
|
+
function escapeJSON(jsonString) {
|
|
2112
|
+
return jsonString.replace(/\\/g, '\\\\') // Escape backslashes
|
|
2113
|
+
.replace(/'/g, "\\'") // Escape single quotes
|
|
2114
|
+
.replace(/"/g, '\\"'); // Escape double quotes
|
|
2115
|
+
}
|
|
2371
2116
|
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2117
|
+
// A function that takes an import() argument which is a function and returns a new function that will
|
|
2118
|
+
// proxy arguments from the caller to the imported function, retaining all type
|
|
2119
|
+
// information along the way
|
|
2120
|
+
function lazyFn(fn, key) {
|
|
2121
|
+
return async (...args) => {
|
|
2122
|
+
const imported = await fn();
|
|
2123
|
+
return imported[key || 'default'](...args);
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
function isMatchInvalid(match, opts) {
|
|
2127
|
+
const now = Date.now();
|
|
2128
|
+
if (match.invalid) {
|
|
2129
|
+
return true;
|
|
2130
|
+
}
|
|
2131
|
+
if (opts?.preload) {
|
|
2132
|
+
return match.preloadMaxAge < 0 ? false : match.updatedAt + match.preloadMaxAge < now;
|
|
2133
|
+
}
|
|
2134
|
+
return match.maxAge < 0 ? false : match.updatedAt + match.maxAge < now;
|
|
2135
|
+
}
|
|
2376
2136
|
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2137
|
+
const windowKey = 'window';
|
|
2138
|
+
const delimiter = '___';
|
|
2139
|
+
let weakScrolledElementsByRestoreKey = {};
|
|
2140
|
+
let cache;
|
|
2141
|
+
let pathDidChange = false;
|
|
2142
|
+
const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
|
|
2143
|
+
const defaultGetKey = location => location.state.key;
|
|
2144
|
+
function watchScrollPositions(router, opts) {
|
|
2145
|
+
const getKey = opts?.getKey || defaultGetKey;
|
|
2146
|
+
if (sessionsStorage) {
|
|
2147
|
+
if (!cache) {
|
|
2148
|
+
cache = (() => {
|
|
2149
|
+
const storageKey = 'tsr-scroll-restoration-v1';
|
|
2150
|
+
const current = JSON.parse(window.sessionStorage.getItem(storageKey) || '{}');
|
|
2382
2151
|
return {
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
href: "" + pathname + searchStr + hash,
|
|
2389
|
-
key: dest.key
|
|
2152
|
+
current,
|
|
2153
|
+
set: (key, value) => {
|
|
2154
|
+
current[key] = value;
|
|
2155
|
+
window.sessionStorage.setItem(storageKey, JSON.stringify(cache));
|
|
2156
|
+
}
|
|
2390
2157
|
};
|
|
2391
|
-
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2158
|
+
})();
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
const {
|
|
2162
|
+
history
|
|
2163
|
+
} = window;
|
|
2164
|
+
if (history.scrollRestoration) {
|
|
2165
|
+
history.scrollRestoration = 'manual';
|
|
2166
|
+
}
|
|
2167
|
+
const onScroll = event => {
|
|
2168
|
+
const restoreKey = getKey(router.state.resolvedLocation);
|
|
2169
|
+
if (!weakScrolledElementsByRestoreKey[restoreKey]) {
|
|
2170
|
+
weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet();
|
|
2171
|
+
}
|
|
2172
|
+
const set = weakScrolledElementsByRestoreKey[restoreKey];
|
|
2173
|
+
if (set.has(event.target)) return;
|
|
2174
|
+
set.add(event.target);
|
|
2175
|
+
const cacheKey = [restoreKey, event.target === document || event.target === window ? windowKey : getCssSelector(event.target)].join(delimiter);
|
|
2176
|
+
if (!cache.current[cacheKey]) {
|
|
2177
|
+
cache.set(cacheKey, {
|
|
2178
|
+
scrollX: NaN,
|
|
2179
|
+
scrollY: NaN
|
|
2180
|
+
});
|
|
2181
|
+
}
|
|
2182
|
+
};
|
|
2183
|
+
const getCssSelector = el => {
|
|
2184
|
+
let path = [],
|
|
2185
|
+
parent;
|
|
2186
|
+
while (parent = el.parentNode) {
|
|
2187
|
+
path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
|
|
2188
|
+
el = parent;
|
|
2189
|
+
}
|
|
2190
|
+
return `${path.join(' > ')}`.toLowerCase();
|
|
2191
|
+
};
|
|
2192
|
+
const onPathWillChange = from => {
|
|
2193
|
+
const restoreKey = getKey(from);
|
|
2194
|
+
for (const cacheKey in cache.current) {
|
|
2195
|
+
const entry = cache.current[cacheKey];
|
|
2196
|
+
const [key, elementSelector] = cacheKey.split(delimiter);
|
|
2197
|
+
if (restoreKey === key) {
|
|
2198
|
+
if (elementSelector === windowKey) {
|
|
2199
|
+
entry.scrollX = window.scrollX || 0;
|
|
2200
|
+
entry.scrollY = window.scrollY || 0;
|
|
2201
|
+
} else if (elementSelector) {
|
|
2202
|
+
const element = document.querySelector(elementSelector);
|
|
2203
|
+
entry.scrollX = element?.scrollLeft || 0;
|
|
2204
|
+
entry.scrollY = element?.scrollTop || 0;
|
|
2423
2205
|
}
|
|
2424
|
-
|
|
2425
|
-
router.navigationPromise = new Promise(resolve => {
|
|
2426
|
-
const previousNavigationResolve = router.resolveNavigation;
|
|
2427
|
-
|
|
2428
|
-
router.resolveNavigation = () => {
|
|
2429
|
-
previousNavigationResolve();
|
|
2430
|
-
resolve();
|
|
2431
|
-
};
|
|
2432
|
-
});
|
|
2433
|
-
return router.navigationPromise;
|
|
2206
|
+
cache.set(cacheKey, entry);
|
|
2434
2207
|
}
|
|
2435
2208
|
}
|
|
2436
2209
|
};
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2210
|
+
const onPathChange = () => {
|
|
2211
|
+
pathDidChange = true;
|
|
2212
|
+
};
|
|
2213
|
+
if (typeof document !== 'undefined') {
|
|
2214
|
+
document.addEventListener('scroll', onScroll, true);
|
|
2215
|
+
}
|
|
2216
|
+
const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
|
|
2217
|
+
if (event.pathChanged) onPathWillChange(event.from);
|
|
2218
|
+
});
|
|
2219
|
+
const unsubOnLoad = router.subscribe('onLoad', event => {
|
|
2220
|
+
if (event.pathChanged) onPathChange();
|
|
2221
|
+
});
|
|
2222
|
+
return () => {
|
|
2223
|
+
document.removeEventListener('scroll', onScroll);
|
|
2224
|
+
unsubOnBeforeLoad();
|
|
2225
|
+
unsubOnLoad();
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
function restoreScrollPositions(router, opts) {
|
|
2229
|
+
if (pathDidChange) {
|
|
2230
|
+
if (!router.resetNextScroll) {
|
|
2231
|
+
return;
|
|
2232
|
+
}
|
|
2233
|
+
const getKey = opts?.getKey || defaultGetKey;
|
|
2234
|
+
pathDidChange = false;
|
|
2235
|
+
const restoreKey = getKey(router.state.location);
|
|
2236
|
+
let windowRestored = false;
|
|
2237
|
+
for (const cacheKey in cache.current) {
|
|
2238
|
+
const entry = cache.current[cacheKey];
|
|
2239
|
+
const [key, elementSelector] = cacheKey.split(delimiter);
|
|
2240
|
+
if (key === restoreKey) {
|
|
2241
|
+
if (elementSelector === windowKey) {
|
|
2242
|
+
windowRestored = true;
|
|
2243
|
+
window.scrollTo(entry.scrollX, entry.scrollY);
|
|
2244
|
+
} else if (elementSelector) {
|
|
2245
|
+
const element = document.querySelector(elementSelector);
|
|
2246
|
+
if (element) {
|
|
2247
|
+
element.scrollLeft = entry.scrollX;
|
|
2248
|
+
element.scrollTop = entry.scrollY;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
if (!windowRestored) {
|
|
2254
|
+
window.scrollTo(0, 0);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2443
2257
|
}
|
|
2444
2258
|
|
|
2445
|
-
function
|
|
2446
|
-
|
|
2259
|
+
function defer(_promise) {
|
|
2260
|
+
const promise = _promise;
|
|
2261
|
+
if (!promise.__deferredState) {
|
|
2262
|
+
promise.__deferredState = {
|
|
2263
|
+
uid: Math.random().toString(36).slice(2),
|
|
2264
|
+
status: 'pending'
|
|
2265
|
+
};
|
|
2266
|
+
const state = promise.__deferredState;
|
|
2267
|
+
promise.then(data => {
|
|
2268
|
+
state.status = 'success';
|
|
2269
|
+
state.data = data;
|
|
2270
|
+
}).catch(error => {
|
|
2271
|
+
state.status = 'error';
|
|
2272
|
+
state.error = error;
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
return promise;
|
|
2276
|
+
}
|
|
2277
|
+
function isDehydratedDeferred(obj) {
|
|
2278
|
+
return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
|
|
2447
2279
|
}
|
|
2448
2280
|
|
|
2449
|
-
exports.
|
|
2281
|
+
exports.FileRoute = FileRoute;
|
|
2282
|
+
exports.PathParamError = PathParamError;
|
|
2283
|
+
exports.RootRoute = RootRoute;
|
|
2284
|
+
exports.Route = Route;
|
|
2285
|
+
exports.Router = Router;
|
|
2286
|
+
exports.RouterContext = RouterContext;
|
|
2287
|
+
exports.SearchParamError = SearchParamError;
|
|
2450
2288
|
exports.cleanPath = cleanPath;
|
|
2289
|
+
exports.componentTypes = componentTypes;
|
|
2451
2290
|
exports.createBrowserHistory = createBrowserHistory;
|
|
2452
2291
|
exports.createHashHistory = createHashHistory;
|
|
2453
2292
|
exports.createMemoryHistory = createMemoryHistory;
|
|
2454
|
-
exports.
|
|
2455
|
-
exports.createRouteConfig = createRouteConfig;
|
|
2456
|
-
exports.createRouteMatch = createRouteMatch;
|
|
2457
|
-
exports.createRouter = createRouter;
|
|
2293
|
+
exports.createRouteMask = createRouteMask;
|
|
2458
2294
|
exports.decode = decode;
|
|
2459
2295
|
exports.defaultParseSearch = defaultParseSearch;
|
|
2460
2296
|
exports.defaultStringifySearch = defaultStringifySearch;
|
|
2297
|
+
exports.defer = defer;
|
|
2461
2298
|
exports.encode = encode;
|
|
2462
2299
|
exports.functionalUpdate = functionalUpdate;
|
|
2463
2300
|
exports.interpolatePath = interpolatePath;
|
|
2464
2301
|
exports.invariant = invariant;
|
|
2302
|
+
exports.isDehydratedDeferred = isDehydratedDeferred;
|
|
2303
|
+
exports.isMatchInvalid = isMatchInvalid;
|
|
2304
|
+
exports.isPlainObject = isPlainObject;
|
|
2305
|
+
exports.isRedirect = isRedirect;
|
|
2465
2306
|
exports.joinPaths = joinPaths;
|
|
2466
2307
|
exports.last = last;
|
|
2308
|
+
exports.lazyFn = lazyFn;
|
|
2467
2309
|
exports.matchByPath = matchByPath;
|
|
2468
2310
|
exports.matchPathname = matchPathname;
|
|
2469
2311
|
exports.parsePathname = parsePathname;
|
|
2470
2312
|
exports.parseSearchWith = parseSearchWith;
|
|
2313
|
+
exports.partialDeepEqual = partialDeepEqual;
|
|
2314
|
+
exports.pick = pick;
|
|
2315
|
+
exports.redirect = redirect;
|
|
2471
2316
|
exports.replaceEqualDeep = replaceEqualDeep;
|
|
2472
2317
|
exports.resolvePath = resolvePath;
|
|
2318
|
+
exports.restoreScrollPositions = restoreScrollPositions;
|
|
2473
2319
|
exports.rootRouteId = rootRouteId;
|
|
2474
2320
|
exports.stringifySearchWith = stringifySearchWith;
|
|
2475
2321
|
exports.trimPath = trimPath;
|
|
2476
2322
|
exports.trimPathLeft = trimPathLeft;
|
|
2477
2323
|
exports.trimPathRight = trimPathRight;
|
|
2478
2324
|
exports.warning = warning;
|
|
2325
|
+
exports.watchScrollPositions = watchScrollPositions;
|
|
2479
2326
|
|
|
2480
2327
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2481
2328
|
|