@tanstack/react-router 0.0.1-beta.204 → 0.0.1-beta.206
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/RouterProvider.js +963 -0
- package/build/cjs/RouterProvider.js.map +1 -0
- package/build/cjs/fileRoute.js +29 -0
- package/build/cjs/fileRoute.js.map +1 -0
- package/build/cjs/index.js +69 -21
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/path.js +211 -0
- package/build/cjs/path.js.map +1 -0
- package/build/cjs/qss.js +65 -0
- package/build/cjs/qss.js.map +1 -0
- package/build/cjs/react.js +148 -190
- package/build/cjs/react.js.map +1 -1
- package/build/cjs/redirects.js +27 -0
- package/build/cjs/redirects.js.map +1 -0
- package/build/cjs/route.js +136 -0
- package/build/cjs/route.js.map +1 -0
- package/build/cjs/router.js +203 -0
- package/build/cjs/router.js.map +1 -0
- package/build/cjs/searchParams.js +83 -0
- package/build/cjs/searchParams.js.map +1 -0
- package/build/cjs/utils.js +196 -0
- package/build/cjs/utils.js.map +1 -0
- package/build/esm/index.js +1801 -211
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +385 -164
- package/build/types/RouteMatch.d.ts +23 -0
- package/build/types/RouterProvider.d.ts +54 -0
- package/build/types/awaited.d.ts +0 -8
- package/build/types/defer.d.ts +0 -0
- package/build/types/fileRoute.d.ts +17 -0
- package/build/types/history.d.ts +7 -0
- package/build/types/index.d.ts +17 -4
- package/build/types/link.d.ts +98 -0
- package/build/types/location.d.ts +14 -0
- package/build/types/path.d.ts +16 -0
- package/build/types/qss.d.ts +2 -0
- package/build/types/react.d.ts +23 -83
- package/build/types/redirects.d.ts +10 -0
- package/build/types/route.d.ts +222 -0
- package/build/types/routeInfo.d.ts +22 -0
- package/build/types/router.d.ts +115 -0
- package/build/types/scroll-restoration.d.ts +0 -3
- package/build/types/searchParams.d.ts +7 -0
- package/build/types/utils.d.ts +48 -0
- package/build/umd/index.development.js +1118 -1540
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +2 -33
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -4
- package/src/RouteMatch.ts +28 -0
- package/src/RouterProvider.tsx +1390 -0
- package/src/awaited.tsx +40 -40
- package/src/defer.ts +55 -0
- package/src/fileRoute.ts +143 -0
- package/src/history.ts +8 -0
- package/src/index.tsx +18 -5
- package/src/link.ts +347 -0
- package/src/location.ts +14 -0
- package/src/path.ts +256 -0
- package/src/qss.ts +53 -0
- package/src/react.tsx +174 -422
- package/src/redirects.ts +31 -0
- package/src/route.ts +710 -0
- package/src/routeInfo.ts +68 -0
- package/src/router.ts +373 -0
- package/src/scroll-restoration.tsx +205 -27
- package/src/searchParams.ts +78 -0
- package/src/utils.ts +257 -0
- package/build/cjs/awaited.js +0 -45
- package/build/cjs/awaited.js.map +0 -1
- package/build/cjs/scroll-restoration.js +0 -56
- package/build/cjs/scroll-restoration.js.map +0 -1
|
@@ -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('
|
|
13
|
-
typeof define === 'function' && define.amd ? define(['exports', '
|
|
14
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.
|
|
15
|
-
})(this, (function (exports,
|
|
12
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
|
|
13
|
+
typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
|
|
14
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React));
|
|
15
|
+
})(this, (function (exports, React) { 'use strict';
|
|
16
16
|
|
|
17
17
|
function _interopNamespace(e) {
|
|
18
18
|
if (e && e.__esModule) return e;
|
|
@@ -34,106 +34,6 @@
|
|
|
34
34
|
|
|
35
35
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
36
36
|
|
|
37
|
-
/**
|
|
38
|
-
* @tanstack/store/src/index.ts
|
|
39
|
-
*
|
|
40
|
-
* Copyright (c) TanStack
|
|
41
|
-
*
|
|
42
|
-
* This source code is licensed under the MIT license found in the
|
|
43
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
44
|
-
*
|
|
45
|
-
* @license MIT
|
|
46
|
-
*/
|
|
47
|
-
class Store {
|
|
48
|
-
listeners = new Set();
|
|
49
|
-
_batching = false;
|
|
50
|
-
_flushing = 0;
|
|
51
|
-
_nextPriority = null;
|
|
52
|
-
constructor(initialState, options) {
|
|
53
|
-
this.state = initialState;
|
|
54
|
-
this.options = options;
|
|
55
|
-
}
|
|
56
|
-
subscribe = listener => {
|
|
57
|
-
this.listeners.add(listener);
|
|
58
|
-
const unsub = this.options?.onSubscribe?.(listener, this);
|
|
59
|
-
return () => {
|
|
60
|
-
this.listeners.delete(listener);
|
|
61
|
-
unsub?.();
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
setState = (updater, opts) => {
|
|
65
|
-
const previous = this.state;
|
|
66
|
-
this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
|
|
67
|
-
const priority = opts?.priority ?? this.options?.defaultPriority ?? 'high';
|
|
68
|
-
if (this._nextPriority === null) {
|
|
69
|
-
this._nextPriority = priority;
|
|
70
|
-
} else if (this._nextPriority === 'high') {
|
|
71
|
-
this._nextPriority = priority;
|
|
72
|
-
} else {
|
|
73
|
-
this._nextPriority = this.options?.defaultPriority ?? 'high';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Always run onUpdate, regardless of batching
|
|
77
|
-
this.options?.onUpdate?.({
|
|
78
|
-
priority: this._nextPriority
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Attempt to flush
|
|
82
|
-
this._flush();
|
|
83
|
-
};
|
|
84
|
-
_flush = () => {
|
|
85
|
-
if (this._batching) return;
|
|
86
|
-
const flushId = ++this._flushing;
|
|
87
|
-
this.listeners.forEach(listener => {
|
|
88
|
-
if (this._flushing !== flushId) return;
|
|
89
|
-
listener({
|
|
90
|
-
priority: this._nextPriority ?? 'high'
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
batch = cb => {
|
|
95
|
-
if (this._batching) return cb();
|
|
96
|
-
this._batching = true;
|
|
97
|
-
cb();
|
|
98
|
-
this._batching = false;
|
|
99
|
-
this._flush();
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* @tanstack/react-store/src/index.tsx
|
|
105
|
-
*
|
|
106
|
-
* Copyright (c) TanStack
|
|
107
|
-
*
|
|
108
|
-
* This source code is licensed under the MIT license found in the
|
|
109
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
110
|
-
*
|
|
111
|
-
* @license MIT
|
|
112
|
-
*/
|
|
113
|
-
|
|
114
|
-
function useStore(store, selector = d => d) {
|
|
115
|
-
const slice = withSelector.useSyncExternalStoreWithSelector(store.subscribe, () => store.state, () => store.state, selector, shallow$1);
|
|
116
|
-
return slice;
|
|
117
|
-
}
|
|
118
|
-
function shallow$1(objA, objB) {
|
|
119
|
-
if (Object.is(objA, objB)) {
|
|
120
|
-
return true;
|
|
121
|
-
}
|
|
122
|
-
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
const keysA = Object.keys(objA);
|
|
126
|
-
if (keysA.length !== Object.keys(objB).length) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
for (let i = 0; i < keysA.length; i++) {
|
|
130
|
-
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
37
|
/**
|
|
138
38
|
* @tanstack/history/src/index.ts
|
|
139
39
|
*
|
|
@@ -181,7 +81,6 @@
|
|
|
181
81
|
while (queue.length) {
|
|
182
82
|
queue.shift()?.();
|
|
183
83
|
}
|
|
184
|
-
onUpdate();
|
|
185
84
|
};
|
|
186
85
|
const queueTask = task => {
|
|
187
86
|
queue.push(task);
|
|
@@ -241,7 +140,7 @@
|
|
|
241
140
|
},
|
|
242
141
|
flush: () => opts.flush?.(),
|
|
243
142
|
destroy: () => opts.destroy?.(),
|
|
244
|
-
|
|
143
|
+
notify: onUpdate
|
|
245
144
|
};
|
|
246
145
|
}
|
|
247
146
|
function assignKey(state) {
|
|
@@ -327,7 +226,7 @@
|
|
|
327
226
|
};
|
|
328
227
|
const onPushPop = () => {
|
|
329
228
|
currentLocation = parseLocation(getHref(), window.history.state);
|
|
330
|
-
history.
|
|
229
|
+
history.notify();
|
|
331
230
|
};
|
|
332
231
|
var originalPushState = window.history.pushState;
|
|
333
232
|
var originalReplaceState = window.history.replaceState;
|
|
@@ -351,12 +250,12 @@
|
|
|
351
250
|
window.addEventListener(popStateEvent, onPushPop);
|
|
352
251
|
window.history.pushState = function () {
|
|
353
252
|
let res = originalPushState.apply(window.history, arguments);
|
|
354
|
-
if (tracking) history.
|
|
253
|
+
if (tracking) history.notify();
|
|
355
254
|
return res;
|
|
356
255
|
};
|
|
357
256
|
window.history.replaceState = function () {
|
|
358
257
|
let res = originalReplaceState.apply(window.history, arguments);
|
|
359
|
-
if (tracking) history.
|
|
258
|
+
if (tracking) history.notify();
|
|
360
259
|
return res;
|
|
361
260
|
};
|
|
362
261
|
return history;
|
|
@@ -442,17 +341,6 @@
|
|
|
442
341
|
}
|
|
443
342
|
}
|
|
444
343
|
|
|
445
|
-
/**
|
|
446
|
-
* @tanstack/router-core/src/index.ts
|
|
447
|
-
*
|
|
448
|
-
* Copyright (c) TanStack
|
|
449
|
-
*
|
|
450
|
-
* This source code is licensed under the MIT license found in the
|
|
451
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
452
|
-
*
|
|
453
|
-
* @license MIT
|
|
454
|
-
*/
|
|
455
|
-
|
|
456
344
|
// export type Expand<T> = T
|
|
457
345
|
|
|
458
346
|
// type Compute<T> = { [K in keyof T]: T[K] } | never
|
|
@@ -470,6 +358,40 @@
|
|
|
470
358
|
// : never
|
|
471
359
|
// }
|
|
472
360
|
// >
|
|
361
|
+
// // Sample types to merge
|
|
362
|
+
// type TypeA = {
|
|
363
|
+
// shared: string
|
|
364
|
+
// onlyInA: string
|
|
365
|
+
// nested: {
|
|
366
|
+
// shared: string
|
|
367
|
+
// aProp: string
|
|
368
|
+
// }
|
|
369
|
+
// array: string[]
|
|
370
|
+
// }
|
|
371
|
+
// type TypeB = {
|
|
372
|
+
// shared: number
|
|
373
|
+
// onlyInB: number
|
|
374
|
+
// nested: {
|
|
375
|
+
// shared: number
|
|
376
|
+
// bProp: number
|
|
377
|
+
// }
|
|
378
|
+
// array: number[]
|
|
379
|
+
// }
|
|
380
|
+
// type TypeC = {
|
|
381
|
+
// shared: boolean
|
|
382
|
+
// onlyInC: boolean
|
|
383
|
+
// nested: {
|
|
384
|
+
// shared: boolean
|
|
385
|
+
// cProp: boolean
|
|
386
|
+
// }
|
|
387
|
+
// array: boolean[]
|
|
388
|
+
// }
|
|
389
|
+
// type Test = Expand<Assign<TypeA, TypeB>>
|
|
390
|
+
// // Using DeepMerge to merge TypeA and TypeB
|
|
391
|
+
// type MergedType = Expand<AssignAll<[TypeA, TypeB, TypeC]>>
|
|
392
|
+
//
|
|
393
|
+
|
|
394
|
+
const isServer = typeof document === 'undefined';
|
|
473
395
|
function last(arr) {
|
|
474
396
|
return arr[arr.length - 1];
|
|
475
397
|
}
|
|
@@ -563,6 +485,12 @@
|
|
|
563
485
|
}
|
|
564
486
|
return false;
|
|
565
487
|
}
|
|
488
|
+
function useStableCallback(fn) {
|
|
489
|
+
const fnRef = React__namespace.useRef(fn);
|
|
490
|
+
fnRef.current = fn;
|
|
491
|
+
const ref = React__namespace.useRef((...args) => fnRef.current(...args));
|
|
492
|
+
return ref.current;
|
|
493
|
+
}
|
|
566
494
|
|
|
567
495
|
function joinPaths(paths) {
|
|
568
496
|
return cleanPath(paths.filter(Boolean).join('/'));
|
|
@@ -796,102 +724,19 @@
|
|
|
796
724
|
return out;
|
|
797
725
|
}
|
|
798
726
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
// export type UseLoaderResultPromise<T> = T extends Promise<infer U>
|
|
810
|
-
// ? StreamedPromise<U>
|
|
811
|
-
// : T
|
|
812
|
-
class Route {
|
|
813
|
-
// Set up in this.init()
|
|
814
|
-
|
|
815
|
-
// customId!: TCustomId
|
|
816
|
-
|
|
817
|
-
// Optional
|
|
818
|
-
|
|
819
|
-
constructor(options) {
|
|
820
|
-
this.options = options || {};
|
|
821
|
-
this.isRoot = !options?.getParentRoute;
|
|
822
|
-
Route.__onInit(this);
|
|
823
|
-
}
|
|
824
|
-
init = opts => {
|
|
825
|
-
this.originalIndex = opts.originalIndex;
|
|
826
|
-
this.router = opts.router;
|
|
827
|
-
const options = this.options;
|
|
828
|
-
const isRoot = !options?.path && !options?.id;
|
|
829
|
-
this.parentRoute = this.options?.getParentRoute?.();
|
|
830
|
-
if (isRoot) {
|
|
831
|
-
this.path = rootRouteId;
|
|
832
|
-
} else {
|
|
833
|
-
invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
|
|
834
|
-
}
|
|
835
|
-
let path = isRoot ? rootRouteId : options.path;
|
|
836
|
-
|
|
837
|
-
// If the path is anything other than an index path, trim it up
|
|
838
|
-
if (path && path !== '/') {
|
|
839
|
-
path = trimPath(path);
|
|
840
|
-
}
|
|
841
|
-
const customId = options?.id || path;
|
|
842
|
-
|
|
843
|
-
// Strip the parentId prefix from the first level of children
|
|
844
|
-
let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
|
|
845
|
-
if (path === rootRouteId) {
|
|
846
|
-
path = '/';
|
|
847
|
-
}
|
|
848
|
-
if (id !== rootRouteId) {
|
|
849
|
-
id = joinPaths(['/', id]);
|
|
727
|
+
function _extends() {
|
|
728
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
729
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
730
|
+
var source = arguments[i];
|
|
731
|
+
for (var key in source) {
|
|
732
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
733
|
+
target[key] = source[key];
|
|
734
|
+
}
|
|
735
|
+
}
|
|
850
736
|
}
|
|
851
|
-
|
|
852
|
-
this.path = path;
|
|
853
|
-
this.id = id;
|
|
854
|
-
// this.customId = customId as TCustomId
|
|
855
|
-
this.fullPath = fullPath;
|
|
856
|
-
this.to = fullPath;
|
|
857
|
-
};
|
|
858
|
-
addChildren = children => {
|
|
859
|
-
this.children = children;
|
|
860
|
-
return this;
|
|
861
|
-
};
|
|
862
|
-
update = options => {
|
|
863
|
-
Object.assign(this.options, options);
|
|
864
|
-
return this;
|
|
865
|
-
};
|
|
866
|
-
static __onInit = route => {
|
|
867
|
-
// This is a dummy static method that should get
|
|
868
|
-
// replaced by a framework specific implementation if necessary
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
class RouterContext {
|
|
872
|
-
constructor() {}
|
|
873
|
-
createRootRoute = options => {
|
|
874
|
-
return new RootRoute(options);
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
class RootRoute extends Route {
|
|
878
|
-
constructor(options) {
|
|
879
|
-
super(options);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
function createRouteMask(opts) {
|
|
883
|
-
return opts;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
class FileRoute {
|
|
887
|
-
constructor(path) {
|
|
888
|
-
this.path = path;
|
|
889
|
-
}
|
|
890
|
-
createRoute = options => {
|
|
891
|
-
const route = new Route(options);
|
|
892
|
-
route.isRoot = false;
|
|
893
|
-
return route;
|
|
737
|
+
return target;
|
|
894
738
|
};
|
|
739
|
+
return _extends.apply(this, arguments);
|
|
895
740
|
}
|
|
896
741
|
|
|
897
742
|
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
@@ -958,76 +803,22 @@
|
|
|
958
803
|
|
|
959
804
|
//
|
|
960
805
|
|
|
806
|
+
//
|
|
807
|
+
|
|
961
808
|
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
962
|
-
const visibilityChangeEvent = 'visibilitychange';
|
|
963
|
-
const focusEvent = 'focus';
|
|
964
|
-
const preloadWarning = 'Error preloading route! ☝️';
|
|
965
809
|
class Router {
|
|
966
|
-
|
|
967
|
-
resetNextScroll = false
|
|
968
|
-
tempLocationKey = `${Math.round(Math.random() * 10000000)}
|
|
969
|
-
// nextTemporaryLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
970
|
-
|
|
810
|
+
// dehydratedData?: TDehydrated
|
|
811
|
+
// resetNextScroll = false
|
|
812
|
+
// tempLocationKey = `${Math.round(Math.random() * 10000000)}`
|
|
971
813
|
constructor(options) {
|
|
972
814
|
this.options = {
|
|
973
815
|
defaultPreloadDelay: 50,
|
|
974
|
-
|
|
816
|
+
meta: undefined,
|
|
975
817
|
...options,
|
|
976
818
|
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
977
819
|
parseSearch: options?.parseSearch ?? defaultParseSearch
|
|
978
|
-
// fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn,
|
|
979
820
|
};
|
|
980
|
-
|
|
981
|
-
this.__store = new Store(getInitialRouterState(), {
|
|
982
|
-
onUpdate: () => {
|
|
983
|
-
const prev = this.state;
|
|
984
|
-
const next = this.__store.state;
|
|
985
|
-
const matchesByIdChanged = prev.matchesById !== next.matchesById;
|
|
986
|
-
let matchesChanged;
|
|
987
|
-
let pendingMatchesChanged;
|
|
988
|
-
if (!matchesByIdChanged) {
|
|
989
|
-
matchesChanged = prev.matchIds.length !== next.matchIds.length || prev.matchIds.some((d, i) => d !== next.matchIds[i]);
|
|
990
|
-
pendingMatchesChanged = prev.pendingMatchIds.length !== next.pendingMatchIds.length || prev.pendingMatchIds.some((d, i) => d !== next.pendingMatchIds[i]);
|
|
991
|
-
}
|
|
992
|
-
if (matchesByIdChanged || matchesChanged) {
|
|
993
|
-
next.matches = next.matchIds.map(id => {
|
|
994
|
-
return next.matchesById[id];
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
|
-
if (matchesByIdChanged || pendingMatchesChanged) {
|
|
998
|
-
next.pendingMatches = next.pendingMatchIds.map(id => {
|
|
999
|
-
return next.matchesById[id];
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
if (matchesByIdChanged || matchesChanged || pendingMatchesChanged) {
|
|
1003
|
-
const hasPendingComponent = next.pendingMatches.some(d => {
|
|
1004
|
-
const route = this.getRoute(d.routeId);
|
|
1005
|
-
return !!route?.options.pendingComponent;
|
|
1006
|
-
});
|
|
1007
|
-
next.renderedMatchIds = hasPendingComponent ? next.pendingMatchIds : next.matchIds;
|
|
1008
|
-
next.renderedMatches = next.renderedMatchIds.map(id => {
|
|
1009
|
-
return next.matchesById[id];
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1012
|
-
next.isFetching = [...next.matches, ...next.pendingMatches].some(d => d.isFetching);
|
|
1013
|
-
this.state = next;
|
|
1014
|
-
},
|
|
1015
|
-
defaultPriority: 'low'
|
|
1016
|
-
});
|
|
1017
|
-
this.state = this.__store.state;
|
|
1018
|
-
this.update(options);
|
|
1019
|
-
const nextLocation = this.buildLocation({
|
|
1020
|
-
search: true,
|
|
1021
|
-
params: true,
|
|
1022
|
-
hash: true,
|
|
1023
|
-
state: true
|
|
1024
|
-
});
|
|
1025
|
-
if (this.state.location.href !== nextLocation.href) {
|
|
1026
|
-
this.#commitLocation({
|
|
1027
|
-
...nextLocation,
|
|
1028
|
-
replace: true
|
|
1029
|
-
});
|
|
1030
|
-
}
|
|
821
|
+
this.routeTree = this.options.routeTree;
|
|
1031
822
|
}
|
|
1032
823
|
subscribers = new Set();
|
|
1033
824
|
subscribe = (eventType, fn) => {
|
|
@@ -1040,245 +831,329 @@
|
|
|
1040
831
|
this.subscribers.delete(listener);
|
|
1041
832
|
};
|
|
1042
833
|
};
|
|
1043
|
-
|
|
834
|
+
emit = routerEvent => {
|
|
1044
835
|
this.subscribers.forEach(listener => {
|
|
1045
836
|
if (listener.eventType === routerEvent.type) {
|
|
1046
837
|
listener.fn(routerEvent);
|
|
1047
838
|
}
|
|
1048
839
|
});
|
|
1049
840
|
};
|
|
1050
|
-
reset = () => {
|
|
1051
|
-
this.__store.setState(s => Object.assign(s, getInitialRouterState()));
|
|
1052
|
-
};
|
|
1053
|
-
mount = () => {
|
|
1054
|
-
// addEventListener does not exist in React Native, but window does
|
|
1055
|
-
// In the future, we might need to invert control here for more adapters
|
|
1056
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1057
|
-
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
1058
|
-
window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
|
|
1059
|
-
window.addEventListener(focusEvent, this.#onFocus, false);
|
|
1060
|
-
}
|
|
1061
|
-
this.safeLoad();
|
|
1062
|
-
return () => {
|
|
1063
|
-
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
1064
|
-
window.removeEventListener(visibilityChangeEvent, this.#onFocus);
|
|
1065
|
-
window.removeEventListener(focusEvent, this.#onFocus);
|
|
1066
|
-
}
|
|
1067
|
-
};
|
|
1068
|
-
};
|
|
1069
|
-
#onFocus = () => {
|
|
1070
|
-
if (this.options.reloadOnWindowFocus ?? true) {
|
|
1071
|
-
this.invalidate({
|
|
1072
|
-
__fromFocus: true
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
};
|
|
1076
|
-
update = opts => {
|
|
1077
|
-
this.options = {
|
|
1078
|
-
...this.options,
|
|
1079
|
-
...opts,
|
|
1080
|
-
context: {
|
|
1081
|
-
...this.options.context,
|
|
1082
|
-
...opts?.context
|
|
1083
|
-
}
|
|
1084
|
-
};
|
|
1085
|
-
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
1086
|
-
if (this.#unsubHistory) {
|
|
1087
|
-
this.#unsubHistory();
|
|
1088
|
-
}
|
|
1089
|
-
this.history = this.options.history ?? (isServer ? createMemoryHistory() : createBrowserHistory());
|
|
1090
|
-
const parsedLocation = this.#parseLocation();
|
|
1091
|
-
this.__store.setState(s => ({
|
|
1092
|
-
...s,
|
|
1093
|
-
resolvedLocation: parsedLocation,
|
|
1094
|
-
location: parsedLocation
|
|
1095
|
-
}));
|
|
1096
|
-
this.#unsubHistory = this.history.subscribe(() => {
|
|
1097
|
-
this.safeLoad({
|
|
1098
|
-
next: this.#parseLocation(this.state.location)
|
|
1099
|
-
});
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
const {
|
|
1103
|
-
basepath,
|
|
1104
|
-
routeTree
|
|
1105
|
-
} = this.options;
|
|
1106
|
-
this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
|
|
1107
|
-
if (routeTree && routeTree !== this.routeTree) {
|
|
1108
|
-
this.#processRoutes(routeTree);
|
|
1109
|
-
}
|
|
1110
|
-
return this;
|
|
1111
|
-
};
|
|
1112
|
-
cancelMatches = () => {
|
|
1113
|
-
this.state.matches.forEach(match => {
|
|
1114
|
-
this.cancelMatch(match.id);
|
|
1115
|
-
});
|
|
1116
|
-
};
|
|
1117
|
-
cancelMatch = id => {
|
|
1118
|
-
this.getRouteMatch(id)?.abortController?.abort();
|
|
1119
|
-
};
|
|
1120
|
-
safeLoad = async opts => {
|
|
1121
|
-
try {
|
|
1122
|
-
return this.load(opts);
|
|
1123
|
-
} catch (err) {
|
|
1124
|
-
// Don't do anything
|
|
1125
|
-
}
|
|
1126
|
-
};
|
|
1127
|
-
latestLoadPromise = Promise.resolve();
|
|
1128
|
-
load = async opts => {
|
|
1129
|
-
const promise = new Promise(async (resolve, reject) => {
|
|
1130
|
-
const prevLocation = this.state.resolvedLocation;
|
|
1131
|
-
const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
|
|
1132
|
-
let latestPromise;
|
|
1133
|
-
const checkLatest = () => {
|
|
1134
|
-
return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
|
|
1135
|
-
};
|
|
1136
841
|
|
|
1137
|
-
|
|
842
|
+
// dehydrate = (): DehydratedRouter => {
|
|
843
|
+
// return {
|
|
844
|
+
// state: {
|
|
845
|
+
// dehydratedMatches: state.matches.map((d) =>
|
|
846
|
+
// pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
|
|
847
|
+
// ),
|
|
848
|
+
// },
|
|
849
|
+
// }
|
|
850
|
+
// }
|
|
1138
851
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
852
|
+
// hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
|
|
853
|
+
// let _ctx = __do_not_use_server_ctx
|
|
854
|
+
// // Client hydrates from window
|
|
855
|
+
// if (typeof document !== 'undefined') {
|
|
856
|
+
// _ctx = window.__TSR_DEHYDRATED__
|
|
857
|
+
// }
|
|
858
|
+
|
|
859
|
+
// invariant(
|
|
860
|
+
// _ctx,
|
|
861
|
+
// 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
|
|
862
|
+
// )
|
|
863
|
+
|
|
864
|
+
// const ctx = _ctx
|
|
865
|
+
// this.dehydratedData = ctx.payload as any
|
|
866
|
+
// this.options.hydrate?.(ctx.payload as any)
|
|
867
|
+
// const dehydratedState = ctx.router.state
|
|
868
|
+
|
|
869
|
+
// let matches = this.matchRoutes(
|
|
870
|
+
// state.location.pathname,
|
|
871
|
+
// state.location.search,
|
|
872
|
+
// ).map((match) => {
|
|
873
|
+
// const dehydratedMatch = dehydratedState.dehydratedMatches.find(
|
|
874
|
+
// (d) => d.id === match.id,
|
|
875
|
+
// )
|
|
876
|
+
|
|
877
|
+
// invariant(
|
|
878
|
+
// dehydratedMatch,
|
|
879
|
+
// `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
|
|
880
|
+
// )
|
|
881
|
+
|
|
882
|
+
// if (dehydratedMatch) {
|
|
883
|
+
// return {
|
|
884
|
+
// ...match,
|
|
885
|
+
// ...dehydratedMatch,
|
|
886
|
+
// }
|
|
887
|
+
// }
|
|
888
|
+
// return match
|
|
889
|
+
// })
|
|
890
|
+
|
|
891
|
+
// this.setState((s) => {
|
|
892
|
+
// return {
|
|
893
|
+
// ...s,
|
|
894
|
+
// matches: dehydratedState.dehydratedMatches as any,
|
|
895
|
+
// }
|
|
896
|
+
// })
|
|
897
|
+
// }
|
|
1154
898
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
throwOnError: opts?.throwOnError,
|
|
1158
|
-
debug: true
|
|
1159
|
-
});
|
|
1160
|
-
this.__store.setState(s => ({
|
|
1161
|
-
...s,
|
|
1162
|
-
status: 'pending',
|
|
1163
|
-
pendingMatchIds: pendingMatches.map(d => d.id),
|
|
1164
|
-
matchesById: this.#mergeMatches(s.matchesById, pendingMatches)
|
|
1165
|
-
}));
|
|
1166
|
-
});
|
|
1167
|
-
try {
|
|
1168
|
-
// Load the matches
|
|
1169
|
-
try {
|
|
1170
|
-
await this.loadMatches(pendingMatches.map(d => d.id));
|
|
1171
|
-
} catch (err) {
|
|
1172
|
-
// swallow this error, since we'll display the
|
|
1173
|
-
// errors on the route components
|
|
1174
|
-
}
|
|
899
|
+
// TODO:
|
|
900
|
+
// injectedHtml: (string | (() => Promise<string> | string))[] = []
|
|
1175
901
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
902
|
+
// TODO:
|
|
903
|
+
// injectHtml = async (html: string | (() => Promise<string> | string)) => {
|
|
904
|
+
// this.injectedHtml.push(html)
|
|
905
|
+
// }
|
|
906
|
+
|
|
907
|
+
// TODO:
|
|
908
|
+
// dehydrateData = <T>(key: any, getData: T | (() => Promise<T> | T)) => {
|
|
909
|
+
// if (typeof document === 'undefined') {
|
|
910
|
+
// const strKey = typeof key === 'string' ? key : JSON.stringify(key)
|
|
911
|
+
|
|
912
|
+
// this.injectHtml(async () => {
|
|
913
|
+
// const id = `__TSR_DEHYDRATED__${strKey}`
|
|
914
|
+
// const data =
|
|
915
|
+
// typeof getData === 'function' ? await (getData as any)() : getData
|
|
916
|
+
// return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(
|
|
917
|
+
// strKey,
|
|
918
|
+
// )}"] = ${JSON.stringify(data)}
|
|
919
|
+
// ;(() => {
|
|
920
|
+
// var el = document.getElementById('${id}')
|
|
921
|
+
// el.parentElement.removeChild(el)
|
|
922
|
+
// })()
|
|
923
|
+
// </script>`
|
|
924
|
+
// })
|
|
925
|
+
|
|
926
|
+
// return () => this.hydrateData<T>(key)
|
|
927
|
+
// }
|
|
928
|
+
|
|
929
|
+
// return () => undefined
|
|
930
|
+
// }
|
|
931
|
+
|
|
932
|
+
// hydrateData = <T = unknown>(key: any) => {
|
|
933
|
+
// if (typeof document !== 'undefined') {
|
|
934
|
+
// const strKey = typeof key === 'string' ? key : JSON.stringify(key)
|
|
935
|
+
|
|
936
|
+
// return window[`__TSR_DEHYDRATED__${strKey}` as any] as T
|
|
937
|
+
// }
|
|
938
|
+
|
|
939
|
+
// return undefined
|
|
940
|
+
// }
|
|
941
|
+
|
|
942
|
+
// resolveMatchPromise = (matchId: string, key: string, value: any) => {
|
|
943
|
+
// state.matches
|
|
944
|
+
// .find((d) => d.id === matchId)
|
|
945
|
+
// ?.__promisesByKey[key]?.resolve(value)
|
|
946
|
+
// }
|
|
947
|
+
|
|
948
|
+
// setRouteMatch = (
|
|
949
|
+
// id: string,
|
|
950
|
+
// pending: boolean,
|
|
951
|
+
// updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
|
|
952
|
+
// ) => {
|
|
953
|
+
// const key = pending ? 'pendingMatches' : 'matches'
|
|
954
|
+
|
|
955
|
+
// this.setState((prev) => {
|
|
956
|
+
// return {
|
|
957
|
+
// ...prev,
|
|
958
|
+
// [key]: prev[key].map((d) => {
|
|
959
|
+
// if (d.id === id) {
|
|
960
|
+
// return functionalUpdate(updater, d)
|
|
961
|
+
// }
|
|
962
|
+
|
|
963
|
+
// return d
|
|
964
|
+
// }),
|
|
965
|
+
// }
|
|
966
|
+
// })
|
|
967
|
+
// }
|
|
968
|
+
|
|
969
|
+
// setPendingRouteMatch = (
|
|
970
|
+
// id: string,
|
|
971
|
+
// updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
|
|
972
|
+
// ) => {
|
|
973
|
+
// this.setRouteMatch(id, true, updater)
|
|
974
|
+
// }
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// A function that takes an import() argument which is a function and returns a new function that will
|
|
978
|
+
// proxy arguments from the caller to the imported function, retaining all type
|
|
979
|
+
// information along the way
|
|
980
|
+
function lazyFn(fn, key) {
|
|
981
|
+
return async (...args) => {
|
|
982
|
+
const imported = await fn();
|
|
983
|
+
return imported[key || 'default'](...args);
|
|
1217
984
|
};
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Detect if we're in the DOM
|
|
988
|
+
|
|
989
|
+
function redirect(opts) {
|
|
990
|
+
opts.isRedirect = true;
|
|
991
|
+
return opts;
|
|
992
|
+
}
|
|
993
|
+
function isRedirect(obj) {
|
|
994
|
+
return !!obj?.isRedirect;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
const preloadWarning = 'Error preloading route! ☝️';
|
|
998
|
+
const routerContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
999
|
+
function getInitialRouterState(location) {
|
|
1000
|
+
return {
|
|
1001
|
+
status: 'idle',
|
|
1002
|
+
isFetching: false,
|
|
1003
|
+
resolvedLocation: location,
|
|
1004
|
+
location: location,
|
|
1005
|
+
matches: [],
|
|
1006
|
+
pendingMatches: [],
|
|
1007
|
+
lastUpdated: Date.now()
|
|
1232
1008
|
};
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1009
|
+
}
|
|
1010
|
+
function RouterProvider({
|
|
1011
|
+
router,
|
|
1012
|
+
...rest
|
|
1013
|
+
}) {
|
|
1014
|
+
const options = {
|
|
1015
|
+
...router.options,
|
|
1016
|
+
...rest,
|
|
1017
|
+
meta: {
|
|
1018
|
+
...router.options.meta,
|
|
1019
|
+
...rest?.meta
|
|
1020
|
+
}
|
|
1237
1021
|
};
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1022
|
+
const history = React__namespace.useState(() => options.history ?? createBrowserHistory())[0];
|
|
1023
|
+
const tempLocationKeyRef = React__namespace.useRef(`${Math.round(Math.random() * 10000000)}`);
|
|
1024
|
+
const resetNextScrollRef = React__namespace.useRef(false);
|
|
1025
|
+
const navigateTimeoutRef = React__namespace.useRef(null);
|
|
1026
|
+
const parseLocation = useStableCallback(previousLocation => {
|
|
1027
|
+
const parse = ({
|
|
1028
|
+
pathname,
|
|
1029
|
+
search,
|
|
1030
|
+
hash,
|
|
1031
|
+
state
|
|
1032
|
+
}) => {
|
|
1033
|
+
const parsedSearch = options.parseSearch(search);
|
|
1244
1034
|
return {
|
|
1245
|
-
|
|
1246
|
-
|
|
1035
|
+
pathname: pathname,
|
|
1036
|
+
searchStr: search,
|
|
1037
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
1038
|
+
hash: hash.split('#').reverse()[0] ?? '',
|
|
1039
|
+
href: `${pathname}${search}${hash}`,
|
|
1040
|
+
state: replaceEqualDeep(previousLocation?.state, state)
|
|
1247
1041
|
};
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
return
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1042
|
+
};
|
|
1043
|
+
const location = parse(history.location);
|
|
1044
|
+
let {
|
|
1045
|
+
__tempLocation,
|
|
1046
|
+
__tempKey
|
|
1047
|
+
} = location.state;
|
|
1048
|
+
if (__tempLocation && (!__tempKey || __tempKey === tempLocationKeyRef.current)) {
|
|
1049
|
+
// Sync up the location keys
|
|
1050
|
+
const parsedTempLocation = parse(__tempLocation);
|
|
1051
|
+
parsedTempLocation.state.key = location.state.key;
|
|
1052
|
+
delete parsedTempLocation.state.__tempLocation;
|
|
1053
|
+
return {
|
|
1054
|
+
...parsedTempLocation,
|
|
1055
|
+
maskedLocation: location
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
return location;
|
|
1059
|
+
});
|
|
1060
|
+
const [state, setState] = React__namespace.useState(() => getInitialRouterState(parseLocation()));
|
|
1061
|
+
const basepath = `/${trimPath(options.basepath ?? '') ?? ''}`;
|
|
1062
|
+
const resolvePathWithBase = useStableCallback((from, path) => {
|
|
1063
|
+
return resolvePath(basepath, from, cleanPath(path));
|
|
1064
|
+
});
|
|
1065
|
+
const [routesById, routesByPath] = React__namespace.useMemo(() => {
|
|
1066
|
+
const routesById = {};
|
|
1067
|
+
const routesByPath = {};
|
|
1068
|
+
const recurseRoutes = routes => {
|
|
1069
|
+
routes.forEach((route, i) => {
|
|
1070
|
+
route.init({
|
|
1071
|
+
originalIndex: i
|
|
1268
1072
|
});
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1073
|
+
const existingRoute = routesById[route.id];
|
|
1074
|
+
invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
|
|
1075
|
+
routesById[route.id] = route;
|
|
1076
|
+
if (!route.isRoot && route.path) {
|
|
1077
|
+
const trimmedFullPath = trimPathRight(route.fullPath);
|
|
1078
|
+
if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
|
|
1079
|
+
routesByPath[trimmedFullPath] = route;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
const children = route.children;
|
|
1083
|
+
if (children?.length) {
|
|
1084
|
+
recurseRoutes(children);
|
|
1085
|
+
}
|
|
1273
1086
|
});
|
|
1087
|
+
};
|
|
1088
|
+
recurseRoutes([router.routeTree]);
|
|
1089
|
+
return [routesById, routesByPath];
|
|
1090
|
+
}, []);
|
|
1091
|
+
const looseRoutesById = routesById;
|
|
1092
|
+
const flatRoutes = React__namespace.useMemo(() => Object.values(routesByPath).map((d, i) => {
|
|
1093
|
+
const trimmed = trimPath(d.fullPath);
|
|
1094
|
+
const parsed = parsePathname(trimmed);
|
|
1095
|
+
while (parsed.length > 1 && parsed[0]?.value === '/') {
|
|
1096
|
+
parsed.shift();
|
|
1097
|
+
}
|
|
1098
|
+
const score = parsed.map(d => {
|
|
1099
|
+
if (d.type === 'param') {
|
|
1100
|
+
return 0.5;
|
|
1101
|
+
}
|
|
1102
|
+
if (d.type === 'wildcard') {
|
|
1103
|
+
return 0.25;
|
|
1104
|
+
}
|
|
1105
|
+
return 1;
|
|
1106
|
+
});
|
|
1107
|
+
return {
|
|
1108
|
+
child: d,
|
|
1109
|
+
trimmed,
|
|
1110
|
+
parsed,
|
|
1111
|
+
index: i,
|
|
1112
|
+
score
|
|
1113
|
+
};
|
|
1114
|
+
}).sort((a, b) => {
|
|
1115
|
+
let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
|
|
1116
|
+
if (isIndex !== 0) return isIndex;
|
|
1117
|
+
const length = Math.min(a.score.length, b.score.length);
|
|
1118
|
+
|
|
1119
|
+
// Sort by length of score
|
|
1120
|
+
if (a.score.length !== b.score.length) {
|
|
1121
|
+
return b.score.length - a.score.length;
|
|
1274
1122
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1123
|
+
|
|
1124
|
+
// Sort by min available score
|
|
1125
|
+
for (let i = 0; i < length; i++) {
|
|
1126
|
+
if (a.score[i] !== b.score[i]) {
|
|
1127
|
+
return b.score[i] - a.score[i];
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// Sort by min available parsed value
|
|
1132
|
+
for (let i = 0; i < length; i++) {
|
|
1133
|
+
if (a.parsed[i].value !== b.parsed[i].value) {
|
|
1134
|
+
return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// Sort by length of trimmed full path
|
|
1139
|
+
if (a.trimmed !== b.trimmed) {
|
|
1140
|
+
return a.trimmed > b.trimmed ? 1 : -1;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
// Sort by original index
|
|
1144
|
+
return a.index - b.index;
|
|
1145
|
+
}).map((d, i) => {
|
|
1146
|
+
d.child.rank = i;
|
|
1147
|
+
return d.child;
|
|
1148
|
+
}), [routesByPath]);
|
|
1149
|
+
const latestLoadPromiseRef = React__namespace.useRef(Promise.resolve());
|
|
1150
|
+
const matchRoutes = useStableCallback((pathname, locationSearch, opts) => {
|
|
1277
1151
|
let routeParams = {};
|
|
1278
|
-
let foundRoute =
|
|
1279
|
-
const matchedParams = matchPathname(
|
|
1152
|
+
let foundRoute = flatRoutes.find(route => {
|
|
1153
|
+
const matchedParams = matchPathname(basepath, trimPathRight(pathname), {
|
|
1280
1154
|
to: route.fullPath,
|
|
1281
|
-
caseSensitive: route.options.caseSensitive ??
|
|
1155
|
+
caseSensitive: route.options.caseSensitive ?? options.caseSensitive,
|
|
1156
|
+
fuzzy: false
|
|
1282
1157
|
});
|
|
1283
1158
|
if (matchedParams) {
|
|
1284
1159
|
routeParams = matchedParams;
|
|
@@ -1286,7 +1161,7 @@
|
|
|
1286
1161
|
}
|
|
1287
1162
|
return false;
|
|
1288
1163
|
});
|
|
1289
|
-
let routeCursor = foundRoute ||
|
|
1164
|
+
let routeCursor = foundRoute || routesById['__root__'];
|
|
1290
1165
|
let matchedRoutes = [routeCursor];
|
|
1291
1166
|
// let includingLayouts = true
|
|
1292
1167
|
while (routeCursor?.parentRoute) {
|
|
@@ -1318,24 +1193,12 @@
|
|
|
1318
1193
|
});
|
|
1319
1194
|
const matches = matchedRoutes.map((route, index) => {
|
|
1320
1195
|
const interpolatedPath = interpolatePath(route.path, routeParams);
|
|
1321
|
-
const
|
|
1322
|
-
search: locationSearch
|
|
1323
|
-
}) : undefined;
|
|
1324
|
-
const matchId = JSON.stringify([interpolatePath(route.id, routeParams, true), loaderContext].filter(d => d !== undefined), (key, value) => {
|
|
1325
|
-
if (typeof value === 'function') {
|
|
1326
|
-
console.info(route);
|
|
1327
|
-
invariant(false, `Cannot return functions and other non-serializable values from routeOptions.loaderContext! Please use routeOptions.beforeLoad to do this. Route info is logged above 👆`);
|
|
1328
|
-
}
|
|
1329
|
-
if (typeof value === 'object' && value !== null) {
|
|
1330
|
-
return Object.fromEntries(Object.keys(value).sort().map(key => [key, value[key]]));
|
|
1331
|
-
}
|
|
1332
|
-
return value;
|
|
1333
|
-
});
|
|
1196
|
+
const matchId = interpolatePath(route.id, routeParams, true);
|
|
1334
1197
|
|
|
1335
1198
|
// Waste not, want not. If we already have a match for this route,
|
|
1336
1199
|
// reuse it. This is important for layout routes, which might stick
|
|
1337
1200
|
// around between navigation actions that only change leaf routes.
|
|
1338
|
-
const existingMatch =
|
|
1201
|
+
const existingMatch = getRouteMatch(state, matchId);
|
|
1339
1202
|
if (existingMatch) {
|
|
1340
1203
|
return {
|
|
1341
1204
|
...existingMatch
|
|
@@ -1343,16 +1206,13 @@
|
|
|
1343
1206
|
}
|
|
1344
1207
|
|
|
1345
1208
|
// Create a fresh route match
|
|
1346
|
-
const hasLoaders = !!(route.options.
|
|
1209
|
+
const hasLoaders = !!(route.options.load || componentTypes.some(d => route.options[d]?.preload));
|
|
1347
1210
|
const routeMatch = {
|
|
1348
1211
|
id: matchId,
|
|
1349
|
-
loaderContext,
|
|
1350
1212
|
routeId: route.id,
|
|
1351
1213
|
params: routeParams,
|
|
1352
|
-
pathname: joinPaths([
|
|
1214
|
+
pathname: joinPaths([basepath, interpolatedPath]),
|
|
1353
1215
|
updatedAt: Date.now(),
|
|
1354
|
-
maxAge: -1,
|
|
1355
|
-
preloadMaxAge: -1,
|
|
1356
1216
|
routeSearch: {},
|
|
1357
1217
|
search: {},
|
|
1358
1218
|
status: hasLoaders ? 'pending' : 'success',
|
|
@@ -1361,21 +1221,20 @@
|
|
|
1361
1221
|
error: undefined,
|
|
1362
1222
|
paramsError: parseErrors[index],
|
|
1363
1223
|
searchError: undefined,
|
|
1364
|
-
loaderData: undefined,
|
|
1365
1224
|
loadPromise: Promise.resolve(),
|
|
1366
|
-
|
|
1225
|
+
meta: undefined,
|
|
1367
1226
|
abortController: new AbortController(),
|
|
1368
1227
|
fetchedAt: 0
|
|
1369
1228
|
};
|
|
1370
1229
|
return routeMatch;
|
|
1371
1230
|
});
|
|
1372
1231
|
|
|
1373
|
-
// Take each match and resolve its search params and
|
|
1232
|
+
// Take each match and resolve its search params and meta
|
|
1374
1233
|
// This has to happen after the matches are created or found
|
|
1375
|
-
// so that we can use the parent match's search params and
|
|
1234
|
+
// so that we can use the parent match's search params and meta
|
|
1376
1235
|
matches.forEach((match, i) => {
|
|
1377
1236
|
const parentMatch = matches[i - 1];
|
|
1378
|
-
const route =
|
|
1237
|
+
const route = looseRoutesById[match.routeId];
|
|
1379
1238
|
const searchInfo = (() => {
|
|
1380
1239
|
// Validate the search params and stabilize them
|
|
1381
1240
|
const parentSearchInfo = {
|
|
@@ -1409,117 +1268,268 @@
|
|
|
1409
1268
|
Object.assign(match, searchInfo);
|
|
1410
1269
|
});
|
|
1411
1270
|
return matches;
|
|
1412
|
-
};
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1271
|
+
});
|
|
1272
|
+
const cancelMatch = useStableCallback(id => {
|
|
1273
|
+
getRouteMatch(state, id)?.abortController?.abort();
|
|
1274
|
+
});
|
|
1275
|
+
const cancelMatches = useStableCallback(state => {
|
|
1276
|
+
state.matches.forEach(match => {
|
|
1277
|
+
cancelMatch(match.id);
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
const buildLocation = useStableCallback((opts = {}) => {
|
|
1281
|
+
const build = (dest = {}, matches) => {
|
|
1282
|
+
const from = latestLocationRef.current;
|
|
1283
|
+
const fromPathname = dest.from ?? from.pathname;
|
|
1284
|
+
let pathname = resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
|
|
1285
|
+
const fromMatches = matchRoutes(fromPathname, from.search);
|
|
1286
|
+
const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
|
|
1287
|
+
const prevParams = {
|
|
1288
|
+
...last(fromMatches)?.params
|
|
1289
|
+
};
|
|
1290
|
+
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
1291
|
+
if (nextParams) {
|
|
1292
|
+
matches?.map(d => looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
1293
|
+
nextParams = {
|
|
1294
|
+
...nextParams,
|
|
1295
|
+
...fn(nextParams)
|
|
1296
|
+
};
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
1300
|
+
const preSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1301
|
+
const postSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1432
1302
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1303
|
+
// Pre filters first
|
|
1304
|
+
const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
|
|
1305
|
+
|
|
1306
|
+
// Then the link/navigate function
|
|
1307
|
+
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
1308
|
+
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
1309
|
+
: preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
1310
|
+
: {};
|
|
1311
|
+
|
|
1312
|
+
// Then post filters
|
|
1313
|
+
const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1314
|
+
const search = replaceEqualDeep(from.search, postFilteredSearch);
|
|
1315
|
+
const searchStr = options.stringifySearch(search);
|
|
1316
|
+
const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
|
|
1317
|
+
const hashStr = hash ? `#${hash}` : '';
|
|
1318
|
+
let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
|
|
1319
|
+
nextState = replaceEqualDeep(from.state, nextState);
|
|
1320
|
+
return {
|
|
1321
|
+
pathname,
|
|
1322
|
+
search,
|
|
1323
|
+
searchStr,
|
|
1324
|
+
state: nextState,
|
|
1325
|
+
hash,
|
|
1326
|
+
href: history.createHref(`${pathname}${searchStr}${hashStr}`),
|
|
1327
|
+
unmaskOnReload: dest.unmaskOnReload
|
|
1328
|
+
};
|
|
1329
|
+
};
|
|
1330
|
+
const buildWithMatches = (dest = {}, maskedDest) => {
|
|
1331
|
+
let next = build(dest);
|
|
1332
|
+
let maskedNext = maskedDest ? build(maskedDest) : undefined;
|
|
1333
|
+
if (!maskedNext) {
|
|
1334
|
+
let params = {};
|
|
1335
|
+
let foundMask = options.routeMasks?.find(d => {
|
|
1336
|
+
const match = matchPathname(basepath, next.pathname, {
|
|
1337
|
+
to: d.from,
|
|
1338
|
+
caseSensitive: false,
|
|
1339
|
+
fuzzy: false
|
|
1340
|
+
});
|
|
1341
|
+
if (match) {
|
|
1342
|
+
params = match;
|
|
1343
|
+
return true;
|
|
1451
1344
|
}
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
};
|
|
1459
|
-
if (match.paramsError) {
|
|
1460
|
-
handleError(match.paramsError, 'PARSE_PARAMS');
|
|
1461
|
-
}
|
|
1462
|
-
if (match.searchError) {
|
|
1463
|
-
handleError(match.searchError, 'VALIDATE_SEARCH');
|
|
1464
|
-
}
|
|
1465
|
-
let didError = false;
|
|
1466
|
-
const parentContext = parentMatch?.context ?? this?.options.context ?? {};
|
|
1467
|
-
try {
|
|
1468
|
-
const beforeLoadContext = (await route.options.beforeLoad?.({
|
|
1469
|
-
abortController: match.abortController,
|
|
1470
|
-
params: match.params,
|
|
1471
|
-
preload: !!opts?.preload,
|
|
1472
|
-
context: {
|
|
1473
|
-
...parentContext,
|
|
1474
|
-
...match.loaderContext
|
|
1475
|
-
}
|
|
1476
|
-
})) ?? {};
|
|
1477
|
-
const context = {
|
|
1478
|
-
...parentContext,
|
|
1479
|
-
...match.loaderContext,
|
|
1480
|
-
...beforeLoadContext
|
|
1345
|
+
return false;
|
|
1346
|
+
});
|
|
1347
|
+
if (foundMask) {
|
|
1348
|
+
foundMask = {
|
|
1349
|
+
...foundMask,
|
|
1350
|
+
from: interpolatePath(foundMask.from, params)
|
|
1481
1351
|
};
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
context: replaceEqualDeep(s.context, context)
|
|
1485
|
-
}));
|
|
1486
|
-
} catch (err) {
|
|
1487
|
-
handleError(err, 'BEFORE_LOAD');
|
|
1488
|
-
didError = true;
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
// If we errored, do not run the next matches' middleware
|
|
1492
|
-
if (didError) {
|
|
1493
|
-
break;
|
|
1352
|
+
maskedDest = foundMask;
|
|
1353
|
+
maskedNext = build(maskedDest);
|
|
1494
1354
|
}
|
|
1495
1355
|
}
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1356
|
+
const nextMatches = matchRoutes(next.pathname, next.search);
|
|
1357
|
+
const maskedMatches = maskedNext ? matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
|
|
1358
|
+
const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
|
|
1359
|
+
const final = build(dest, nextMatches);
|
|
1360
|
+
if (maskedFinal) {
|
|
1361
|
+
final.maskedLocation = maskedFinal;
|
|
1500
1362
|
}
|
|
1501
|
-
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1363
|
+
return final;
|
|
1364
|
+
};
|
|
1365
|
+
if (opts.mask) {
|
|
1366
|
+
return buildWithMatches(opts, {
|
|
1367
|
+
...pick(opts, ['from']),
|
|
1368
|
+
...opts.mask
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
return buildWithMatches(opts);
|
|
1372
|
+
});
|
|
1373
|
+
const commitLocation = useStableCallback(async next => {
|
|
1374
|
+
if (navigateTimeoutRef.current) clearTimeout(navigateTimeoutRef.current);
|
|
1375
|
+
const isSameUrl = latestLocationRef.current.href === next.href;
|
|
1376
|
+
|
|
1377
|
+
// If the next urls are the same and we're not replacing,
|
|
1378
|
+
// do nothing
|
|
1379
|
+
if (!isSameUrl || !next.replace) {
|
|
1380
|
+
let {
|
|
1381
|
+
maskedLocation,
|
|
1382
|
+
...nextHistory
|
|
1383
|
+
} = next;
|
|
1384
|
+
if (maskedLocation) {
|
|
1385
|
+
nextHistory = {
|
|
1386
|
+
...maskedLocation,
|
|
1387
|
+
state: {
|
|
1388
|
+
...maskedLocation.state,
|
|
1389
|
+
__tempKey: undefined,
|
|
1390
|
+
__tempLocation: {
|
|
1391
|
+
...nextHistory,
|
|
1392
|
+
search: nextHistory.searchStr,
|
|
1393
|
+
state: {
|
|
1394
|
+
...nextHistory.state,
|
|
1395
|
+
__tempKey: undefined,
|
|
1396
|
+
__tempLocation: undefined,
|
|
1397
|
+
key: undefined
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
};
|
|
1402
|
+
if (nextHistory.unmaskOnReload ?? options.unmaskOnReload ?? false) {
|
|
1403
|
+
nextHistory.state.__tempKey = tempLocationKeyRef.current;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
|
|
1407
|
+
}
|
|
1408
|
+
resetNextScrollRef.current = next.resetScroll ?? true;
|
|
1409
|
+
return latestLoadPromiseRef.current;
|
|
1410
|
+
});
|
|
1411
|
+
const buildAndCommitLocation = useStableCallback(({
|
|
1412
|
+
replace,
|
|
1413
|
+
resetScroll,
|
|
1414
|
+
...rest
|
|
1415
|
+
} = {}) => {
|
|
1416
|
+
const location = buildLocation(rest);
|
|
1417
|
+
return commitLocation({
|
|
1418
|
+
...location,
|
|
1419
|
+
replace,
|
|
1420
|
+
resetScroll
|
|
1421
|
+
});
|
|
1422
|
+
});
|
|
1423
|
+
const navigate = useStableCallback(({
|
|
1424
|
+
from,
|
|
1425
|
+
to = '',
|
|
1426
|
+
...rest
|
|
1427
|
+
}) => {
|
|
1428
|
+
// If this link simply reloads the current route,
|
|
1429
|
+
// make sure it has a new key so it will trigger a data refresh
|
|
1430
|
+
|
|
1431
|
+
// If this `to` is a valid external URL, return
|
|
1432
|
+
// null for LinkUtils
|
|
1433
|
+
const toString = String(to);
|
|
1434
|
+
const fromString = typeof from === 'undefined' ? from : String(from);
|
|
1435
|
+
let isExternal;
|
|
1436
|
+
try {
|
|
1437
|
+
new URL(`${toString}`);
|
|
1438
|
+
isExternal = true;
|
|
1439
|
+
} catch (e) {}
|
|
1440
|
+
invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
|
|
1441
|
+
return buildAndCommitLocation({
|
|
1442
|
+
...rest,
|
|
1443
|
+
from: fromString,
|
|
1444
|
+
to: toString
|
|
1445
|
+
});
|
|
1446
|
+
});
|
|
1447
|
+
const loadMatches = useStableCallback(async ({
|
|
1448
|
+
matches,
|
|
1449
|
+
preload
|
|
1450
|
+
}) => {
|
|
1451
|
+
let firstBadMatchIndex;
|
|
1452
|
+
|
|
1453
|
+
// Check each match middleware to see if the route can be accessed
|
|
1454
|
+
try {
|
|
1455
|
+
for (let [index, match] of matches.entries()) {
|
|
1456
|
+
const parentMatch = matches[index - 1];
|
|
1457
|
+
const route = looseRoutesById[match.routeId];
|
|
1458
|
+
const handleError = (err, code) => {
|
|
1459
|
+
err.routerCode = code;
|
|
1460
|
+
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
1461
|
+
if (isRedirect(err)) {
|
|
1462
|
+
throw err;
|
|
1463
|
+
}
|
|
1464
|
+
try {
|
|
1465
|
+
route.options.onError?.(err);
|
|
1466
|
+
} catch (errorHandlerErr) {
|
|
1467
|
+
err = errorHandlerErr;
|
|
1468
|
+
if (isRedirect(errorHandlerErr)) {
|
|
1469
|
+
throw errorHandlerErr;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
matches[index] = match = {
|
|
1473
|
+
...match,
|
|
1474
|
+
error: err,
|
|
1475
|
+
status: 'error',
|
|
1476
|
+
updatedAt: Date.now()
|
|
1477
|
+
};
|
|
1478
|
+
};
|
|
1479
|
+
try {
|
|
1480
|
+
if (match.paramsError) {
|
|
1481
|
+
handleError(match.paramsError, 'PARSE_PARAMS');
|
|
1482
|
+
}
|
|
1483
|
+
if (match.searchError) {
|
|
1484
|
+
handleError(match.searchError, 'VALIDATE_SEARCH');
|
|
1485
|
+
}
|
|
1486
|
+
const parentMeta = parentMatch?.meta ?? options.meta ?? {};
|
|
1487
|
+
const beforeLoadMeta = (await route.options.beforeLoad?.({
|
|
1488
|
+
search: match.search,
|
|
1489
|
+
abortController: match.abortController,
|
|
1490
|
+
params: match.params,
|
|
1491
|
+
preload: !!preload,
|
|
1492
|
+
meta: parentMeta,
|
|
1493
|
+
location: state.location // TODO: This might need to be latestLocationRef.current...?
|
|
1494
|
+
})) ?? {};
|
|
1495
|
+
const meta = {
|
|
1496
|
+
...parentMeta,
|
|
1497
|
+
...beforeLoadMeta
|
|
1498
|
+
};
|
|
1499
|
+
matches[index] = match = {
|
|
1500
|
+
...match,
|
|
1501
|
+
meta: replaceEqualDeep(match.meta, meta)
|
|
1502
|
+
};
|
|
1503
|
+
} catch (err) {
|
|
1504
|
+
handleError(err, 'BEFORE_LOAD');
|
|
1505
|
+
break;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
} catch (err) {
|
|
1509
|
+
if (isRedirect(err)) {
|
|
1510
|
+
if (!preload) navigate(err);
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
throw err;
|
|
1514
|
+
}
|
|
1515
|
+
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
1516
|
+
const matchPromises = [];
|
|
1517
|
+
validResolvedMatches.forEach((match, index) => {
|
|
1518
|
+
matchPromises.push((async () => {
|
|
1519
|
+
const parentMatchPromise = matchPromises[index - 1];
|
|
1520
|
+
const route = looseRoutesById[match.routeId];
|
|
1521
|
+
if (match.isFetching) {
|
|
1522
|
+
return getRouteMatch(state, match.id)?.loadPromise;
|
|
1513
1523
|
}
|
|
1514
1524
|
const fetchedAt = Date.now();
|
|
1515
1525
|
const checkLatest = () => {
|
|
1516
|
-
const latest =
|
|
1526
|
+
const latest = getRouteMatch(state, match.id);
|
|
1517
1527
|
return latest && latest.fetchedAt !== fetchedAt ? latest.loadPromise : undefined;
|
|
1518
1528
|
};
|
|
1519
1529
|
const handleIfRedirect = err => {
|
|
1520
1530
|
if (isRedirect(err)) {
|
|
1521
|
-
if (!
|
|
1522
|
-
|
|
1531
|
+
if (!preload) {
|
|
1532
|
+
navigate(err);
|
|
1523
1533
|
}
|
|
1524
1534
|
return true;
|
|
1525
1535
|
}
|
|
@@ -1534,16 +1544,23 @@
|
|
|
1534
1544
|
await component.preload();
|
|
1535
1545
|
}
|
|
1536
1546
|
}));
|
|
1537
|
-
const loaderPromise = route.options.
|
|
1547
|
+
const loaderPromise = route.options.load?.({
|
|
1538
1548
|
params: match.params,
|
|
1539
|
-
|
|
1549
|
+
search: match.search,
|
|
1550
|
+
preload: !!preload,
|
|
1540
1551
|
parentMatchPromise,
|
|
1541
1552
|
abortController: match.abortController,
|
|
1542
|
-
|
|
1553
|
+
meta: match.meta
|
|
1543
1554
|
});
|
|
1544
|
-
|
|
1555
|
+
await Promise.all([componentsPromise, loaderPromise]);
|
|
1545
1556
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1546
|
-
|
|
1557
|
+
matches[index] = match = {
|
|
1558
|
+
...match,
|
|
1559
|
+
error: undefined,
|
|
1560
|
+
status: 'success',
|
|
1561
|
+
isFetching: false,
|
|
1562
|
+
updatedAt: Date.now()
|
|
1563
|
+
};
|
|
1547
1564
|
} catch (error) {
|
|
1548
1565
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1549
1566
|
if (handleIfRedirect(error)) return;
|
|
@@ -1553,88 +1570,150 @@
|
|
|
1553
1570
|
error = onErrorError;
|
|
1554
1571
|
if (handleIfRedirect(onErrorError)) return;
|
|
1555
1572
|
}
|
|
1556
|
-
|
|
1557
|
-
...
|
|
1573
|
+
matches[index] = match = {
|
|
1574
|
+
...match,
|
|
1558
1575
|
error,
|
|
1559
1576
|
status: 'error',
|
|
1560
1577
|
isFetching: false,
|
|
1561
1578
|
updatedAt: Date.now()
|
|
1562
|
-
}
|
|
1579
|
+
};
|
|
1563
1580
|
}
|
|
1564
1581
|
};
|
|
1565
1582
|
let loadPromise;
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
loadPromise
|
|
1578
|
-
}));
|
|
1579
|
-
});
|
|
1583
|
+
matches[index] = match = {
|
|
1584
|
+
...match,
|
|
1585
|
+
isFetching: true,
|
|
1586
|
+
fetchedAt,
|
|
1587
|
+
invalid: false
|
|
1588
|
+
};
|
|
1589
|
+
loadPromise = load();
|
|
1590
|
+
matches[index] = match = {
|
|
1591
|
+
...match,
|
|
1592
|
+
loadPromise
|
|
1593
|
+
};
|
|
1580
1594
|
await loadPromise;
|
|
1581
1595
|
})());
|
|
1582
1596
|
});
|
|
1583
1597
|
await Promise.all(matchPromises);
|
|
1584
|
-
};
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
// If this link simply reloads the current route,
|
|
1594
|
-
// make sure it has a new key so it will trigger a data refresh
|
|
1598
|
+
});
|
|
1599
|
+
const load = useStableCallback(async opts => {
|
|
1600
|
+
const promise = new Promise(async (resolve, reject) => {
|
|
1601
|
+
const prevLocation = state.resolvedLocation;
|
|
1602
|
+
const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
|
|
1603
|
+
let latestPromise;
|
|
1604
|
+
const checkLatest = () => {
|
|
1605
|
+
return latestLoadPromiseRef.current !== promise ? latestLoadPromiseRef.current : undefined;
|
|
1606
|
+
};
|
|
1595
1607
|
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1608
|
+
// Cancel any pending matches
|
|
1609
|
+
cancelMatches(state);
|
|
1610
|
+
router.emit({
|
|
1611
|
+
type: 'onBeforeLoad',
|
|
1612
|
+
from: prevLocation,
|
|
1613
|
+
to: opts?.next ?? state.location,
|
|
1614
|
+
pathChanged: pathDidChange
|
|
1615
|
+
});
|
|
1616
|
+
if (opts?.next) {
|
|
1617
|
+
// Ingest the new location
|
|
1618
|
+
setState(s => ({
|
|
1619
|
+
...s,
|
|
1620
|
+
location: opts.next
|
|
1621
|
+
}));
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// Match the routes
|
|
1625
|
+
const matches = matchRoutes(state.location.pathname, state.location.search, {
|
|
1626
|
+
throwOnError: opts?.throwOnError,
|
|
1627
|
+
debug: true
|
|
1628
|
+
});
|
|
1629
|
+
setState(s => ({
|
|
1630
|
+
...s,
|
|
1631
|
+
status: 'pending',
|
|
1632
|
+
matches
|
|
1633
|
+
}));
|
|
1634
|
+
try {
|
|
1635
|
+
// Load the matches
|
|
1636
|
+
try {
|
|
1637
|
+
await loadMatches({
|
|
1638
|
+
matches
|
|
1639
|
+
});
|
|
1640
|
+
} catch (err) {
|
|
1641
|
+
// swallow this error, since we'll display the
|
|
1642
|
+
// errors on the route components
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
// Only apply the latest transition
|
|
1646
|
+
if (latestPromise = checkLatest()) {
|
|
1647
|
+
return latestPromise;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// TODO:
|
|
1651
|
+
// const exitingMatchIds = previousMatches.filter(
|
|
1652
|
+
// (id) => !state.pendingMatches.includes(id),
|
|
1653
|
+
// )
|
|
1654
|
+
// const enteringMatchIds = state.pendingMatches.filter(
|
|
1655
|
+
// (id) => !previousMatches.includes(id),
|
|
1656
|
+
// )
|
|
1657
|
+
// const stayingMatchIds = previousMatches.filter((id) =>
|
|
1658
|
+
// state.pendingMatches.includes(id),
|
|
1659
|
+
// )
|
|
1660
|
+
|
|
1661
|
+
setState(s => ({
|
|
1662
|
+
...s,
|
|
1663
|
+
status: 'idle',
|
|
1664
|
+
resolvedLocation: s.location
|
|
1665
|
+
}));
|
|
1666
|
+
|
|
1667
|
+
// TODO:
|
|
1668
|
+
// ;(
|
|
1669
|
+
// [
|
|
1670
|
+
// [exitingMatchIds, 'onLeave'],
|
|
1671
|
+
// [enteringMatchIds, 'onEnter'],
|
|
1672
|
+
// [stayingMatchIds, 'onTransition'],
|
|
1673
|
+
// ] as const
|
|
1674
|
+
// ).forEach(([matches, hook]) => {
|
|
1675
|
+
// matches.forEach((match) => {
|
|
1676
|
+
// const route = this.getRoute(match.routeId)
|
|
1677
|
+
// route.options[hook]?.(match)
|
|
1678
|
+
// })
|
|
1679
|
+
// })
|
|
1680
|
+
router.emit({
|
|
1681
|
+
type: 'onLoad',
|
|
1682
|
+
from: prevLocation,
|
|
1683
|
+
to: state.location,
|
|
1684
|
+
pathChanged: pathDidChange
|
|
1685
|
+
});
|
|
1686
|
+
resolve();
|
|
1687
|
+
} catch (err) {
|
|
1688
|
+
// Only apply the latest transition
|
|
1689
|
+
if (latestPromise = checkLatest()) {
|
|
1690
|
+
return latestPromise;
|
|
1691
|
+
}
|
|
1692
|
+
reject(err);
|
|
1693
|
+
}
|
|
1610
1694
|
});
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
return false;
|
|
1620
|
-
}
|
|
1621
|
-
const baseLocation = opts?.pending ? this.state.location : this.state.resolvedLocation;
|
|
1622
|
-
if (!baseLocation) {
|
|
1623
|
-
return false;
|
|
1695
|
+
latestLoadPromiseRef.current = promise;
|
|
1696
|
+
return latestLoadPromiseRef.current;
|
|
1697
|
+
});
|
|
1698
|
+
const safeLoad = React__namespace.useCallback(async () => {
|
|
1699
|
+
try {
|
|
1700
|
+
return load();
|
|
1701
|
+
} catch (err) {
|
|
1702
|
+
// Don't do anything
|
|
1624
1703
|
}
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1704
|
+
}, []);
|
|
1705
|
+
const preloadRoute = useStableCallback(async (navigateOpts = state.location) => {
|
|
1706
|
+
let next = buildLocation(navigateOpts);
|
|
1707
|
+
let matches = matchRoutes(next.pathname, next.search, {
|
|
1708
|
+
throwOnError: true
|
|
1628
1709
|
});
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
};
|
|
1637
|
-
buildLink = dest => {
|
|
1710
|
+
await loadMatches({
|
|
1711
|
+
matches,
|
|
1712
|
+
preload: true
|
|
1713
|
+
});
|
|
1714
|
+
return [last(matches), matches];
|
|
1715
|
+
});
|
|
1716
|
+
const buildLink = useStableCallback((state, dest) => {
|
|
1638
1717
|
// If this link simply reloads the current route,
|
|
1639
1718
|
// make sure it has a new key so it will trigger a data refresh
|
|
1640
1719
|
|
|
@@ -1659,18 +1738,18 @@
|
|
|
1659
1738
|
};
|
|
1660
1739
|
} catch (e) {}
|
|
1661
1740
|
const nextOpts = dest;
|
|
1662
|
-
const next =
|
|
1663
|
-
const preload = userPreload ??
|
|
1664
|
-
const preloadDelay = userPreloadDelay ??
|
|
1741
|
+
const next = buildLocation(nextOpts);
|
|
1742
|
+
const preload = userPreload ?? options.defaultPreload;
|
|
1743
|
+
const preloadDelay = userPreloadDelay ?? options.defaultPreloadDelay ?? 0;
|
|
1665
1744
|
|
|
1666
1745
|
// Compare path/hash for matches
|
|
1667
|
-
const currentPathSplit =
|
|
1746
|
+
const currentPathSplit = latestLocationRef.current.pathname.split('/');
|
|
1668
1747
|
const nextPathSplit = next.pathname.split('/');
|
|
1669
1748
|
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1670
1749
|
// Combine the matches based on user options
|
|
1671
|
-
const pathTest = activeOptions?.exact ?
|
|
1672
|
-
const hashTest = activeOptions?.includeHash ?
|
|
1673
|
-
const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(
|
|
1750
|
+
const pathTest = activeOptions?.exact ? latestLocationRef.current.pathname === next.pathname : pathIsFuzzyEqual;
|
|
1751
|
+
const hashTest = activeOptions?.includeHash ? latestLocationRef.current.hash === next.hash : true;
|
|
1752
|
+
const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(latestLocationRef.current.search, next.search) : true;
|
|
1674
1753
|
|
|
1675
1754
|
// The final "active" test
|
|
1676
1755
|
const isActive = pathTest && hashTest && searchTest;
|
|
@@ -1681,7 +1760,7 @@
|
|
|
1681
1760
|
e.preventDefault();
|
|
1682
1761
|
|
|
1683
1762
|
// All is well? Navigate!
|
|
1684
|
-
|
|
1763
|
+
commitLocation({
|
|
1685
1764
|
...next,
|
|
1686
1765
|
replace,
|
|
1687
1766
|
resetScroll
|
|
@@ -1692,14 +1771,14 @@
|
|
|
1692
1771
|
// The click handler
|
|
1693
1772
|
const handleFocus = e => {
|
|
1694
1773
|
if (preload) {
|
|
1695
|
-
|
|
1774
|
+
preloadRoute(nextOpts).catch(err => {
|
|
1696
1775
|
console.warn(err);
|
|
1697
1776
|
console.warn(preloadWarning);
|
|
1698
1777
|
});
|
|
1699
1778
|
}
|
|
1700
1779
|
};
|
|
1701
1780
|
const handleTouchStart = e => {
|
|
1702
|
-
|
|
1781
|
+
preloadRoute(nextOpts).catch(err => {
|
|
1703
1782
|
console.warn(err);
|
|
1704
1783
|
console.warn(preloadWarning);
|
|
1705
1784
|
});
|
|
@@ -1712,7 +1791,7 @@
|
|
|
1712
1791
|
}
|
|
1713
1792
|
target.preloadTimeout = setTimeout(() => {
|
|
1714
1793
|
target.preloadTimeout = null;
|
|
1715
|
-
|
|
1794
|
+
preloadRoute(nextOpts).catch(err => {
|
|
1716
1795
|
console.warn(err);
|
|
1717
1796
|
console.warn(preloadWarning);
|
|
1718
1797
|
});
|
|
@@ -1737,663 +1816,95 @@
|
|
|
1737
1816
|
isActive,
|
|
1738
1817
|
disabled
|
|
1739
1818
|
};
|
|
1740
|
-
};
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
// Client hydrates from window
|
|
1752
|
-
if (typeof document !== 'undefined') {
|
|
1753
|
-
_ctx = window.__TSR_DEHYDRATED__;
|
|
1754
|
-
}
|
|
1755
|
-
invariant(_ctx, 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?');
|
|
1756
|
-
const ctx = _ctx;
|
|
1757
|
-
this.dehydratedData = ctx.payload;
|
|
1758
|
-
this.options.hydrate?.(ctx.payload);
|
|
1759
|
-
const dehydratedState = ctx.router.state;
|
|
1760
|
-
let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
|
|
1761
|
-
const dehydratedMatch = dehydratedState.dehydratedMatches.find(d => d.id === match.id);
|
|
1762
|
-
invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
|
|
1763
|
-
if (dehydratedMatch) {
|
|
1764
|
-
return {
|
|
1765
|
-
...match,
|
|
1766
|
-
...dehydratedMatch
|
|
1767
|
-
};
|
|
1768
|
-
}
|
|
1769
|
-
return match;
|
|
1819
|
+
});
|
|
1820
|
+
const latestLocationRef = React__namespace.useRef(state.location);
|
|
1821
|
+
React__namespace.useLayoutEffect(() => {
|
|
1822
|
+
const unsub = history.subscribe(() => {
|
|
1823
|
+
latestLocationRef.current = parseLocation(latestLocationRef.current);
|
|
1824
|
+
React__namespace.startTransition(() => {
|
|
1825
|
+
setState(s => ({
|
|
1826
|
+
...s,
|
|
1827
|
+
location: latestLocationRef.current
|
|
1828
|
+
}));
|
|
1829
|
+
});
|
|
1770
1830
|
});
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
matchesById: this.#mergeMatches(s.matchesById, matches)
|
|
1777
|
-
};
|
|
1831
|
+
const nextLocation = buildLocation({
|
|
1832
|
+
search: true,
|
|
1833
|
+
params: true,
|
|
1834
|
+
hash: true,
|
|
1835
|
+
state: true
|
|
1778
1836
|
});
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
};
|
|
1784
|
-
dehydrateData = (key, getData) => {
|
|
1785
|
-
if (typeof document === 'undefined') {
|
|
1786
|
-
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
1787
|
-
this.injectHtml(async () => {
|
|
1788
|
-
const id = `__TSR_DEHYDRATED__${strKey}`;
|
|
1789
|
-
const data = typeof getData === 'function' ? await getData() : getData;
|
|
1790
|
-
return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
|
|
1791
|
-
;(() => {
|
|
1792
|
-
var el = document.getElementById('${id}')
|
|
1793
|
-
el.parentElement.removeChild(el)
|
|
1794
|
-
})()
|
|
1795
|
-
</script>`;
|
|
1837
|
+
if (state.location.href !== nextLocation.href) {
|
|
1838
|
+
commitLocation({
|
|
1839
|
+
...nextLocation,
|
|
1840
|
+
replace: true
|
|
1796
1841
|
});
|
|
1797
|
-
return () => this.hydrateData(key);
|
|
1798
|
-
}
|
|
1799
|
-
return () => undefined;
|
|
1800
|
-
};
|
|
1801
|
-
hydrateData = key => {
|
|
1802
|
-
if (typeof document !== 'undefined') {
|
|
1803
|
-
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
1804
|
-
return window[`__TSR_DEHYDRATED__${strKey}`];
|
|
1805
|
-
}
|
|
1806
|
-
return undefined;
|
|
1807
|
-
};
|
|
1808
|
-
|
|
1809
|
-
// resolveMatchPromise = (matchId: string, key: string, value: any) => {
|
|
1810
|
-
// this.state.matches
|
|
1811
|
-
// .find((d) => d.id === matchId)
|
|
1812
|
-
// ?.__promisesByKey[key]?.resolve(value)
|
|
1813
|
-
// }
|
|
1814
|
-
|
|
1815
|
-
#processRoutes = routeTree => {
|
|
1816
|
-
this.routeTree = routeTree;
|
|
1817
|
-
this.routesById = {};
|
|
1818
|
-
this.routesByPath = {};
|
|
1819
|
-
this.flatRoutes = [];
|
|
1820
|
-
const recurseRoutes = routes => {
|
|
1821
|
-
routes.forEach((route, i) => {
|
|
1822
|
-
route.init({
|
|
1823
|
-
originalIndex: i,
|
|
1824
|
-
router: this
|
|
1825
|
-
});
|
|
1826
|
-
const existingRoute = this.routesById[route.id];
|
|
1827
|
-
invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
|
|
1828
|
-
this.routesById[route.id] = route;
|
|
1829
|
-
if (!route.isRoot && route.path) {
|
|
1830
|
-
const trimmedFullPath = trimPathRight(route.fullPath);
|
|
1831
|
-
if (!this.routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
|
|
1832
|
-
this.routesByPath[trimmedFullPath] = route;
|
|
1833
|
-
}
|
|
1834
|
-
}
|
|
1835
|
-
const children = route.children;
|
|
1836
|
-
if (children?.length) {
|
|
1837
|
-
recurseRoutes(children);
|
|
1838
|
-
}
|
|
1839
|
-
});
|
|
1840
|
-
};
|
|
1841
|
-
recurseRoutes([routeTree]);
|
|
1842
|
-
this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
|
|
1843
|
-
const trimmed = trimPath(d.fullPath);
|
|
1844
|
-
const parsed = parsePathname(trimmed);
|
|
1845
|
-
while (parsed.length > 1 && parsed[0]?.value === '/') {
|
|
1846
|
-
parsed.shift();
|
|
1847
|
-
}
|
|
1848
|
-
const score = parsed.map(d => {
|
|
1849
|
-
if (d.type === 'param') {
|
|
1850
|
-
return 0.5;
|
|
1851
|
-
}
|
|
1852
|
-
if (d.type === 'wildcard') {
|
|
1853
|
-
return 0.25;
|
|
1854
|
-
}
|
|
1855
|
-
return 1;
|
|
1856
|
-
});
|
|
1857
|
-
return {
|
|
1858
|
-
child: d,
|
|
1859
|
-
trimmed,
|
|
1860
|
-
parsed,
|
|
1861
|
-
index: i,
|
|
1862
|
-
score
|
|
1863
|
-
};
|
|
1864
|
-
}).sort((a, b) => {
|
|
1865
|
-
let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
|
|
1866
|
-
if (isIndex !== 0) return isIndex;
|
|
1867
|
-
const length = Math.min(a.score.length, b.score.length);
|
|
1868
|
-
|
|
1869
|
-
// Sort by length of score
|
|
1870
|
-
if (a.score.length !== b.score.length) {
|
|
1871
|
-
return b.score.length - a.score.length;
|
|
1872
|
-
}
|
|
1873
|
-
|
|
1874
|
-
// Sort by min available score
|
|
1875
|
-
for (let i = 0; i < length; i++) {
|
|
1876
|
-
if (a.score[i] !== b.score[i]) {
|
|
1877
|
-
return b.score[i] - a.score[i];
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
|
|
1881
|
-
// Sort by min available parsed value
|
|
1882
|
-
for (let i = 0; i < length; i++) {
|
|
1883
|
-
if (a.parsed[i].value !== b.parsed[i].value) {
|
|
1884
|
-
return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
// Sort by length of trimmed full path
|
|
1889
|
-
if (a.trimmed !== b.trimmed) {
|
|
1890
|
-
return a.trimmed > b.trimmed ? 1 : -1;
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
|
-
// Sort by original index
|
|
1894
|
-
return a.index - b.index;
|
|
1895
|
-
}).map((d, i) => {
|
|
1896
|
-
d.child.rank = i;
|
|
1897
|
-
return d.child;
|
|
1898
|
-
});
|
|
1899
|
-
};
|
|
1900
|
-
#parseLocation = previousLocation => {
|
|
1901
|
-
const parse = ({
|
|
1902
|
-
pathname,
|
|
1903
|
-
search,
|
|
1904
|
-
hash,
|
|
1905
|
-
state
|
|
1906
|
-
}) => {
|
|
1907
|
-
const parsedSearch = this.options.parseSearch(search);
|
|
1908
|
-
return {
|
|
1909
|
-
pathname: pathname,
|
|
1910
|
-
searchStr: search,
|
|
1911
|
-
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
1912
|
-
hash: hash.split('#').reverse()[0] ?? '',
|
|
1913
|
-
href: `${pathname}${search}${hash}`,
|
|
1914
|
-
state: replaceEqualDeep(previousLocation?.state, state)
|
|
1915
|
-
};
|
|
1916
|
-
};
|
|
1917
|
-
const location = parse(this.history.location);
|
|
1918
|
-
let {
|
|
1919
|
-
__tempLocation,
|
|
1920
|
-
__tempKey
|
|
1921
|
-
} = location.state;
|
|
1922
|
-
if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
|
|
1923
|
-
// Sync up the location keys
|
|
1924
|
-
const parsedTempLocation = parse(__tempLocation);
|
|
1925
|
-
parsedTempLocation.state.key = location.state.key;
|
|
1926
|
-
delete parsedTempLocation.state.__tempLocation;
|
|
1927
|
-
return {
|
|
1928
|
-
...parsedTempLocation,
|
|
1929
|
-
maskedLocation: location
|
|
1930
|
-
};
|
|
1931
|
-
}
|
|
1932
|
-
return location;
|
|
1933
|
-
};
|
|
1934
|
-
buildLocation = (opts = {}) => {
|
|
1935
|
-
const build = (dest = {}, matches) => {
|
|
1936
|
-
const from = this.state.location;
|
|
1937
|
-
const fromPathname = dest.from ?? from.pathname;
|
|
1938
|
-
let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? ''}`);
|
|
1939
|
-
const fromMatches = this.matchRoutes(fromPathname, from.search);
|
|
1940
|
-
const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
|
|
1941
|
-
const prevParams = {
|
|
1942
|
-
...last(fromMatches)?.params
|
|
1943
|
-
};
|
|
1944
|
-
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
1945
|
-
if (nextParams) {
|
|
1946
|
-
matches?.map(d => this.getRoute(d.routeId).options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
1947
|
-
nextParams = {
|
|
1948
|
-
...nextParams,
|
|
1949
|
-
...fn(nextParams)
|
|
1950
|
-
};
|
|
1951
|
-
});
|
|
1952
|
-
}
|
|
1953
|
-
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
1954
|
-
const preSearchFilters = stayingMatches?.map(match => this.getRoute(match.routeId).options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1955
|
-
const postSearchFilters = stayingMatches?.map(match => this.getRoute(match.routeId).options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1956
|
-
|
|
1957
|
-
// Pre filters first
|
|
1958
|
-
const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
|
|
1959
|
-
|
|
1960
|
-
// Then the link/navigate function
|
|
1961
|
-
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
1962
|
-
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
1963
|
-
: preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
1964
|
-
: {};
|
|
1965
|
-
|
|
1966
|
-
// Then post filters
|
|
1967
|
-
const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1968
|
-
const search = replaceEqualDeep(from.search, postFilteredSearch);
|
|
1969
|
-
const searchStr = this.options.stringifySearch(search);
|
|
1970
|
-
const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
|
|
1971
|
-
const hashStr = hash ? `#${hash}` : '';
|
|
1972
|
-
let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
|
|
1973
|
-
nextState = replaceEqualDeep(from.state, nextState);
|
|
1974
|
-
return {
|
|
1975
|
-
pathname,
|
|
1976
|
-
search,
|
|
1977
|
-
searchStr,
|
|
1978
|
-
state: nextState,
|
|
1979
|
-
hash,
|
|
1980
|
-
href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
|
|
1981
|
-
unmaskOnReload: dest.unmaskOnReload
|
|
1982
|
-
};
|
|
1983
|
-
};
|
|
1984
|
-
const buildWithMatches = (dest = {}, maskedDest) => {
|
|
1985
|
-
let next = build(dest);
|
|
1986
|
-
let maskedNext = maskedDest ? build(maskedDest) : undefined;
|
|
1987
|
-
if (!maskedNext) {
|
|
1988
|
-
let params = {};
|
|
1989
|
-
let foundMask = this.options.routeMasks?.find(d => {
|
|
1990
|
-
const match = matchPathname(this.basepath, next.pathname, {
|
|
1991
|
-
to: d.from,
|
|
1992
|
-
fuzzy: false
|
|
1993
|
-
});
|
|
1994
|
-
if (match) {
|
|
1995
|
-
params = match;
|
|
1996
|
-
return true;
|
|
1997
|
-
}
|
|
1998
|
-
return false;
|
|
1999
|
-
});
|
|
2000
|
-
if (foundMask) {
|
|
2001
|
-
foundMask = {
|
|
2002
|
-
...foundMask,
|
|
2003
|
-
from: interpolatePath(foundMask.from, params)
|
|
2004
|
-
};
|
|
2005
|
-
maskedDest = foundMask;
|
|
2006
|
-
maskedNext = build(maskedDest);
|
|
2007
|
-
}
|
|
2008
|
-
}
|
|
2009
|
-
const nextMatches = this.matchRoutes(next.pathname, next.search);
|
|
2010
|
-
const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
|
|
2011
|
-
const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
|
|
2012
|
-
const final = build(dest, nextMatches);
|
|
2013
|
-
if (maskedFinal) {
|
|
2014
|
-
final.maskedLocation = maskedFinal;
|
|
2015
|
-
}
|
|
2016
|
-
return final;
|
|
2017
|
-
};
|
|
2018
|
-
if (opts.mask) {
|
|
2019
|
-
return buildWithMatches(opts, {
|
|
2020
|
-
...pick(opts, ['from']),
|
|
2021
|
-
...opts.mask
|
|
2022
|
-
});
|
|
2023
|
-
}
|
|
2024
|
-
return buildWithMatches(opts);
|
|
2025
|
-
};
|
|
2026
|
-
#buildAndCommitLocation = ({
|
|
2027
|
-
replace,
|
|
2028
|
-
resetScroll,
|
|
2029
|
-
...rest
|
|
2030
|
-
} = {}) => {
|
|
2031
|
-
const location = this.buildLocation(rest);
|
|
2032
|
-
return this.#commitLocation({
|
|
2033
|
-
...location,
|
|
2034
|
-
replace,
|
|
2035
|
-
resetScroll
|
|
2036
|
-
});
|
|
2037
|
-
};
|
|
2038
|
-
#commitLocation = async next => {
|
|
2039
|
-
if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
|
|
2040
|
-
const isSameUrl = this.state.location.href === next.href;
|
|
2041
|
-
|
|
2042
|
-
// If the next urls are the same and we're not replacing,
|
|
2043
|
-
// do nothing
|
|
2044
|
-
if (!isSameUrl || !next.replace) {
|
|
2045
|
-
let {
|
|
2046
|
-
maskedLocation,
|
|
2047
|
-
...nextHistory
|
|
2048
|
-
} = next;
|
|
2049
|
-
if (maskedLocation) {
|
|
2050
|
-
nextHistory = {
|
|
2051
|
-
...maskedLocation,
|
|
2052
|
-
state: {
|
|
2053
|
-
...maskedLocation.state,
|
|
2054
|
-
__tempKey: undefined,
|
|
2055
|
-
__tempLocation: {
|
|
2056
|
-
...nextHistory,
|
|
2057
|
-
search: nextHistory.searchStr,
|
|
2058
|
-
state: {
|
|
2059
|
-
...nextHistory.state,
|
|
2060
|
-
__tempKey: undefined,
|
|
2061
|
-
__tempLocation: undefined,
|
|
2062
|
-
key: undefined
|
|
2063
|
-
}
|
|
2064
|
-
}
|
|
2065
|
-
}
|
|
2066
|
-
};
|
|
2067
|
-
if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
|
|
2068
|
-
nextHistory.state.__tempKey = this.tempLocationKey;
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
|
|
2072
|
-
}
|
|
2073
|
-
this.resetNextScroll = next.resetScroll ?? true;
|
|
2074
|
-
return this.latestLoadPromise;
|
|
2075
|
-
};
|
|
2076
|
-
getRouteMatch = id => {
|
|
2077
|
-
return this.state.matchesById[id];
|
|
2078
|
-
};
|
|
2079
|
-
setRouteMatch = (id, updater) => {
|
|
2080
|
-
this.__store.setState(prev => {
|
|
2081
|
-
if (!prev.matchesById[id]) {
|
|
2082
|
-
return prev;
|
|
2083
|
-
}
|
|
2084
|
-
return {
|
|
2085
|
-
...prev,
|
|
2086
|
-
matchesById: {
|
|
2087
|
-
...prev.matchesById,
|
|
2088
|
-
[id]: updater(prev.matchesById[id])
|
|
2089
|
-
}
|
|
2090
|
-
};
|
|
2091
|
-
});
|
|
2092
|
-
};
|
|
2093
|
-
setRouteMatchData = (id, updater, opts) => {
|
|
2094
|
-
const match = this.getRouteMatch(id);
|
|
2095
|
-
if (!match) return;
|
|
2096
|
-
const route = this.getRoute(match.routeId);
|
|
2097
|
-
const updatedAt = opts?.updatedAt ?? Date.now();
|
|
2098
|
-
const preloadMaxAge = opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000;
|
|
2099
|
-
const maxAge = opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? -1;
|
|
2100
|
-
this.setRouteMatch(id, s => ({
|
|
2101
|
-
...s,
|
|
2102
|
-
error: undefined,
|
|
2103
|
-
status: 'success',
|
|
2104
|
-
isFetching: false,
|
|
2105
|
-
updatedAt: updatedAt,
|
|
2106
|
-
loaderData: functionalUpdate(updater, s.loaderData),
|
|
2107
|
-
preloadMaxAge,
|
|
2108
|
-
maxAge
|
|
2109
|
-
}));
|
|
2110
|
-
};
|
|
2111
|
-
invalidate = async opts => {
|
|
2112
|
-
if (opts?.matchId) {
|
|
2113
|
-
this.setRouteMatch(opts.matchId, s => ({
|
|
2114
|
-
...s,
|
|
2115
|
-
invalid: true
|
|
2116
|
-
}));
|
|
2117
|
-
const matchIndex = this.state.matches.findIndex(d => d.id === opts.matchId);
|
|
2118
|
-
const childMatch = this.state.matches[matchIndex + 1];
|
|
2119
|
-
if (childMatch) {
|
|
2120
|
-
return this.invalidate({
|
|
2121
|
-
matchId: childMatch.id,
|
|
2122
|
-
reload: false,
|
|
2123
|
-
__fromFocus: opts.__fromFocus
|
|
2124
|
-
});
|
|
2125
|
-
}
|
|
2126
|
-
} else {
|
|
2127
|
-
this.__store.batch(() => {
|
|
2128
|
-
Object.values(this.state.matchesById).forEach(match => {
|
|
2129
|
-
const route = this.getRoute(match.routeId);
|
|
2130
|
-
const shouldInvalidate = opts?.__fromFocus ? route.options.reloadOnWindowFocus ?? true : true;
|
|
2131
|
-
if (shouldInvalidate) {
|
|
2132
|
-
this.setRouteMatch(match.id, s => ({
|
|
2133
|
-
...s,
|
|
2134
|
-
invalid: true
|
|
2135
|
-
}));
|
|
2136
|
-
}
|
|
2137
|
-
});
|
|
2138
|
-
});
|
|
2139
|
-
}
|
|
2140
|
-
if (opts?.reload ?? true) {
|
|
2141
|
-
return this.load();
|
|
2142
|
-
}
|
|
2143
|
-
};
|
|
2144
|
-
}
|
|
2145
|
-
|
|
2146
|
-
// Detect if we're in the DOM
|
|
2147
|
-
const isServer = typeof window === 'undefined' || !window.document.createElement;
|
|
2148
|
-
function getInitialRouterState() {
|
|
2149
|
-
return {
|
|
2150
|
-
status: 'idle',
|
|
2151
|
-
isFetching: false,
|
|
2152
|
-
resolvedLocation: null,
|
|
2153
|
-
location: null,
|
|
2154
|
-
matchesById: {},
|
|
2155
|
-
matchIds: [],
|
|
2156
|
-
pendingMatchIds: [],
|
|
2157
|
-
matches: [],
|
|
2158
|
-
pendingMatches: [],
|
|
2159
|
-
renderedMatchIds: [],
|
|
2160
|
-
renderedMatches: [],
|
|
2161
|
-
lastUpdated: Date.now()
|
|
2162
|
-
};
|
|
2163
|
-
}
|
|
2164
|
-
function isCtrlEvent(e) {
|
|
2165
|
-
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
2166
|
-
}
|
|
2167
|
-
function redirect(opts) {
|
|
2168
|
-
opts.isRedirect = true;
|
|
2169
|
-
return opts;
|
|
2170
|
-
}
|
|
2171
|
-
function isRedirect(obj) {
|
|
2172
|
-
return !!obj?.isRedirect;
|
|
2173
|
-
}
|
|
2174
|
-
class SearchParamError extends Error {}
|
|
2175
|
-
class PathParamError extends Error {}
|
|
2176
|
-
function escapeJSON(jsonString) {
|
|
2177
|
-
return jsonString.replace(/\\/g, '\\\\') // Escape backslashes
|
|
2178
|
-
.replace(/'/g, "\\'") // Escape single quotes
|
|
2179
|
-
.replace(/"/g, '\\"'); // Escape double quotes
|
|
2180
|
-
}
|
|
2181
|
-
|
|
2182
|
-
// A function that takes an import() argument which is a function and returns a new function that will
|
|
2183
|
-
// proxy arguments from the caller to the imported function, retaining all type
|
|
2184
|
-
// information along the way
|
|
2185
|
-
function lazyFn(fn, key) {
|
|
2186
|
-
return async (...args) => {
|
|
2187
|
-
const imported = await fn();
|
|
2188
|
-
return imported[key || 'default'](...args);
|
|
2189
|
-
};
|
|
2190
|
-
}
|
|
2191
|
-
function isMatchInvalid(match, opts) {
|
|
2192
|
-
const now = Date.now();
|
|
2193
|
-
if (match.invalid) {
|
|
2194
|
-
return true;
|
|
2195
|
-
}
|
|
2196
|
-
if (opts?.preload) {
|
|
2197
|
-
return match.preloadMaxAge < 0 ? false : match.updatedAt + match.preloadMaxAge < now;
|
|
2198
|
-
}
|
|
2199
|
-
return match.maxAge < 0 ? false : match.updatedAt + match.maxAge < now;
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
const windowKey = 'window';
|
|
2203
|
-
const delimiter = '___';
|
|
2204
|
-
let weakScrolledElementsByRestoreKey = {};
|
|
2205
|
-
let cache;
|
|
2206
|
-
let pathDidChange = false;
|
|
2207
|
-
const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
|
|
2208
|
-
const defaultGetKey = location => location.state.key;
|
|
2209
|
-
function watchScrollPositions(router, opts) {
|
|
2210
|
-
const getKey = opts?.getKey || defaultGetKey;
|
|
2211
|
-
if (sessionsStorage) {
|
|
2212
|
-
if (!cache) {
|
|
2213
|
-
cache = (() => {
|
|
2214
|
-
const storageKey = 'tsr-scroll-restoration-v1';
|
|
2215
|
-
const current = JSON.parse(window.sessionStorage.getItem(storageKey) || '{}');
|
|
2216
|
-
return {
|
|
2217
|
-
current,
|
|
2218
|
-
set: (key, value) => {
|
|
2219
|
-
current[key] = value;
|
|
2220
|
-
window.sessionStorage.setItem(storageKey, JSON.stringify(cache));
|
|
2221
|
-
}
|
|
2222
|
-
};
|
|
2223
|
-
})();
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
|
-
const {
|
|
2227
|
-
history
|
|
2228
|
-
} = window;
|
|
2229
|
-
if (history.scrollRestoration) {
|
|
2230
|
-
history.scrollRestoration = 'manual';
|
|
2231
|
-
}
|
|
2232
|
-
const onScroll = event => {
|
|
2233
|
-
const restoreKey = getKey(router.state.resolvedLocation);
|
|
2234
|
-
if (!weakScrolledElementsByRestoreKey[restoreKey]) {
|
|
2235
|
-
weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet();
|
|
2236
|
-
}
|
|
2237
|
-
const set = weakScrolledElementsByRestoreKey[restoreKey];
|
|
2238
|
-
if (set.has(event.target)) return;
|
|
2239
|
-
set.add(event.target);
|
|
2240
|
-
const cacheKey = [restoreKey, event.target === document || event.target === window ? windowKey : getCssSelector(event.target)].join(delimiter);
|
|
2241
|
-
if (!cache.current[cacheKey]) {
|
|
2242
|
-
cache.set(cacheKey, {
|
|
2243
|
-
scrollX: NaN,
|
|
2244
|
-
scrollY: NaN
|
|
2245
|
-
});
|
|
2246
|
-
}
|
|
2247
|
-
};
|
|
2248
|
-
const getCssSelector = el => {
|
|
2249
|
-
let path = [],
|
|
2250
|
-
parent;
|
|
2251
|
-
while (parent = el.parentNode) {
|
|
2252
|
-
path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
|
|
2253
|
-
el = parent;
|
|
2254
|
-
}
|
|
2255
|
-
return `${path.join(' > ')}`.toLowerCase();
|
|
2256
|
-
};
|
|
2257
|
-
const onPathWillChange = from => {
|
|
2258
|
-
const restoreKey = getKey(from);
|
|
2259
|
-
for (const cacheKey in cache.current) {
|
|
2260
|
-
const entry = cache.current[cacheKey];
|
|
2261
|
-
const [key, elementSelector] = cacheKey.split(delimiter);
|
|
2262
|
-
if (restoreKey === key) {
|
|
2263
|
-
if (elementSelector === windowKey) {
|
|
2264
|
-
entry.scrollX = window.scrollX || 0;
|
|
2265
|
-
entry.scrollY = window.scrollY || 0;
|
|
2266
|
-
} else if (elementSelector) {
|
|
2267
|
-
const element = document.querySelector(elementSelector);
|
|
2268
|
-
entry.scrollX = element?.scrollLeft || 0;
|
|
2269
|
-
entry.scrollY = element?.scrollTop || 0;
|
|
2270
|
-
}
|
|
2271
|
-
cache.set(cacheKey, entry);
|
|
2272
|
-
}
|
|
2273
|
-
}
|
|
2274
|
-
};
|
|
2275
|
-
const onPathChange = () => {
|
|
2276
|
-
pathDidChange = true;
|
|
2277
|
-
};
|
|
2278
|
-
if (typeof document !== 'undefined') {
|
|
2279
|
-
document.addEventListener('scroll', onScroll, true);
|
|
2280
|
-
}
|
|
2281
|
-
const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
|
|
2282
|
-
if (event.pathChanged) onPathWillChange(event.from);
|
|
2283
|
-
});
|
|
2284
|
-
const unsubOnLoad = router.subscribe('onLoad', event => {
|
|
2285
|
-
if (event.pathChanged) onPathChange();
|
|
2286
|
-
});
|
|
2287
|
-
return () => {
|
|
2288
|
-
document.removeEventListener('scroll', onScroll);
|
|
2289
|
-
unsubOnBeforeLoad();
|
|
2290
|
-
unsubOnLoad();
|
|
2291
|
-
};
|
|
2292
|
-
}
|
|
2293
|
-
function restoreScrollPositions(router, opts) {
|
|
2294
|
-
if (pathDidChange) {
|
|
2295
|
-
if (!router.resetNextScroll) {
|
|
2296
|
-
return;
|
|
2297
|
-
}
|
|
2298
|
-
const getKey = opts?.getKey || defaultGetKey;
|
|
2299
|
-
pathDidChange = false;
|
|
2300
|
-
const restoreKey = getKey(router.state.location);
|
|
2301
|
-
let windowRestored = false;
|
|
2302
|
-
for (const cacheKey in cache.current) {
|
|
2303
|
-
const entry = cache.current[cacheKey];
|
|
2304
|
-
const [key, elementSelector] = cacheKey.split(delimiter);
|
|
2305
|
-
if (key === restoreKey) {
|
|
2306
|
-
if (elementSelector === windowKey) {
|
|
2307
|
-
windowRestored = true;
|
|
2308
|
-
window.scrollTo(entry.scrollX, entry.scrollY);
|
|
2309
|
-
} else if (elementSelector) {
|
|
2310
|
-
const element = document.querySelector(elementSelector);
|
|
2311
|
-
if (element) {
|
|
2312
|
-
element.scrollLeft = entry.scrollX;
|
|
2313
|
-
element.scrollTop = entry.scrollY;
|
|
2314
|
-
}
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
if (!windowRestored) {
|
|
2319
|
-
window.scrollTo(0, 0);
|
|
2320
1842
|
}
|
|
1843
|
+
return () => {
|
|
1844
|
+
unsub();
|
|
1845
|
+
};
|
|
1846
|
+
}, [history]);
|
|
1847
|
+
const initialLoad = React__namespace.useRef(true);
|
|
1848
|
+
if (initialLoad.current) {
|
|
1849
|
+
initialLoad.current = false;
|
|
1850
|
+
safeLoad();
|
|
2321
1851
|
}
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
1852
|
+
React__namespace.useLayoutEffect(() => {
|
|
1853
|
+
if (state.resolvedLocation !== state.location) {
|
|
1854
|
+
safeLoad();
|
|
1855
|
+
}
|
|
1856
|
+
}, [state.location]);
|
|
1857
|
+
React__namespace.useMemo(() => [...state.matches, ...state.pendingMatches].some(d => d.isFetching), [state.matches, state.pendingMatches]);
|
|
1858
|
+
const matchRoute = useStableCallback((state, location, opts) => {
|
|
1859
|
+
location = {
|
|
1860
|
+
...location,
|
|
1861
|
+
to: location.to ? resolvePathWithBase(location.from || '', location.to) : undefined
|
|
2330
1862
|
};
|
|
2331
|
-
const
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
1863
|
+
const next = buildLocation(location);
|
|
1864
|
+
if (opts?.pending && state.status !== 'pending') {
|
|
1865
|
+
return false;
|
|
1866
|
+
}
|
|
1867
|
+
const baseLocation = opts?.pending ? latestLocationRef.current : state.resolvedLocation;
|
|
1868
|
+
if (!baseLocation) {
|
|
1869
|
+
return false;
|
|
1870
|
+
}
|
|
1871
|
+
const match = matchPathname(basepath, baseLocation.pathname, {
|
|
1872
|
+
...opts,
|
|
1873
|
+
to: next.pathname
|
|
2338
1874
|
});
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
}
|
|
2342
|
-
function isDehydratedDeferred(obj) {
|
|
2343
|
-
return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
|
|
2344
|
-
}
|
|
2345
|
-
|
|
2346
|
-
function _extends() {
|
|
2347
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
2348
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
2349
|
-
var source = arguments[i];
|
|
2350
|
-
for (var key in source) {
|
|
2351
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
2352
|
-
target[key] = source[key];
|
|
2353
|
-
}
|
|
2354
|
-
}
|
|
1875
|
+
if (!match) {
|
|
1876
|
+
return false;
|
|
2355
1877
|
}
|
|
2356
|
-
|
|
1878
|
+
if (opts?.includeSearch ?? true) {
|
|
1879
|
+
return partialDeepEqual(baseLocation.search, next.search) ? match : false;
|
|
1880
|
+
}
|
|
1881
|
+
return match;
|
|
1882
|
+
});
|
|
1883
|
+
const routerContextValue = {
|
|
1884
|
+
routeTree: router.routeTree,
|
|
1885
|
+
navigate,
|
|
1886
|
+
buildLink,
|
|
1887
|
+
state,
|
|
1888
|
+
matchRoute,
|
|
1889
|
+
routesById,
|
|
1890
|
+
options,
|
|
1891
|
+
history,
|
|
1892
|
+
load
|
|
2357
1893
|
};
|
|
2358
|
-
return
|
|
1894
|
+
return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
|
|
1895
|
+
value: routerContextValue
|
|
1896
|
+
}, /*#__PURE__*/React__namespace.createElement(Matches, null));
|
|
1897
|
+
}
|
|
1898
|
+
function isCtrlEvent(e) {
|
|
1899
|
+
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
1900
|
+
}
|
|
1901
|
+
class SearchParamError extends Error {}
|
|
1902
|
+
class PathParamError extends Error {}
|
|
1903
|
+
function getRouteMatch(state, id) {
|
|
1904
|
+
return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
|
|
2359
1905
|
}
|
|
2360
1906
|
|
|
2361
|
-
const useLayoutEffect
|
|
2362
|
-
Route.__onInit = route => {
|
|
2363
|
-
Object.assign(route, {
|
|
2364
|
-
useMatch: (opts = {}) => {
|
|
2365
|
-
return useMatch({
|
|
2366
|
-
...opts,
|
|
2367
|
-
from: route.id
|
|
2368
|
-
});
|
|
2369
|
-
},
|
|
2370
|
-
useLoader: (opts = {}) => {
|
|
2371
|
-
return useLoader({
|
|
2372
|
-
...opts,
|
|
2373
|
-
from: route.id
|
|
2374
|
-
});
|
|
2375
|
-
},
|
|
2376
|
-
useRouteContext: (opts = {}) => {
|
|
2377
|
-
return useMatch({
|
|
2378
|
-
...opts,
|
|
2379
|
-
from: route.id,
|
|
2380
|
-
select: d => opts?.select ? opts.select(d.context) : d.context
|
|
2381
|
-
});
|
|
2382
|
-
},
|
|
2383
|
-
useSearch: (opts = {}) => {
|
|
2384
|
-
return useSearch({
|
|
2385
|
-
...opts,
|
|
2386
|
-
from: route.id
|
|
2387
|
-
});
|
|
2388
|
-
},
|
|
2389
|
-
useParams: (opts = {}) => {
|
|
2390
|
-
return useParams({
|
|
2391
|
-
...opts,
|
|
2392
|
-
from: route.id
|
|
2393
|
-
});
|
|
2394
|
-
}
|
|
2395
|
-
});
|
|
2396
|
-
};
|
|
1907
|
+
const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
|
|
2397
1908
|
|
|
2398
1909
|
//
|
|
2399
1910
|
|
|
@@ -2418,7 +1929,10 @@
|
|
|
2418
1929
|
//
|
|
2419
1930
|
|
|
2420
1931
|
function useLinkProps(options) {
|
|
2421
|
-
const
|
|
1932
|
+
const {
|
|
1933
|
+
buildLink,
|
|
1934
|
+
state: routerState
|
|
1935
|
+
} = useRouter();
|
|
2422
1936
|
const match = useMatch({
|
|
2423
1937
|
strict: false
|
|
2424
1938
|
});
|
|
@@ -2452,7 +1966,7 @@
|
|
|
2452
1966
|
onTouchStart,
|
|
2453
1967
|
...rest
|
|
2454
1968
|
} = options;
|
|
2455
|
-
const linkInfo =
|
|
1969
|
+
const linkInfo = buildLink(routerState, {
|
|
2456
1970
|
from: options.to ? match.pathname : undefined,
|
|
2457
1971
|
...options
|
|
2458
1972
|
});
|
|
@@ -2528,92 +2042,48 @@
|
|
|
2528
2042
|
}));
|
|
2529
2043
|
});
|
|
2530
2044
|
function Navigate(props) {
|
|
2531
|
-
const
|
|
2045
|
+
const {
|
|
2046
|
+
navigate
|
|
2047
|
+
} = useRouter();
|
|
2532
2048
|
const match = useMatch({
|
|
2533
2049
|
strict: false
|
|
2534
2050
|
});
|
|
2535
|
-
useLayoutEffect
|
|
2536
|
-
|
|
2051
|
+
useLayoutEffect(() => {
|
|
2052
|
+
navigate({
|
|
2537
2053
|
from: props.to ? match.pathname : undefined,
|
|
2538
2054
|
...props
|
|
2539
2055
|
});
|
|
2540
2056
|
}, []);
|
|
2541
2057
|
return null;
|
|
2542
2058
|
}
|
|
2543
|
-
const
|
|
2544
|
-
const routerContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
2545
|
-
function useRouterState(opts) {
|
|
2546
|
-
const router = useRouter();
|
|
2547
|
-
return useStore(router.__store, opts?.select);
|
|
2548
|
-
}
|
|
2549
|
-
function RouterProvider({
|
|
2550
|
-
router,
|
|
2551
|
-
...rest
|
|
2552
|
-
}) {
|
|
2553
|
-
router.update(rest);
|
|
2554
|
-
React__namespace.useEffect(() => {
|
|
2555
|
-
let unsub;
|
|
2556
|
-
React__namespace.startTransition(() => {
|
|
2557
|
-
unsub = router.mount();
|
|
2558
|
-
});
|
|
2559
|
-
return unsub;
|
|
2560
|
-
}, [router]);
|
|
2561
|
-
const Wrap = router.options.Wrap || React__namespace.Fragment;
|
|
2562
|
-
return /*#__PURE__*/React__namespace.createElement(Wrap, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
|
|
2563
|
-
value: router
|
|
2564
|
-
}, /*#__PURE__*/React__namespace.createElement(Matches, null)));
|
|
2565
|
-
}
|
|
2566
|
-
function Matches() {
|
|
2567
|
-
const router = useRouter();
|
|
2568
|
-
const matchIds = useRouterState({
|
|
2569
|
-
select: state => {
|
|
2570
|
-
return state.renderedMatchIds;
|
|
2571
|
-
}
|
|
2572
|
-
});
|
|
2573
|
-
const locationKey = useRouterState({
|
|
2574
|
-
select: d => d.resolvedLocation.state?.key
|
|
2575
|
-
});
|
|
2576
|
-
const route = router.getRoute(rootRouteId);
|
|
2577
|
-
const errorComponent = React__namespace.useCallback(props => {
|
|
2578
|
-
return /*#__PURE__*/React__namespace.createElement(ErrorComponent, {
|
|
2579
|
-
...props,
|
|
2580
|
-
useMatch: route.useMatch,
|
|
2581
|
-
useRouteContext: route.useRouteContext,
|
|
2582
|
-
useSearch: route.useSearch,
|
|
2583
|
-
useParams: route.useParams
|
|
2584
|
-
});
|
|
2585
|
-
}, [route]);
|
|
2586
|
-
return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
|
|
2587
|
-
value: [undefined, ...matchIds]
|
|
2588
|
-
}, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
2589
|
-
resetKey: locationKey,
|
|
2590
|
-
errorComponent: errorComponent,
|
|
2591
|
-
onCatch: () => {
|
|
2592
|
-
warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
|
|
2593
|
-
}
|
|
2594
|
-
}, /*#__PURE__*/React__namespace.createElement(Outlet, null)));
|
|
2595
|
-
}
|
|
2059
|
+
const matchesContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
2596
2060
|
function useRouter() {
|
|
2597
2061
|
const value = React__namespace.useContext(routerContext);
|
|
2598
|
-
warning(value, 'useRouter must be used inside a <
|
|
2062
|
+
warning(value, 'useRouter must be used inside a <RouterProvider> component!');
|
|
2599
2063
|
return value;
|
|
2600
2064
|
}
|
|
2065
|
+
function useRouterState(opts) {
|
|
2066
|
+
const {
|
|
2067
|
+
state
|
|
2068
|
+
} = useRouter();
|
|
2069
|
+
// return useStore(router.__store, opts?.select as any)
|
|
2070
|
+
return opts?.select ? opts.select(state) : state;
|
|
2071
|
+
}
|
|
2601
2072
|
function useMatches(opts) {
|
|
2602
|
-
const
|
|
2073
|
+
const contextMatches = React__namespace.useContext(matchesContext);
|
|
2603
2074
|
return useRouterState({
|
|
2604
2075
|
select: state => {
|
|
2605
|
-
const matches = state.
|
|
2076
|
+
const matches = state.matches.slice(state.matches.findIndex(d => d.id === contextMatches[0]?.id));
|
|
2606
2077
|
return opts?.select ? opts.select(matches) : matches;
|
|
2607
2078
|
}
|
|
2608
2079
|
});
|
|
2609
2080
|
}
|
|
2610
2081
|
function useMatch(opts) {
|
|
2611
|
-
const
|
|
2612
|
-
const
|
|
2613
|
-
const nearestMatchRouteId = router.getRouteMatch(nearestMatchId)?.routeId;
|
|
2082
|
+
const nearestMatch = React__namespace.useContext(matchesContext)[0];
|
|
2083
|
+
const nearestMatchRouteId = nearestMatch?.routeId;
|
|
2614
2084
|
const matchRouteId = useRouterState({
|
|
2615
2085
|
select: state => {
|
|
2616
|
-
const match = opts?.from ? state.
|
|
2086
|
+
const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
|
|
2617
2087
|
return match.routeId;
|
|
2618
2088
|
}
|
|
2619
2089
|
});
|
|
@@ -2622,29 +2092,17 @@
|
|
|
2622
2092
|
}
|
|
2623
2093
|
const matchSelection = useRouterState({
|
|
2624
2094
|
select: state => {
|
|
2625
|
-
const match = opts?.from ? state.
|
|
2095
|
+
const match = opts?.from ? state.matches.find(d => d.routeId === opts?.from) : state.matches.find(d => d.id === nearestMatch.id);
|
|
2626
2096
|
invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
|
|
2627
2097
|
return opts?.select ? opts.select(match) : match;
|
|
2628
2098
|
}
|
|
2629
2099
|
});
|
|
2630
2100
|
return matchSelection;
|
|
2631
2101
|
}
|
|
2632
|
-
function
|
|
2633
|
-
return useMatch({
|
|
2634
|
-
...opts,
|
|
2635
|
-
select: match => opts?.select ? opts?.select(match.loaderData) : match.loaderData
|
|
2636
|
-
});
|
|
2637
|
-
}
|
|
2638
|
-
function useRouterContext(opts) {
|
|
2639
|
-
return useMatch({
|
|
2640
|
-
...opts,
|
|
2641
|
-
select: match => opts?.select ? opts.select(match.context) : match.context
|
|
2642
|
-
});
|
|
2643
|
-
}
|
|
2644
|
-
function useRouteContext(opts) {
|
|
2102
|
+
function useRouteMeta(opts) {
|
|
2645
2103
|
return useMatch({
|
|
2646
2104
|
...opts,
|
|
2647
|
-
select: match => opts?.select ? opts.select(match.
|
|
2105
|
+
select: match => opts?.select ? opts.select(match.meta) : match.meta
|
|
2648
2106
|
});
|
|
2649
2107
|
}
|
|
2650
2108
|
function useSearch(opts) {
|
|
@@ -2658,18 +2116,20 @@
|
|
|
2658
2116
|
function useParams(opts) {
|
|
2659
2117
|
return useRouterState({
|
|
2660
2118
|
select: state => {
|
|
2661
|
-
const params = last(state.
|
|
2119
|
+
const params = last(state.matches)?.params;
|
|
2662
2120
|
return opts?.select ? opts.select(params) : params;
|
|
2663
2121
|
}
|
|
2664
2122
|
});
|
|
2665
2123
|
}
|
|
2666
2124
|
function useNavigate(defaultOpts) {
|
|
2667
|
-
const
|
|
2125
|
+
const {
|
|
2126
|
+
navigate
|
|
2127
|
+
} = useRouter();
|
|
2668
2128
|
const match = useMatch({
|
|
2669
2129
|
strict: false
|
|
2670
2130
|
});
|
|
2671
2131
|
return React__namespace.useCallback(opts => {
|
|
2672
|
-
return
|
|
2132
|
+
return navigate({
|
|
2673
2133
|
from: opts?.to ? match.pathname : undefined,
|
|
2674
2134
|
...defaultOpts,
|
|
2675
2135
|
...opts
|
|
@@ -2677,19 +2137,62 @@
|
|
|
2677
2137
|
}, []);
|
|
2678
2138
|
}
|
|
2679
2139
|
function useMatchRoute() {
|
|
2680
|
-
const
|
|
2140
|
+
const {
|
|
2141
|
+
state,
|
|
2142
|
+
matchRoute
|
|
2143
|
+
} = useRouter();
|
|
2681
2144
|
return React__namespace.useCallback(opts => {
|
|
2682
2145
|
const {
|
|
2683
2146
|
pending,
|
|
2684
2147
|
caseSensitive,
|
|
2685
2148
|
...rest
|
|
2686
2149
|
} = opts;
|
|
2687
|
-
return
|
|
2150
|
+
return matchRoute(state, rest, {
|
|
2688
2151
|
pending,
|
|
2689
2152
|
caseSensitive
|
|
2690
2153
|
});
|
|
2691
2154
|
}, []);
|
|
2692
2155
|
}
|
|
2156
|
+
function Matches() {
|
|
2157
|
+
const {
|
|
2158
|
+
routesById,
|
|
2159
|
+
state
|
|
2160
|
+
} = useRouter();
|
|
2161
|
+
|
|
2162
|
+
// const matches = useRouterState({
|
|
2163
|
+
// select: (state) => {
|
|
2164
|
+
// return state.matches
|
|
2165
|
+
// },
|
|
2166
|
+
// })
|
|
2167
|
+
|
|
2168
|
+
const {
|
|
2169
|
+
matches
|
|
2170
|
+
} = state;
|
|
2171
|
+
const locationKey = useRouterState({
|
|
2172
|
+
select: d => d.resolvedLocation.state?.key
|
|
2173
|
+
});
|
|
2174
|
+
const route = routesById[rootRouteId];
|
|
2175
|
+
const errorComponent = React__namespace.useCallback(props => {
|
|
2176
|
+
return /*#__PURE__*/React__namespace.createElement(ErrorComponent, {
|
|
2177
|
+
...props,
|
|
2178
|
+
useMatch: route.useMatch,
|
|
2179
|
+
useRouteMeta: route.useRouteMeta,
|
|
2180
|
+
useSearch: route.useSearch,
|
|
2181
|
+
useParams: route.useParams
|
|
2182
|
+
});
|
|
2183
|
+
}, [route]);
|
|
2184
|
+
return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
|
|
2185
|
+
value: matches
|
|
2186
|
+
}, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
2187
|
+
resetKey: locationKey,
|
|
2188
|
+
errorComponent: errorComponent,
|
|
2189
|
+
onCatch: () => {
|
|
2190
|
+
warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
|
|
2191
|
+
}
|
|
2192
|
+
}, matches.length ? /*#__PURE__*/React__namespace.createElement(Match, {
|
|
2193
|
+
matches: matches
|
|
2194
|
+
}) : null));
|
|
2195
|
+
}
|
|
2693
2196
|
function MatchRoute(props) {
|
|
2694
2197
|
const matchRoute = useMatchRoute();
|
|
2695
2198
|
const params = matchRoute(props);
|
|
@@ -2699,44 +2202,47 @@
|
|
|
2699
2202
|
return !!params ? props.children : null;
|
|
2700
2203
|
}
|
|
2701
2204
|
function Outlet() {
|
|
2702
|
-
const
|
|
2703
|
-
if (!
|
|
2205
|
+
const matches = React__namespace.useContext(matchesContext).slice(1);
|
|
2206
|
+
if (!matches[0]) {
|
|
2704
2207
|
return null;
|
|
2705
2208
|
}
|
|
2706
2209
|
return /*#__PURE__*/React__namespace.createElement(Match, {
|
|
2707
|
-
|
|
2210
|
+
matches: matches
|
|
2708
2211
|
});
|
|
2709
2212
|
}
|
|
2710
2213
|
const defaultPending = () => null;
|
|
2711
2214
|
function Match({
|
|
2712
|
-
|
|
2215
|
+
matches
|
|
2713
2216
|
}) {
|
|
2714
|
-
const
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2217
|
+
const {
|
|
2218
|
+
options,
|
|
2219
|
+
routesById
|
|
2220
|
+
} = useRouter();
|
|
2221
|
+
const match = matches[0];
|
|
2222
|
+
const routeId = match?.routeId;
|
|
2223
|
+
const route = routesById[routeId];
|
|
2718
2224
|
const locationKey = useRouterState({
|
|
2719
2225
|
select: s => s.resolvedLocation.state?.key
|
|
2720
2226
|
});
|
|
2721
|
-
const PendingComponent = route.options.pendingComponent ??
|
|
2722
|
-
const routeErrorComponent = route.options.errorComponent ??
|
|
2227
|
+
const PendingComponent = route.options.pendingComponent ?? options.defaultPendingComponent ?? defaultPending;
|
|
2228
|
+
const routeErrorComponent = route.options.errorComponent ?? options.defaultErrorComponent ?? ErrorComponent;
|
|
2723
2229
|
const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? !route.isRoot ? React__namespace.Suspense : SafeFragment;
|
|
2724
2230
|
const ResolvedCatchBoundary = !!routeErrorComponent ? CatchBoundary : SafeFragment;
|
|
2725
2231
|
const errorComponent = React__namespace.useCallback(props => {
|
|
2726
2232
|
return /*#__PURE__*/React__namespace.createElement(routeErrorComponent, {
|
|
2727
2233
|
...props,
|
|
2728
2234
|
useMatch: route.useMatch,
|
|
2729
|
-
|
|
2235
|
+
useRouteMeta: route.useRouteMeta,
|
|
2730
2236
|
useSearch: route.useSearch,
|
|
2731
2237
|
useParams: route.useParams
|
|
2732
2238
|
});
|
|
2733
2239
|
}, [route]);
|
|
2734
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
2735
|
-
value:
|
|
2240
|
+
return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
|
|
2241
|
+
value: matches
|
|
2736
2242
|
}, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
|
|
2737
2243
|
fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, {
|
|
2738
2244
|
useMatch: route.useMatch,
|
|
2739
|
-
|
|
2245
|
+
useRouteMeta: route.useRouteMeta,
|
|
2740
2246
|
useSearch: route.useSearch,
|
|
2741
2247
|
useParams: route.useParams
|
|
2742
2248
|
})
|
|
@@ -2744,44 +2250,32 @@
|
|
|
2744
2250
|
resetKey: locationKey,
|
|
2745
2251
|
errorComponent: errorComponent,
|
|
2746
2252
|
onCatch: () => {
|
|
2747
|
-
warning(false, `Error in route match: ${
|
|
2253
|
+
warning(false, `Error in route match: ${match.id}`);
|
|
2748
2254
|
}
|
|
2749
2255
|
}, /*#__PURE__*/React__namespace.createElement(MatchInner, {
|
|
2750
|
-
|
|
2751
|
-
PendingComponent: PendingComponent
|
|
2256
|
+
match: match
|
|
2752
2257
|
}))));
|
|
2753
2258
|
}
|
|
2754
2259
|
function MatchInner({
|
|
2755
|
-
|
|
2756
|
-
PendingComponent
|
|
2260
|
+
match
|
|
2757
2261
|
}) {
|
|
2758
|
-
const
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
}
|
|
2764
|
-
});
|
|
2765
|
-
const route = router.getRoute(match.routeId);
|
|
2262
|
+
const {
|
|
2263
|
+
options,
|
|
2264
|
+
routesById
|
|
2265
|
+
} = useRouter();
|
|
2266
|
+
const route = routesById[match.routeId];
|
|
2766
2267
|
if (match.status === 'error') {
|
|
2767
2268
|
throw match.error;
|
|
2768
2269
|
}
|
|
2769
2270
|
if (match.status === 'pending') {
|
|
2770
|
-
|
|
2771
|
-
useLoader: route.useLoader,
|
|
2772
|
-
useMatch: route.useMatch,
|
|
2773
|
-
useRouteContext: route.useRouteContext,
|
|
2774
|
-
useSearch: route.useSearch,
|
|
2775
|
-
useParams: route.useParams
|
|
2776
|
-
});
|
|
2271
|
+
throw match.loadPromise;
|
|
2777
2272
|
}
|
|
2778
2273
|
if (match.status === 'success') {
|
|
2779
|
-
let comp = route.options.component ??
|
|
2274
|
+
let comp = route.options.component ?? options.defaultComponent;
|
|
2780
2275
|
if (comp) {
|
|
2781
2276
|
return /*#__PURE__*/React__namespace.createElement(comp, {
|
|
2782
|
-
useLoader: route.useLoader,
|
|
2783
2277
|
useMatch: route.useMatch,
|
|
2784
|
-
|
|
2278
|
+
useRouteMeta: route.useRouteMeta,
|
|
2785
2279
|
useSearch: route.useSearch,
|
|
2786
2280
|
useParams: route.useParams
|
|
2787
2281
|
});
|
|
@@ -2793,24 +2287,37 @@
|
|
|
2793
2287
|
function SafeFragment(props) {
|
|
2794
2288
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
|
|
2795
2289
|
}
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
function
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2290
|
+
|
|
2291
|
+
// export function useInjectHtml() {
|
|
2292
|
+
// const { } = useRouter()
|
|
2293
|
+
|
|
2294
|
+
// return React.useCallback(
|
|
2295
|
+
// (html: string | (() => Promise<string> | string)) => {
|
|
2296
|
+
// router.injectHtml(html)
|
|
2297
|
+
// },
|
|
2298
|
+
// [],
|
|
2299
|
+
// )
|
|
2300
|
+
// }
|
|
2301
|
+
|
|
2302
|
+
// export function useDehydrate() {
|
|
2303
|
+
// const { } = useRouter()
|
|
2304
|
+
|
|
2305
|
+
// return React.useCallback(function dehydrate<T>(
|
|
2306
|
+
// key: any,
|
|
2307
|
+
// data: T | (() => Promise<T> | T),
|
|
2308
|
+
// ) {
|
|
2309
|
+
// return router.dehydrateData(key, data)
|
|
2310
|
+
// },
|
|
2311
|
+
// [])
|
|
2312
|
+
// }
|
|
2313
|
+
|
|
2314
|
+
// export function useHydrate() {
|
|
2315
|
+
// const { } = useRouter()
|
|
2316
|
+
|
|
2317
|
+
// return function hydrate<T = unknown>(key: any) {
|
|
2318
|
+
// return router.hydrateData(key) as T
|
|
2319
|
+
// }
|
|
2320
|
+
// }
|
|
2814
2321
|
|
|
2815
2322
|
// This is the messiest thing ever... I'm either seriously tired (likely) or
|
|
2816
2323
|
// there has to be a better way to reset error boundaries when the
|
|
@@ -2901,10 +2408,12 @@
|
|
|
2901
2408
|
}, error.message ? /*#__PURE__*/React__namespace.createElement("code", null, error.message) : null)) : null);
|
|
2902
2409
|
}
|
|
2903
2410
|
function useBlocker(message, condition = true) {
|
|
2904
|
-
const
|
|
2411
|
+
const {
|
|
2412
|
+
history
|
|
2413
|
+
} = useRouter();
|
|
2905
2414
|
React__namespace.useEffect(() => {
|
|
2906
2415
|
if (!condition) return;
|
|
2907
|
-
let unblock =
|
|
2416
|
+
let unblock = history.block((retry, cancel) => {
|
|
2908
2417
|
if (window.confirm(message)) {
|
|
2909
2418
|
unblock();
|
|
2910
2419
|
retry();
|
|
@@ -2940,47 +2449,125 @@
|
|
|
2940
2449
|
return true;
|
|
2941
2450
|
}
|
|
2942
2451
|
|
|
2943
|
-
const
|
|
2944
|
-
function useScrollRestoration(options) {
|
|
2945
|
-
const router = useRouter();
|
|
2946
|
-
useLayoutEffect(() => {
|
|
2947
|
-
return watchScrollPositions(router, options);
|
|
2948
|
-
}, []);
|
|
2949
|
-
useLayoutEffect(() => {
|
|
2950
|
-
restoreScrollPositions(router, options);
|
|
2951
|
-
});
|
|
2952
|
-
}
|
|
2953
|
-
function ScrollRestoration(props) {
|
|
2954
|
-
useScrollRestoration(props);
|
|
2955
|
-
return null;
|
|
2956
|
-
}
|
|
2452
|
+
const rootRouteId = '__root__';
|
|
2957
2453
|
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2454
|
+
// export type MetaOptions = keyof PickRequired<RouteMeta> extends never
|
|
2455
|
+
// ? {
|
|
2456
|
+
// meta?: RouteMeta
|
|
2457
|
+
// }
|
|
2458
|
+
// : {
|
|
2459
|
+
// meta: RouteMeta
|
|
2460
|
+
// }
|
|
2461
|
+
// The parse type here allows a zod schema to be passed directly to the validator
|
|
2462
|
+
class Route {
|
|
2463
|
+
// Set up in this.init()
|
|
2464
|
+
|
|
2465
|
+
// customId!: TCustomId
|
|
2466
|
+
|
|
2467
|
+
// Optional
|
|
2468
|
+
|
|
2469
|
+
constructor(options) {
|
|
2470
|
+
this.options = options || {};
|
|
2471
|
+
this.isRoot = !options?.getParentRoute;
|
|
2472
|
+
Route.__onInit(this);
|
|
2971
2473
|
}
|
|
2972
|
-
|
|
2973
|
-
|
|
2474
|
+
init = opts => {
|
|
2475
|
+
this.originalIndex = opts.originalIndex;
|
|
2476
|
+
const options = this.options;
|
|
2477
|
+
const isRoot = !options?.path && !options?.id;
|
|
2478
|
+
this.parentRoute = this.options?.getParentRoute?.();
|
|
2479
|
+
if (isRoot) {
|
|
2480
|
+
this.path = rootRouteId;
|
|
2481
|
+
} else {
|
|
2482
|
+
invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
|
|
2483
|
+
}
|
|
2484
|
+
let path = isRoot ? rootRouteId : options.path;
|
|
2485
|
+
|
|
2486
|
+
// If the path is anything other than an index path, trim it up
|
|
2487
|
+
if (path && path !== '/') {
|
|
2488
|
+
path = trimPath(path);
|
|
2489
|
+
}
|
|
2490
|
+
const customId = options?.id || path;
|
|
2491
|
+
|
|
2492
|
+
// Strip the parentId prefix from the first level of children
|
|
2493
|
+
let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
|
|
2494
|
+
if (path === rootRouteId) {
|
|
2495
|
+
path = '/';
|
|
2496
|
+
}
|
|
2497
|
+
if (id !== rootRouteId) {
|
|
2498
|
+
id = joinPaths(['/', id]);
|
|
2499
|
+
}
|
|
2500
|
+
const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
|
|
2501
|
+
this.path = path;
|
|
2502
|
+
this.id = id;
|
|
2503
|
+
// this.customId = customId as TCustomId
|
|
2504
|
+
this.fullPath = fullPath;
|
|
2505
|
+
this.to = fullPath;
|
|
2506
|
+
};
|
|
2507
|
+
addChildren = children => {
|
|
2508
|
+
this.children = children;
|
|
2509
|
+
return this;
|
|
2510
|
+
};
|
|
2511
|
+
update = options => {
|
|
2512
|
+
Object.assign(this.options, options);
|
|
2513
|
+
return this;
|
|
2514
|
+
};
|
|
2515
|
+
static __onInit = route => {
|
|
2516
|
+
// This is a dummy static method that should get
|
|
2517
|
+
// replaced by a framework specific implementation if necessary
|
|
2518
|
+
};
|
|
2519
|
+
useMatch = opts => {
|
|
2520
|
+
return useMatch({
|
|
2521
|
+
...opts,
|
|
2522
|
+
from: this.id
|
|
2523
|
+
});
|
|
2524
|
+
};
|
|
2525
|
+
useRouteMeta = opts => {
|
|
2526
|
+
return useMatch({
|
|
2527
|
+
...opts,
|
|
2528
|
+
from: this.id,
|
|
2529
|
+
select: d => opts?.select ? opts.select(d.meta) : d.meta
|
|
2530
|
+
});
|
|
2531
|
+
};
|
|
2532
|
+
useSearch = opts => {
|
|
2533
|
+
return useSearch({
|
|
2534
|
+
...opts,
|
|
2535
|
+
from: this.id
|
|
2536
|
+
});
|
|
2537
|
+
};
|
|
2538
|
+
useParams = opts => {
|
|
2539
|
+
return useParams({
|
|
2540
|
+
...opts,
|
|
2541
|
+
from: this.id
|
|
2542
|
+
});
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
class RouterMeta {
|
|
2546
|
+
constructor() {}
|
|
2547
|
+
createRootRoute = options => {
|
|
2548
|
+
return new RootRoute(options);
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
class RootRoute extends Route {
|
|
2552
|
+
constructor(options) {
|
|
2553
|
+
super(options);
|
|
2974
2554
|
}
|
|
2975
|
-
router.dehydrateData(key, state);
|
|
2976
|
-
return [state.data];
|
|
2977
2555
|
}
|
|
2978
|
-
function
|
|
2979
|
-
|
|
2980
|
-
|
|
2556
|
+
function createRouteMask(opts) {
|
|
2557
|
+
return opts;
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
class FileRoute {
|
|
2561
|
+
constructor(path) {
|
|
2562
|
+
this.path = path;
|
|
2563
|
+
}
|
|
2564
|
+
createRoute = options => {
|
|
2565
|
+
const route = new Route(options);
|
|
2566
|
+
route.isRoot = false;
|
|
2567
|
+
return route;
|
|
2568
|
+
};
|
|
2981
2569
|
}
|
|
2982
2570
|
|
|
2983
|
-
exports.Await = Await;
|
|
2984
2571
|
exports.Block = Block;
|
|
2985
2572
|
exports.CatchBoundary = CatchBoundary;
|
|
2986
2573
|
exports.CatchBoundaryImpl = CatchBoundaryImpl;
|
|
@@ -2988,15 +2575,15 @@
|
|
|
2988
2575
|
exports.FileRoute = FileRoute;
|
|
2989
2576
|
exports.Link = Link;
|
|
2990
2577
|
exports.MatchRoute = MatchRoute;
|
|
2578
|
+
exports.Matches = Matches;
|
|
2991
2579
|
exports.Navigate = Navigate;
|
|
2992
2580
|
exports.Outlet = Outlet;
|
|
2993
2581
|
exports.PathParamError = PathParamError;
|
|
2994
2582
|
exports.RootRoute = RootRoute;
|
|
2995
2583
|
exports.Route = Route;
|
|
2996
2584
|
exports.Router = Router;
|
|
2997
|
-
exports.
|
|
2585
|
+
exports.RouterMeta = RouterMeta;
|
|
2998
2586
|
exports.RouterProvider = RouterProvider;
|
|
2999
|
-
exports.ScrollRestoration = ScrollRestoration;
|
|
3000
2587
|
exports.SearchParamError = SearchParamError;
|
|
3001
2588
|
exports.cleanPath = cleanPath;
|
|
3002
2589
|
exports.componentTypes = componentTypes;
|
|
@@ -3007,22 +2594,22 @@
|
|
|
3007
2594
|
exports.decode = decode;
|
|
3008
2595
|
exports.defaultParseSearch = defaultParseSearch;
|
|
3009
2596
|
exports.defaultStringifySearch = defaultStringifySearch;
|
|
3010
|
-
exports.defer = defer;
|
|
3011
2597
|
exports.encode = encode;
|
|
3012
2598
|
exports.functionalUpdate = functionalUpdate;
|
|
2599
|
+
exports.getInitialRouterState = getInitialRouterState;
|
|
2600
|
+
exports.getRouteMatch = getRouteMatch;
|
|
3013
2601
|
exports.interpolatePath = interpolatePath;
|
|
3014
2602
|
exports.invariant = invariant;
|
|
3015
|
-
exports.isDehydratedDeferred = isDehydratedDeferred;
|
|
3016
|
-
exports.isMatchInvalid = isMatchInvalid;
|
|
3017
2603
|
exports.isPlainObject = isPlainObject;
|
|
3018
2604
|
exports.isRedirect = isRedirect;
|
|
2605
|
+
exports.isServer = isServer;
|
|
3019
2606
|
exports.joinPaths = joinPaths;
|
|
3020
2607
|
exports.last = last;
|
|
3021
2608
|
exports.lazyFn = lazyFn;
|
|
3022
2609
|
exports.lazyRouteComponent = lazyRouteComponent;
|
|
3023
2610
|
exports.matchByPath = matchByPath;
|
|
3024
|
-
exports.matchIdsContext = matchIdsContext;
|
|
3025
2611
|
exports.matchPathname = matchPathname;
|
|
2612
|
+
exports.matchesContext = matchesContext;
|
|
3026
2613
|
exports.parsePathname = parsePathname;
|
|
3027
2614
|
exports.parseSearchWith = parseSearchWith;
|
|
3028
2615
|
exports.partialDeepEqual = partialDeepEqual;
|
|
@@ -3030,7 +2617,6 @@
|
|
|
3030
2617
|
exports.redirect = redirect;
|
|
3031
2618
|
exports.replaceEqualDeep = replaceEqualDeep;
|
|
3032
2619
|
exports.resolvePath = resolvePath;
|
|
3033
|
-
exports.restoreScrollPositions = restoreScrollPositions;
|
|
3034
2620
|
exports.rootRouteId = rootRouteId;
|
|
3035
2621
|
exports.routerContext = routerContext;
|
|
3036
2622
|
exports.shallow = shallow;
|
|
@@ -3038,27 +2624,19 @@
|
|
|
3038
2624
|
exports.trimPath = trimPath;
|
|
3039
2625
|
exports.trimPathLeft = trimPathLeft;
|
|
3040
2626
|
exports.trimPathRight = trimPathRight;
|
|
3041
|
-
exports.useAwaited = useAwaited;
|
|
3042
2627
|
exports.useBlocker = useBlocker;
|
|
3043
|
-
exports.useDehydrate = useDehydrate;
|
|
3044
|
-
exports.useHydrate = useHydrate;
|
|
3045
|
-
exports.useInjectHtml = useInjectHtml;
|
|
3046
2628
|
exports.useLinkProps = useLinkProps;
|
|
3047
|
-
exports.useLoader = useLoader;
|
|
3048
2629
|
exports.useMatch = useMatch;
|
|
3049
2630
|
exports.useMatchRoute = useMatchRoute;
|
|
3050
2631
|
exports.useMatches = useMatches;
|
|
3051
2632
|
exports.useNavigate = useNavigate;
|
|
3052
2633
|
exports.useParams = useParams;
|
|
3053
|
-
exports.
|
|
2634
|
+
exports.useRouteMeta = useRouteMeta;
|
|
3054
2635
|
exports.useRouter = useRouter;
|
|
3055
|
-
exports.useRouterContext = useRouterContext;
|
|
3056
2636
|
exports.useRouterState = useRouterState;
|
|
3057
|
-
exports.useScrollRestoration = useScrollRestoration;
|
|
3058
2637
|
exports.useSearch = useSearch;
|
|
3059
|
-
exports.
|
|
2638
|
+
exports.useStableCallback = useStableCallback;
|
|
3060
2639
|
exports.warning = warning;
|
|
3061
|
-
exports.watchScrollPositions = watchScrollPositions;
|
|
3062
2640
|
|
|
3063
2641
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
3064
2642
|
|