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