@tanstack/react-router 0.0.1-beta.48 → 0.0.1-beta.49
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/build/cjs/index.js +121 -172
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/useStore.js +64 -0
- package/build/cjs/useStore.js.map +1 -0
- package/build/esm/index.js +167 -165
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +76 -102
- package/build/types/index.d.ts +21 -16
- package/build/umd/index.development.js +1542 -2549
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +3 -2
- package/build/umd/index.production.js.map +1 -1
- package/package.json +3 -3
- package/src/index.tsx +173 -200
- package/src/useStore.ts +70 -0
- package/src/uSES/useSyncExternalStore.ts +0 -16
- package/src/uSES/useSyncExternalStoreShim.ts +0 -20
- package/src/uSES/useSyncExternalStoreShimClient.ts +0 -87
- package/src/uSES/useSyncExternalStoreShimServer.ts +0 -20
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
(function (global, factory) {
|
|
12
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('use-sync-external-store/shim')) :
|
|
13
|
-
typeof define === 'function' && define.amd ? define(['exports', 'react', 'use-sync-external-store/shim'], factory) :
|
|
14
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React, global.
|
|
15
|
-
})(this, (function (exports, React,
|
|
12
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('use-sync-external-store/shim/with-selector')) :
|
|
13
|
+
typeof define === 'function' && define.amd ? define(['exports', 'react', 'use-sync-external-store/shim/with-selector'], factory) :
|
|
14
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React, global.withSelector));
|
|
15
|
+
})(this, (function (exports, React, withSelector) { 'use strict';
|
|
16
16
|
|
|
17
17
|
function _interopNamespace(e) {
|
|
18
18
|
if (e && e.__esModule) return e;
|
|
@@ -34,414 +34,6 @@
|
|
|
34
34
|
|
|
35
35
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
36
36
|
|
|
37
|
-
function _extends$1() {
|
|
38
|
-
_extends$1 = Object.assign ? Object.assign.bind() : function (target) {
|
|
39
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
40
|
-
var source = arguments[i];
|
|
41
|
-
for (var key in source) {
|
|
42
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
43
|
-
target[key] = source[key];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return target;
|
|
48
|
-
};
|
|
49
|
-
return _extends$1.apply(this, arguments);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/core.ts
|
|
53
|
-
var CurrentReaction = void 0;
|
|
54
|
-
var CurrentGets = null;
|
|
55
|
-
var CurrentGetsIndex = 0;
|
|
56
|
-
var EffectQueue = null;
|
|
57
|
-
var CacheClean = 0;
|
|
58
|
-
var CacheCheck = 1;
|
|
59
|
-
var CacheDirty = 2;
|
|
60
|
-
var Root;
|
|
61
|
-
var Reactive = class {
|
|
62
|
-
value;
|
|
63
|
-
fn;
|
|
64
|
-
observers = null;
|
|
65
|
-
sources = null;
|
|
66
|
-
state;
|
|
67
|
-
effect;
|
|
68
|
-
cleanups = null;
|
|
69
|
-
alwaysUpdate = false;
|
|
70
|
-
constructor(fnOrValue, type) {
|
|
71
|
-
if (type != 0 /* Signal */) {
|
|
72
|
-
this.fn = fnOrValue;
|
|
73
|
-
this.value = void 0;
|
|
74
|
-
this.state = CacheDirty;
|
|
75
|
-
if (Root)
|
|
76
|
-
Root.push(this);
|
|
77
|
-
else
|
|
78
|
-
console.error("Memos and effects must be wrapped in a createRoot");
|
|
79
|
-
this.effect = type == 2 /* Effect */;
|
|
80
|
-
if (this.effect)
|
|
81
|
-
this.update();
|
|
82
|
-
} else {
|
|
83
|
-
this.fn = void 0;
|
|
84
|
-
this.value = fnOrValue;
|
|
85
|
-
this.state = CacheClean;
|
|
86
|
-
this.effect = false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
get() {
|
|
90
|
-
if (CurrentReaction) {
|
|
91
|
-
if (!CurrentGets && CurrentReaction.sources && CurrentReaction.sources[CurrentGetsIndex] == this) {
|
|
92
|
-
CurrentGetsIndex++;
|
|
93
|
-
} else {
|
|
94
|
-
if (!CurrentGets)
|
|
95
|
-
CurrentGets = [this];
|
|
96
|
-
else
|
|
97
|
-
CurrentGets.push(this);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (this.fn)
|
|
101
|
-
this.updateIfNecessary();
|
|
102
|
-
return this.value;
|
|
103
|
-
}
|
|
104
|
-
set(value) {
|
|
105
|
-
const notInBatch = !EffectQueue;
|
|
106
|
-
const newValue = typeof value === "function" ? value(this.value) : value;
|
|
107
|
-
if ((this.value !== newValue || this.alwaysUpdate) && this.observers) {
|
|
108
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
109
|
-
this.observers[i].stale(CacheDirty);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
this.value = newValue;
|
|
113
|
-
if (notInBatch)
|
|
114
|
-
stabilize();
|
|
115
|
-
return newValue;
|
|
116
|
-
}
|
|
117
|
-
stale(state) {
|
|
118
|
-
if (this.state < state) {
|
|
119
|
-
if (this.state === CacheClean && this.effect) {
|
|
120
|
-
if (EffectQueue)
|
|
121
|
-
EffectQueue.push(this);
|
|
122
|
-
else
|
|
123
|
-
EffectQueue = [this];
|
|
124
|
-
}
|
|
125
|
-
this.state = state;
|
|
126
|
-
if (this.observers) {
|
|
127
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
128
|
-
this.observers[i].stale(CacheCheck);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
update() {
|
|
134
|
-
const oldValue = this.value;
|
|
135
|
-
const prevReaction = CurrentReaction;
|
|
136
|
-
const prevGets = CurrentGets;
|
|
137
|
-
const prevIndex = CurrentGetsIndex;
|
|
138
|
-
CurrentReaction = this;
|
|
139
|
-
CurrentGets = null;
|
|
140
|
-
CurrentGetsIndex = 0;
|
|
141
|
-
try {
|
|
142
|
-
if (this.cleanups) {
|
|
143
|
-
this.cleanups.forEach((c) => c());
|
|
144
|
-
this.cleanups = null;
|
|
145
|
-
}
|
|
146
|
-
this.value = this.fn();
|
|
147
|
-
if (CurrentGets) {
|
|
148
|
-
this.removeParentObservers(CurrentGetsIndex);
|
|
149
|
-
if (this.sources && CurrentGetsIndex > 0) {
|
|
150
|
-
this.sources.length = CurrentGetsIndex + CurrentGets.length;
|
|
151
|
-
for (let i = 0; i < CurrentGets.length; i++) {
|
|
152
|
-
this.sources[CurrentGetsIndex + i] = CurrentGets[i];
|
|
153
|
-
}
|
|
154
|
-
} else {
|
|
155
|
-
this.sources = CurrentGets;
|
|
156
|
-
}
|
|
157
|
-
for (let i = CurrentGetsIndex; i < this.sources.length; i++) {
|
|
158
|
-
const source = this.sources[i];
|
|
159
|
-
if (!source.observers) {
|
|
160
|
-
source.observers = [this];
|
|
161
|
-
} else {
|
|
162
|
-
source.observers.push(this);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
} else if (this.sources && CurrentGetsIndex < this.sources.length) {
|
|
166
|
-
this.removeParentObservers(CurrentGetsIndex);
|
|
167
|
-
this.sources.length = CurrentGetsIndex;
|
|
168
|
-
}
|
|
169
|
-
} finally {
|
|
170
|
-
CurrentGets = prevGets;
|
|
171
|
-
CurrentReaction = prevReaction;
|
|
172
|
-
CurrentGetsIndex = prevIndex;
|
|
173
|
-
}
|
|
174
|
-
if ((oldValue !== this.value || this.alwaysUpdate) && this.observers) {
|
|
175
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
176
|
-
this.observers[i].state = CacheDirty;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
this.state = CacheClean;
|
|
180
|
-
}
|
|
181
|
-
updateIfNecessary() {
|
|
182
|
-
if (this.state === CacheCheck) {
|
|
183
|
-
for (const source of this.sources) {
|
|
184
|
-
source.updateIfNecessary();
|
|
185
|
-
if (this.state === CacheDirty) {
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (this.state === CacheDirty) {
|
|
191
|
-
this.update();
|
|
192
|
-
}
|
|
193
|
-
this.state = CacheClean;
|
|
194
|
-
}
|
|
195
|
-
removeParentObservers(index) {
|
|
196
|
-
if (!this.sources)
|
|
197
|
-
return;
|
|
198
|
-
for (let i = index; i < this.sources.length; i++) {
|
|
199
|
-
const source = this.sources[i];
|
|
200
|
-
const swap = source.observers.findIndex((v) => v === this);
|
|
201
|
-
source.observers[swap] = source.observers[source.observers.length - 1];
|
|
202
|
-
source.observers.pop();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
destroy() {
|
|
206
|
-
if (this.cleanups) {
|
|
207
|
-
this.cleanups.forEach((c) => c());
|
|
208
|
-
this.cleanups = null;
|
|
209
|
-
}
|
|
210
|
-
this.removeParentObservers(0);
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
function onCleanup(fn) {
|
|
214
|
-
if (CurrentReaction) {
|
|
215
|
-
if (!CurrentReaction.cleanups)
|
|
216
|
-
CurrentReaction.cleanups = [fn];
|
|
217
|
-
else
|
|
218
|
-
CurrentReaction.cleanups.push(fn);
|
|
219
|
-
} else {
|
|
220
|
-
console.error("onCleanup must be called from within a memo or effect");
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
function stabilize() {
|
|
224
|
-
if (!EffectQueue)
|
|
225
|
-
return;
|
|
226
|
-
for (let i = 0; i < EffectQueue.length; i++) {
|
|
227
|
-
EffectQueue[i].get();
|
|
228
|
-
}
|
|
229
|
-
EffectQueue = null;
|
|
230
|
-
}
|
|
231
|
-
function createSignal(value, options) {
|
|
232
|
-
const signal = new Reactive(value, 0 /* Signal */);
|
|
233
|
-
if (options?.equals !== void 0)
|
|
234
|
-
signal.alwaysUpdate = true;
|
|
235
|
-
return [signal.get.bind(signal), signal.set.bind(signal)];
|
|
236
|
-
}
|
|
237
|
-
function createMemo(fn) {
|
|
238
|
-
const memo = new Reactive(fn, 1 /* Memo */);
|
|
239
|
-
return memo.get.bind(memo);
|
|
240
|
-
}
|
|
241
|
-
function createEffect(fn) {
|
|
242
|
-
const effect = new Reactive(fn, 2 /* Effect */);
|
|
243
|
-
return effect.get.bind(effect);
|
|
244
|
-
}
|
|
245
|
-
function createRoot(fn) {
|
|
246
|
-
let root = [];
|
|
247
|
-
Root = root;
|
|
248
|
-
fn();
|
|
249
|
-
Root = null;
|
|
250
|
-
return () => {
|
|
251
|
-
if (!root)
|
|
252
|
-
return;
|
|
253
|
-
root.forEach((r) => r.destroy());
|
|
254
|
-
root = null;
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
function batch(fn) {
|
|
258
|
-
EffectQueue = [];
|
|
259
|
-
let out = fn();
|
|
260
|
-
stabilize();
|
|
261
|
-
return out;
|
|
262
|
-
}
|
|
263
|
-
function untrack(fn) {
|
|
264
|
-
const listener = CurrentReaction;
|
|
265
|
-
CurrentReaction = void 0;
|
|
266
|
-
try {
|
|
267
|
-
return fn();
|
|
268
|
-
} finally {
|
|
269
|
-
CurrentReaction = listener;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// src/store.ts
|
|
274
|
-
var $RAW = Symbol("store-raw");
|
|
275
|
-
var $TRACK = Symbol("track");
|
|
276
|
-
var $PROXY = Symbol("store-proxy");
|
|
277
|
-
var $NODE = Symbol("store-node");
|
|
278
|
-
function wrap(value) {
|
|
279
|
-
let p = value[$PROXY];
|
|
280
|
-
if (!p) {
|
|
281
|
-
Object.defineProperty(value, $PROXY, {
|
|
282
|
-
value: p = new Proxy(value, proxyTraps)
|
|
283
|
-
});
|
|
284
|
-
if (!Array.isArray(value)) {
|
|
285
|
-
const keys = Object.keys(value);
|
|
286
|
-
const desc = Object.getOwnPropertyDescriptors(value);
|
|
287
|
-
for (let i = 0, l = keys.length; i < l; i++) {
|
|
288
|
-
const prop = keys[i];
|
|
289
|
-
if (desc[prop].get) {
|
|
290
|
-
const get = desc[prop].get.bind(p);
|
|
291
|
-
Object.defineProperty(value, prop, {
|
|
292
|
-
enumerable: desc[prop].enumerable,
|
|
293
|
-
get
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return p;
|
|
300
|
-
}
|
|
301
|
-
function isWrappable(obj) {
|
|
302
|
-
let proto;
|
|
303
|
-
return obj != null && typeof obj === "object" && (obj[$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
|
|
304
|
-
}
|
|
305
|
-
function unwrap(item, set = /* @__PURE__ */ new Set()) {
|
|
306
|
-
let result, unwrapped, v, prop;
|
|
307
|
-
if (result = item != null && item[$RAW])
|
|
308
|
-
return result;
|
|
309
|
-
if (!isWrappable(item) || set.has(item))
|
|
310
|
-
return item;
|
|
311
|
-
if (Array.isArray(item)) {
|
|
312
|
-
if (Object.isFrozen(item))
|
|
313
|
-
item = item.slice(0);
|
|
314
|
-
else
|
|
315
|
-
set.add(item);
|
|
316
|
-
for (let i = 0, l = item.length; i < l; i++) {
|
|
317
|
-
v = item[i];
|
|
318
|
-
if ((unwrapped = unwrap(v, set)) !== v)
|
|
319
|
-
item[i] = unwrapped;
|
|
320
|
-
}
|
|
321
|
-
} else {
|
|
322
|
-
if (Object.isFrozen(item))
|
|
323
|
-
item = Object.assign({}, item);
|
|
324
|
-
else
|
|
325
|
-
set.add(item);
|
|
326
|
-
const keys = Object.keys(item);
|
|
327
|
-
const desc = Object.getOwnPropertyDescriptors(item);
|
|
328
|
-
for (let i = 0, l = keys.length; i < l; i++) {
|
|
329
|
-
prop = keys[i];
|
|
330
|
-
if (desc[prop].get)
|
|
331
|
-
continue;
|
|
332
|
-
v = item[prop];
|
|
333
|
-
if ((unwrapped = unwrap(v, set)) !== v)
|
|
334
|
-
item[prop] = unwrapped;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
return item;
|
|
338
|
-
}
|
|
339
|
-
function getDataNodes(target) {
|
|
340
|
-
let nodes = target[$NODE];
|
|
341
|
-
if (!nodes)
|
|
342
|
-
Object.defineProperty(target, $NODE, { value: nodes = {} });
|
|
343
|
-
return nodes;
|
|
344
|
-
}
|
|
345
|
-
function getDataNode(nodes, property, value) {
|
|
346
|
-
return nodes[property] || (nodes[property] = createDataNode(value));
|
|
347
|
-
}
|
|
348
|
-
function proxyDescriptor(target, property) {
|
|
349
|
-
const desc = Reflect.getOwnPropertyDescriptor(target, property);
|
|
350
|
-
if (!desc || desc.get || !desc.configurable || property === $PROXY || property === $NODE)
|
|
351
|
-
return desc;
|
|
352
|
-
delete desc.value;
|
|
353
|
-
delete desc.writable;
|
|
354
|
-
desc.get = () => target[$PROXY][property];
|
|
355
|
-
return desc;
|
|
356
|
-
}
|
|
357
|
-
function trackSelf(target) {
|
|
358
|
-
if (CurrentReaction) {
|
|
359
|
-
const nodes = getDataNodes(target);
|
|
360
|
-
(nodes._ || (nodes._ = createDataNode())).get();
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
function ownKeys(target) {
|
|
364
|
-
trackSelf(target);
|
|
365
|
-
return Reflect.ownKeys(target);
|
|
366
|
-
}
|
|
367
|
-
function createDataNode(value) {
|
|
368
|
-
const s = new Reactive(value, 0);
|
|
369
|
-
s.alwaysUpdate = true;
|
|
370
|
-
return s;
|
|
371
|
-
}
|
|
372
|
-
var Writing = false;
|
|
373
|
-
var proxyTraps = {
|
|
374
|
-
get(target, property, receiver) {
|
|
375
|
-
if (property === $RAW)
|
|
376
|
-
return target;
|
|
377
|
-
if (property === $PROXY)
|
|
378
|
-
return receiver;
|
|
379
|
-
if (property === $TRACK) {
|
|
380
|
-
trackSelf(target);
|
|
381
|
-
return receiver;
|
|
382
|
-
}
|
|
383
|
-
const nodes = getDataNodes(target);
|
|
384
|
-
const tracked = nodes.hasOwnProperty(property);
|
|
385
|
-
let value = tracked ? nodes[property].get() : target[property];
|
|
386
|
-
if (property === $NODE || property === "__proto__")
|
|
387
|
-
return value;
|
|
388
|
-
if (!tracked) {
|
|
389
|
-
const desc = Object.getOwnPropertyDescriptor(target, property);
|
|
390
|
-
if (CurrentReaction && (typeof value !== "function" || target.hasOwnProperty(property)) && !(desc && desc.get))
|
|
391
|
-
value = getDataNode(nodes, property, value).get();
|
|
392
|
-
}
|
|
393
|
-
return isWrappable(value) ? wrap(value) : value;
|
|
394
|
-
},
|
|
395
|
-
has(target, property) {
|
|
396
|
-
if (property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === "__proto__")
|
|
397
|
-
return true;
|
|
398
|
-
this.get(target, property, target);
|
|
399
|
-
return property in target;
|
|
400
|
-
},
|
|
401
|
-
set(target, property, value) {
|
|
402
|
-
Writing && setProperty(target, property, unwrap(value));
|
|
403
|
-
return true;
|
|
404
|
-
},
|
|
405
|
-
deleteProperty(target, property) {
|
|
406
|
-
Writing && setProperty(target, property, void 0, true);
|
|
407
|
-
return true;
|
|
408
|
-
},
|
|
409
|
-
ownKeys,
|
|
410
|
-
getOwnPropertyDescriptor: proxyDescriptor
|
|
411
|
-
};
|
|
412
|
-
function setProperty(state, property, value, deleting = false) {
|
|
413
|
-
if (!deleting && state[property] === value)
|
|
414
|
-
return;
|
|
415
|
-
const prev = state[property];
|
|
416
|
-
const len = state.length;
|
|
417
|
-
if (deleting)
|
|
418
|
-
delete state[property];
|
|
419
|
-
else
|
|
420
|
-
state[property] = value;
|
|
421
|
-
const nodes = getDataNodes(state);
|
|
422
|
-
let node;
|
|
423
|
-
if (node = getDataNode(nodes, property, prev))
|
|
424
|
-
node.set(() => value);
|
|
425
|
-
if (Array.isArray(state) && state.length !== len)
|
|
426
|
-
(node = getDataNode(nodes, "length", len)) && node.set(state.length);
|
|
427
|
-
(node = nodes._) && node.set();
|
|
428
|
-
}
|
|
429
|
-
function createStore(store) {
|
|
430
|
-
const unwrappedStore = unwrap(store);
|
|
431
|
-
const wrappedStore = wrap(unwrappedStore);
|
|
432
|
-
const setStore = (fn) => {
|
|
433
|
-
batch(() => {
|
|
434
|
-
try {
|
|
435
|
-
Writing = true;
|
|
436
|
-
fn(wrappedStore);
|
|
437
|
-
} finally {
|
|
438
|
-
Writing = false;
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
};
|
|
442
|
-
return [wrappedStore, setStore];
|
|
443
|
-
}
|
|
444
|
-
|
|
445
37
|
function _extends() {
|
|
446
38
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
447
39
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -457,818 +49,174 @@
|
|
|
457
49
|
return _extends.apply(this, arguments);
|
|
458
50
|
}
|
|
459
51
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
*/
|
|
465
|
-
var Action;
|
|
466
|
-
|
|
467
|
-
(function (Action) {
|
|
468
|
-
/**
|
|
469
|
-
* A POP indicates a change to an arbitrary index in the history stack, such
|
|
470
|
-
* as a back or forward navigation. It does not describe the direction of the
|
|
471
|
-
* navigation, only that the current index changed.
|
|
472
|
-
*
|
|
473
|
-
* Note: This is the default action for newly created history objects.
|
|
474
|
-
*/
|
|
475
|
-
Action["Pop"] = "POP";
|
|
476
|
-
/**
|
|
477
|
-
* A PUSH indicates a new entry being added to the history stack, such as when
|
|
478
|
-
* a link is clicked and a new page loads. When this happens, all subsequent
|
|
479
|
-
* entries in the stack are lost.
|
|
480
|
-
*/
|
|
481
|
-
|
|
482
|
-
Action["Push"] = "PUSH";
|
|
483
|
-
/**
|
|
484
|
-
* A REPLACE indicates the entry at the current index in the history stack
|
|
485
|
-
* being replaced by a new one.
|
|
486
|
-
*/
|
|
487
|
-
|
|
488
|
-
Action["Replace"] = "REPLACE";
|
|
489
|
-
})(Action || (Action = {}));
|
|
490
|
-
|
|
491
|
-
var readOnly = function (obj) {
|
|
492
|
-
return Object.freeze(obj);
|
|
493
|
-
} ;
|
|
494
|
-
|
|
495
|
-
function warning$1(cond, message) {
|
|
496
|
-
if (!cond) {
|
|
497
|
-
// eslint-disable-next-line no-console
|
|
498
|
-
if (typeof console !== 'undefined') console.warn(message);
|
|
499
|
-
|
|
500
|
-
try {
|
|
501
|
-
// Welcome to debugging history!
|
|
502
|
-
//
|
|
503
|
-
// This error is thrown as a convenience so you can more easily
|
|
504
|
-
// find the source for a warning that appears in the console by
|
|
505
|
-
// enabling "pause on exceptions" in your JavaScript debugger.
|
|
506
|
-
throw new Error(message); // eslint-disable-next-line no-empty
|
|
507
|
-
} catch (e) {}
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
var BeforeUnloadEventType = 'beforeunload';
|
|
512
|
-
var HashChangeEventType = 'hashchange';
|
|
513
|
-
var PopStateEventType = 'popstate';
|
|
514
|
-
/**
|
|
515
|
-
* Browser history stores the location in regular URLs. This is the standard for
|
|
516
|
-
* most web apps, but it requires some configuration on the server to ensure you
|
|
517
|
-
* serve the same app at multiple URLs.
|
|
518
|
-
*
|
|
519
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createbrowserhistory
|
|
520
|
-
*/
|
|
521
|
-
|
|
522
|
-
function createBrowserHistory(options) {
|
|
523
|
-
if (options === void 0) {
|
|
524
|
-
options = {};
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
var _options = options,
|
|
528
|
-
_options$window = _options.window,
|
|
529
|
-
window = _options$window === void 0 ? document.defaultView : _options$window;
|
|
530
|
-
var globalHistory = window.history;
|
|
531
|
-
|
|
532
|
-
function getIndexAndLocation() {
|
|
533
|
-
var _window$location = window.location,
|
|
534
|
-
pathname = _window$location.pathname,
|
|
535
|
-
search = _window$location.search,
|
|
536
|
-
hash = _window$location.hash;
|
|
537
|
-
var state = globalHistory.state || {};
|
|
538
|
-
return [state.idx, readOnly({
|
|
539
|
-
pathname: pathname,
|
|
540
|
-
search: search,
|
|
541
|
-
hash: hash,
|
|
542
|
-
state: state.usr || null,
|
|
543
|
-
key: state.key || 'default'
|
|
544
|
-
})];
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
var blockedPopTx = null;
|
|
548
|
-
|
|
549
|
-
function handlePop() {
|
|
550
|
-
if (blockedPopTx) {
|
|
551
|
-
blockers.call(blockedPopTx);
|
|
552
|
-
blockedPopTx = null;
|
|
553
|
-
} else {
|
|
554
|
-
var nextAction = Action.Pop;
|
|
555
|
-
|
|
556
|
-
var _getIndexAndLocation = getIndexAndLocation(),
|
|
557
|
-
nextIndex = _getIndexAndLocation[0],
|
|
558
|
-
nextLocation = _getIndexAndLocation[1];
|
|
559
|
-
|
|
560
|
-
if (blockers.length) {
|
|
561
|
-
if (nextIndex != null) {
|
|
562
|
-
var delta = index - nextIndex;
|
|
563
|
-
|
|
564
|
-
if (delta) {
|
|
565
|
-
// Revert the POP
|
|
566
|
-
blockedPopTx = {
|
|
567
|
-
action: nextAction,
|
|
568
|
-
location: nextLocation,
|
|
569
|
-
retry: function retry() {
|
|
570
|
-
go(delta * -1);
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
|
-
go(delta);
|
|
574
|
-
}
|
|
575
|
-
} else {
|
|
576
|
-
// Trying to POP to a location with no index. We did not create
|
|
577
|
-
// this location, so we can't effectively block the navigation.
|
|
578
|
-
warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
|
|
579
|
-
// detail and link to it here so people can understand better what
|
|
580
|
-
// is going on and how to avoid it.
|
|
581
|
-
"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.") ;
|
|
582
|
-
}
|
|
583
|
-
} else {
|
|
584
|
-
applyTx(nextAction);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
window.addEventListener(PopStateEventType, handlePop);
|
|
590
|
-
var action = Action.Pop;
|
|
591
|
-
|
|
592
|
-
var _getIndexAndLocation2 = getIndexAndLocation(),
|
|
593
|
-
index = _getIndexAndLocation2[0],
|
|
594
|
-
location = _getIndexAndLocation2[1];
|
|
595
|
-
|
|
596
|
-
var listeners = createEvents();
|
|
597
|
-
var blockers = createEvents();
|
|
598
|
-
|
|
599
|
-
if (index == null) {
|
|
600
|
-
index = 0;
|
|
601
|
-
globalHistory.replaceState(_extends({}, globalHistory.state, {
|
|
602
|
-
idx: index
|
|
603
|
-
}), '');
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
function createHref(to) {
|
|
607
|
-
return typeof to === 'string' ? to : createPath(to);
|
|
608
|
-
} // state defaults to `null` because `window.history.state` does
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
function getNextLocation(to, state) {
|
|
612
|
-
if (state === void 0) {
|
|
613
|
-
state = null;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
return readOnly(_extends({
|
|
617
|
-
pathname: location.pathname,
|
|
618
|
-
hash: '',
|
|
619
|
-
search: ''
|
|
620
|
-
}, typeof to === 'string' ? parsePath(to) : to, {
|
|
621
|
-
state: state,
|
|
622
|
-
key: createKey()
|
|
623
|
-
}));
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
function getHistoryStateAndUrl(nextLocation, index) {
|
|
627
|
-
return [{
|
|
628
|
-
usr: nextLocation.state,
|
|
629
|
-
key: nextLocation.key,
|
|
630
|
-
idx: index
|
|
631
|
-
}, createHref(nextLocation)];
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
function allowTx(action, location, retry) {
|
|
635
|
-
return !blockers.length || (blockers.call({
|
|
636
|
-
action: action,
|
|
637
|
-
location: location,
|
|
638
|
-
retry: retry
|
|
639
|
-
}), false);
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
function applyTx(nextAction) {
|
|
643
|
-
action = nextAction;
|
|
644
|
-
|
|
645
|
-
var _getIndexAndLocation3 = getIndexAndLocation();
|
|
646
|
-
|
|
647
|
-
index = _getIndexAndLocation3[0];
|
|
648
|
-
location = _getIndexAndLocation3[1];
|
|
649
|
-
listeners.call({
|
|
650
|
-
action: action,
|
|
651
|
-
location: location
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
function push(to, state) {
|
|
656
|
-
var nextAction = Action.Push;
|
|
657
|
-
var nextLocation = getNextLocation(to, state);
|
|
658
|
-
|
|
659
|
-
function retry() {
|
|
660
|
-
push(to, state);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
664
|
-
var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1),
|
|
665
|
-
historyState = _getHistoryStateAndUr[0],
|
|
666
|
-
url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading
|
|
667
|
-
// try...catch because iOS limits us to 100 pushState calls :/
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
try {
|
|
671
|
-
globalHistory.pushState(historyState, '', url);
|
|
672
|
-
} catch (error) {
|
|
673
|
-
// They are going to lose state here, but there is no real
|
|
674
|
-
// way to warn them about it since the page will refresh...
|
|
675
|
-
window.location.assign(url);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
applyTx(nextAction);
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
function replace(to, state) {
|
|
683
|
-
var nextAction = Action.Replace;
|
|
684
|
-
var nextLocation = getNextLocation(to, state);
|
|
685
|
-
|
|
686
|
-
function retry() {
|
|
687
|
-
replace(to, state);
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
691
|
-
var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index),
|
|
692
|
-
historyState = _getHistoryStateAndUr2[0],
|
|
693
|
-
url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
globalHistory.replaceState(historyState, '', url);
|
|
697
|
-
applyTx(nextAction);
|
|
52
|
+
var prefix = 'Invariant failed';
|
|
53
|
+
function invariant(condition, message) {
|
|
54
|
+
if (condition) {
|
|
55
|
+
return;
|
|
698
56
|
}
|
|
699
|
-
|
|
57
|
+
var provided = typeof message === 'function' ? message() : message;
|
|
58
|
+
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
59
|
+
throw new Error(value);
|
|
60
|
+
}
|
|
700
61
|
|
|
701
|
-
function go(delta) {
|
|
702
|
-
globalHistory.go(delta);
|
|
703
|
-
}
|
|
62
|
+
function n(n){for(var r=arguments.length,t=Array(r>1?r-1:0),e=1;e<r;e++)t[e-1]=arguments[e];{var i=Y[n],o=i?"function"==typeof i?i.apply(null,t):i:"unknown error nr: "+n;throw Error("[Immer] "+o)}}function r(n){return !!n&&!!n[Q]}function t(n){var r;return !!n&&(function(n){if(!n||"object"!=typeof n)return !1;var r=Object.getPrototypeOf(n);if(null===r)return !0;var t=Object.hasOwnProperty.call(r,"constructor")&&r.constructor;return t===Object||"function"==typeof t&&Function.toString.call(t)===Z}(n)||Array.isArray(n)||!!n[L]||!!(null===(r=n.constructor)||void 0===r?void 0:r[L])||s(n)||v(n))}function i(n,r,t){void 0===t&&(t=!1),0===o(n)?(t?Object.keys:nn)(n).forEach((function(e){t&&"symbol"==typeof e||r(e,n[e],n);})):n.forEach((function(t,e){return r(e,t,n)}));}function o(n){var r=n[Q];return r?r.i>3?r.i-4:r.i:Array.isArray(n)?1:s(n)?2:v(n)?3:0}function u(n,r){return 2===o(n)?n.has(r):Object.prototype.hasOwnProperty.call(n,r)}function a(n,r){return 2===o(n)?n.get(r):n[r]}function f(n,r,t){var e=o(n);2===e?n.set(r,t):3===e?(n.delete(r),n.add(t)):n[r]=t;}function c(n,r){return n===r?0!==n||1/n==1/r:n!=n&&r!=r}function s(n){return X&&n instanceof Map}function v(n){return q&&n instanceof Set}function p(n){return n.o||n.t}function l(n){if(Array.isArray(n))return Array.prototype.slice.call(n);var r=rn(n);delete r[Q];for(var t=nn(r),e=0;e<t.length;e++){var i=t[e],o=r[i];!1===o.writable&&(o.writable=!0,o.configurable=!0),(o.get||o.set)&&(r[i]={configurable:!0,writable:!0,enumerable:o.enumerable,value:n[i]});}return Object.create(Object.getPrototypeOf(n),r)}function d(n,e){return void 0===e&&(e=!1),y(n)||r(n)||!t(n)?n:(o(n)>1&&(n.set=n.add=n.clear=n.delete=h),Object.freeze(n),e&&i(n,(function(n,r){return d(r,!0)}),!0),n)}function h(){n(2);}function y(n){return null==n||"object"!=typeof n||Object.isFrozen(n)}function b(r){var t=tn[r];return t||n(18,r),t}function _(){return U||n(0),U}function j(n,r){r&&(b("Patches"),n.u=[],n.s=[],n.v=r);}function O(n){g(n),n.p.forEach(S),n.p=null;}function g(n){n===U&&(U=n.l);}function w(n){return U={p:[],l:U,h:n,m:!0,_:0}}function S(n){var r=n[Q];0===r.i||1===r.i?r.j():r.O=!0;}function P(r,e){e._=e.p.length;var i=e.p[0],o=void 0!==r&&r!==i;return e.h.g||b("ES5").S(e,r,o),o?(i[Q].P&&(O(e),n(4)),t(r)&&(r=M(e,r),e.l||x(e,r)),e.u&&b("Patches").M(i[Q].t,r,e.u,e.s)):r=M(e,i,[]),O(e),e.u&&e.v(e.u,e.s),r!==H?r:void 0}function M(n,r,t){if(y(r))return r;var e=r[Q];if(!e)return i(r,(function(i,o){return A(n,e,r,i,o,t)}),!0),r;if(e.A!==n)return r;if(!e.P)return x(n,e.t,!0),e.t;if(!e.I){e.I=!0,e.A._--;var o=4===e.i||5===e.i?e.o=l(e.k):e.o;i(3===e.i?new Set(o):o,(function(r,i){return A(n,e,o,r,i,t)})),x(n,o,!1),t&&n.u&&b("Patches").R(e,t,n.u,n.s);}return e.o}function A(e,i,o,a,c,s){if(c===o&&n(5),r(c)){var v=M(e,c,s&&i&&3!==i.i&&!u(i.D,a)?s.concat(a):void 0);if(f(o,a,v),!r(v))return;e.m=!1;}if(t(c)&&!y(c)){if(!e.h.F&&e._<1)return;M(e,c),i&&i.A.l||x(e,c);}}function x(n,r,t){void 0===t&&(t=!1),n.h.F&&n.m&&d(r,t);}function z(n,r){var t=n[Q];return (t?p(t):n)[r]}function I(n,r){if(r in n)for(var t=Object.getPrototypeOf(n);t;){var e=Object.getOwnPropertyDescriptor(t,r);if(e)return e;t=Object.getPrototypeOf(t);}}function k(n){n.P||(n.P=!0,n.l&&k(n.l));}function E(n){n.o||(n.o=l(n.t));}function R(n,r,t){var e=s(r)?b("MapSet").N(r,t):v(r)?b("MapSet").T(r,t):n.g?function(n,r){var t=Array.isArray(n),e={i:t?1:0,A:r?r.A:_(),P:!1,I:!1,D:{},l:r,t:n,k:null,o:null,j:null,C:!1},i=e,o=en;t&&(i=[e],o=on);var u=Proxy.revocable(i,o),a=u.revoke,f=u.proxy;return e.k=f,e.j=a,f}(r,t):b("ES5").J(r,t);return (t?t.A:_()).p.push(e),e}function D(e){return r(e)||n(22,e),function n(r){if(!t(r))return r;var e,u=r[Q],c=o(r);if(u){if(!u.P&&(u.i<4||!b("ES5").K(u)))return u.t;u.I=!0,e=F(r,c),u.I=!1;}else e=F(r,c);return i(e,(function(r,t){u&&a(u.t,r)===t||f(e,r,n(t));})),3===c?new Set(e):e}(e)}function F(n,r){switch(r){case 2:return new Map(n);case 3:return Array.from(n)}return l(n)}var G,U,W="undefined"!=typeof Symbol&&"symbol"==typeof Symbol("x"),X="undefined"!=typeof Map,q="undefined"!=typeof Set,B="undefined"!=typeof Proxy&&void 0!==Proxy.revocable&&"undefined"!=typeof Reflect,H=W?Symbol.for("immer-nothing"):((G={})["immer-nothing"]=!0,G),L=W?Symbol.for("immer-draftable"):"__$immer_draftable",Q=W?Symbol.for("immer-state"):"__$immer_state",Y={0:"Illegal state",1:"Immer drafts cannot have computed properties",2:"This object has been frozen and should not be mutated",3:function(n){return "Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? "+n},4:"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",5:"Immer forbids circular references",6:"The first or second argument to `produce` must be a function",7:"The third argument to `produce` must be a function or undefined",8:"First argument to `createDraft` must be a plain object, an array, or an immerable object",9:"First argument to `finishDraft` must be a draft returned by `createDraft`",10:"The given draft is already finalized",11:"Object.defineProperty() cannot be used on an Immer draft",12:"Object.setPrototypeOf() cannot be used on an Immer draft",13:"Immer only supports deleting array indices",14:"Immer only supports setting array indices and the 'length' property",15:function(n){return "Cannot apply patch, path doesn't resolve: "+n},16:'Sets cannot have "replace" patches.',17:function(n){return "Unsupported patch operation: "+n},18:function(n){return "The plugin for '"+n+"' has not been loaded into Immer. To enable the plugin, import and call `enable"+n+"()` when initializing your application."},20:"Cannot use proxies if Proxy, Proxy.revocable or Reflect are not available",21:function(n){return "produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '"+n+"'"},22:function(n){return "'current' expects a draft, got: "+n},23:function(n){return "'original' expects a draft, got: "+n},24:"Patching reserved attributes like __proto__, prototype and constructor is not allowed"},Z=""+Object.prototype.constructor,nn="undefined"!=typeof Reflect&&Reflect.ownKeys?Reflect.ownKeys:void 0!==Object.getOwnPropertySymbols?function(n){return Object.getOwnPropertyNames(n).concat(Object.getOwnPropertySymbols(n))}:Object.getOwnPropertyNames,rn=Object.getOwnPropertyDescriptors||function(n){var r={};return nn(n).forEach((function(t){r[t]=Object.getOwnPropertyDescriptor(n,t);})),r},tn={},en={get:function(n,r){if(r===Q)return n;var e=p(n);if(!u(e,r))return function(n,r,t){var e,i=I(r,t);return i?"value"in i?i.value:null===(e=i.get)||void 0===e?void 0:e.call(n.k):void 0}(n,e,r);var i=e[r];return n.I||!t(i)?i:i===z(n.t,r)?(E(n),n.o[r]=R(n.A.h,i,n)):i},has:function(n,r){return r in p(n)},ownKeys:function(n){return Reflect.ownKeys(p(n))},set:function(n,r,t){var e=I(p(n),r);if(null==e?void 0:e.set)return e.set.call(n.k,t),!0;if(!n.P){var i=z(p(n),r),o=null==i?void 0:i[Q];if(o&&o.t===t)return n.o[r]=t,n.D[r]=!1,!0;if(c(t,i)&&(void 0!==t||u(n.t,r)))return !0;E(n),k(n);}return n.o[r]===t&&"number"!=typeof t&&(void 0!==t||r in n.o)||(n.o[r]=t,n.D[r]=!0,!0)},deleteProperty:function(n,r){return void 0!==z(n.t,r)||r in n.t?(n.D[r]=!1,E(n),k(n)):delete n.D[r],n.o&&delete n.o[r],!0},getOwnPropertyDescriptor:function(n,r){var t=p(n),e=Reflect.getOwnPropertyDescriptor(t,r);return e?{writable:!0,configurable:1!==n.i||"length"!==r,enumerable:e.enumerable,value:t[r]}:e},defineProperty:function(){n(11);},getPrototypeOf:function(n){return Object.getPrototypeOf(n.t)},setPrototypeOf:function(){n(12);}},on={};i(en,(function(n,r){on[n]=function(){return arguments[0]=arguments[0][0],r.apply(this,arguments)};})),on.deleteProperty=function(r,t){return isNaN(parseInt(t))&&n(13),on.set.call(this,r,t,void 0)},on.set=function(r,t,e){return "length"!==t&&isNaN(parseInt(t))&&n(14),en.set.call(this,r[0],t,e,r[0])};var un=function(){function e(r){var e=this;this.g=B,this.F=!0,this.produce=function(r,i,o){if("function"==typeof r&&"function"!=typeof i){var u=i;i=r;var a=e;return function(n){var r=this;void 0===n&&(n=u);for(var t=arguments.length,e=Array(t>1?t-1:0),o=1;o<t;o++)e[o-1]=arguments[o];return a.produce(n,(function(n){var t;return (t=i).call.apply(t,[r,n].concat(e))}))}}var f;if("function"!=typeof i&&n(6),void 0!==o&&"function"!=typeof o&&n(7),t(r)){var c=w(e),s=R(e,r,void 0),v=!0;try{f=i(s),v=!1;}finally{v?O(c):g(c);}return "undefined"!=typeof Promise&&f instanceof Promise?f.then((function(n){return j(c,o),P(n,c)}),(function(n){throw O(c),n})):(j(c,o),P(f,c))}if(!r||"object"!=typeof r){if(void 0===(f=i(r))&&(f=r),f===H&&(f=void 0),e.F&&d(f,!0),o){var p=[],l=[];b("Patches").M(r,f,p,l),o(p,l);}return f}n(21,r);},this.produceWithPatches=function(n,r){if("function"==typeof n)return function(r){for(var t=arguments.length,i=Array(t>1?t-1:0),o=1;o<t;o++)i[o-1]=arguments[o];return e.produceWithPatches(r,(function(r){return n.apply(void 0,[r].concat(i))}))};var t,i,o=e.produce(n,r,(function(n,r){t=n,i=r;}));return "undefined"!=typeof Promise&&o instanceof Promise?o.then((function(n){return [n,t,i]})):[o,t,i]},"boolean"==typeof(null==r?void 0:r.useProxies)&&this.setUseProxies(r.useProxies),"boolean"==typeof(null==r?void 0:r.autoFreeze)&&this.setAutoFreeze(r.autoFreeze);}var i=e.prototype;return i.createDraft=function(e){t(e)||n(8),r(e)&&(e=D(e));var i=w(this),o=R(this,e,void 0);return o[Q].C=!0,g(i),o},i.finishDraft=function(r,t){var e=r&&r[Q];(e&&e.C||n(9),e.I&&n(10));var i=e.A;return j(i,t),P(void 0,i)},i.setAutoFreeze=function(n){this.F=n;},i.setUseProxies=function(r){r&&!B&&n(20),this.g=r;},i.applyPatches=function(n,t){var e;for(e=t.length-1;e>=0;e--){var i=t[e];if(0===i.path.length&&"replace"===i.op){n=i.value;break}}e>-1&&(t=t.slice(e+1));var o=b("Patches").$;return r(n)?o(n,t):this.produce(n,(function(n){return o(n,t)}))},e}(),an=new un,fn=an.produce;an.produceWithPatches.bind(an);var sn=an.setAutoFreeze.bind(an);an.setUseProxies.bind(an);an.applyPatches.bind(an);an.createDraft.bind(an);an.finishDraft.bind(an);
|
|
704
63
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
64
|
+
/**
|
|
65
|
+
* router-core
|
|
66
|
+
*
|
|
67
|
+
* Copyright (c) TanStack
|
|
68
|
+
*
|
|
69
|
+
* This source code is licensed under the MIT license found in the
|
|
70
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
71
|
+
*
|
|
72
|
+
* @license MIT
|
|
73
|
+
*/
|
|
709
74
|
|
|
75
|
+
// While the public API was clearly inspired by the "history" npm package,
|
|
76
|
+
// This implementation attempts to be more lightweight by
|
|
77
|
+
// making assumptions about the way TanStack Router works
|
|
78
|
+
|
|
79
|
+
const popStateEvent = 'popstate';
|
|
80
|
+
function createHistory(opts) {
|
|
81
|
+
let currentLocation = opts.getLocation();
|
|
82
|
+
let unsub = () => {};
|
|
83
|
+
let listeners = new Set();
|
|
84
|
+
const onUpdate = () => {
|
|
85
|
+
currentLocation = opts.getLocation();
|
|
86
|
+
listeners.forEach(listener => listener());
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
710
89
|
get location() {
|
|
711
|
-
return
|
|
712
|
-
},
|
|
713
|
-
|
|
714
|
-
createHref: createHref,
|
|
715
|
-
push: push,
|
|
716
|
-
replace: replace,
|
|
717
|
-
go: go,
|
|
718
|
-
back: function back() {
|
|
719
|
-
go(-1);
|
|
90
|
+
return currentLocation;
|
|
720
91
|
},
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
listen: function listen(listener) {
|
|
725
|
-
return listeners.push(listener);
|
|
726
|
-
},
|
|
727
|
-
block: function block(blocker) {
|
|
728
|
-
var unblock = blockers.push(blocker);
|
|
729
|
-
|
|
730
|
-
if (blockers.length === 1) {
|
|
731
|
-
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
|
|
92
|
+
listen: cb => {
|
|
93
|
+
if (listeners.size === 0) {
|
|
94
|
+
unsub = opts.listener(onUpdate);
|
|
732
95
|
}
|
|
733
|
-
|
|
734
|
-
return
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
if (!blockers.length) {
|
|
740
|
-
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
|
|
96
|
+
listeners.add(cb);
|
|
97
|
+
return () => {
|
|
98
|
+
listeners.delete(cb);
|
|
99
|
+
if (listeners.size === 0) {
|
|
100
|
+
unsub();
|
|
741
101
|
}
|
|
742
102
|
};
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
return history;
|
|
746
|
-
}
|
|
747
|
-
/**
|
|
748
|
-
* Hash history stores the location in window.location.hash. This makes it ideal
|
|
749
|
-
* for situations where you don't want to send the location to the server for
|
|
750
|
-
* some reason, either because you do cannot configure it or the URL space is
|
|
751
|
-
* reserved for something else.
|
|
752
|
-
*
|
|
753
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createhashhistory
|
|
754
|
-
*/
|
|
755
|
-
|
|
756
|
-
function createHashHistory(options) {
|
|
757
|
-
if (options === void 0) {
|
|
758
|
-
options = {};
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
var _options2 = options,
|
|
762
|
-
_options2$window = _options2.window,
|
|
763
|
-
window = _options2$window === void 0 ? document.defaultView : _options2$window;
|
|
764
|
-
var globalHistory = window.history;
|
|
765
|
-
|
|
766
|
-
function getIndexAndLocation() {
|
|
767
|
-
var _parsePath = parsePath(window.location.hash.substr(1)),
|
|
768
|
-
_parsePath$pathname = _parsePath.pathname,
|
|
769
|
-
pathname = _parsePath$pathname === void 0 ? '/' : _parsePath$pathname,
|
|
770
|
-
_parsePath$search = _parsePath.search,
|
|
771
|
-
search = _parsePath$search === void 0 ? '' : _parsePath$search,
|
|
772
|
-
_parsePath$hash = _parsePath.hash,
|
|
773
|
-
hash = _parsePath$hash === void 0 ? '' : _parsePath$hash;
|
|
774
|
-
|
|
775
|
-
var state = globalHistory.state || {};
|
|
776
|
-
return [state.idx, readOnly({
|
|
777
|
-
pathname: pathname,
|
|
778
|
-
search: search,
|
|
779
|
-
hash: hash,
|
|
780
|
-
state: state.usr || null,
|
|
781
|
-
key: state.key || 'default'
|
|
782
|
-
})];
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
var blockedPopTx = null;
|
|
786
|
-
|
|
787
|
-
function handlePop() {
|
|
788
|
-
if (blockedPopTx) {
|
|
789
|
-
blockers.call(blockedPopTx);
|
|
790
|
-
blockedPopTx = null;
|
|
791
|
-
} else {
|
|
792
|
-
var nextAction = Action.Pop;
|
|
793
|
-
|
|
794
|
-
var _getIndexAndLocation4 = getIndexAndLocation(),
|
|
795
|
-
nextIndex = _getIndexAndLocation4[0],
|
|
796
|
-
nextLocation = _getIndexAndLocation4[1];
|
|
797
|
-
|
|
798
|
-
if (blockers.length) {
|
|
799
|
-
if (nextIndex != null) {
|
|
800
|
-
var delta = index - nextIndex;
|
|
801
|
-
|
|
802
|
-
if (delta) {
|
|
803
|
-
// Revert the POP
|
|
804
|
-
blockedPopTx = {
|
|
805
|
-
action: nextAction,
|
|
806
|
-
location: nextLocation,
|
|
807
|
-
retry: function retry() {
|
|
808
|
-
go(delta * -1);
|
|
809
|
-
}
|
|
810
|
-
};
|
|
811
|
-
go(delta);
|
|
812
|
-
}
|
|
813
|
-
} else {
|
|
814
|
-
// Trying to POP to a location with no index. We did not create
|
|
815
|
-
// this location, so we can't effectively block the navigation.
|
|
816
|
-
warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
|
|
817
|
-
// detail and link to it here so people can understand better
|
|
818
|
-
// what is going on and how to avoid it.
|
|
819
|
-
"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.") ;
|
|
820
|
-
}
|
|
821
|
-
} else {
|
|
822
|
-
applyTx(nextAction);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
window.addEventListener(PopStateEventType, handlePop); // popstate does not fire on hashchange in IE 11 and old (trident) Edge
|
|
828
|
-
// https://developer.mozilla.org/de/docs/Web/API/Window/popstate_event
|
|
829
|
-
|
|
830
|
-
window.addEventListener(HashChangeEventType, function () {
|
|
831
|
-
var _getIndexAndLocation5 = getIndexAndLocation(),
|
|
832
|
-
nextLocation = _getIndexAndLocation5[1]; // Ignore extraneous hashchange events.
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
if (createPath(nextLocation) !== createPath(location)) {
|
|
836
|
-
handlePop();
|
|
837
|
-
}
|
|
838
|
-
});
|
|
839
|
-
var action = Action.Pop;
|
|
840
|
-
|
|
841
|
-
var _getIndexAndLocation6 = getIndexAndLocation(),
|
|
842
|
-
index = _getIndexAndLocation6[0],
|
|
843
|
-
location = _getIndexAndLocation6[1];
|
|
844
|
-
|
|
845
|
-
var listeners = createEvents();
|
|
846
|
-
var blockers = createEvents();
|
|
847
|
-
|
|
848
|
-
if (index == null) {
|
|
849
|
-
index = 0;
|
|
850
|
-
globalHistory.replaceState(_extends({}, globalHistory.state, {
|
|
851
|
-
idx: index
|
|
852
|
-
}), '');
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
function getBaseHref() {
|
|
856
|
-
var base = document.querySelector('base');
|
|
857
|
-
var href = '';
|
|
858
|
-
|
|
859
|
-
if (base && base.getAttribute('href')) {
|
|
860
|
-
var url = window.location.href;
|
|
861
|
-
var hashIndex = url.indexOf('#');
|
|
862
|
-
href = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
return href;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
function createHref(to) {
|
|
869
|
-
return getBaseHref() + '#' + (typeof to === 'string' ? to : createPath(to));
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
function getNextLocation(to, state) {
|
|
873
|
-
if (state === void 0) {
|
|
874
|
-
state = null;
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
return readOnly(_extends({
|
|
878
|
-
pathname: location.pathname,
|
|
879
|
-
hash: '',
|
|
880
|
-
search: ''
|
|
881
|
-
}, typeof to === 'string' ? parsePath(to) : to, {
|
|
882
|
-
state: state,
|
|
883
|
-
key: createKey()
|
|
884
|
-
}));
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
function getHistoryStateAndUrl(nextLocation, index) {
|
|
888
|
-
return [{
|
|
889
|
-
usr: nextLocation.state,
|
|
890
|
-
key: nextLocation.key,
|
|
891
|
-
idx: index
|
|
892
|
-
}, createHref(nextLocation)];
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
function allowTx(action, location, retry) {
|
|
896
|
-
return !blockers.length || (blockers.call({
|
|
897
|
-
action: action,
|
|
898
|
-
location: location,
|
|
899
|
-
retry: retry
|
|
900
|
-
}), false);
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
function applyTx(nextAction) {
|
|
904
|
-
action = nextAction;
|
|
905
|
-
|
|
906
|
-
var _getIndexAndLocation7 = getIndexAndLocation();
|
|
907
|
-
|
|
908
|
-
index = _getIndexAndLocation7[0];
|
|
909
|
-
location = _getIndexAndLocation7[1];
|
|
910
|
-
listeners.call({
|
|
911
|
-
action: action,
|
|
912
|
-
location: location
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
function push(to, state) {
|
|
917
|
-
var nextAction = Action.Push;
|
|
918
|
-
var nextLocation = getNextLocation(to, state);
|
|
919
|
-
|
|
920
|
-
function retry() {
|
|
921
|
-
push(to, state);
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.push(" + JSON.stringify(to) + ")") ;
|
|
925
|
-
|
|
926
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
927
|
-
var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1),
|
|
928
|
-
historyState = _getHistoryStateAndUr3[0],
|
|
929
|
-
url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading
|
|
930
|
-
// try...catch because iOS limits us to 100 pushState calls :/
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
try {
|
|
934
|
-
globalHistory.pushState(historyState, '', url);
|
|
935
|
-
} catch (error) {
|
|
936
|
-
// They are going to lose state here, but there is no real
|
|
937
|
-
// way to warn them about it since the page will refresh...
|
|
938
|
-
window.location.assign(url);
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
applyTx(nextAction);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
function replace(to, state) {
|
|
946
|
-
var nextAction = Action.Replace;
|
|
947
|
-
var nextLocation = getNextLocation(to, state);
|
|
948
|
-
|
|
949
|
-
function retry() {
|
|
950
|
-
replace(to, state);
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.replace(" + JSON.stringify(to) + ")") ;
|
|
954
|
-
|
|
955
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
956
|
-
var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index),
|
|
957
|
-
historyState = _getHistoryStateAndUr4[0],
|
|
958
|
-
url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
globalHistory.replaceState(historyState, '', url);
|
|
962
|
-
applyTx(nextAction);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
function go(delta) {
|
|
967
|
-
globalHistory.go(delta);
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
var history = {
|
|
971
|
-
get action() {
|
|
972
|
-
return action;
|
|
973
103
|
},
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
104
|
+
push: (path, state) => {
|
|
105
|
+
opts.pushState(path, state);
|
|
106
|
+
onUpdate();
|
|
977
107
|
},
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
replace: replace,
|
|
982
|
-
go: go,
|
|
983
|
-
back: function back() {
|
|
984
|
-
go(-1);
|
|
108
|
+
replace: (path, state) => {
|
|
109
|
+
opts.replaceState(path, state);
|
|
110
|
+
onUpdate();
|
|
985
111
|
},
|
|
986
|
-
|
|
987
|
-
go(
|
|
112
|
+
go: index => {
|
|
113
|
+
opts.go(index);
|
|
114
|
+
onUpdate();
|
|
988
115
|
},
|
|
989
|
-
|
|
990
|
-
|
|
116
|
+
back: () => {
|
|
117
|
+
opts.back();
|
|
118
|
+
onUpdate();
|
|
991
119
|
},
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
if (blockers.length === 1) {
|
|
996
|
-
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
return function () {
|
|
1000
|
-
unblock(); // Remove the beforeunload listener so the document may
|
|
1001
|
-
// still be salvageable in the pagehide event.
|
|
1002
|
-
// See https://html.spec.whatwg.org/#unloading-documents
|
|
1003
|
-
|
|
1004
|
-
if (!blockers.length) {
|
|
1005
|
-
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
|
|
1006
|
-
}
|
|
1007
|
-
};
|
|
120
|
+
forward: () => {
|
|
121
|
+
opts.forward();
|
|
122
|
+
onUpdate();
|
|
1008
123
|
}
|
|
1009
124
|
};
|
|
1010
|
-
return history;
|
|
1011
125
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
var _options3 = options,
|
|
1025
|
-
_options3$initialEntr = _options3.initialEntries,
|
|
1026
|
-
initialEntries = _options3$initialEntr === void 0 ? ['/'] : _options3$initialEntr,
|
|
1027
|
-
initialIndex = _options3.initialIndex;
|
|
1028
|
-
var entries = initialEntries.map(function (entry) {
|
|
1029
|
-
var location = readOnly(_extends({
|
|
1030
|
-
pathname: '/',
|
|
1031
|
-
search: '',
|
|
1032
|
-
hash: '',
|
|
1033
|
-
state: null,
|
|
1034
|
-
key: createKey()
|
|
1035
|
-
}, typeof entry === 'string' ? parsePath(entry) : entry));
|
|
1036
|
-
warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + JSON.stringify(entry) + ")") ;
|
|
1037
|
-
return location;
|
|
1038
|
-
});
|
|
1039
|
-
var index = clamp(initialIndex == null ? entries.length - 1 : initialIndex, 0, entries.length - 1);
|
|
1040
|
-
var action = Action.Pop;
|
|
1041
|
-
var location = entries[index];
|
|
1042
|
-
var listeners = createEvents();
|
|
1043
|
-
var blockers = createEvents();
|
|
1044
|
-
|
|
1045
|
-
function createHref(to) {
|
|
1046
|
-
return typeof to === 'string' ? to : createPath(to);
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
function getNextLocation(to, state) {
|
|
1050
|
-
if (state === void 0) {
|
|
1051
|
-
state = null;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
return readOnly(_extends({
|
|
1055
|
-
pathname: location.pathname,
|
|
1056
|
-
search: '',
|
|
1057
|
-
hash: ''
|
|
1058
|
-
}, typeof to === 'string' ? parsePath(to) : to, {
|
|
1059
|
-
state: state,
|
|
1060
|
-
key: createKey()
|
|
1061
|
-
}));
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
function allowTx(action, location, retry) {
|
|
1065
|
-
return !blockers.length || (blockers.call({
|
|
1066
|
-
action: action,
|
|
1067
|
-
location: location,
|
|
1068
|
-
retry: retry
|
|
1069
|
-
}), false);
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
function applyTx(nextAction, nextLocation) {
|
|
1073
|
-
action = nextAction;
|
|
1074
|
-
location = nextLocation;
|
|
1075
|
-
listeners.call({
|
|
1076
|
-
action: action,
|
|
1077
|
-
location: location
|
|
1078
|
-
});
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
function push(to, state) {
|
|
1082
|
-
var nextAction = Action.Push;
|
|
1083
|
-
var nextLocation = getNextLocation(to, state);
|
|
1084
|
-
|
|
1085
|
-
function retry() {
|
|
1086
|
-
push(to, state);
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.push(" + JSON.stringify(to) + ")") ;
|
|
1090
|
-
|
|
1091
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
1092
|
-
index += 1;
|
|
1093
|
-
entries.splice(index, entries.length, nextLocation);
|
|
1094
|
-
applyTx(nextAction, nextLocation);
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
function replace(to, state) {
|
|
1099
|
-
var nextAction = Action.Replace;
|
|
1100
|
-
var nextLocation = getNextLocation(to, state);
|
|
1101
|
-
|
|
1102
|
-
function retry() {
|
|
1103
|
-
replace(to, state);
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.replace(" + JSON.stringify(to) + ")") ;
|
|
1107
|
-
|
|
1108
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
1109
|
-
entries[index] = nextLocation;
|
|
1110
|
-
applyTx(nextAction, nextLocation);
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
function go(delta) {
|
|
1115
|
-
var nextIndex = clamp(index + delta, 0, entries.length - 1);
|
|
1116
|
-
var nextAction = Action.Pop;
|
|
1117
|
-
var nextLocation = entries[nextIndex];
|
|
1118
|
-
|
|
1119
|
-
function retry() {
|
|
1120
|
-
go(delta);
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
if (allowTx(nextAction, nextLocation, retry)) {
|
|
1124
|
-
index = nextIndex;
|
|
1125
|
-
applyTx(nextAction, nextLocation);
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
var history = {
|
|
1130
|
-
get index() {
|
|
1131
|
-
return index;
|
|
1132
|
-
},
|
|
1133
|
-
|
|
1134
|
-
get action() {
|
|
1135
|
-
return action;
|
|
1136
|
-
},
|
|
1137
|
-
|
|
1138
|
-
get location() {
|
|
1139
|
-
return location;
|
|
1140
|
-
},
|
|
1141
|
-
|
|
1142
|
-
createHref: createHref,
|
|
1143
|
-
push: push,
|
|
1144
|
-
replace: replace,
|
|
1145
|
-
go: go,
|
|
1146
|
-
back: function back() {
|
|
1147
|
-
go(-1);
|
|
126
|
+
function createBrowserHistory(opts) {
|
|
127
|
+
const getHref = opts?.getHref ?? (() => `${window.location.pathname}${window.location.hash}${window.location.search}`);
|
|
128
|
+
const createHref = opts?.createHref ?? (path => path);
|
|
129
|
+
const getLocation = () => parseLocation(getHref(), history.state);
|
|
130
|
+
return createHistory({
|
|
131
|
+
getLocation,
|
|
132
|
+
listener: onUpdate => {
|
|
133
|
+
window.addEventListener(popStateEvent, onUpdate);
|
|
134
|
+
return () => {
|
|
135
|
+
window.removeEventListener(popStateEvent, onUpdate);
|
|
136
|
+
};
|
|
1148
137
|
},
|
|
1149
|
-
|
|
1150
|
-
|
|
138
|
+
pushState: (path, state) => {
|
|
139
|
+
window.history.pushState({
|
|
140
|
+
...state,
|
|
141
|
+
key: createRandomKey()
|
|
142
|
+
}, '', createHref(path));
|
|
1151
143
|
},
|
|
1152
|
-
|
|
1153
|
-
|
|
144
|
+
replaceState: (path, state) => {
|
|
145
|
+
window.history.replaceState({
|
|
146
|
+
...state,
|
|
147
|
+
key: createRandomKey()
|
|
148
|
+
}, '', createHref(path));
|
|
1154
149
|
},
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
};
|
|
1159
|
-
return history;
|
|
1160
|
-
} ////////////////////////////////////////////////////////////////////////////////
|
|
1161
|
-
// UTILS
|
|
1162
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
1163
|
-
|
|
1164
|
-
function clamp(n, lowerBound, upperBound) {
|
|
1165
|
-
return Math.min(Math.max(n, lowerBound), upperBound);
|
|
150
|
+
back: () => window.history.back(),
|
|
151
|
+
forward: () => window.history.forward(),
|
|
152
|
+
go: n => window.history.go(n)
|
|
153
|
+
});
|
|
1166
154
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
event.returnValue = '';
|
|
155
|
+
function createHashHistory() {
|
|
156
|
+
return createBrowserHistory({
|
|
157
|
+
getHref: () => window.location.hash.substring(1),
|
|
158
|
+
createHref: path => `#${path}`
|
|
159
|
+
});
|
|
1173
160
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
161
|
+
function createMemoryHistory(opts = {
|
|
162
|
+
initialEntries: ['/']
|
|
163
|
+
}) {
|
|
164
|
+
const entries = opts.initialEntries;
|
|
165
|
+
let index = opts.initialIndex ?? entries.length - 1;
|
|
166
|
+
let currentState = {};
|
|
167
|
+
const getLocation = () => parseLocation(entries[index], currentState);
|
|
168
|
+
return createHistory({
|
|
169
|
+
getLocation,
|
|
170
|
+
listener: onUpdate => {
|
|
171
|
+
window.addEventListener(popStateEvent, onUpdate);
|
|
172
|
+
// We might need to handle the hashchange event in the future
|
|
173
|
+
// window.addEventListener(hashChangeEvent, onUpdate)
|
|
174
|
+
return () => {
|
|
175
|
+
window.removeEventListener(popStateEvent, onUpdate);
|
|
176
|
+
};
|
|
1180
177
|
},
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
handlers = handlers.filter(function (handler) {
|
|
1186
|
-
return handler !== fn;
|
|
1187
|
-
});
|
|
178
|
+
pushState: (path, state) => {
|
|
179
|
+
currentState = {
|
|
180
|
+
...state,
|
|
181
|
+
key: createRandomKey()
|
|
1188
182
|
};
|
|
183
|
+
entries.push(path);
|
|
184
|
+
index++;
|
|
1189
185
|
},
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
186
|
+
replaceState: (path, state) => {
|
|
187
|
+
currentState = {
|
|
188
|
+
...state,
|
|
189
|
+
key: createRandomKey()
|
|
190
|
+
};
|
|
191
|
+
entries[index] = path;
|
|
192
|
+
},
|
|
193
|
+
back: () => {
|
|
194
|
+
index--;
|
|
195
|
+
},
|
|
196
|
+
forward: () => {
|
|
197
|
+
index = Math.min(index + 1, entries.length - 1);
|
|
198
|
+
},
|
|
199
|
+
go: n => window.history.go(n)
|
|
200
|
+
});
|
|
1200
201
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
search = _ref$search === void 0 ? '' : _ref$search,
|
|
1213
|
-
_ref$hash = _ref.hash,
|
|
1214
|
-
hash = _ref$hash === void 0 ? '' : _ref$hash;
|
|
1215
|
-
if (search && search !== '?') pathname += search.charAt(0) === '?' ? search : '?' + search;
|
|
1216
|
-
if (hash && hash !== '#') pathname += hash.charAt(0) === '#' ? hash : '#' + hash;
|
|
1217
|
-
return pathname;
|
|
1218
|
-
}
|
|
1219
|
-
/**
|
|
1220
|
-
* Parses a string URL path into its separate pathname, search, and hash components.
|
|
1221
|
-
*
|
|
1222
|
-
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#parsepath
|
|
1223
|
-
*/
|
|
1224
|
-
|
|
1225
|
-
function parsePath(path) {
|
|
1226
|
-
var parsedPath = {};
|
|
1227
|
-
|
|
1228
|
-
if (path) {
|
|
1229
|
-
var hashIndex = path.indexOf('#');
|
|
1230
|
-
|
|
1231
|
-
if (hashIndex >= 0) {
|
|
1232
|
-
parsedPath.hash = path.substr(hashIndex);
|
|
1233
|
-
path = path.substr(0, hashIndex);
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
var searchIndex = path.indexOf('?');
|
|
1237
|
-
|
|
1238
|
-
if (searchIndex >= 0) {
|
|
1239
|
-
parsedPath.search = path.substr(searchIndex);
|
|
1240
|
-
path = path.substr(0, searchIndex);
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
if (path) {
|
|
1244
|
-
parsedPath.pathname = path;
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
return parsedPath;
|
|
202
|
+
function parseLocation(href, state) {
|
|
203
|
+
let hashIndex = href.indexOf('#');
|
|
204
|
+
let searchIndex = href.indexOf('?');
|
|
205
|
+
const pathEnd = Math.min(hashIndex, searchIndex);
|
|
206
|
+
return {
|
|
207
|
+
href,
|
|
208
|
+
pathname: pathEnd > -1 ? href.substring(0, pathEnd) : href,
|
|
209
|
+
hash: hashIndex > -1 ? href.substring(hashIndex, searchIndex) : '',
|
|
210
|
+
search: searchIndex > -1 ? href.substring(searchIndex) : '',
|
|
211
|
+
state
|
|
212
|
+
};
|
|
1249
213
|
}
|
|
1250
214
|
|
|
1251
|
-
|
|
1252
|
-
function
|
|
1253
|
-
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
var provided = typeof message === 'function' ? message() : message;
|
|
1257
|
-
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
1258
|
-
throw new Error(value);
|
|
215
|
+
// Thanks co-pilot!
|
|
216
|
+
function createRandomKey() {
|
|
217
|
+
return (Math.random() + 1).toString(36).substring(7);
|
|
1259
218
|
}
|
|
1260
219
|
|
|
1261
|
-
/**
|
|
1262
|
-
* router-core
|
|
1263
|
-
*
|
|
1264
|
-
* Copyright (c) TanStack
|
|
1265
|
-
*
|
|
1266
|
-
* This source code is licensed under the MIT license found in the
|
|
1267
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
1268
|
-
*
|
|
1269
|
-
* @license MIT
|
|
1270
|
-
*/
|
|
1271
|
-
|
|
1272
220
|
function last(arr) {
|
|
1273
221
|
return arr[arr.length - 1];
|
|
1274
222
|
}
|
|
@@ -1328,9 +276,8 @@
|
|
|
1328
276
|
baseSegments.push(toSegment);
|
|
1329
277
|
} else ;
|
|
1330
278
|
} else if (toSegment.value === '..') {
|
|
1331
|
-
var _last;
|
|
1332
279
|
// Extra trailing slash? pop it off
|
|
1333
|
-
if (baseSegments.length > 1 &&
|
|
280
|
+
if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
|
|
1334
281
|
baseSegments.pop();
|
|
1335
282
|
}
|
|
1336
283
|
baseSegments.pop();
|
|
@@ -1427,14 +374,14 @@
|
|
|
1427
374
|
const isLastBaseSegment = i === baseSegments.length - 1;
|
|
1428
375
|
if (routeSegment) {
|
|
1429
376
|
if (routeSegment.type === 'wildcard') {
|
|
1430
|
-
if (baseSegment
|
|
377
|
+
if (baseSegment?.value) {
|
|
1431
378
|
params['*'] = joinPaths(baseSegments.slice(i).map(d => d.value));
|
|
1432
379
|
return true;
|
|
1433
380
|
}
|
|
1434
381
|
return false;
|
|
1435
382
|
}
|
|
1436
383
|
if (routeSegment.type === 'pathname') {
|
|
1437
|
-
if (routeSegment.value === '/' && !
|
|
384
|
+
if (routeSegment.value === '/' && !baseSegment?.value) {
|
|
1438
385
|
return true;
|
|
1439
386
|
}
|
|
1440
387
|
if (baseSegment) {
|
|
@@ -1451,7 +398,7 @@
|
|
|
1451
398
|
return false;
|
|
1452
399
|
}
|
|
1453
400
|
if (routeSegment.type === 'param') {
|
|
1454
|
-
if (
|
|
401
|
+
if (baseSegment?.value === '/') {
|
|
1455
402
|
return false;
|
|
1456
403
|
}
|
|
1457
404
|
if (baseSegment.value.charAt(0) !== '$') {
|
|
@@ -1517,151 +464,25 @@
|
|
|
1517
464
|
return out;
|
|
1518
465
|
}
|
|
1519
466
|
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
router,
|
|
1536
|
-
childRoutes: undefined,
|
|
1537
|
-
parentRoute: parent,
|
|
1538
|
-
get action() {
|
|
1539
|
-
let action = router.store.actions[id] || (() => {
|
|
1540
|
-
router.setStore(s => {
|
|
1541
|
-
s.actions[id] = {
|
|
1542
|
-
submissions: [],
|
|
1543
|
-
submit: async (submission, actionOpts) => {
|
|
1544
|
-
if (!route) {
|
|
1545
|
-
return;
|
|
1546
|
-
}
|
|
1547
|
-
const invalidate = (actionOpts == null ? void 0 : actionOpts.invalidate) ?? true;
|
|
1548
|
-
const [actionStore, setActionStore] = createStore({
|
|
1549
|
-
submittedAt: Date.now(),
|
|
1550
|
-
status: 'pending',
|
|
1551
|
-
submission,
|
|
1552
|
-
isMulti: !!(actionOpts != null && actionOpts.multi)
|
|
1553
|
-
});
|
|
1554
|
-
router.setStore(s => {
|
|
1555
|
-
if (!(actionOpts != null && actionOpts.multi)) {
|
|
1556
|
-
s.actions[id].submissions = action.submissions.filter(d => d.isMulti);
|
|
1557
|
-
}
|
|
1558
|
-
s.actions[id].current = actionStore;
|
|
1559
|
-
s.actions[id].latest = actionStore;
|
|
1560
|
-
s.actions[id].submissions.push(actionStore);
|
|
1561
|
-
});
|
|
1562
|
-
try {
|
|
1563
|
-
const res = await (route.options.action == null ? void 0 : route.options.action(submission));
|
|
1564
|
-
setActionStore(s => {
|
|
1565
|
-
s.data = res;
|
|
1566
|
-
});
|
|
1567
|
-
if (invalidate) {
|
|
1568
|
-
router.invalidateRoute({
|
|
1569
|
-
to: '.',
|
|
1570
|
-
fromCurrent: true
|
|
1571
|
-
});
|
|
1572
|
-
await router.reload();
|
|
1573
|
-
}
|
|
1574
|
-
setActionStore(s => {
|
|
1575
|
-
s.status = 'success';
|
|
1576
|
-
});
|
|
1577
|
-
return res;
|
|
1578
|
-
} catch (err) {
|
|
1579
|
-
console.error(err);
|
|
1580
|
-
setActionStore(s => {
|
|
1581
|
-
s.error = err;
|
|
1582
|
-
s.status = 'error';
|
|
1583
|
-
});
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
};
|
|
1587
|
-
});
|
|
1588
|
-
return router.store.actions[id];
|
|
1589
|
-
})();
|
|
1590
|
-
return action;
|
|
1591
|
-
},
|
|
1592
|
-
get loader() {
|
|
1593
|
-
let loader = router.store.loaders[id] || (() => {
|
|
1594
|
-
router.setStore(s => {
|
|
1595
|
-
s.loaders[id] = {
|
|
1596
|
-
pending: [],
|
|
1597
|
-
fetch: async loaderContext => {
|
|
1598
|
-
if (!route) {
|
|
1599
|
-
return;
|
|
1600
|
-
}
|
|
1601
|
-
const loaderState = {
|
|
1602
|
-
loadedAt: Date.now(),
|
|
1603
|
-
loaderContext
|
|
1604
|
-
};
|
|
1605
|
-
router.setStore(s => {
|
|
1606
|
-
s.loaders[id].current = loaderState;
|
|
1607
|
-
s.loaders[id].latest = loaderState;
|
|
1608
|
-
s.loaders[id].pending.push(loaderState);
|
|
1609
|
-
});
|
|
1610
|
-
try {
|
|
1611
|
-
return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
|
|
1612
|
-
} finally {
|
|
1613
|
-
router.setStore(s => {
|
|
1614
|
-
s.loaders[id].pending = s.loaders[id].pending.filter(d => d !== loaderState);
|
|
1615
|
-
});
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
};
|
|
1619
|
-
});
|
|
1620
|
-
return router.store.loaders[id];
|
|
1621
|
-
})();
|
|
1622
|
-
return loader;
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
// buildLink: (options) => {
|
|
1626
|
-
// return router.buildLink({
|
|
1627
|
-
// ...options,
|
|
1628
|
-
// from: fullPath,
|
|
1629
|
-
// } as any) as any
|
|
1630
|
-
// },
|
|
1631
|
-
|
|
1632
|
-
// navigate: (options) => {
|
|
1633
|
-
// return router.navigate({
|
|
1634
|
-
// ...options,
|
|
1635
|
-
// from: fullPath,
|
|
1636
|
-
// } as any) as any
|
|
1637
|
-
// },
|
|
1638
|
-
|
|
1639
|
-
// matchRoute: (matchLocation, opts) => {
|
|
1640
|
-
// return router.matchRoute(
|
|
1641
|
-
// {
|
|
1642
|
-
// ...matchLocation,
|
|
1643
|
-
// from: fullPath,
|
|
1644
|
-
// } as any,
|
|
1645
|
-
// opts,
|
|
1646
|
-
// ) as any
|
|
1647
|
-
// },
|
|
1648
|
-
};
|
|
1649
|
-
|
|
1650
|
-
router.options.createRoute == null ? void 0 : router.options.createRoute({
|
|
1651
|
-
router,
|
|
1652
|
-
route
|
|
1653
|
-
});
|
|
1654
|
-
return route;
|
|
467
|
+
class Route {
|
|
468
|
+
constructor(routeConfig, options, originalIndex, parent, router) {
|
|
469
|
+
Object.assign(this, {
|
|
470
|
+
...routeConfig,
|
|
471
|
+
originalIndex,
|
|
472
|
+
options,
|
|
473
|
+
getRouter: () => router,
|
|
474
|
+
childRoutes: undefined,
|
|
475
|
+
getParentRoute: () => parent
|
|
476
|
+
});
|
|
477
|
+
router.options.createRoute?.({
|
|
478
|
+
router,
|
|
479
|
+
route: this
|
|
480
|
+
});
|
|
481
|
+
}
|
|
1655
482
|
}
|
|
1656
483
|
|
|
1657
484
|
const rootRouteId = '__root__';
|
|
1658
|
-
const createRouteConfig =
|
|
1659
|
-
if (options === void 0) {
|
|
1660
|
-
options = {};
|
|
1661
|
-
}
|
|
1662
|
-
if (isRoot === void 0) {
|
|
1663
|
-
isRoot = true;
|
|
1664
|
-
}
|
|
485
|
+
const createRouteConfig = (options = {}, children = [], isRoot = true, parentId, parentPath) => {
|
|
1665
486
|
if (isRoot) {
|
|
1666
487
|
options.path = rootRouteId;
|
|
1667
488
|
}
|
|
@@ -1700,80 +521,153 @@
|
|
|
1700
521
|
};
|
|
1701
522
|
};
|
|
1702
523
|
|
|
524
|
+
sn(false);
|
|
525
|
+
let queue = [];
|
|
526
|
+
let batching = false;
|
|
527
|
+
function flush() {
|
|
528
|
+
if (batching) return;
|
|
529
|
+
queue.forEach(cb => cb());
|
|
530
|
+
queue = [];
|
|
531
|
+
}
|
|
532
|
+
function createStore(initialState, debug) {
|
|
533
|
+
const listeners = new Set();
|
|
534
|
+
const store = {
|
|
535
|
+
state: initialState,
|
|
536
|
+
subscribe: listener => {
|
|
537
|
+
listeners.add(listener);
|
|
538
|
+
return () => listeners.delete(listener);
|
|
539
|
+
},
|
|
540
|
+
setState: updater => {
|
|
541
|
+
const previous = store.state;
|
|
542
|
+
store.state = fn(d => {
|
|
543
|
+
updater(d);
|
|
544
|
+
})(previous);
|
|
545
|
+
if (debug) console.log(store.state);
|
|
546
|
+
queue.push(() => listeners.forEach(listener => listener(store.state, previous)));
|
|
547
|
+
flush();
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
return store;
|
|
551
|
+
}
|
|
552
|
+
function batch(cb) {
|
|
553
|
+
batching = true;
|
|
554
|
+
cb();
|
|
555
|
+
batching = false;
|
|
556
|
+
flush();
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// /**
|
|
560
|
+
// * This function converts a store to an immutable value, which is
|
|
561
|
+
// * more complex than you think. On first read, (when prev is undefined)
|
|
562
|
+
// * every value must be recursively touched so tracking is "deep".
|
|
563
|
+
// * Every object/array structure must also be cloned to
|
|
564
|
+
// * have a new reference, otherwise it will get mutated by subsequent
|
|
565
|
+
// * store updates.
|
|
566
|
+
// *
|
|
567
|
+
// * In the case that prev is supplied, we have to do deep comparisons
|
|
568
|
+
// * between prev and next objects/array references and if they are deeply
|
|
569
|
+
// * equal, we can return the prev version for referential equality.
|
|
570
|
+
// */
|
|
571
|
+
// export function storeToImmutable<T>(prev: any, next: T): T {
|
|
572
|
+
// const cache = new Map()
|
|
573
|
+
|
|
574
|
+
// // Visit all nodes
|
|
575
|
+
// // clone all next structures
|
|
576
|
+
// // from bottom up, if prev === next, return prev
|
|
577
|
+
|
|
578
|
+
// function recurse(prev: any, next: any) {
|
|
579
|
+
// if (cache.has(next)) {
|
|
580
|
+
// return cache.get(next)
|
|
581
|
+
// }
|
|
582
|
+
|
|
583
|
+
// const prevIsArray = Array.isArray(prev)
|
|
584
|
+
// const nextIsArray = Array.isArray(next)
|
|
585
|
+
// const prevIsObj = isPlainObject(prev)
|
|
586
|
+
// const nextIsObj = isPlainObject(next)
|
|
587
|
+
// const nextIsComplex = nextIsArray || nextIsObj
|
|
588
|
+
|
|
589
|
+
// const isArray = prevIsArray && nextIsArray
|
|
590
|
+
// const isObj = prevIsObj && nextIsObj
|
|
591
|
+
|
|
592
|
+
// const isSameStructure = isArray || isObj
|
|
593
|
+
|
|
594
|
+
// if (nextIsComplex) {
|
|
595
|
+
// const prevSize = isArray
|
|
596
|
+
// ? prev.length
|
|
597
|
+
// : isObj
|
|
598
|
+
// ? Object.keys(prev).length
|
|
599
|
+
// : -1
|
|
600
|
+
// const nextKeys = isArray ? next : Object.keys(next)
|
|
601
|
+
// const nextSize = nextKeys.length
|
|
602
|
+
|
|
603
|
+
// let changed = false
|
|
604
|
+
// const copy: any = nextIsArray ? [] : {}
|
|
605
|
+
|
|
606
|
+
// for (let i = 0; i < nextSize; i++) {
|
|
607
|
+
// const key = isArray ? i : nextKeys[i]
|
|
608
|
+
// const prevValue = isSameStructure ? prev[key] : undefined
|
|
609
|
+
// const nextValue = next[key]
|
|
610
|
+
|
|
611
|
+
// // Recurse the new value
|
|
612
|
+
// try {
|
|
613
|
+
// console.count(key)
|
|
614
|
+
// copy[key] = recurse(prevValue, nextValue)
|
|
615
|
+
// } catch {}
|
|
616
|
+
|
|
617
|
+
// // If the new value has changed reference,
|
|
618
|
+
// // mark the obj/array as changed
|
|
619
|
+
// if (!changed && copy[key] !== prevValue) {
|
|
620
|
+
// changed = true
|
|
621
|
+
// }
|
|
622
|
+
// }
|
|
623
|
+
|
|
624
|
+
// // No items have changed!
|
|
625
|
+
// // If something has changed, return a clone of the next obj/array
|
|
626
|
+
// if (changed || prevSize !== nextSize) {
|
|
627
|
+
// cache.set(next, copy)
|
|
628
|
+
// return copy
|
|
629
|
+
// }
|
|
630
|
+
|
|
631
|
+
// // If they are exactly the same, return the prev obj/array
|
|
632
|
+
// cache.set(next, prev)
|
|
633
|
+
// return prev
|
|
634
|
+
// }
|
|
635
|
+
|
|
636
|
+
// cache.set(next, next)
|
|
637
|
+
// return next
|
|
638
|
+
// }
|
|
639
|
+
|
|
640
|
+
// return recurse(prev, next)
|
|
641
|
+
// }
|
|
642
|
+
|
|
1703
643
|
/**
|
|
1704
644
|
* This function returns `a` if `b` is deeply equal.
|
|
1705
645
|
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
|
1706
|
-
* This can be used for structural sharing between JSON values for example.
|
|
646
|
+
* This can be used for structural sharing between immutable JSON values for example.
|
|
647
|
+
* Do not use this with signals
|
|
1707
648
|
*/
|
|
1708
|
-
function
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
const
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
// Both are arrays or objects
|
|
1726
|
-
if (isSameStructure) {
|
|
1727
|
-
const aSize = isArray ? prev.length : Object.keys(prev).length;
|
|
1728
|
-
const bItems = isArray ? next : Object.keys(next);
|
|
1729
|
-
const bSize = bItems.length;
|
|
1730
|
-
const copy = isArray ? [] : {};
|
|
1731
|
-
let equalItems = 0;
|
|
1732
|
-
for (let i = 0; i < bSize; i++) {
|
|
1733
|
-
const key = isArray ? i : bItems[i];
|
|
1734
|
-
if (copy[key] === prev[key]) {
|
|
1735
|
-
equalItems++;
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
if (aSize === bSize && equalItems === aSize) {
|
|
1739
|
-
things.set(next, prev);
|
|
1740
|
-
return prev;
|
|
1741
|
-
}
|
|
1742
|
-
things.set(next, copy);
|
|
1743
|
-
for (let i = 0; i < bSize; i++) {
|
|
1744
|
-
const key = isArray ? i : bItems[i];
|
|
1745
|
-
if (typeof bItems[i] === 'function') {
|
|
1746
|
-
copy[key] = prev[key];
|
|
1747
|
-
} else {
|
|
1748
|
-
copy[key] = recurse(prev[key], next[key]);
|
|
1749
|
-
}
|
|
1750
|
-
if (copy[key] === prev[key]) {
|
|
1751
|
-
equalItems++;
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
return copy;
|
|
1755
|
-
}
|
|
1756
|
-
if (nextIsArray) {
|
|
1757
|
-
const copy = [];
|
|
1758
|
-
things.set(next, copy);
|
|
1759
|
-
for (let i = 0; i < next.length; i++) {
|
|
1760
|
-
copy[i] = recurse(undefined, next[i]);
|
|
1761
|
-
}
|
|
1762
|
-
return copy;
|
|
1763
|
-
}
|
|
1764
|
-
if (nextIsObj) {
|
|
1765
|
-
const copy = {};
|
|
1766
|
-
things.set(next, copy);
|
|
1767
|
-
const nextKeys = Object.keys(next);
|
|
1768
|
-
for (let i = 0; i < nextKeys.length; i++) {
|
|
1769
|
-
const key = nextKeys[i];
|
|
1770
|
-
copy[key] = recurse(undefined, next[key]);
|
|
649
|
+
function replaceEqualDeep(prev, _next) {
|
|
650
|
+
if (prev === _next) {
|
|
651
|
+
return prev;
|
|
652
|
+
}
|
|
653
|
+
const next = _next;
|
|
654
|
+
const array = Array.isArray(prev) && Array.isArray(next);
|
|
655
|
+
if (array || isPlainObject(prev) && isPlainObject(next)) {
|
|
656
|
+
const prevSize = array ? prev.length : Object.keys(prev).length;
|
|
657
|
+
const nextItems = array ? next : Object.keys(next);
|
|
658
|
+
const nextSize = nextItems.length;
|
|
659
|
+
const copy = array ? [] : {};
|
|
660
|
+
let equalItems = 0;
|
|
661
|
+
for (let i = 0; i < nextSize; i++) {
|
|
662
|
+
const key = array ? i : nextItems[i];
|
|
663
|
+
copy[key] = replaceEqualDeep(prev[key], next[key]);
|
|
664
|
+
if (copy[key] === prev[key]) {
|
|
665
|
+
equalItems++;
|
|
1771
666
|
}
|
|
1772
|
-
return copy;
|
|
1773
667
|
}
|
|
1774
|
-
return
|
|
668
|
+
return prevSize === nextSize && equalItems === prevSize ? prev : copy;
|
|
1775
669
|
}
|
|
1776
|
-
return
|
|
670
|
+
return next;
|
|
1777
671
|
}
|
|
1778
672
|
|
|
1779
673
|
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
|
@@ -1805,1039 +699,1072 @@
|
|
|
1805
699
|
function hasObjectPrototype(o) {
|
|
1806
700
|
return Object.prototype.toString.call(o) === '[object Object]';
|
|
1807
701
|
}
|
|
702
|
+
function trackDeep(obj) {
|
|
703
|
+
const seen = new Set();
|
|
704
|
+
JSON.stringify(obj, (_, value) => {
|
|
705
|
+
if (typeof value === 'function') {
|
|
706
|
+
return undefined;
|
|
707
|
+
}
|
|
708
|
+
if (typeof value === 'object' && value !== null) {
|
|
709
|
+
if (seen.has(value)) return;
|
|
710
|
+
seen.add(value);
|
|
711
|
+
}
|
|
712
|
+
return value;
|
|
713
|
+
});
|
|
714
|
+
return obj;
|
|
715
|
+
}
|
|
1808
716
|
|
|
1809
717
|
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
718
|
+
class RouteMatch {
|
|
719
|
+
abortController = new AbortController();
|
|
720
|
+
#latestId = '';
|
|
721
|
+
#resolve = () => {};
|
|
722
|
+
onLoaderDataListeners = new Set();
|
|
723
|
+
constructor(router, route, opts) {
|
|
724
|
+
Object.assign(this, {
|
|
725
|
+
route,
|
|
726
|
+
router,
|
|
727
|
+
matchId: opts.matchId,
|
|
728
|
+
pathname: opts.pathname,
|
|
729
|
+
params: opts.params,
|
|
730
|
+
store: createStore({
|
|
731
|
+
routeSearch: {},
|
|
732
|
+
search: {},
|
|
733
|
+
status: 'idle',
|
|
734
|
+
routeLoaderData: {},
|
|
735
|
+
loaderData: {},
|
|
736
|
+
isFetching: false,
|
|
737
|
+
invalid: false,
|
|
738
|
+
invalidAt: Infinity
|
|
739
|
+
})
|
|
1821
740
|
});
|
|
741
|
+
if (!this.__hasLoaders()) {
|
|
742
|
+
this.store.setState(s => s.status = 'success');
|
|
743
|
+
}
|
|
1822
744
|
}
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
...((_store$parentMatch = store.parentMatch) == null ? void 0 : _store$parentMatch.store.loaderData),
|
|
1828
|
-
...s.routeLoaderData
|
|
745
|
+
#setLoaderData = loaderData => {
|
|
746
|
+
batch(() => {
|
|
747
|
+
this.store.setState(s => {
|
|
748
|
+
s.routeLoaderData = loaderData;
|
|
1829
749
|
});
|
|
750
|
+
this.#updateLoaderData();
|
|
1830
751
|
});
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
}
|
|
1845
|
-
});
|
|
1846
|
-
const routeMatch = {
|
|
1847
|
-
...route,
|
|
1848
|
-
...opts,
|
|
1849
|
-
store,
|
|
1850
|
-
// setStore,
|
|
1851
|
-
router,
|
|
1852
|
-
childMatches: [],
|
|
1853
|
-
__: {
|
|
1854
|
-
setParentMatch: parentMatch => {
|
|
1855
|
-
batch(() => {
|
|
1856
|
-
setStore(s => {
|
|
1857
|
-
s.parentMatch = parentMatch;
|
|
1858
|
-
});
|
|
1859
|
-
updateLoaderData();
|
|
1860
|
-
});
|
|
1861
|
-
},
|
|
1862
|
-
abortController: new AbortController(),
|
|
1863
|
-
validate: () => {
|
|
1864
|
-
var _store$parentMatch2;
|
|
1865
|
-
// Validate the search params and stabilize them
|
|
1866
|
-
const parentSearch = ((_store$parentMatch2 = store.parentMatch) == null ? void 0 : _store$parentMatch2.store.search) ?? router.store.currentLocation.search;
|
|
1867
|
-
try {
|
|
1868
|
-
const prevSearch = store.routeSearch;
|
|
1869
|
-
const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
|
|
1870
|
-
let nextSearch = sharedClone(prevSearch, (validator == null ? void 0 : validator(parentSearch)) ?? {});
|
|
1871
|
-
batch(() => {
|
|
1872
|
-
// Invalidate route matches when search param stability changes
|
|
1873
|
-
if (prevSearch !== nextSearch) {
|
|
1874
|
-
setStore(s => s.invalid = true);
|
|
1875
|
-
}
|
|
1876
|
-
|
|
1877
|
-
// TODO: Alright, do we need batch() here?
|
|
1878
|
-
setStore(s => {
|
|
1879
|
-
s.routeSearch = nextSearch;
|
|
1880
|
-
s.search = sharedClone(parentSearch, {
|
|
1881
|
-
...parentSearch,
|
|
1882
|
-
...nextSearch
|
|
1883
|
-
});
|
|
1884
|
-
});
|
|
1885
|
-
});
|
|
1886
|
-
componentTypes.map(async type => {
|
|
1887
|
-
const component = routeMatch.options[type];
|
|
1888
|
-
if (typeof routeMatch.__[type] !== 'function') {
|
|
1889
|
-
routeMatch.__[type] = component;
|
|
1890
|
-
}
|
|
1891
|
-
});
|
|
1892
|
-
} catch (err) {
|
|
1893
|
-
console.error(err);
|
|
1894
|
-
const error = new Error('Invalid search params found', {
|
|
1895
|
-
cause: err
|
|
1896
|
-
});
|
|
1897
|
-
error.code = 'INVALID_SEARCH_PARAMS';
|
|
1898
|
-
setStore(s => {
|
|
1899
|
-
s.status = 'error';
|
|
1900
|
-
s.error = error;
|
|
1901
|
-
});
|
|
1902
|
-
|
|
1903
|
-
// Do not proceed with loading the route
|
|
1904
|
-
return;
|
|
1905
|
-
}
|
|
752
|
+
};
|
|
753
|
+
cancel = () => {
|
|
754
|
+
this.abortController?.abort();
|
|
755
|
+
};
|
|
756
|
+
load = async loaderOpts => {
|
|
757
|
+
const now = Date.now();
|
|
758
|
+
const minMaxAge = loaderOpts?.preload ? Math.max(loaderOpts?.maxAge, loaderOpts?.gcMaxAge) : 0;
|
|
759
|
+
|
|
760
|
+
// If this is a preload, add it to the preload cache
|
|
761
|
+
if (loaderOpts?.preload && minMaxAge > 0) {
|
|
762
|
+
// If the match is currently active, don't preload it
|
|
763
|
+
if (this.router.store.state.currentMatches.find(d => d.id === this.id)) {
|
|
764
|
+
return;
|
|
1906
765
|
}
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
var _routeMatch$__$abortC;
|
|
1910
|
-
(_routeMatch$__$abortC = routeMatch.__.abortController) == null ? void 0 : _routeMatch$__$abortC.abort();
|
|
1911
|
-
},
|
|
1912
|
-
invalidate: () => {
|
|
1913
|
-
setStore(s => s.invalid = true);
|
|
1914
|
-
},
|
|
1915
|
-
hasLoaders: () => {
|
|
1916
|
-
return !!(route.options.loader || componentTypes.some(d => {
|
|
1917
|
-
var _route$options$d;
|
|
1918
|
-
return (_route$options$d = route.options[d]) == null ? void 0 : _route$options$d.preload;
|
|
1919
|
-
}));
|
|
1920
|
-
},
|
|
1921
|
-
load: async loaderOpts => {
|
|
1922
|
-
const now = Date.now();
|
|
1923
|
-
const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0;
|
|
1924
|
-
|
|
1925
|
-
// If this is a preload, add it to the preload cache
|
|
1926
|
-
if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
|
|
1927
|
-
// If the match is currently active, don't preload it
|
|
1928
|
-
if (router.store.currentMatches.find(d => d.matchId === routeMatch.matchId)) {
|
|
1929
|
-
return;
|
|
1930
|
-
}
|
|
1931
|
-
router.store.matchCache[routeMatch.matchId] = {
|
|
766
|
+
this.router.store.setState(s => {
|
|
767
|
+
s.matchCache[this.id] = {
|
|
1932
768
|
gc: now + loaderOpts.gcMaxAge,
|
|
1933
|
-
match:
|
|
1934
|
-
};
|
|
1935
|
-
}
|
|
1936
|
-
|
|
1937
|
-
// If the match is invalid, errored or idle, trigger it to load
|
|
1938
|
-
if (store.status === 'success' && store.isInvalid || store.status === 'error' || store.status === 'idle') {
|
|
1939
|
-
const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
|
|
1940
|
-
await routeMatch.fetch({
|
|
1941
|
-
maxAge
|
|
1942
|
-
});
|
|
1943
|
-
}
|
|
1944
|
-
},
|
|
1945
|
-
fetch: async opts => {
|
|
1946
|
-
const loadId = '' + Date.now() + Math.random();
|
|
1947
|
-
latestId = loadId;
|
|
1948
|
-
const checkLatest = async () => {
|
|
1949
|
-
if (loadId !== latestId) {
|
|
1950
|
-
// warning(true, 'Data loader is out of date!')
|
|
1951
|
-
return new Promise(() => {});
|
|
1952
|
-
}
|
|
1953
|
-
};
|
|
1954
|
-
batch(() => {
|
|
1955
|
-
// If the match was in an error state, set it
|
|
1956
|
-
// to a loading state again. Otherwise, keep it
|
|
1957
|
-
// as loading or resolved
|
|
1958
|
-
if (store.status === 'idle') {
|
|
1959
|
-
setStore(s => s.status = 'loading');
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
// We started loading the route, so it's no longer invalid
|
|
1963
|
-
setStore(s => s.invalid = false);
|
|
1964
|
-
});
|
|
1965
|
-
routeMatch.__.loadPromise = new Promise(async r => {
|
|
1966
|
-
// We are now fetching, even if it's in the background of a
|
|
1967
|
-
// resolved state
|
|
1968
|
-
setStore(s => s.isFetching = true);
|
|
1969
|
-
resolve = r;
|
|
1970
|
-
componentsPromise = (async () => {
|
|
1971
|
-
// then run all component and data loaders in parallel
|
|
1972
|
-
// For each component type, potentially load it asynchronously
|
|
1973
|
-
|
|
1974
|
-
await Promise.all(componentTypes.map(async type => {
|
|
1975
|
-
var _routeMatch$__$type;
|
|
1976
|
-
const component = routeMatch.options[type];
|
|
1977
|
-
if ((_routeMatch$__$type = routeMatch.__[type]) != null && _routeMatch$__$type.preload) {
|
|
1978
|
-
routeMatch.__[type] = await router.options.loadComponent(component);
|
|
1979
|
-
}
|
|
1980
|
-
}));
|
|
1981
|
-
})();
|
|
1982
|
-
dataPromise = Promise.resolve().then(async () => {
|
|
1983
|
-
try {
|
|
1984
|
-
if (routeMatch.options.loader) {
|
|
1985
|
-
const data = await router.loadMatchData(routeMatch);
|
|
1986
|
-
await checkLatest();
|
|
1987
|
-
setLoaderData(data);
|
|
1988
|
-
}
|
|
1989
|
-
setStore(s => {
|
|
1990
|
-
s.error = undefined;
|
|
1991
|
-
s.status = 'success';
|
|
1992
|
-
s.updatedAt = Date.now();
|
|
1993
|
-
s.invalidAt = s.updatedAt + ((opts == null ? void 0 : opts.maxAge) ?? routeMatch.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
|
|
1994
|
-
});
|
|
1995
|
-
return store.routeLoaderData;
|
|
1996
|
-
} catch (err) {
|
|
1997
|
-
await checkLatest();
|
|
1998
|
-
{
|
|
1999
|
-
console.error(err);
|
|
2000
|
-
}
|
|
2001
|
-
setStore(s => {
|
|
2002
|
-
s.error = err;
|
|
2003
|
-
s.status = 'error';
|
|
2004
|
-
s.updatedAt = Date.now();
|
|
2005
|
-
});
|
|
2006
|
-
throw err;
|
|
2007
|
-
}
|
|
2008
|
-
});
|
|
2009
|
-
const after = async () => {
|
|
2010
|
-
await checkLatest();
|
|
2011
|
-
setStore(s => s.isFetching = false);
|
|
2012
|
-
delete routeMatch.__.loadPromise;
|
|
2013
|
-
resolve();
|
|
769
|
+
match: this
|
|
2014
770
|
};
|
|
2015
|
-
try {
|
|
2016
|
-
await Promise.all([componentsPromise, dataPromise.catch(() => {})]);
|
|
2017
|
-
after();
|
|
2018
|
-
} catch {
|
|
2019
|
-
after();
|
|
2020
|
-
}
|
|
2021
|
-
});
|
|
2022
|
-
await routeMatch.__.loadPromise;
|
|
2023
|
-
await checkLatest();
|
|
2024
|
-
}
|
|
2025
|
-
};
|
|
2026
|
-
if (!routeMatch.hasLoaders()) {
|
|
2027
|
-
setStore(s => s.status = 'success');
|
|
2028
|
-
}
|
|
2029
|
-
return routeMatch;
|
|
2030
|
-
}
|
|
2031
|
-
|
|
2032
|
-
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
2033
|
-
const defaultStringifySearch = stringifySearchWith(JSON.stringify);
|
|
2034
|
-
function parseSearchWith(parser) {
|
|
2035
|
-
return searchStr => {
|
|
2036
|
-
if (searchStr.substring(0, 1) === '?') {
|
|
2037
|
-
searchStr = searchStr.substring(1);
|
|
2038
|
-
}
|
|
2039
|
-
let query = decode(searchStr);
|
|
2040
|
-
|
|
2041
|
-
// Try to parse any query params that might be json
|
|
2042
|
-
for (let key in query) {
|
|
2043
|
-
const value = query[key];
|
|
2044
|
-
if (typeof value === 'string') {
|
|
2045
|
-
try {
|
|
2046
|
-
query[key] = parser(value);
|
|
2047
|
-
} catch (err) {
|
|
2048
|
-
//
|
|
2049
|
-
}
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
2052
|
-
return query;
|
|
2053
|
-
};
|
|
2054
|
-
}
|
|
2055
|
-
function stringifySearchWith(stringify) {
|
|
2056
|
-
return search => {
|
|
2057
|
-
search = {
|
|
2058
|
-
...search
|
|
2059
|
-
};
|
|
2060
|
-
if (search) {
|
|
2061
|
-
Object.keys(search).forEach(key => {
|
|
2062
|
-
const val = search[key];
|
|
2063
|
-
if (typeof val === 'undefined' || val === undefined) {
|
|
2064
|
-
delete search[key];
|
|
2065
|
-
} else if (val && typeof val === 'object' && val !== null) {
|
|
2066
|
-
try {
|
|
2067
|
-
search[key] = stringify(val);
|
|
2068
|
-
} catch (err) {
|
|
2069
|
-
// silent
|
|
2070
|
-
}
|
|
2071
|
-
}
|
|
2072
|
-
});
|
|
2073
|
-
}
|
|
2074
|
-
const searchStr = encode(search).toString();
|
|
2075
|
-
return searchStr ? `?${searchStr}` : '';
|
|
2076
|
-
};
|
|
2077
|
-
}
|
|
2078
|
-
|
|
2079
|
-
var _window$document;
|
|
2080
|
-
// Detect if we're in the DOM
|
|
2081
|
-
const isServer = typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement);
|
|
2082
|
-
|
|
2083
|
-
// This is the default history object if none is defined
|
|
2084
|
-
const createDefaultHistory = () => isServer ? createMemoryHistory() : createBrowserHistory();
|
|
2085
|
-
function getInitialRouterState() {
|
|
2086
|
-
return {
|
|
2087
|
-
status: 'idle',
|
|
2088
|
-
latestLocation: null,
|
|
2089
|
-
currentLocation: null,
|
|
2090
|
-
currentMatches: [],
|
|
2091
|
-
actions: {},
|
|
2092
|
-
loaders: {},
|
|
2093
|
-
lastUpdated: Date.now(),
|
|
2094
|
-
matchCache: {},
|
|
2095
|
-
get isFetching() {
|
|
2096
|
-
return this.status === 'loading' || this.currentMatches.some(d => d.store.isFetching);
|
|
2097
|
-
},
|
|
2098
|
-
get isPreloading() {
|
|
2099
|
-
return Object.values(this.matchCache).some(d => d.match.store.isFetching && !this.currentMatches.find(dd => dd.matchId === d.match.matchId));
|
|
2100
|
-
}
|
|
2101
|
-
};
|
|
2102
|
-
}
|
|
2103
|
-
function createRouter(userOptions) {
|
|
2104
|
-
const originalOptions = {
|
|
2105
|
-
defaultLoaderGcMaxAge: 5 * 60 * 1000,
|
|
2106
|
-
defaultLoaderMaxAge: 0,
|
|
2107
|
-
defaultPreloadMaxAge: 2000,
|
|
2108
|
-
defaultPreloadDelay: 50,
|
|
2109
|
-
context: undefined,
|
|
2110
|
-
...userOptions,
|
|
2111
|
-
stringifySearch: (userOptions == null ? void 0 : userOptions.stringifySearch) ?? defaultStringifySearch,
|
|
2112
|
-
parseSearch: (userOptions == null ? void 0 : userOptions.parseSearch) ?? defaultParseSearch
|
|
2113
|
-
};
|
|
2114
|
-
const [store, setStore] = createStore(getInitialRouterState());
|
|
2115
|
-
let navigationPromise;
|
|
2116
|
-
let startedLoadingAt = Date.now();
|
|
2117
|
-
let resolveNavigation = () => {};
|
|
2118
|
-
function onFocus() {
|
|
2119
|
-
router.load();
|
|
2120
|
-
}
|
|
2121
|
-
function buildRouteTree(rootRouteConfig) {
|
|
2122
|
-
const recurseRoutes = (routeConfigs, parent) => {
|
|
2123
|
-
return routeConfigs.map((routeConfig, i) => {
|
|
2124
|
-
const routeOptions = routeConfig.options;
|
|
2125
|
-
const route = createRoute(routeConfig, routeOptions, i, parent, router);
|
|
2126
|
-
const existingRoute = router.routesById[route.routeId];
|
|
2127
|
-
if (existingRoute) {
|
|
2128
|
-
{
|
|
2129
|
-
console.warn(`Duplicate routes found with id: ${String(route.routeId)}`, router.routesById, route);
|
|
2130
|
-
}
|
|
2131
|
-
throw new Error();
|
|
2132
|
-
}
|
|
2133
|
-
router.routesById[route.routeId] = route;
|
|
2134
|
-
const children = routeConfig.children;
|
|
2135
|
-
route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
|
|
2136
|
-
return route;
|
|
2137
|
-
});
|
|
2138
|
-
};
|
|
2139
|
-
const routes = recurseRoutes([rootRouteConfig]);
|
|
2140
|
-
return routes[0];
|
|
2141
|
-
}
|
|
2142
|
-
function parseLocation(location, previousLocation) {
|
|
2143
|
-
const parsedSearch = router.options.parseSearch(location.search);
|
|
2144
|
-
return {
|
|
2145
|
-
pathname: location.pathname,
|
|
2146
|
-
searchStr: location.search,
|
|
2147
|
-
search: sharedClone(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
|
|
2148
|
-
hash: location.hash.split('#').reverse()[0] ?? '',
|
|
2149
|
-
href: `${location.pathname}${location.search}${location.hash}`,
|
|
2150
|
-
state: location.state,
|
|
2151
|
-
key: location.key
|
|
2152
|
-
};
|
|
2153
|
-
}
|
|
2154
|
-
function navigate(location) {
|
|
2155
|
-
const next = router.buildNext(location);
|
|
2156
|
-
return commitLocation(next, location.replace);
|
|
2157
|
-
}
|
|
2158
|
-
function buildLocation(dest) {
|
|
2159
|
-
var _last, _dest$__preSearchFilt, _dest$__preSearchFilt2, _dest$__postSearchFil;
|
|
2160
|
-
if (dest === void 0) {
|
|
2161
|
-
dest = {};
|
|
2162
|
-
}
|
|
2163
|
-
const fromPathname = dest.fromCurrent ? store.latestLocation.pathname : dest.from ?? store.latestLocation.pathname;
|
|
2164
|
-
let pathname = resolvePath(router.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
|
|
2165
|
-
const fromMatches = router.matchRoutes(store.latestLocation.pathname, {
|
|
2166
|
-
strictParseParams: true
|
|
2167
|
-
});
|
|
2168
|
-
const toMatches = router.matchRoutes(pathname);
|
|
2169
|
-
const prevParams = {
|
|
2170
|
-
...((_last = last(fromMatches)) == null ? void 0 : _last.params)
|
|
2171
|
-
};
|
|
2172
|
-
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
2173
|
-
if (nextParams) {
|
|
2174
|
-
toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
2175
|
-
Object.assign({}, nextParams, fn(nextParams));
|
|
2176
|
-
});
|
|
2177
|
-
}
|
|
2178
|
-
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
2179
|
-
|
|
2180
|
-
// Pre filters first
|
|
2181
|
-
const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), store.latestLocation.search) : store.latestLocation.search;
|
|
2182
|
-
|
|
2183
|
-
// Then the link/navigate function
|
|
2184
|
-
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
2185
|
-
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
2186
|
-
: (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
2187
|
-
: {};
|
|
2188
|
-
|
|
2189
|
-
// Then post filters
|
|
2190
|
-
const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
2191
|
-
const search = sharedClone(store.latestLocation.search, postFilteredSearch);
|
|
2192
|
-
const searchStr = router.options.stringifySearch(search);
|
|
2193
|
-
let hash = dest.hash === true ? store.latestLocation.hash : functionalUpdate(dest.hash, store.latestLocation.hash);
|
|
2194
|
-
hash = hash ? `#${hash}` : '';
|
|
2195
|
-
return {
|
|
2196
|
-
pathname,
|
|
2197
|
-
search,
|
|
2198
|
-
searchStr,
|
|
2199
|
-
state: store.latestLocation.state,
|
|
2200
|
-
hash,
|
|
2201
|
-
href: `${pathname}${searchStr}${hash}`,
|
|
2202
|
-
key: dest.key
|
|
2203
|
-
};
|
|
2204
|
-
}
|
|
2205
|
-
function commitLocation(next, replace) {
|
|
2206
|
-
const id = '' + Date.now() + Math.random();
|
|
2207
|
-
let nextAction = 'replace';
|
|
2208
|
-
if (!replace) {
|
|
2209
|
-
nextAction = 'push';
|
|
2210
|
-
}
|
|
2211
|
-
const isSameUrl = parseLocation(router.history.location).href === next.href;
|
|
2212
|
-
if (isSameUrl && !next.key) {
|
|
2213
|
-
nextAction = 'replace';
|
|
2214
|
-
}
|
|
2215
|
-
router.history[nextAction]({
|
|
2216
|
-
pathname: next.pathname,
|
|
2217
|
-
hash: next.hash,
|
|
2218
|
-
search: next.searchStr
|
|
2219
|
-
}, {
|
|
2220
|
-
id,
|
|
2221
|
-
...next.state
|
|
2222
|
-
});
|
|
2223
|
-
return navigationPromise = new Promise(resolve => {
|
|
2224
|
-
const previousNavigationResolve = resolveNavigation;
|
|
2225
|
-
resolveNavigation = () => {
|
|
2226
|
-
previousNavigationResolve();
|
|
2227
|
-
resolve();
|
|
2228
|
-
};
|
|
2229
|
-
});
|
|
2230
|
-
}
|
|
2231
|
-
const router = {
|
|
2232
|
-
types: undefined,
|
|
2233
|
-
// public api
|
|
2234
|
-
history: (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory(),
|
|
2235
|
-
store,
|
|
2236
|
-
setStore,
|
|
2237
|
-
options: originalOptions,
|
|
2238
|
-
basepath: '',
|
|
2239
|
-
routeTree: undefined,
|
|
2240
|
-
routesById: {},
|
|
2241
|
-
reset: () => {
|
|
2242
|
-
setStore(s => Object.assign(s, getInitialRouterState()));
|
|
2243
|
-
},
|
|
2244
|
-
getRoute: id => {
|
|
2245
|
-
return router.routesById[id];
|
|
2246
|
-
},
|
|
2247
|
-
dehydrate: () => {
|
|
2248
|
-
return {
|
|
2249
|
-
store: {
|
|
2250
|
-
...pick(store, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
|
|
2251
|
-
currentMatches: store.currentMatches.map(match => ({
|
|
2252
|
-
matchId: match.matchId,
|
|
2253
|
-
store: pick(match.store, ['status', 'routeLoaderData', 'isInvalid', 'invalidAt'])
|
|
2254
|
-
}))
|
|
2255
|
-
},
|
|
2256
|
-
context: router.options.context
|
|
2257
|
-
};
|
|
2258
|
-
},
|
|
2259
|
-
hydrate: dehydratedRouter => {
|
|
2260
|
-
setStore(s => {
|
|
2261
|
-
// Update the context TODO: make this part of state?
|
|
2262
|
-
router.options.context = dehydratedRouter.context;
|
|
2263
|
-
|
|
2264
|
-
// Match the routes
|
|
2265
|
-
const currentMatches = router.matchRoutes(dehydratedRouter.store.latestLocation.pathname, {
|
|
2266
|
-
strictParseParams: true
|
|
2267
|
-
});
|
|
2268
|
-
currentMatches.forEach((match, index) => {
|
|
2269
|
-
const dehydratedMatch = dehydratedRouter.store.currentMatches[index];
|
|
2270
|
-
invariant(dehydratedMatch && dehydratedMatch.matchId === match.matchId, 'Oh no! There was a hydration mismatch when attempting to restore the state of the router! 😬');
|
|
2271
|
-
Object.assign(match, dehydratedMatch);
|
|
2272
|
-
});
|
|
2273
|
-
currentMatches.forEach(match => match.__.validate());
|
|
2274
|
-
Object.assign(s, {
|
|
2275
|
-
...dehydratedRouter.store,
|
|
2276
|
-
currentMatches
|
|
2277
|
-
});
|
|
2278
771
|
});
|
|
2279
|
-
}
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
}
|
|
2287
|
-
const unsub = router.history.listen(event => {
|
|
2288
|
-
router.load(parseLocation(event.location, store.latestLocation));
|
|
2289
|
-
});
|
|
2290
|
-
|
|
2291
|
-
// addEventListener does not exist in React Native, but window does
|
|
2292
|
-
// In the future, we might need to invert control here for more adapters
|
|
2293
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
2294
|
-
if (window.addEventListener) {
|
|
2295
|
-
// Listen to visibilitychange and focus
|
|
2296
|
-
window.addEventListener('visibilitychange', onFocus, false);
|
|
2297
|
-
window.addEventListener('focus', onFocus, false);
|
|
2298
|
-
}
|
|
2299
|
-
return () => {
|
|
2300
|
-
unsub();
|
|
2301
|
-
if (window.removeEventListener) {
|
|
2302
|
-
// Be sure to unsubscribe if a new handler is set
|
|
2303
|
-
window.removeEventListener('visibilitychange', onFocus);
|
|
2304
|
-
window.removeEventListener('focus', onFocus);
|
|
2305
|
-
}
|
|
2306
|
-
};
|
|
2307
|
-
}
|
|
2308
|
-
return () => {};
|
|
2309
|
-
},
|
|
2310
|
-
update: opts => {
|
|
2311
|
-
const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
|
|
2312
|
-
if (!store.latestLocation || newHistory) {
|
|
2313
|
-
if (opts != null && opts.history) {
|
|
2314
|
-
router.history = opts.history;
|
|
2315
|
-
}
|
|
2316
|
-
setStore(s => {
|
|
2317
|
-
s.latestLocation = parseLocation(router.history.location);
|
|
2318
|
-
s.currentLocation = s.latestLocation;
|
|
2319
|
-
});
|
|
2320
|
-
}
|
|
2321
|
-
Object.assign(router.options, opts);
|
|
2322
|
-
const {
|
|
2323
|
-
basepath,
|
|
2324
|
-
routeConfig
|
|
2325
|
-
} = router.options;
|
|
2326
|
-
router.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
|
|
2327
|
-
if (routeConfig) {
|
|
2328
|
-
router.routesById = {};
|
|
2329
|
-
router.routeTree = buildRouteTree(routeConfig);
|
|
2330
|
-
}
|
|
2331
|
-
return router;
|
|
2332
|
-
},
|
|
2333
|
-
cancelMatches: () => {
|
|
2334
|
-
[...store.currentMatches, ...(store.pendingMatches || [])].forEach(match => {
|
|
2335
|
-
match.cancel();
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// If the match is invalid, errored or idle, trigger it to load
|
|
775
|
+
if (this.store.state.status === 'success' && this.getIsInvalid() || this.store.state.status === 'error' || this.store.state.status === 'idle') {
|
|
776
|
+
const maxAge = loaderOpts?.preload ? loaderOpts?.maxAge : undefined;
|
|
777
|
+
await this.fetch({
|
|
778
|
+
maxAge
|
|
2336
779
|
});
|
|
2337
|
-
}
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
let matches;
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
fetch = async opts => {
|
|
783
|
+
this.__loadPromise = new Promise(async resolve => {
|
|
784
|
+
const loadId = '' + Date.now() + Math.random();
|
|
785
|
+
this.#latestId = loadId;
|
|
786
|
+
const checkLatest = () => loadId !== this.#latestId ? this.__loadPromise?.then(() => resolve()) : undefined;
|
|
787
|
+
let latestPromise;
|
|
2346
788
|
batch(() => {
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
789
|
+
// If the match was in an error state, set it
|
|
790
|
+
// to a loading state again. Otherwise, keep it
|
|
791
|
+
// as loading or resolved
|
|
792
|
+
if (this.store.state.status === 'idle') {
|
|
793
|
+
this.store.setState(s => s.status = 'loading');
|
|
2352
794
|
}
|
|
2353
795
|
|
|
2354
|
-
//
|
|
2355
|
-
|
|
2356
|
-
strictParseParams: true
|
|
2357
|
-
});
|
|
2358
|
-
console.log('set loading', matches);
|
|
2359
|
-
setStore(s => {
|
|
2360
|
-
s.status = 'loading';
|
|
2361
|
-
s.pendingMatches = matches;
|
|
2362
|
-
s.pendingLocation = store.latestLocation;
|
|
2363
|
-
});
|
|
796
|
+
// We started loading the route, so it's no longer invalid
|
|
797
|
+
this.store.setState(s => s.invalid = false);
|
|
2364
798
|
});
|
|
2365
799
|
|
|
2366
|
-
//
|
|
800
|
+
// We are now fetching, even if it's in the background of a
|
|
801
|
+
// resolved state
|
|
802
|
+
this.store.setState(s => s.isFetching = true);
|
|
803
|
+
this.#resolve = resolve;
|
|
804
|
+
const componentsPromise = (async () => {
|
|
805
|
+
// then run all component and data loaders in parallel
|
|
806
|
+
// For each component type, potentially load it asynchronously
|
|
807
|
+
|
|
808
|
+
await Promise.all(componentTypes.map(async type => {
|
|
809
|
+
const component = this.route.options[type];
|
|
810
|
+
if (this[type]?.preload) {
|
|
811
|
+
this[type] = await this.router.options.loadComponent(component);
|
|
812
|
+
}
|
|
813
|
+
}));
|
|
814
|
+
})();
|
|
815
|
+
const dataPromise = Promise.resolve().then(async () => {
|
|
816
|
+
try {
|
|
817
|
+
if (this.route.options.loader) {
|
|
818
|
+
const data = await this.router.loadMatchData(this);
|
|
819
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
820
|
+
this.#setLoaderData(data);
|
|
821
|
+
}
|
|
822
|
+
this.store.setState(s => {
|
|
823
|
+
s.error = undefined;
|
|
824
|
+
s.status = 'success';
|
|
825
|
+
s.updatedAt = Date.now();
|
|
826
|
+
s.invalidAt = s.updatedAt + (opts?.maxAge ?? this.route.options.loaderMaxAge ?? this.router.options.defaultLoaderMaxAge ?? 0);
|
|
827
|
+
});
|
|
828
|
+
return this.store.state.routeLoaderData;
|
|
829
|
+
} catch (err) {
|
|
830
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
831
|
+
{
|
|
832
|
+
console.error(err);
|
|
833
|
+
}
|
|
834
|
+
this.store.setState(s => {
|
|
835
|
+
s.error = err;
|
|
836
|
+
s.status = 'error';
|
|
837
|
+
s.updatedAt = Date.now();
|
|
838
|
+
});
|
|
839
|
+
throw err;
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
const after = async () => {
|
|
843
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
844
|
+
this.store.setState(s => s.isFetching = false);
|
|
845
|
+
this.#resolve();
|
|
846
|
+
delete this.__loadPromise;
|
|
847
|
+
};
|
|
2367
848
|
try {
|
|
2368
|
-
await
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
849
|
+
await Promise.all([componentsPromise, dataPromise.catch(() => {})]);
|
|
850
|
+
after();
|
|
851
|
+
} catch {
|
|
852
|
+
after();
|
|
2372
853
|
}
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
854
|
+
});
|
|
855
|
+
return this.__loadPromise;
|
|
856
|
+
};
|
|
857
|
+
invalidate = async () => {
|
|
858
|
+
this.store.setState(s => s.invalid = true);
|
|
859
|
+
if (this.router.store.state.currentMatches.find(d => d.id === this.id)) {
|
|
860
|
+
await this.load();
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
__hasLoaders = () => {
|
|
864
|
+
return !!(this.route.options.loader || componentTypes.some(d => this.route.options[d]?.preload));
|
|
865
|
+
};
|
|
866
|
+
getIsInvalid = () => {
|
|
867
|
+
const now = Date.now();
|
|
868
|
+
return this.store.state.invalid || this.store.state.invalidAt < now;
|
|
869
|
+
};
|
|
870
|
+
#updateLoaderData = () => {
|
|
871
|
+
this.store.setState(s => {
|
|
872
|
+
s.loaderData = replaceEqualDeep(s.loaderData, {
|
|
873
|
+
...this.parentMatch?.store.state.loaderData,
|
|
874
|
+
...s.routeLoaderData
|
|
2386
875
|
});
|
|
2387
|
-
|
|
2388
|
-
|
|
876
|
+
});
|
|
877
|
+
this.onLoaderDataListeners.forEach(listener => listener());
|
|
878
|
+
};
|
|
879
|
+
__setParentMatch = parentMatch => {
|
|
880
|
+
if (!this.parentMatch && parentMatch) {
|
|
881
|
+
this.parentMatch = parentMatch;
|
|
882
|
+
this.parentMatch.__onLoaderData(() => {
|
|
883
|
+
this.#updateLoaderData();
|
|
2389
884
|
});
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
__onLoaderData = listener => {
|
|
888
|
+
this.onLoaderDataListeners.add(listener);
|
|
889
|
+
// return () => this.onLoaderDataListeners.delete(listener)
|
|
890
|
+
};
|
|
2396
891
|
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
892
|
+
__validate = () => {
|
|
893
|
+
// Validate the search params and stabilize them
|
|
894
|
+
const parentSearch = this.parentMatch?.store.state.search ?? this.router.store.state.latestLocation.search;
|
|
895
|
+
try {
|
|
896
|
+
const prevSearch = this.store.state.routeSearch;
|
|
897
|
+
const validator = typeof this.route.options.validateSearch === 'object' ? this.route.options.validateSearch.parse : this.route.options.validateSearch;
|
|
898
|
+
let nextSearch = validator?.(parentSearch) ?? {};
|
|
899
|
+
batch(() => {
|
|
900
|
+
// Invalidate route matches when search param stability changes
|
|
901
|
+
if (prevSearch !== nextSearch) {
|
|
902
|
+
this.store.setState(s => s.invalid = true);
|
|
2401
903
|
}
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
904
|
+
this.store.setState(s => {
|
|
905
|
+
s.routeSearch = nextSearch;
|
|
906
|
+
s.search = {
|
|
907
|
+
...parentSearch,
|
|
908
|
+
...nextSearch
|
|
2407
909
|
};
|
|
910
|
+
});
|
|
911
|
+
});
|
|
912
|
+
componentTypes.map(async type => {
|
|
913
|
+
const component = this.route.options[type];
|
|
914
|
+
if (typeof this[type] !== 'function') {
|
|
915
|
+
this[type] = component;
|
|
2408
916
|
}
|
|
2409
917
|
});
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
});
|
|
918
|
+
} catch (err) {
|
|
919
|
+
console.error(err);
|
|
920
|
+
const error = new Error('Invalid search params found', {
|
|
921
|
+
cause: err
|
|
2415
922
|
});
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
});
|
|
2421
|
-
delete store.matchCache[d.matchId];
|
|
923
|
+
error.code = 'INVALID_SEARCH_PARAMS';
|
|
924
|
+
this.store.setState(s => {
|
|
925
|
+
s.status = 'error';
|
|
926
|
+
s.error = error;
|
|
2422
927
|
});
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
928
|
+
|
|
929
|
+
// Do not proceed with loading the route
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
936
|
+
const defaultStringifySearch = stringifySearchWith(JSON.stringify);
|
|
937
|
+
function parseSearchWith(parser) {
|
|
938
|
+
return searchStr => {
|
|
939
|
+
if (searchStr.substring(0, 1) === '?') {
|
|
940
|
+
searchStr = searchStr.substring(1);
|
|
941
|
+
}
|
|
942
|
+
let query = decode(searchStr);
|
|
943
|
+
|
|
944
|
+
// Try to parse any query params that might be json
|
|
945
|
+
for (let key in query) {
|
|
946
|
+
const value = query[key];
|
|
947
|
+
if (typeof value === 'string') {
|
|
948
|
+
try {
|
|
949
|
+
query[key] = parser(value);
|
|
950
|
+
} catch (err) {
|
|
951
|
+
//
|
|
952
|
+
}
|
|
2426
953
|
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
954
|
+
}
|
|
955
|
+
return query;
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
function stringifySearchWith(stringify) {
|
|
959
|
+
return search => {
|
|
960
|
+
search = {
|
|
961
|
+
...search
|
|
962
|
+
};
|
|
963
|
+
if (search) {
|
|
964
|
+
Object.keys(search).forEach(key => {
|
|
965
|
+
const val = search[key];
|
|
966
|
+
if (typeof val === 'undefined' || val === undefined) {
|
|
967
|
+
delete search[key];
|
|
968
|
+
} else if (val && typeof val === 'object' && val !== null) {
|
|
969
|
+
try {
|
|
970
|
+
search[key] = stringify(val);
|
|
971
|
+
} catch (err) {
|
|
972
|
+
// silent
|
|
973
|
+
}
|
|
2433
974
|
}
|
|
2434
975
|
});
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
currentMatches: matches,
|
|
2441
|
-
pendingLocation: undefined,
|
|
2442
|
-
pendingMatches: undefined
|
|
2443
|
-
});
|
|
2444
|
-
});
|
|
2445
|
-
resolveNavigation();
|
|
2446
|
-
},
|
|
2447
|
-
cleanMatchCache: () => {
|
|
2448
|
-
const now = Date.now();
|
|
2449
|
-
setStore(s => {
|
|
2450
|
-
Object.keys(s.matchCache).forEach(matchId => {
|
|
2451
|
-
const entry = s.matchCache[matchId];
|
|
2452
|
-
|
|
2453
|
-
// Don't remove loading matches
|
|
2454
|
-
if (entry.match.store.status === 'loading') {
|
|
2455
|
-
return;
|
|
2456
|
-
}
|
|
976
|
+
}
|
|
977
|
+
const searchStr = encode(search).toString();
|
|
978
|
+
return searchStr ? `?${searchStr}` : '';
|
|
979
|
+
};
|
|
980
|
+
}
|
|
2457
981
|
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
982
|
+
const defaultFetchServerDataFn = async ({
|
|
983
|
+
router,
|
|
984
|
+
routeMatch
|
|
985
|
+
}) => {
|
|
986
|
+
const next = router.buildNext({
|
|
987
|
+
to: '.',
|
|
988
|
+
search: d => ({
|
|
989
|
+
...(d ?? {}),
|
|
990
|
+
__data: {
|
|
991
|
+
matchId: routeMatch.id
|
|
992
|
+
}
|
|
993
|
+
})
|
|
994
|
+
});
|
|
995
|
+
const res = await fetch(next.href, {
|
|
996
|
+
method: 'GET',
|
|
997
|
+
signal: routeMatch.abortController.signal
|
|
998
|
+
});
|
|
999
|
+
if (res.ok) {
|
|
1000
|
+
return res.json();
|
|
1001
|
+
}
|
|
1002
|
+
throw new Error('Failed to fetch match data');
|
|
1003
|
+
};
|
|
1004
|
+
class Router {
|
|
1005
|
+
// __location: Location<TAllRouteInfo['fullSearchSchema']>
|
|
1006
|
+
|
|
1007
|
+
startedLoadingAt = Date.now();
|
|
1008
|
+
resolveNavigation = () => {};
|
|
1009
|
+
constructor(options) {
|
|
1010
|
+
this.options = {
|
|
1011
|
+
defaultLoaderGcMaxAge: 5 * 60 * 1000,
|
|
1012
|
+
defaultLoaderMaxAge: 0,
|
|
1013
|
+
defaultPreloadMaxAge: 2000,
|
|
1014
|
+
defaultPreloadDelay: 50,
|
|
1015
|
+
context: undefined,
|
|
1016
|
+
...options,
|
|
1017
|
+
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
1018
|
+
parseSearch: options?.parseSearch ?? defaultParseSearch,
|
|
1019
|
+
fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn
|
|
1020
|
+
};
|
|
1021
|
+
this.history = this.options?.history ?? isServer ? createMemoryHistory() : createBrowserHistory();
|
|
1022
|
+
this.store = createStore(getInitialRouterState());
|
|
1023
|
+
this.basepath = '';
|
|
1024
|
+
this.update(options);
|
|
2462
1025
|
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
1026
|
+
// Allow frameworks to hook into the router creation
|
|
1027
|
+
this.options.createRouter?.(this);
|
|
1028
|
+
}
|
|
1029
|
+
reset = () => {
|
|
1030
|
+
this.store.setState(s => Object.assign(s, getInitialRouterState()));
|
|
1031
|
+
};
|
|
1032
|
+
mount = () => {
|
|
1033
|
+
// Mount only does anything on the client
|
|
1034
|
+
if (!isServer) {
|
|
1035
|
+
// If the router matches are empty, load the matches
|
|
1036
|
+
if (!this.store.state.currentMatches.length) {
|
|
1037
|
+
this.load();
|
|
1038
|
+
}
|
|
1039
|
+
const unsubHistory = this.history.listen(() => {
|
|
1040
|
+
this.load(this.#parseLocation(this.store.state.latestLocation));
|
|
2466
1041
|
});
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
1042
|
+
const visibilityChangeEvent = 'visibilitychange';
|
|
1043
|
+
const focusEvent = 'focus';
|
|
1044
|
+
|
|
1045
|
+
// addEventListener does not exist in React Native, but window does
|
|
1046
|
+
// In the future, we might need to invert control here for more adapters
|
|
1047
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1048
|
+
if (window.addEventListener) {
|
|
1049
|
+
// Listen to visibilitychange and focus
|
|
1050
|
+
window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
|
|
1051
|
+
window.addEventListener(focusEvent, this.#onFocus, false);
|
|
2471
1052
|
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
1053
|
+
return () => {
|
|
1054
|
+
unsubHistory();
|
|
1055
|
+
if (window.removeEventListener) {
|
|
1056
|
+
// Be sure to unsubscribe if a new handler is set
|
|
1057
|
+
|
|
1058
|
+
window.removeEventListener(visibilityChangeEvent, this.#onFocus);
|
|
1059
|
+
window.removeEventListener(focusEvent, this.#onFocus);
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
return () => {};
|
|
1064
|
+
};
|
|
1065
|
+
update = opts => {
|
|
1066
|
+
if (!this.store.state.latestLocation) {
|
|
1067
|
+
this.store.setState(s => {
|
|
1068
|
+
s.latestLocation = this.#parseLocation();
|
|
1069
|
+
s.currentLocation = s.latestLocation;
|
|
2475
1070
|
});
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
1071
|
+
}
|
|
1072
|
+
Object.assign(this.options, opts);
|
|
1073
|
+
const {
|
|
1074
|
+
basepath,
|
|
1075
|
+
routeConfig
|
|
1076
|
+
} = this.options;
|
|
1077
|
+
this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
|
|
1078
|
+
if (routeConfig) {
|
|
1079
|
+
this.routesById = {};
|
|
1080
|
+
this.routeTree = this.#buildRouteTree(routeConfig);
|
|
1081
|
+
}
|
|
1082
|
+
return this;
|
|
1083
|
+
};
|
|
1084
|
+
buildNext = opts => {
|
|
1085
|
+
const next = this.#buildLocation(opts);
|
|
1086
|
+
const matches = this.matchRoutes(next.pathname);
|
|
1087
|
+
const __preSearchFilters = matches.map(match => match.route.options.preSearchFilters ?? []).flat().filter(Boolean);
|
|
1088
|
+
const __postSearchFilters = matches.map(match => match.route.options.postSearchFilters ?? []).flat().filter(Boolean);
|
|
1089
|
+
return this.#buildLocation({
|
|
1090
|
+
...opts,
|
|
1091
|
+
__preSearchFilters,
|
|
1092
|
+
__postSearchFilters
|
|
1093
|
+
});
|
|
1094
|
+
};
|
|
1095
|
+
cancelMatches = () => {
|
|
1096
|
+
[...this.store.state.currentMatches, ...(this.store.state.pendingMatches || [])].forEach(match => {
|
|
1097
|
+
match.cancel();
|
|
1098
|
+
});
|
|
1099
|
+
};
|
|
1100
|
+
load = async next => {
|
|
1101
|
+
let now = Date.now();
|
|
1102
|
+
const startedAt = now;
|
|
1103
|
+
this.startedLoadingAt = startedAt;
|
|
1104
|
+
|
|
1105
|
+
// Cancel any pending matches
|
|
1106
|
+
this.cancelMatches();
|
|
1107
|
+
let matches;
|
|
1108
|
+
batch(() => {
|
|
1109
|
+
if (next) {
|
|
1110
|
+
// Ingest the new location
|
|
1111
|
+
this.store.setState(s => {
|
|
1112
|
+
s.latestLocation = next;
|
|
1113
|
+
});
|
|
2482
1114
|
}
|
|
2483
|
-
|
|
2484
|
-
|
|
1115
|
+
|
|
1116
|
+
// Match the routes
|
|
1117
|
+
matches = this.matchRoutes(this.store.state.latestLocation.pathname, {
|
|
2485
1118
|
strictParseParams: true
|
|
2486
1119
|
});
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
1120
|
+
this.store.setState(s => {
|
|
1121
|
+
s.status = 'loading';
|
|
1122
|
+
s.pendingMatches = matches;
|
|
1123
|
+
s.pendingLocation = this.store.state.latestLocation;
|
|
2491
1124
|
});
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
// Load the matches
|
|
1128
|
+
try {
|
|
1129
|
+
await this.loadMatches(matches);
|
|
1130
|
+
} catch (err) {
|
|
1131
|
+
console.warn(err);
|
|
1132
|
+
invariant(false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
|
|
1133
|
+
}
|
|
1134
|
+
if (this.startedLoadingAt !== startedAt) {
|
|
1135
|
+
// Ignore side-effects of outdated side-effects
|
|
1136
|
+
return this.navigationPromise;
|
|
1137
|
+
}
|
|
1138
|
+
const previousMatches = this.store.state.currentMatches;
|
|
1139
|
+
const exiting = [],
|
|
1140
|
+
staying = [];
|
|
1141
|
+
previousMatches.forEach(d => {
|
|
1142
|
+
if (matches.find(dd => dd.id === d.id)) {
|
|
1143
|
+
staying.push(d);
|
|
1144
|
+
} else {
|
|
1145
|
+
exiting.push(d);
|
|
2499
1146
|
}
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
var _route$childRoutes, _route$childRoutes2;
|
|
2510
|
-
if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
|
|
2511
|
-
return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
|
|
2512
|
-
}
|
|
2513
|
-
const fuzzy = !!(route.routePath !== '/' || (_route$childRoutes2 = route.childRoutes) != null && _route$childRoutes2.length);
|
|
2514
|
-
const matchParams = matchPathname(router.basepath, pathname, {
|
|
2515
|
-
to: route.fullPath,
|
|
2516
|
-
fuzzy,
|
|
2517
|
-
caseSensitive: route.options.caseSensitive ?? router.options.caseSensitive
|
|
2518
|
-
});
|
|
2519
|
-
if (matchParams) {
|
|
2520
|
-
let parsedParams;
|
|
2521
|
-
try {
|
|
2522
|
-
parsedParams = (route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) ?? matchParams;
|
|
2523
|
-
} catch (err) {
|
|
2524
|
-
if (opts != null && opts.strictParseParams) {
|
|
2525
|
-
throw err;
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2528
|
-
params = {
|
|
2529
|
-
...params,
|
|
2530
|
-
...parsedParams
|
|
2531
|
-
};
|
|
2532
|
-
}
|
|
2533
|
-
if (!!matchParams) {
|
|
2534
|
-
foundRoutes = [...parentRoutes, route];
|
|
2535
|
-
}
|
|
2536
|
-
return !!foundRoutes.length;
|
|
2537
|
-
});
|
|
2538
|
-
return !!foundRoutes.length;
|
|
2539
|
-
};
|
|
2540
|
-
findMatchInRoutes([], filteredRoutes);
|
|
2541
|
-
if (!foundRoutes.length) {
|
|
2542
|
-
return;
|
|
2543
|
-
}
|
|
2544
|
-
foundRoutes.forEach(foundRoute => {
|
|
2545
|
-
var _store$matchCache$mat;
|
|
2546
|
-
const interpolatedPath = interpolatePath(foundRoute.routePath, params);
|
|
2547
|
-
const matchId = interpolatePath(foundRoute.routeId, params, true);
|
|
2548
|
-
const match = existingMatches.find(d => d.matchId === matchId) || ((_store$matchCache$mat = store.matchCache[matchId]) == null ? void 0 : _store$matchCache$mat.match) || createRouteMatch(router, foundRoute, {
|
|
2549
|
-
parentMatch,
|
|
2550
|
-
matchId,
|
|
2551
|
-
params,
|
|
2552
|
-
pathname: joinPaths([router.basepath, interpolatedPath])
|
|
2553
|
-
});
|
|
2554
|
-
matches.push(match);
|
|
2555
|
-
});
|
|
2556
|
-
const foundRoute = last(foundRoutes);
|
|
2557
|
-
if ((_foundRoute$childRout = foundRoute.childRoutes) != null && _foundRoute$childRout.length) {
|
|
2558
|
-
recurse(foundRoute.childRoutes);
|
|
2559
|
-
}
|
|
2560
|
-
};
|
|
2561
|
-
recurse([router.routeTree]);
|
|
2562
|
-
linkMatches(matches);
|
|
2563
|
-
return matches;
|
|
2564
|
-
},
|
|
2565
|
-
loadMatches: async (resolvedMatches, loaderOpts) => {
|
|
2566
|
-
resolvedMatches.forEach(async match => {
|
|
2567
|
-
// Validate the match (loads search params etc)
|
|
2568
|
-
match.__.validate();
|
|
1147
|
+
});
|
|
1148
|
+
const entering = matches.filter(d => {
|
|
1149
|
+
return !previousMatches.find(dd => dd.id === d.id);
|
|
1150
|
+
});
|
|
1151
|
+
now = Date.now();
|
|
1152
|
+
exiting.forEach(d => {
|
|
1153
|
+
d.__onExit?.({
|
|
1154
|
+
params: d.params,
|
|
1155
|
+
search: d.store.state.routeSearch
|
|
2569
1156
|
});
|
|
2570
1157
|
|
|
2571
|
-
//
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
1158
|
+
// Clear non-loading error states when match leaves
|
|
1159
|
+
if (d.store.state.status === 'error' && !d.store.state.isFetching) {
|
|
1160
|
+
d.store.setState(s => {
|
|
1161
|
+
s.status = 'idle';
|
|
1162
|
+
s.error = undefined;
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
const gc = Math.max(d.route.options.loaderGcMaxAge ?? this.options.defaultLoaderGcMaxAge ?? 0, d.route.options.loaderMaxAge ?? this.options.defaultLoaderMaxAge ?? 0);
|
|
1166
|
+
if (gc > 0) {
|
|
1167
|
+
this.store.setState(s => {
|
|
1168
|
+
s.matchCache[d.id] = {
|
|
1169
|
+
gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
|
|
1170
|
+
match: d
|
|
1171
|
+
};
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
staying.forEach(d => {
|
|
1176
|
+
d.route.options.onTransition?.({
|
|
1177
|
+
params: d.params,
|
|
1178
|
+
search: d.store.state.routeSearch
|
|
1179
|
+
});
|
|
1180
|
+
});
|
|
1181
|
+
entering.forEach(d => {
|
|
1182
|
+
d.__onExit = d.route.options.onLoaded?.({
|
|
1183
|
+
params: d.params,
|
|
1184
|
+
search: d.store.state.search
|
|
1185
|
+
});
|
|
1186
|
+
delete this.store.state.matchCache[d.id];
|
|
1187
|
+
});
|
|
1188
|
+
this.store.setState(s => {
|
|
1189
|
+
Object.assign(s, {
|
|
1190
|
+
status: 'idle',
|
|
1191
|
+
currentLocation: this.store.state.latestLocation,
|
|
1192
|
+
currentMatches: matches,
|
|
1193
|
+
pendingLocation: undefined,
|
|
1194
|
+
pendingMatches: undefined
|
|
1195
|
+
});
|
|
1196
|
+
});
|
|
1197
|
+
this.options.onRouteChange?.();
|
|
1198
|
+
this.resolveNavigation();
|
|
1199
|
+
};
|
|
1200
|
+
cleanMatchCache = () => {
|
|
1201
|
+
const now = Date.now();
|
|
1202
|
+
this.store.setState(s => {
|
|
1203
|
+
Object.keys(s.matchCache).forEach(matchId => {
|
|
1204
|
+
const entry = s.matchCache[matchId];
|
|
1205
|
+
|
|
1206
|
+
// Don't remove loading matches
|
|
1207
|
+
if (entry.match.store.state.status === 'loading') {
|
|
2589
1208
|
return;
|
|
2590
1209
|
}
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
1210
|
+
|
|
1211
|
+
// Do not remove successful matches that are still valid
|
|
1212
|
+
if (entry.gc > 0 && entry.gc > now) {
|
|
1213
|
+
return;
|
|
2595
1214
|
}
|
|
1215
|
+
|
|
1216
|
+
// Everything else gets removed
|
|
1217
|
+
delete s.matchCache[matchId];
|
|
2596
1218
|
});
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
1219
|
+
});
|
|
1220
|
+
};
|
|
1221
|
+
getRoute = id => {
|
|
1222
|
+
const route = this.routesById[id];
|
|
1223
|
+
invariant(route, `Route with id "${id}" not found`);
|
|
1224
|
+
return route;
|
|
1225
|
+
};
|
|
1226
|
+
loadRoute = async (navigateOpts = this.store.state.latestLocation) => {
|
|
1227
|
+
const next = this.buildNext(navigateOpts);
|
|
1228
|
+
const matches = this.matchRoutes(next.pathname, {
|
|
1229
|
+
strictParseParams: true
|
|
1230
|
+
});
|
|
1231
|
+
await this.loadMatches(matches);
|
|
1232
|
+
return matches;
|
|
1233
|
+
};
|
|
1234
|
+
preloadRoute = async (navigateOpts = this.store.state.latestLocation, loaderOpts) => {
|
|
1235
|
+
const next = this.buildNext(navigateOpts);
|
|
1236
|
+
const matches = this.matchRoutes(next.pathname, {
|
|
1237
|
+
strictParseParams: true
|
|
1238
|
+
});
|
|
1239
|
+
await this.loadMatches(matches, {
|
|
1240
|
+
preload: true,
|
|
1241
|
+
maxAge: loaderOpts.maxAge ?? this.options.defaultPreloadMaxAge ?? this.options.defaultLoaderMaxAge ?? 0,
|
|
1242
|
+
gcMaxAge: loaderOpts.gcMaxAge ?? this.options.defaultPreloadGcMaxAge ?? this.options.defaultLoaderGcMaxAge ?? 0
|
|
1243
|
+
});
|
|
1244
|
+
return matches;
|
|
1245
|
+
};
|
|
1246
|
+
matchRoutes = (pathname, opts) => {
|
|
1247
|
+
const matches = [];
|
|
1248
|
+
if (!this.routeTree) {
|
|
1249
|
+
return matches;
|
|
1250
|
+
}
|
|
1251
|
+
const existingMatches = [...this.store.state.currentMatches, ...(this.store.state.pendingMatches ?? [])];
|
|
1252
|
+
const recurse = async routes => {
|
|
1253
|
+
const parentMatch = last(matches);
|
|
1254
|
+
let params = parentMatch?.params ?? {};
|
|
1255
|
+
const filteredRoutes = this.options.filterRoutes?.(routes) ?? routes;
|
|
1256
|
+
let foundRoutes = [];
|
|
1257
|
+
const findMatchInRoutes = (parentRoutes, routes) => {
|
|
1258
|
+
routes.some(route => {
|
|
1259
|
+
if (!route.path && route.childRoutes?.length) {
|
|
1260
|
+
return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
|
|
1261
|
+
}
|
|
1262
|
+
const fuzzy = !!(route.path !== '/' || route.childRoutes?.length);
|
|
1263
|
+
const matchParams = matchPathname(this.basepath, pathname, {
|
|
1264
|
+
to: route.fullPath,
|
|
1265
|
+
fuzzy,
|
|
1266
|
+
caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive
|
|
1267
|
+
});
|
|
1268
|
+
if (matchParams) {
|
|
1269
|
+
let parsedParams;
|
|
1270
|
+
try {
|
|
1271
|
+
parsedParams = route.options.parseParams?.(matchParams) ?? matchParams;
|
|
1272
|
+
} catch (err) {
|
|
1273
|
+
if (opts?.strictParseParams) {
|
|
1274
|
+
throw err;
|
|
1275
|
+
}
|
|
2614
1276
|
}
|
|
2615
|
-
|
|
1277
|
+
params = {
|
|
1278
|
+
...params,
|
|
1279
|
+
...parsedParams
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
if (!!matchParams) {
|
|
1283
|
+
foundRoutes = [...parentRoutes, route];
|
|
1284
|
+
}
|
|
1285
|
+
return !!foundRoutes.length;
|
|
2616
1286
|
});
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
// signal: routeMatch.__.abortController.signal,
|
|
1287
|
+
return !!foundRoutes.length;
|
|
1288
|
+
};
|
|
1289
|
+
findMatchInRoutes([], filteredRoutes);
|
|
1290
|
+
if (!foundRoutes.length) {
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
foundRoutes.forEach(foundRoute => {
|
|
1294
|
+
const interpolatedPath = interpolatePath(foundRoute.path, params);
|
|
1295
|
+
const matchId = interpolatePath(foundRoute.id, params, true);
|
|
1296
|
+
const match = existingMatches.find(d => d.id === matchId) || this.store.state.matchCache[matchId]?.match || new RouteMatch(this, foundRoute, {
|
|
1297
|
+
matchId,
|
|
1298
|
+
params,
|
|
1299
|
+
pathname: joinPaths([this.basepath, interpolatedPath])
|
|
2631
1300
|
});
|
|
1301
|
+
matches.push(match);
|
|
1302
|
+
});
|
|
1303
|
+
const foundRoute = last(foundRoutes);
|
|
1304
|
+
if (foundRoute.childRoutes?.length) {
|
|
1305
|
+
recurse(foundRoute.childRoutes);
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
recurse([this.routeTree]);
|
|
1309
|
+
linkMatches(matches);
|
|
1310
|
+
return matches;
|
|
1311
|
+
};
|
|
1312
|
+
loadMatches = async (resolvedMatches, loaderOpts) => {
|
|
1313
|
+
this.cleanMatchCache();
|
|
1314
|
+
resolvedMatches.forEach(async match => {
|
|
1315
|
+
// Validate the match (loads search params etc)
|
|
1316
|
+
match.__validate();
|
|
1317
|
+
});
|
|
2632
1318
|
|
|
2633
|
-
|
|
2634
|
-
|
|
1319
|
+
// Check each match middleware to see if the route can be accessed
|
|
1320
|
+
await Promise.all(resolvedMatches.map(async match => {
|
|
1321
|
+
try {
|
|
1322
|
+
await match.route.options.beforeLoad?.({
|
|
1323
|
+
router: this,
|
|
1324
|
+
match
|
|
1325
|
+
});
|
|
1326
|
+
} catch (err) {
|
|
1327
|
+
if (!loaderOpts?.preload) {
|
|
1328
|
+
match.route.options.onLoadError?.(err);
|
|
2635
1329
|
}
|
|
2636
|
-
throw
|
|
1330
|
+
throw err;
|
|
2637
1331
|
}
|
|
2638
|
-
}
|
|
2639
|
-
|
|
2640
|
-
const
|
|
2641
|
-
const
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
1332
|
+
}));
|
|
1333
|
+
const matchPromises = resolvedMatches.map(async (match, index) => {
|
|
1334
|
+
const prevMatch = resolvedMatches[1];
|
|
1335
|
+
const search = match.store.state.search;
|
|
1336
|
+
if (search.__data?.matchId && search.__data.matchId !== match.id) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
match.load(loaderOpts);
|
|
1340
|
+
if (match.store.state.status !== 'success' && match.__loadPromise) {
|
|
1341
|
+
// Wait for the first sign of activity from the match
|
|
1342
|
+
await match.__loadPromise;
|
|
1343
|
+
}
|
|
1344
|
+
if (prevMatch) {
|
|
1345
|
+
await prevMatch.__loadPromise;
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
await Promise.all(matchPromises);
|
|
1349
|
+
};
|
|
1350
|
+
loadMatchData = async routeMatch => {
|
|
1351
|
+
if (isServer || !this.options.useServerData) {
|
|
1352
|
+
return (await routeMatch.route.options.loader?.({
|
|
1353
|
+
// parentLoaderPromise: routeMatch.parentMatch.dataPromise,
|
|
1354
|
+
params: routeMatch.params,
|
|
1355
|
+
search: routeMatch.store.state.routeSearch,
|
|
1356
|
+
signal: routeMatch.abortController.signal
|
|
1357
|
+
})) || {};
|
|
1358
|
+
} else {
|
|
1359
|
+
// Refresh:
|
|
1360
|
+
// '/dashboard'
|
|
1361
|
+
// '/dashboard/invoices/'
|
|
1362
|
+
// '/dashboard/invoices/123'
|
|
1363
|
+
|
|
1364
|
+
// New:
|
|
1365
|
+
// '/dashboard/invoices/456'
|
|
1366
|
+
|
|
1367
|
+
// TODO: batch requests when possible
|
|
1368
|
+
|
|
1369
|
+
return this.options.fetchServerDataFn({
|
|
1370
|
+
router: this,
|
|
1371
|
+
routeMatch
|
|
2646
1372
|
});
|
|
2647
|
-
}
|
|
2648
|
-
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
invalidateRoute = async opts => {
|
|
1376
|
+
const next = this.buildNext(opts);
|
|
1377
|
+
const unloadedMatchIds = this.matchRoutes(next.pathname).map(d => d.id);
|
|
1378
|
+
await Promise.allSettled([...this.store.state.currentMatches, ...(this.store.state.pendingMatches ?? [])].map(async match => {
|
|
1379
|
+
if (unloadedMatchIds.includes(match.id)) {
|
|
1380
|
+
return match.invalidate();
|
|
1381
|
+
}
|
|
1382
|
+
}));
|
|
1383
|
+
};
|
|
1384
|
+
reload = () => {
|
|
1385
|
+
this.navigate({
|
|
2649
1386
|
fromCurrent: true,
|
|
2650
1387
|
replace: true,
|
|
2651
1388
|
search: true
|
|
2652
|
-
})
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
1389
|
+
});
|
|
1390
|
+
};
|
|
1391
|
+
resolvePath = (from, path) => {
|
|
1392
|
+
return resolvePath(this.basepath, from, cleanPath(path));
|
|
1393
|
+
};
|
|
1394
|
+
navigate = async ({
|
|
1395
|
+
from,
|
|
1396
|
+
to = '.',
|
|
1397
|
+
search,
|
|
1398
|
+
hash,
|
|
1399
|
+
replace,
|
|
1400
|
+
params
|
|
1401
|
+
}) => {
|
|
1402
|
+
// If this link simply reloads the current route,
|
|
1403
|
+
// make sure it has a new key so it will trigger a data refresh
|
|
1404
|
+
|
|
1405
|
+
// If this `to` is a valid external URL, return
|
|
1406
|
+
// null for LinkUtils
|
|
1407
|
+
const toString = String(to);
|
|
1408
|
+
const fromString = String(from);
|
|
1409
|
+
let isExternal;
|
|
1410
|
+
try {
|
|
1411
|
+
new URL(`${toString}`);
|
|
1412
|
+
isExternal = true;
|
|
1413
|
+
} catch (e) {}
|
|
1414
|
+
invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
|
|
1415
|
+
return this.#commitLocation({
|
|
1416
|
+
from: fromString,
|
|
1417
|
+
to: toString,
|
|
1418
|
+
search,
|
|
1419
|
+
hash,
|
|
1420
|
+
replace,
|
|
1421
|
+
params
|
|
1422
|
+
});
|
|
1423
|
+
};
|
|
1424
|
+
matchRoute = (location, opts) => {
|
|
1425
|
+
location = {
|
|
1426
|
+
...location,
|
|
1427
|
+
to: location.to ? this.resolvePath(location.from ?? '', location.to) : undefined
|
|
1428
|
+
};
|
|
1429
|
+
const next = this.buildNext(location);
|
|
1430
|
+
if (opts?.pending) {
|
|
1431
|
+
if (!this.store.state.pendingLocation) {
|
|
1432
|
+
return false;
|
|
2672
1433
|
}
|
|
2673
|
-
return matchPathname(
|
|
1434
|
+
return matchPathname(this.basepath, this.store.state.pendingLocation.pathname, {
|
|
2674
1435
|
...opts,
|
|
2675
1436
|
to: next.pathname
|
|
2676
1437
|
});
|
|
2677
|
-
}
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
return navigate({
|
|
2701
|
-
from: fromString,
|
|
2702
|
-
to: toString,
|
|
2703
|
-
search,
|
|
2704
|
-
hash,
|
|
2705
|
-
replace,
|
|
2706
|
-
params
|
|
2707
|
-
});
|
|
2708
|
-
},
|
|
2709
|
-
buildLink: _ref2 => {
|
|
2710
|
-
let {
|
|
2711
|
-
from,
|
|
2712
|
-
to = '.',
|
|
2713
|
-
search,
|
|
2714
|
-
params,
|
|
2715
|
-
hash,
|
|
2716
|
-
target,
|
|
2717
|
-
replace,
|
|
2718
|
-
activeOptions,
|
|
2719
|
-
preload,
|
|
2720
|
-
preloadMaxAge: userPreloadMaxAge,
|
|
2721
|
-
preloadGcMaxAge: userPreloadGcMaxAge,
|
|
2722
|
-
preloadDelay: userPreloadDelay,
|
|
2723
|
-
disabled
|
|
2724
|
-
} = _ref2;
|
|
2725
|
-
// If this link simply reloads the current route,
|
|
2726
|
-
// make sure it has a new key so it will trigger a data refresh
|
|
2727
|
-
|
|
2728
|
-
// If this `to` is a valid external URL, return
|
|
2729
|
-
// null for LinkUtils
|
|
1438
|
+
}
|
|
1439
|
+
return matchPathname(this.basepath, this.store.state.currentLocation.pathname, {
|
|
1440
|
+
...opts,
|
|
1441
|
+
to: next.pathname
|
|
1442
|
+
});
|
|
1443
|
+
};
|
|
1444
|
+
buildLink = ({
|
|
1445
|
+
from,
|
|
1446
|
+
to = '.',
|
|
1447
|
+
search,
|
|
1448
|
+
params,
|
|
1449
|
+
hash,
|
|
1450
|
+
target,
|
|
1451
|
+
replace,
|
|
1452
|
+
activeOptions,
|
|
1453
|
+
preload,
|
|
1454
|
+
preloadMaxAge: userPreloadMaxAge,
|
|
1455
|
+
preloadGcMaxAge: userPreloadGcMaxAge,
|
|
1456
|
+
preloadDelay: userPreloadDelay,
|
|
1457
|
+
disabled
|
|
1458
|
+
}) => {
|
|
1459
|
+
// If this link simply reloads the current route,
|
|
1460
|
+
// make sure it has a new key so it will trigger a data refresh
|
|
2730
1461
|
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
return {
|
|
2734
|
-
type: 'external',
|
|
2735
|
-
href: to
|
|
2736
|
-
};
|
|
2737
|
-
} catch (e) {}
|
|
2738
|
-
const nextOpts = {
|
|
2739
|
-
from,
|
|
2740
|
-
to,
|
|
2741
|
-
search,
|
|
2742
|
-
params,
|
|
2743
|
-
hash,
|
|
2744
|
-
replace
|
|
2745
|
-
};
|
|
2746
|
-
const next = router.buildNext(nextOpts);
|
|
2747
|
-
preload = preload ?? router.options.defaultPreload;
|
|
2748
|
-
const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0;
|
|
2749
|
-
|
|
2750
|
-
// Compare path/hash for matches
|
|
2751
|
-
const pathIsEqual = store.currentLocation.pathname === next.pathname;
|
|
2752
|
-
const currentPathSplit = store.currentLocation.pathname.split('/');
|
|
2753
|
-
const nextPathSplit = next.pathname.split('/');
|
|
2754
|
-
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
2755
|
-
const hashIsEqual = store.currentLocation.hash === next.hash;
|
|
2756
|
-
// Combine the matches based on user options
|
|
2757
|
-
const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
|
|
2758
|
-
const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true;
|
|
2759
|
-
|
|
2760
|
-
// The final "active" test
|
|
2761
|
-
const isActive = pathTest && hashTest;
|
|
2762
|
-
|
|
2763
|
-
// The click handler
|
|
2764
|
-
const handleClick = e => {
|
|
2765
|
-
if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
|
|
2766
|
-
e.preventDefault();
|
|
2767
|
-
if (pathIsEqual && !search && !hash) {
|
|
2768
|
-
router.invalidateRoute(nextOpts);
|
|
2769
|
-
}
|
|
1462
|
+
// If this `to` is a valid external URL, return
|
|
1463
|
+
// null for LinkUtils
|
|
2770
1464
|
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
1465
|
+
try {
|
|
1466
|
+
new URL(`${to}`);
|
|
1467
|
+
return {
|
|
1468
|
+
type: 'external',
|
|
1469
|
+
href: to
|
|
2774
1470
|
};
|
|
1471
|
+
} catch (e) {}
|
|
1472
|
+
const nextOpts = {
|
|
1473
|
+
from,
|
|
1474
|
+
to,
|
|
1475
|
+
search,
|
|
1476
|
+
params,
|
|
1477
|
+
hash,
|
|
1478
|
+
replace
|
|
1479
|
+
};
|
|
1480
|
+
const next = this.buildNext(nextOpts);
|
|
1481
|
+
preload = preload ?? this.options.defaultPreload;
|
|
1482
|
+
const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
|
|
1483
|
+
|
|
1484
|
+
// Compare path/hash for matches
|
|
1485
|
+
const pathIsEqual = this.store.state.currentLocation.pathname === next.pathname;
|
|
1486
|
+
const currentPathSplit = this.store.state.currentLocation.pathname.split('/');
|
|
1487
|
+
const nextPathSplit = next.pathname.split('/');
|
|
1488
|
+
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1489
|
+
const hashIsEqual = this.store.state.currentLocation.hash === next.hash;
|
|
1490
|
+
// Combine the matches based on user options
|
|
1491
|
+
const pathTest = activeOptions?.exact ? pathIsEqual : pathIsFuzzyEqual;
|
|
1492
|
+
const hashTest = activeOptions?.includeHash ? hashIsEqual : true;
|
|
1493
|
+
|
|
1494
|
+
// The final "active" test
|
|
1495
|
+
const isActive = pathTest && hashTest;
|
|
1496
|
+
|
|
1497
|
+
// The click handler
|
|
1498
|
+
const handleClick = e => {
|
|
1499
|
+
if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
|
|
1500
|
+
e.preventDefault();
|
|
1501
|
+
if (pathIsEqual && !search && !hash) {
|
|
1502
|
+
this.invalidateRoute(nextOpts);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
// All is well? Navigate!
|
|
1506
|
+
this.#commitLocation(nextOpts);
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
2775
1509
|
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
1510
|
+
// The click handler
|
|
1511
|
+
const handleFocus = e => {
|
|
1512
|
+
if (preload) {
|
|
1513
|
+
this.preloadRoute(nextOpts, {
|
|
1514
|
+
maxAge: userPreloadMaxAge,
|
|
1515
|
+
gcMaxAge: userPreloadGcMaxAge
|
|
1516
|
+
}).catch(err => {
|
|
1517
|
+
console.warn(err);
|
|
1518
|
+
console.warn('Error preloading route! ☝️');
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
const handleEnter = e => {
|
|
1523
|
+
const target = e.target || {};
|
|
1524
|
+
if (preload) {
|
|
1525
|
+
if (target.preloadTimeout) {
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
target.preloadTimeout = setTimeout(() => {
|
|
1529
|
+
target.preloadTimeout = null;
|
|
1530
|
+
this.preloadRoute(nextOpts, {
|
|
2780
1531
|
maxAge: userPreloadMaxAge,
|
|
2781
1532
|
gcMaxAge: userPreloadGcMaxAge
|
|
2782
1533
|
}).catch(err => {
|
|
2783
|
-
console.
|
|
1534
|
+
console.warn(err);
|
|
2784
1535
|
console.warn('Error preloading route! ☝️');
|
|
2785
1536
|
});
|
|
2786
|
-
}
|
|
2787
|
-
}
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
1537
|
+
}, preloadDelay);
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
const handleLeave = e => {
|
|
1541
|
+
const target = e.target || {};
|
|
1542
|
+
if (target.preloadTimeout) {
|
|
1543
|
+
clearTimeout(target.preloadTimeout);
|
|
1544
|
+
target.preloadTimeout = null;
|
|
1545
|
+
}
|
|
1546
|
+
};
|
|
1547
|
+
return {
|
|
1548
|
+
type: 'internal',
|
|
1549
|
+
next,
|
|
1550
|
+
handleFocus,
|
|
1551
|
+
handleClick,
|
|
1552
|
+
handleEnter,
|
|
1553
|
+
handleLeave,
|
|
1554
|
+
isActive,
|
|
1555
|
+
disabled
|
|
1556
|
+
};
|
|
1557
|
+
};
|
|
1558
|
+
dehydrate = () => {
|
|
1559
|
+
return {
|
|
1560
|
+
state: {
|
|
1561
|
+
...pick(this.store.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
|
|
1562
|
+
currentMatches: this.store.state.currentMatches.map(match => ({
|
|
1563
|
+
matchId: match.id,
|
|
1564
|
+
state: {
|
|
1565
|
+
...pick(match.store.state, ['status', 'routeLoaderData', 'invalidAt', 'invalid'])
|
|
2793
1566
|
}
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
1567
|
+
}))
|
|
1568
|
+
},
|
|
1569
|
+
context: this.options.context
|
|
1570
|
+
};
|
|
1571
|
+
};
|
|
1572
|
+
hydrate = dehydratedRouter => {
|
|
1573
|
+
this.store.setState(s => {
|
|
1574
|
+
// Update the context TODO: make this part of state?
|
|
1575
|
+
this.options.context = dehydratedRouter.context;
|
|
1576
|
+
|
|
1577
|
+
// Match the routes
|
|
1578
|
+
const currentMatches = this.matchRoutes(dehydratedRouter.state.latestLocation.pathname, {
|
|
1579
|
+
strictParseParams: true
|
|
1580
|
+
});
|
|
1581
|
+
currentMatches.forEach((match, index) => {
|
|
1582
|
+
const dehydratedMatch = dehydratedRouter.state.currentMatches[index];
|
|
1583
|
+
invariant(dehydratedMatch && dehydratedMatch.matchId === match.id, 'Oh no! There was a hydration mismatch when attempting to rethis.store the state of the router! 😬');
|
|
1584
|
+
Object.assign(match, dehydratedMatch);
|
|
1585
|
+
});
|
|
1586
|
+
currentMatches.forEach(match => match.__validate());
|
|
1587
|
+
Object.assign(s, {
|
|
1588
|
+
...dehydratedRouter.state,
|
|
1589
|
+
currentMatches
|
|
1590
|
+
});
|
|
1591
|
+
});
|
|
1592
|
+
};
|
|
1593
|
+
getLoader = opts => {
|
|
1594
|
+
const id = opts.from || '/';
|
|
1595
|
+
const route = this.getRoute(id);
|
|
1596
|
+
if (!route) return undefined;
|
|
1597
|
+
let loader = this.store.state.loaders[id] || (() => {
|
|
1598
|
+
this.store.setState(s => {
|
|
1599
|
+
s.loaders[id] = {
|
|
1600
|
+
pending: [],
|
|
1601
|
+
fetch: async loaderContext => {
|
|
1602
|
+
if (!route) {
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
const loaderState = {
|
|
1606
|
+
loadedAt: Date.now(),
|
|
1607
|
+
loaderContext
|
|
1608
|
+
};
|
|
1609
|
+
this.store.setState(s => {
|
|
1610
|
+
s.loaders[id].current = loaderState;
|
|
1611
|
+
s.loaders[id].latest = loaderState;
|
|
1612
|
+
s.loaders[id].pending.push(loaderState);
|
|
2802
1613
|
});
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
1614
|
+
try {
|
|
1615
|
+
return await route.options.loader?.(loaderContext);
|
|
1616
|
+
} finally {
|
|
1617
|
+
this.store.setState(s => {
|
|
1618
|
+
s.loaders[id].pending = s.loaders[id].pending.filter(d => d !== loaderState);
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
});
|
|
1624
|
+
return this.store.state.loaders[id];
|
|
1625
|
+
})();
|
|
1626
|
+
return loader;
|
|
1627
|
+
};
|
|
1628
|
+
#buildRouteTree = rootRouteConfig => {
|
|
1629
|
+
const recurseRoutes = (routeConfigs, parent) => {
|
|
1630
|
+
return routeConfigs.map((routeConfig, i) => {
|
|
1631
|
+
const routeOptions = routeConfig.options;
|
|
1632
|
+
const route = new Route(routeConfig, routeOptions, i, parent, this);
|
|
1633
|
+
const existingRoute = this.routesById[route.id];
|
|
1634
|
+
if (existingRoute) {
|
|
1635
|
+
{
|
|
1636
|
+
console.warn(`Duplicate routes found with id: ${String(route.id)}`, this.routesById, route);
|
|
1637
|
+
}
|
|
1638
|
+
throw new Error();
|
|
2811
1639
|
}
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
1640
|
+
this.routesById[route.id] = route;
|
|
1641
|
+
const children = routeConfig.children;
|
|
1642
|
+
route.childRoutes = children.length ? recurseRoutes(children, route) : undefined;
|
|
1643
|
+
return route;
|
|
1644
|
+
});
|
|
1645
|
+
};
|
|
1646
|
+
const routes = recurseRoutes([rootRouteConfig]);
|
|
1647
|
+
return routes[0];
|
|
1648
|
+
};
|
|
1649
|
+
#parseLocation = previousLocation => {
|
|
1650
|
+
let {
|
|
1651
|
+
pathname,
|
|
1652
|
+
search,
|
|
1653
|
+
hash,
|
|
1654
|
+
state
|
|
1655
|
+
} = this.history.location;
|
|
1656
|
+
const parsedSearch = this.options.parseSearch(search);
|
|
1657
|
+
console.log({
|
|
1658
|
+
pathname: pathname,
|
|
1659
|
+
searchStr: search,
|
|
1660
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
1661
|
+
hash: hash.split('#').reverse()[0] ?? '',
|
|
1662
|
+
href: `${pathname}${search}${hash}`,
|
|
1663
|
+
state: state,
|
|
1664
|
+
key: state?.key || '__init__'
|
|
1665
|
+
});
|
|
1666
|
+
return {
|
|
1667
|
+
pathname: pathname,
|
|
1668
|
+
searchStr: search,
|
|
1669
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
1670
|
+
hash: hash.split('#').reverse()[0] ?? '',
|
|
1671
|
+
href: `${pathname}${search}${hash}`,
|
|
1672
|
+
state: state,
|
|
1673
|
+
key: state?.key || '__init__'
|
|
1674
|
+
};
|
|
1675
|
+
};
|
|
1676
|
+
#onFocus = () => {
|
|
1677
|
+
this.load();
|
|
1678
|
+
};
|
|
1679
|
+
#buildLocation = (dest = {}) => {
|
|
1680
|
+
const fromPathname = dest.fromCurrent ? this.store.state.latestLocation.pathname : dest.from ?? this.store.state.latestLocation.pathname;
|
|
1681
|
+
let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
|
|
1682
|
+
const fromMatches = this.matchRoutes(this.store.state.latestLocation.pathname, {
|
|
1683
|
+
strictParseParams: true
|
|
1684
|
+
});
|
|
1685
|
+
const toMatches = this.matchRoutes(pathname);
|
|
1686
|
+
const prevParams = {
|
|
1687
|
+
...last(fromMatches)?.params
|
|
1688
|
+
};
|
|
1689
|
+
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
1690
|
+
if (nextParams) {
|
|
1691
|
+
toMatches.map(d => d.route.options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
1692
|
+
Object.assign({}, nextParams, fn(nextParams));
|
|
2833
1693
|
});
|
|
2834
1694
|
}
|
|
1695
|
+
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
1696
|
+
|
|
1697
|
+
// Pre filters first
|
|
1698
|
+
const preFilteredSearch = dest.__preSearchFilters?.length ? dest.__preSearchFilters?.reduce((prev, next) => next(prev), this.store.state.latestLocation.search) : this.store.state.latestLocation.search;
|
|
1699
|
+
|
|
1700
|
+
// Then the link/navigate function
|
|
1701
|
+
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
1702
|
+
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
1703
|
+
: dest.__preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
1704
|
+
: {};
|
|
1705
|
+
|
|
1706
|
+
// Then post filters
|
|
1707
|
+
const postFilteredSearch = dest.__postSearchFilters?.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1708
|
+
const search = replaceEqualDeep(this.store.state.latestLocation.search, postFilteredSearch);
|
|
1709
|
+
const searchStr = this.options.stringifySearch(search);
|
|
1710
|
+
let hash = dest.hash === true ? this.store.state.latestLocation.hash : functionalUpdate(dest.hash, this.store.state.latestLocation.hash);
|
|
1711
|
+
hash = hash ? `#${hash}` : '';
|
|
1712
|
+
return {
|
|
1713
|
+
pathname,
|
|
1714
|
+
search,
|
|
1715
|
+
searchStr,
|
|
1716
|
+
state: this.store.state.latestLocation.state,
|
|
1717
|
+
hash,
|
|
1718
|
+
href: `${pathname}${searchStr}${hash}`,
|
|
1719
|
+
key: dest.key
|
|
1720
|
+
};
|
|
1721
|
+
};
|
|
1722
|
+
#commitLocation = location => {
|
|
1723
|
+
const next = this.buildNext(location);
|
|
1724
|
+
const id = '' + Date.now() + Math.random();
|
|
1725
|
+
if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
|
|
1726
|
+
let nextAction = 'replace';
|
|
1727
|
+
if (!location.replace) {
|
|
1728
|
+
nextAction = 'push';
|
|
1729
|
+
}
|
|
1730
|
+
const isSameUrl = this.store.state.latestLocation.href === next.href;
|
|
1731
|
+
if (isSameUrl && !next.key) {
|
|
1732
|
+
nextAction = 'replace';
|
|
1733
|
+
}
|
|
1734
|
+
const href = `${next.pathname}${next.searchStr}${next.hash ? `#${next.hash}` : ''}`;
|
|
1735
|
+
this.history[nextAction === 'push' ? 'push' : 'replace'](href, {
|
|
1736
|
+
id,
|
|
1737
|
+
...next.state
|
|
1738
|
+
});
|
|
1739
|
+
this.load(this.#parseLocation(this.store.state.latestLocation));
|
|
1740
|
+
return this.navigationPromise = new Promise(resolve => {
|
|
1741
|
+
const previousNavigationResolve = this.resolveNavigation;
|
|
1742
|
+
this.resolveNavigation = () => {
|
|
1743
|
+
previousNavigationResolve();
|
|
1744
|
+
resolve();
|
|
1745
|
+
};
|
|
1746
|
+
});
|
|
2835
1747
|
};
|
|
2836
|
-
|
|
1748
|
+
}
|
|
2837
1749
|
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
1750
|
+
// Detect if we're in the DOM
|
|
1751
|
+
const isServer = typeof window === 'undefined' || !window.document.createElement;
|
|
1752
|
+
function getInitialRouterState() {
|
|
1753
|
+
return {
|
|
1754
|
+
status: 'idle',
|
|
1755
|
+
latestLocation: null,
|
|
1756
|
+
currentLocation: null,
|
|
1757
|
+
currentMatches: [],
|
|
1758
|
+
loaders: {},
|
|
1759
|
+
lastUpdated: Date.now(),
|
|
1760
|
+
matchCache: {},
|
|
1761
|
+
get isFetching() {
|
|
1762
|
+
return this.status === 'loading' || this.currentMatches.some(d => d.store.state.isFetching);
|
|
1763
|
+
},
|
|
1764
|
+
get isPreloading() {
|
|
1765
|
+
return Object.values(this.matchCache).some(d => d.match.store.state.isFetching && !this.currentMatches.find(dd => dd.id === d.match.id));
|
|
1766
|
+
}
|
|
1767
|
+
};
|
|
2841
1768
|
}
|
|
2842
1769
|
function isCtrlEvent(e) {
|
|
2843
1770
|
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
@@ -2846,13 +1773,130 @@
|
|
|
2846
1773
|
matches.forEach((match, index) => {
|
|
2847
1774
|
const parent = matches[index - 1];
|
|
2848
1775
|
if (parent) {
|
|
2849
|
-
match.
|
|
2850
|
-
} else {
|
|
2851
|
-
match.__.setParentMatch(undefined);
|
|
1776
|
+
match.__setParentMatch(parent);
|
|
2852
1777
|
}
|
|
2853
1778
|
});
|
|
2854
1779
|
}
|
|
2855
1780
|
|
|
1781
|
+
// createRouterAction is a constrained identify function that takes options: key, action, onSuccess, onError, onSettled, etc
|
|
1782
|
+
function createAction(options) {
|
|
1783
|
+
const store = createStore({
|
|
1784
|
+
submissions: []
|
|
1785
|
+
}, options.debug);
|
|
1786
|
+
return {
|
|
1787
|
+
options,
|
|
1788
|
+
store,
|
|
1789
|
+
reset: () => {
|
|
1790
|
+
store.setState(s => {
|
|
1791
|
+
s.submissions = [];
|
|
1792
|
+
});
|
|
1793
|
+
},
|
|
1794
|
+
submit: async payload => {
|
|
1795
|
+
const submission = {
|
|
1796
|
+
submittedAt: Date.now(),
|
|
1797
|
+
status: 'pending',
|
|
1798
|
+
payload: payload,
|
|
1799
|
+
invalidate: () => {
|
|
1800
|
+
setSubmission(s => {
|
|
1801
|
+
s.isInvalid = true;
|
|
1802
|
+
});
|
|
1803
|
+
},
|
|
1804
|
+
getIsLatest: () => store.state.submissions[store.state.submissions.length - 1]?.submittedAt === submission.submittedAt
|
|
1805
|
+
};
|
|
1806
|
+
const setSubmission = updater => {
|
|
1807
|
+
store.setState(s => {
|
|
1808
|
+
const a = s.submissions.find(d => d.submittedAt === submission.submittedAt);
|
|
1809
|
+
invariant(a, 'Could not find submission in store');
|
|
1810
|
+
updater(a);
|
|
1811
|
+
});
|
|
1812
|
+
};
|
|
1813
|
+
store.setState(s => {
|
|
1814
|
+
s.submissions.push(submission);
|
|
1815
|
+
s.submissions.reverse();
|
|
1816
|
+
s.submissions = s.submissions.slice(0, options.maxSubmissions ?? 10);
|
|
1817
|
+
s.submissions.reverse();
|
|
1818
|
+
});
|
|
1819
|
+
const after = async () => {
|
|
1820
|
+
options.onEachSettled?.(submission);
|
|
1821
|
+
if (submission.getIsLatest()) await options.onLatestSettled?.(submission);
|
|
1822
|
+
};
|
|
1823
|
+
try {
|
|
1824
|
+
const res = await options.action?.(submission.payload);
|
|
1825
|
+
setSubmission(s => {
|
|
1826
|
+
s.response = res;
|
|
1827
|
+
});
|
|
1828
|
+
await options.onEachSuccess?.(submission);
|
|
1829
|
+
if (submission.getIsLatest()) await options.onLatestSuccess?.(submission);
|
|
1830
|
+
await after();
|
|
1831
|
+
setSubmission(s => {
|
|
1832
|
+
s.status = 'success';
|
|
1833
|
+
});
|
|
1834
|
+
return res;
|
|
1835
|
+
} catch (err) {
|
|
1836
|
+
console.error(err);
|
|
1837
|
+
setSubmission(s => {
|
|
1838
|
+
s.error = err;
|
|
1839
|
+
});
|
|
1840
|
+
await options.onEachError?.(submission);
|
|
1841
|
+
if (submission.getIsLatest()) await options.onLatestError?.(submission);
|
|
1842
|
+
await after();
|
|
1843
|
+
setSubmission(s => {
|
|
1844
|
+
s.status = 'error';
|
|
1845
|
+
});
|
|
1846
|
+
throw err;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
function useStore(store, selector = d => d, compareShallow) {
|
|
1853
|
+
const slice = withSelector.useSyncExternalStoreWithSelector(store.subscribe, () => store.state, () => store.state, selector, compareShallow ? shallow : undefined);
|
|
1854
|
+
return slice;
|
|
1855
|
+
}
|
|
1856
|
+
function shallow(objA, objB) {
|
|
1857
|
+
if (Object.is(objA, objB)) {
|
|
1858
|
+
return true;
|
|
1859
|
+
}
|
|
1860
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
1861
|
+
return false;
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
// if (objA instanceof Map && objB instanceof Map) {
|
|
1865
|
+
// if (objA.size !== objB.size) return false
|
|
1866
|
+
|
|
1867
|
+
// for (const [key, value] of objA) {
|
|
1868
|
+
// if (!Object.is(value, objB.get(key))) {
|
|
1869
|
+
// return false
|
|
1870
|
+
// }
|
|
1871
|
+
// }
|
|
1872
|
+
// return true
|
|
1873
|
+
// }
|
|
1874
|
+
|
|
1875
|
+
// if (objA instanceof Set && objB instanceof Set) {
|
|
1876
|
+
// if (objA.size !== objB.size) return false
|
|
1877
|
+
|
|
1878
|
+
// for (const value of objA) {
|
|
1879
|
+
// if (!objB.has(value)) {
|
|
1880
|
+
// return false
|
|
1881
|
+
// }
|
|
1882
|
+
// }
|
|
1883
|
+
// return true
|
|
1884
|
+
// }
|
|
1885
|
+
|
|
1886
|
+
const keysA = Object.keys(objA);
|
|
1887
|
+
if (keysA.length !== Object.keys(objB).length) {
|
|
1888
|
+
return false;
|
|
1889
|
+
}
|
|
1890
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
1891
|
+
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
|
|
1892
|
+
return false;
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
return true;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
//
|
|
1899
|
+
|
|
2856
1900
|
function lazy(importer) {
|
|
2857
1901
|
const lazyComp = /*#__PURE__*/React__namespace.lazy(importer);
|
|
2858
1902
|
const finalComp = lazyComp;
|
|
@@ -2882,7 +1926,7 @@
|
|
|
2882
1926
|
hash,
|
|
2883
1927
|
search,
|
|
2884
1928
|
params,
|
|
2885
|
-
to,
|
|
1929
|
+
to = '.',
|
|
2886
1930
|
preload,
|
|
2887
1931
|
preloadDelay,
|
|
2888
1932
|
preloadMaxAge,
|
|
@@ -2963,7 +2007,7 @@
|
|
|
2963
2007
|
}
|
|
2964
2008
|
const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
2965
2009
|
const linkProps = useLinkProps(props);
|
|
2966
|
-
return /*#__PURE__*/React__namespace.createElement("a", _extends
|
|
2010
|
+
return /*#__PURE__*/React__namespace.createElement("a", _extends({
|
|
2967
2011
|
ref: ref
|
|
2968
2012
|
}, linkProps, {
|
|
2969
2013
|
children: typeof props.children === 'function' ? props.children({
|
|
@@ -2973,82 +2017,26 @@
|
|
|
2973
2017
|
});
|
|
2974
2018
|
const matchesContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
2975
2019
|
const routerContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
valueRef.current = sharedClone(undefined, getValue());
|
|
2987
|
-
}
|
|
2988
|
-
|
|
2989
|
-
// Snapshot should just return the current cached value
|
|
2990
|
-
const getSnapshot = React__namespace.useCallback(() => valueRef.current, []);
|
|
2991
|
-
const getStore = React__namespace.useCallback(cb => {
|
|
2992
|
-
// A root is necessary to track effects
|
|
2993
|
-
return createRoot(() => {
|
|
2994
|
-
createEffect(() => {
|
|
2995
|
-
// Read and update the value
|
|
2996
|
-
// getValue will handle which values are accessed and
|
|
2997
|
-
// thus tracked.
|
|
2998
|
-
// sharedClone will both recursively track the end result
|
|
2999
|
-
// and ensure that the previous value is structurally shared
|
|
3000
|
-
// into the new version.
|
|
3001
|
-
valueRef.current = unwrap(
|
|
3002
|
-
// Unwrap the value to get rid of any proxy structures
|
|
3003
|
-
sharedClone(valueRef.current, getValue()));
|
|
3004
|
-
cb();
|
|
3005
|
-
});
|
|
2020
|
+
class ReactRouter extends Router {
|
|
2021
|
+
constructor(opts) {
|
|
2022
|
+
super({
|
|
2023
|
+
...opts,
|
|
2024
|
+
loadComponent: async component => {
|
|
2025
|
+
if (component.preload) {
|
|
2026
|
+
await component.preload();
|
|
2027
|
+
}
|
|
2028
|
+
return component;
|
|
2029
|
+
}
|
|
3006
2030
|
});
|
|
3007
|
-
}, []);
|
|
3008
|
-
return shim.useSyncExternalStore(getStore, getSnapshot, getSnapshot);
|
|
3009
|
-
};
|
|
3010
|
-
const [store, setStore] = createStore({
|
|
3011
|
-
foo: 'foo',
|
|
3012
|
-
bar: {
|
|
3013
|
-
baz: 'baz'
|
|
3014
2031
|
}
|
|
3015
|
-
});
|
|
3016
|
-
createRoot(() => {
|
|
3017
|
-
let prev;
|
|
3018
|
-
createEffect(() => {
|
|
3019
|
-
console.log('effect');
|
|
3020
|
-
const next = sharedClone(prev, store);
|
|
3021
|
-
console.log(next);
|
|
3022
|
-
prev = untrack(() => next);
|
|
3023
|
-
});
|
|
3024
|
-
});
|
|
3025
|
-
setStore(s => {
|
|
3026
|
-
s.foo = '1';
|
|
3027
|
-
});
|
|
3028
|
-
setStore(s => {
|
|
3029
|
-
s.bar.baz = '2';
|
|
3030
|
-
});
|
|
3031
|
-
function createReactRouter(opts) {
|
|
3032
|
-
const coreRouter = createRouter({
|
|
3033
|
-
...opts,
|
|
3034
|
-
loadComponent: async component => {
|
|
3035
|
-
if (component.preload) {
|
|
3036
|
-
await component.preload();
|
|
3037
|
-
}
|
|
3038
|
-
return component;
|
|
3039
|
-
}
|
|
3040
|
-
});
|
|
3041
|
-
return coreRouter;
|
|
3042
2032
|
}
|
|
3043
|
-
function RouterProvider(
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
} = _ref;
|
|
2033
|
+
function RouterProvider({
|
|
2034
|
+
router,
|
|
2035
|
+
...rest
|
|
2036
|
+
}) {
|
|
3048
2037
|
router.update(rest);
|
|
3049
|
-
const [,, currentMatches] =
|
|
2038
|
+
const [,, currentMatches] = useStore(router.store, s => [s.status, s.pendingMatches, s.currentMatches], true);
|
|
3050
2039
|
React__namespace.useEffect(router.mount, [router]);
|
|
3051
|
-
console.log('current', currentMatches);
|
|
3052
2040
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
|
|
3053
2041
|
value: {
|
|
3054
2042
|
router: router
|
|
@@ -3062,9 +2050,9 @@
|
|
|
3062
2050
|
warning(!value, 'useRouter must be used inside a <Router> component!');
|
|
3063
2051
|
return value.router;
|
|
3064
2052
|
}
|
|
3065
|
-
function useRouterStore(selector) {
|
|
2053
|
+
function useRouterStore(selector, shallow) {
|
|
3066
2054
|
const router = useRouter();
|
|
3067
|
-
return
|
|
2055
|
+
return useStore(router.store, selector, shallow);
|
|
3068
2056
|
}
|
|
3069
2057
|
function useMatches() {
|
|
3070
2058
|
return React__namespace.useContext(matchesContext);
|
|
@@ -3072,12 +2060,12 @@
|
|
|
3072
2060
|
function useMatch(opts) {
|
|
3073
2061
|
const router = useRouter();
|
|
3074
2062
|
const nearestMatch = useMatches()[0];
|
|
3075
|
-
const match = opts
|
|
3076
|
-
invariant(match, `Could not find ${opts
|
|
3077
|
-
if (
|
|
3078
|
-
invariant(nearestMatch.
|
|
2063
|
+
const match = opts?.from ? router.store.state.currentMatches.find(d => d.route.id === opts?.from) : nearestMatch;
|
|
2064
|
+
invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
|
|
2065
|
+
if (opts?.strict ?? true) {
|
|
2066
|
+
invariant(nearestMatch.route.id == match?.route.id, `useMatch("${match?.route.id}") is being called in a component that is meant to render the '${nearestMatch.route.id}' route. Did you mean to 'useMatch("${match?.route.id}", { strict: false })' or 'useRoute("${match?.route.id}")' instead?`);
|
|
3079
2067
|
}
|
|
3080
|
-
|
|
2068
|
+
useStore(match.store, d => opts?.track?.(match) ?? match, opts?.shallow);
|
|
3081
2069
|
return match;
|
|
3082
2070
|
}
|
|
3083
2071
|
function useRoute(routeId) {
|
|
@@ -3088,18 +2076,22 @@
|
|
|
3088
2076
|
}
|
|
3089
2077
|
function useLoaderData(opts) {
|
|
3090
2078
|
const match = useMatch(opts);
|
|
3091
|
-
|
|
2079
|
+
invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
|
|
2080
|
+
useStore(match.store, d => opts?.track?.(d.loaderData) ?? d.loaderData);
|
|
2081
|
+
return match.store.state.loaderData;
|
|
3092
2082
|
}
|
|
3093
2083
|
function useSearch(opts) {
|
|
3094
2084
|
const match = useMatch(opts);
|
|
3095
|
-
|
|
2085
|
+
useStore(match.store, d => opts?.track?.(d.search) ?? d.search);
|
|
2086
|
+
return match.store.state.search;
|
|
3096
2087
|
}
|
|
3097
2088
|
function useParams(opts) {
|
|
3098
2089
|
const router = useRouter();
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
return (
|
|
3102
|
-
}
|
|
2090
|
+
useStore(router.store, d => {
|
|
2091
|
+
const params = last(d.currentMatches)?.params;
|
|
2092
|
+
return opts?.track?.(params) ?? params;
|
|
2093
|
+
});
|
|
2094
|
+
return last(router.store.state.currentMatches)?.params;
|
|
3103
2095
|
}
|
|
3104
2096
|
function useNavigate(defaultOpts) {
|
|
3105
2097
|
const router = useRouter();
|
|
@@ -3110,12 +2102,6 @@
|
|
|
3110
2102
|
});
|
|
3111
2103
|
};
|
|
3112
2104
|
}
|
|
3113
|
-
function useAction(opts) {
|
|
3114
|
-
const route = useRoute(opts.from);
|
|
3115
|
-
const action = route.action;
|
|
3116
|
-
__useStoreValue(() => action);
|
|
3117
|
-
return action;
|
|
3118
|
-
}
|
|
3119
2105
|
function useMatchRoute() {
|
|
3120
2106
|
const router = useRouter();
|
|
3121
2107
|
return opts => {
|
|
@@ -3136,37 +2122,49 @@
|
|
|
3136
2122
|
if (!params) {
|
|
3137
2123
|
return null;
|
|
3138
2124
|
}
|
|
3139
|
-
|
|
2125
|
+
if (typeof props.children === 'function') {
|
|
2126
|
+
return props.children(params);
|
|
2127
|
+
}
|
|
2128
|
+
return params ? props.children : null;
|
|
3140
2129
|
}
|
|
3141
2130
|
function Outlet() {
|
|
3142
|
-
const router = useRouter();
|
|
3143
2131
|
const matches = useMatches().slice(1);
|
|
3144
2132
|
const match = matches[0];
|
|
2133
|
+
if (!match) {
|
|
2134
|
+
return null;
|
|
2135
|
+
}
|
|
2136
|
+
return /*#__PURE__*/React__namespace.createElement(SubOutlet, {
|
|
2137
|
+
matches: matches,
|
|
2138
|
+
match: match
|
|
2139
|
+
});
|
|
2140
|
+
}
|
|
2141
|
+
function SubOutlet({
|
|
2142
|
+
matches,
|
|
2143
|
+
match
|
|
2144
|
+
}) {
|
|
2145
|
+
const router = useRouter();
|
|
2146
|
+
useStore(match.store);
|
|
3145
2147
|
const defaultPending = React__namespace.useCallback(() => null, []);
|
|
3146
|
-
__useStoreValue(() => match == null ? void 0 : match.store);
|
|
3147
2148
|
const Inner = React__namespace.useCallback(props => {
|
|
3148
|
-
if (props.match.store.status === 'error') {
|
|
3149
|
-
throw props.match.store.error;
|
|
2149
|
+
if (props.match.store.state.status === 'error') {
|
|
2150
|
+
throw props.match.store.state.error;
|
|
3150
2151
|
}
|
|
3151
|
-
if (props.match.store.status === 'success') {
|
|
3152
|
-
return /*#__PURE__*/React__namespace.createElement(props.match.
|
|
2152
|
+
if (props.match.store.state.status === 'success') {
|
|
2153
|
+
return /*#__PURE__*/React__namespace.createElement(props.match.component ?? router.options.defaultComponent ?? Outlet);
|
|
3153
2154
|
}
|
|
3154
|
-
if (props.match.store.status === 'loading') {
|
|
3155
|
-
throw props.match.
|
|
2155
|
+
if (props.match.store.state.status === 'loading') {
|
|
2156
|
+
throw props.match.__loadPromise;
|
|
3156
2157
|
}
|
|
3157
2158
|
invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
|
|
3158
2159
|
}, []);
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
}
|
|
3162
|
-
const PendingComponent = match.__.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
|
|
3163
|
-
const errorComponent = match.__.errorComponent ?? router.options.defaultErrorComponent;
|
|
2160
|
+
const PendingComponent = match.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
|
|
2161
|
+
const errorComponent = match.errorComponent ?? router.options.defaultErrorComponent;
|
|
3164
2162
|
return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
|
|
3165
2163
|
value: matches
|
|
3166
2164
|
}, /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
|
|
3167
2165
|
fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, null)
|
|
3168
2166
|
}, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
3169
|
-
key: match.
|
|
2167
|
+
key: match.route.id,
|
|
3170
2168
|
errorComponent: errorComponent,
|
|
3171
2169
|
match: match
|
|
3172
2170
|
}, /*#__PURE__*/React__namespace.createElement(Inner, {
|
|
@@ -3179,7 +2177,7 @@
|
|
|
3179
2177
|
info: undefined
|
|
3180
2178
|
};
|
|
3181
2179
|
componentDidCatch(error, info) {
|
|
3182
|
-
console.error(`Error in route match: ${this.props.match.
|
|
2180
|
+
console.error(`Error in route match: ${this.props.match.id}`);
|
|
3183
2181
|
console.error(error);
|
|
3184
2182
|
this.setState({
|
|
3185
2183
|
error,
|
|
@@ -3187,7 +2185,7 @@
|
|
|
3187
2185
|
});
|
|
3188
2186
|
}
|
|
3189
2187
|
render() {
|
|
3190
|
-
return /*#__PURE__*/React__namespace.createElement(CatchBoundaryInner, _extends
|
|
2188
|
+
return /*#__PURE__*/React__namespace.createElement(CatchBoundaryInner, _extends({}, this.props, {
|
|
3191
2189
|
errorState: this.state,
|
|
3192
2190
|
reset: () => this.setState({})
|
|
3193
2191
|
}));
|
|
@@ -3199,20 +2197,27 @@
|
|
|
3199
2197
|
// router's location key changes.
|
|
3200
2198
|
function CatchBoundaryInner(props) {
|
|
3201
2199
|
const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
|
|
3202
|
-
|
|
2200
|
+
useRouter();
|
|
3203
2201
|
const errorComponent = props.errorComponent ?? DefaultErrorBoundary;
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
2202
|
+
|
|
2203
|
+
// React.useEffect(() => {
|
|
2204
|
+
// if (activeErrorState) {
|
|
2205
|
+
// let prevKey = router.store.currentLocation.key
|
|
2206
|
+
// return createRoot((dispose) => {
|
|
2207
|
+
// createEffect(() => {
|
|
2208
|
+
// if (router.store.currentLocation.key !== prevKey) {
|
|
2209
|
+
// prevKey = router.store.currentLocation.key
|
|
2210
|
+
// setActiveErrorState({} as any)
|
|
2211
|
+
// }
|
|
2212
|
+
// })
|
|
2213
|
+
|
|
2214
|
+
// return dispose
|
|
2215
|
+
// })
|
|
2216
|
+
// }
|
|
2217
|
+
|
|
2218
|
+
// return
|
|
2219
|
+
// }, [activeErrorState])
|
|
2220
|
+
|
|
3216
2221
|
React__namespace.useEffect(() => {
|
|
3217
2222
|
if (props.errorState.error) {
|
|
3218
2223
|
setActiveErrorState(props.errorState);
|
|
@@ -3224,10 +2229,9 @@
|
|
|
3224
2229
|
}
|
|
3225
2230
|
return props.children;
|
|
3226
2231
|
}
|
|
3227
|
-
function DefaultErrorBoundary(
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
} = _ref2;
|
|
2232
|
+
function DefaultErrorBoundary({
|
|
2233
|
+
error
|
|
2234
|
+
}) {
|
|
3231
2235
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
3232
2236
|
style: {
|
|
3233
2237
|
padding: '.5rem',
|
|
@@ -3251,98 +2255,87 @@
|
|
|
3251
2255
|
}
|
|
3252
2256
|
}, error.message) : null)));
|
|
3253
2257
|
}
|
|
3254
|
-
function
|
|
3255
|
-
|
|
3256
|
-
React__namespace.
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
//
|
|
3280
|
-
// const seen = new Set()
|
|
3281
|
-
|
|
3282
|
-
// return (
|
|
3283
|
-
// JSON.stringify(obj, (_, value) => {
|
|
3284
|
-
// if (typeof value === 'function') {
|
|
3285
|
-
// return undefined
|
|
3286
|
-
// }
|
|
3287
|
-
// if (typeof value === 'object' && value !== null) {
|
|
3288
|
-
// if (seen.has(value)) return
|
|
3289
|
-
// seen.add(value)
|
|
2258
|
+
function useAction(action, opts) {
|
|
2259
|
+
useStore(action.store, d => opts?.track?.(d) ?? d, true);
|
|
2260
|
+
const [ref] = React__namespace.useState({});
|
|
2261
|
+
Object.assign(ref, {
|
|
2262
|
+
...action,
|
|
2263
|
+
latestSubmission: action.store.state.submissions[action.store.state.submissions.length - 1],
|
|
2264
|
+
pendingSubmissions: React__namespace.useMemo(() => action.store.state.submissions.filter(d => d.status === 'pending'), [action.store.state.submissions])
|
|
2265
|
+
});
|
|
2266
|
+
return ref;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
// TODO: While we migrate away from the history package, these need to be disabled
|
|
2270
|
+
// export function usePrompt(message: string, when: boolean | any): void {
|
|
2271
|
+
// const router = useRouter()
|
|
2272
|
+
|
|
2273
|
+
// React.useEffect(() => {
|
|
2274
|
+
// if (!when) return
|
|
2275
|
+
|
|
2276
|
+
// let unblock = router.getHistory().block((transition) => {
|
|
2277
|
+
// if (window.confirm(message)) {
|
|
2278
|
+
// unblock()
|
|
2279
|
+
// transition.retry()
|
|
2280
|
+
// } else {
|
|
2281
|
+
// router.setStore((s) => {
|
|
2282
|
+
// s.currentLocation.pathname = window.location.pathname
|
|
2283
|
+
// })
|
|
3290
2284
|
// }
|
|
3291
|
-
//
|
|
3292
|
-
|
|
3293
|
-
//
|
|
2285
|
+
// })
|
|
2286
|
+
|
|
2287
|
+
// return unblock
|
|
2288
|
+
// }, [when, message])
|
|
2289
|
+
// }
|
|
2290
|
+
|
|
2291
|
+
// export function Prompt({ message, when, children }: PromptProps) {
|
|
2292
|
+
// usePrompt(message, when ?? true)
|
|
2293
|
+
// return (children ?? null) as ReactNode
|
|
3294
2294
|
// }
|
|
3295
2295
|
|
|
3296
2296
|
exports.DefaultErrorBoundary = DefaultErrorBoundary;
|
|
3297
2297
|
exports.Link = Link;
|
|
3298
2298
|
exports.MatchRoute = MatchRoute;
|
|
3299
2299
|
exports.Outlet = Outlet;
|
|
3300
|
-
exports.
|
|
2300
|
+
exports.ReactRouter = ReactRouter;
|
|
2301
|
+
exports.Route = Route;
|
|
2302
|
+
exports.RouteMatch = RouteMatch;
|
|
2303
|
+
exports.Router = Router;
|
|
3301
2304
|
exports.RouterProvider = RouterProvider;
|
|
3302
|
-
exports.__useStoreValue = __useStoreValue;
|
|
3303
2305
|
exports.batch = batch;
|
|
3304
2306
|
exports.cleanPath = cleanPath;
|
|
2307
|
+
exports.createAction = createAction;
|
|
3305
2308
|
exports.createBrowserHistory = createBrowserHistory;
|
|
3306
|
-
exports.createEffect = createEffect;
|
|
3307
2309
|
exports.createHashHistory = createHashHistory;
|
|
3308
|
-
exports.createMemo = createMemo;
|
|
3309
2310
|
exports.createMemoryHistory = createMemoryHistory;
|
|
3310
|
-
exports.createReactRouter = createReactRouter;
|
|
3311
|
-
exports.createRoot = createRoot;
|
|
3312
|
-
exports.createRoute = createRoute;
|
|
3313
2311
|
exports.createRouteConfig = createRouteConfig;
|
|
3314
|
-
exports.createRouteMatch = createRouteMatch;
|
|
3315
|
-
exports.createRouter = createRouter;
|
|
3316
|
-
exports.createSignal = createSignal;
|
|
3317
2312
|
exports.createStore = createStore;
|
|
3318
2313
|
exports.decode = decode;
|
|
2314
|
+
exports.defaultFetchServerDataFn = defaultFetchServerDataFn;
|
|
3319
2315
|
exports.defaultParseSearch = defaultParseSearch;
|
|
3320
2316
|
exports.defaultStringifySearch = defaultStringifySearch;
|
|
3321
2317
|
exports.encode = encode;
|
|
3322
2318
|
exports.functionalUpdate = functionalUpdate;
|
|
3323
2319
|
exports.interpolatePath = interpolatePath;
|
|
3324
2320
|
exports.invariant = invariant;
|
|
3325
|
-
exports.isWrappable = isWrappable;
|
|
3326
2321
|
exports.joinPaths = joinPaths;
|
|
3327
2322
|
exports.last = last;
|
|
3328
2323
|
exports.lazy = lazy;
|
|
3329
2324
|
exports.matchByPath = matchByPath;
|
|
3330
2325
|
exports.matchPathname = matchPathname;
|
|
3331
2326
|
exports.matchesContext = matchesContext;
|
|
3332
|
-
exports.onCleanup = onCleanup;
|
|
3333
2327
|
exports.parsePathname = parsePathname;
|
|
3334
2328
|
exports.parseSearchWith = parseSearchWith;
|
|
3335
2329
|
exports.pick = pick;
|
|
2330
|
+
exports.replaceEqualDeep = replaceEqualDeep;
|
|
3336
2331
|
exports.resolvePath = resolvePath;
|
|
3337
2332
|
exports.rootRouteId = rootRouteId;
|
|
3338
2333
|
exports.routerContext = routerContext;
|
|
3339
|
-
exports.sharedClone = sharedClone;
|
|
3340
2334
|
exports.stringifySearchWith = stringifySearchWith;
|
|
2335
|
+
exports.trackDeep = trackDeep;
|
|
3341
2336
|
exports.trimPath = trimPath;
|
|
3342
2337
|
exports.trimPathLeft = trimPathLeft;
|
|
3343
2338
|
exports.trimPathRight = trimPathRight;
|
|
3344
|
-
exports.untrack = untrack;
|
|
3345
|
-
exports.unwrap = unwrap;
|
|
3346
2339
|
exports.useAction = useAction;
|
|
3347
2340
|
exports.useLinkProps = useLinkProps;
|
|
3348
2341
|
exports.useLoaderData = useLoaderData;
|
|
@@ -3351,11 +2344,11 @@
|
|
|
3351
2344
|
exports.useMatches = useMatches;
|
|
3352
2345
|
exports.useNavigate = useNavigate;
|
|
3353
2346
|
exports.useParams = useParams;
|
|
3354
|
-
exports.usePrompt = usePrompt;
|
|
3355
2347
|
exports.useRoute = useRoute;
|
|
3356
2348
|
exports.useRouter = useRouter;
|
|
3357
2349
|
exports.useRouterStore = useRouterStore;
|
|
3358
2350
|
exports.useSearch = useSearch;
|
|
2351
|
+
exports.useStore = useStore;
|
|
3359
2352
|
exports.warning = warning;
|
|
3360
2353
|
|
|
3361
2354
|
Object.defineProperty(exports, '__esModule', { value: true });
|