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