@tanstack/react-router 0.0.1-beta.83 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/build/cjs/CatchBoundary.js +128 -0
- package/build/cjs/CatchBoundary.js.map +1 -0
- package/build/cjs/Matches.js +233 -0
- package/build/cjs/Matches.js.map +1 -0
- package/build/cjs/RouterProvider.js +170 -0
- package/build/cjs/RouterProvider.js.map +1 -0
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +2 -4
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
- package/build/cjs/_virtual/with-selector.development.js +16 -0
- package/build/cjs/_virtual/with-selector.development.js.map +1 -0
- package/build/cjs/_virtual/with-selector.js +16 -0
- package/build/cjs/_virtual/with-selector.js.map +1 -0
- package/build/cjs/_virtual/with-selector.production.min.js +16 -0
- package/build/cjs/_virtual/with-selector.production.min.js.map +1 -0
- package/build/cjs/awaited.js +43 -0
- package/build/cjs/awaited.js.map +1 -0
- package/build/cjs/build/esm/index.js +79 -0
- package/build/cjs/build/esm/index.js.map +1 -0
- package/build/cjs/defer.js +37 -0
- package/build/cjs/defer.js.map +1 -0
- package/build/cjs/fileRoute.js +27 -0
- package/build/cjs/fileRoute.js.map +1 -0
- package/build/cjs/index.js +113 -451
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/lazyRouteComponent.js +54 -0
- package/build/cjs/lazyRouteComponent.js.map +1 -0
- package/build/cjs/link.js +223 -0
- package/build/cjs/link.js.map +1 -0
- package/build/cjs/node_modules/.pnpm/@tanstack_react-store@0.2.1_react-dom@18.2.0_react@18.2.0/node_modules/@tanstack/react-store/build/modern/index.js +47 -0
- package/build/cjs/node_modules/.pnpm/@tanstack_react-store@0.2.1_react-dom@18.2.0_react@18.2.0/node_modules/@tanstack/react-store/build/modern/index.js.map +1 -0
- package/build/cjs/node_modules/.pnpm/@tanstack_store@0.1.3/node_modules/@tanstack/store/build/modern/index.js +70 -0
- package/build/cjs/node_modules/.pnpm/@tanstack_store@0.1.3/node_modules/@tanstack/store/build/modern/index.js.map +1 -0
- package/build/cjs/node_modules/.pnpm/use-sync-external-store@1.2.0_react@18.2.0/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js +188 -0
- package/build/cjs/node_modules/.pnpm/use-sync-external-store@1.2.0_react@18.2.0/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js.map +1 -0
- package/build/cjs/node_modules/.pnpm/use-sync-external-store@1.2.0_react@18.2.0/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.production.min.js +39 -0
- package/build/cjs/node_modules/.pnpm/use-sync-external-store@1.2.0_react@18.2.0/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.production.min.js.map +1 -0
- package/build/cjs/node_modules/.pnpm/use-sync-external-store@1.2.0_react@18.2.0/node_modules/use-sync-external-store/shim/with-selector.js +26 -0
- package/build/cjs/node_modules/.pnpm/use-sync-external-store@1.2.0_react@18.2.0/node_modules/use-sync-external-store/shim/with-selector.js.map +1 -0
- package/build/cjs/packages/react-router/src/CatchBoundary.js +123 -0
- package/build/cjs/packages/react-router/src/CatchBoundary.js.map +1 -0
- package/build/cjs/packages/react-router/src/Matches.js +235 -0
- package/build/cjs/packages/react-router/src/Matches.js.map +1 -0
- package/build/cjs/packages/react-router/src/RouterProvider.js +144 -0
- package/build/cjs/packages/react-router/src/RouterProvider.js.map +1 -0
- package/build/cjs/packages/react-router/src/awaited.js +43 -0
- package/build/cjs/packages/react-router/src/awaited.js.map +1 -0
- package/build/cjs/packages/react-router/src/defer.js +37 -0
- package/build/cjs/packages/react-router/src/defer.js.map +1 -0
- package/build/cjs/packages/react-router/src/fileRoute.js +27 -0
- package/build/cjs/packages/react-router/src/fileRoute.js.map +1 -0
- package/build/cjs/packages/react-router/src/index.js +61 -0
- package/build/cjs/packages/react-router/src/index.js.map +1 -0
- package/build/cjs/packages/react-router/src/lazyRouteComponent.js +54 -0
- package/build/cjs/packages/react-router/src/lazyRouteComponent.js.map +1 -0
- package/build/cjs/packages/react-router/src/link.js +148 -0
- package/build/cjs/packages/react-router/src/link.js.map +1 -0
- package/build/cjs/packages/react-router/src/path.js +209 -0
- package/build/cjs/packages/react-router/src/path.js.map +1 -0
- package/build/cjs/packages/react-router/src/qss.js +63 -0
- package/build/cjs/packages/react-router/src/qss.js.map +1 -0
- package/build/cjs/packages/react-router/src/react.js +634 -0
- package/build/cjs/packages/react-router/src/react.js.map +1 -0
- package/build/cjs/packages/react-router/src/redirects.js +25 -0
- package/build/cjs/packages/react-router/src/redirects.js.map +1 -0
- package/build/cjs/packages/react-router/src/route.js +134 -0
- package/build/cjs/packages/react-router/src/route.js.map +1 -0
- package/build/cjs/packages/react-router/src/router.js +1111 -0
- package/build/cjs/packages/react-router/src/router.js.map +1 -0
- package/build/cjs/packages/react-router/src/scroll-restoration.js +53 -0
- package/build/cjs/packages/react-router/src/scroll-restoration.js.map +1 -0
- package/build/cjs/packages/react-router/src/searchParams.js +81 -0
- package/build/cjs/packages/react-router/src/searchParams.js.map +1 -0
- package/build/cjs/packages/react-router/src/useBlocker.js +61 -0
- package/build/cjs/packages/react-router/src/useBlocker.js.map +1 -0
- package/build/cjs/packages/react-router/src/useNavigate.js +75 -0
- package/build/cjs/packages/react-router/src/useNavigate.js.map +1 -0
- package/build/cjs/packages/react-router/src/useParams.js +26 -0
- package/build/cjs/packages/react-router/src/useParams.js.map +1 -0
- package/build/cjs/packages/react-router/src/useSearch.js +25 -0
- package/build/cjs/packages/react-router/src/useSearch.js.map +1 -0
- package/build/cjs/packages/react-router/src/utils.js +239 -0
- package/build/cjs/packages/react-router/src/utils.js.map +1 -0
- package/build/cjs/path.js +214 -0
- package/build/cjs/path.js.map +1 -0
- package/build/cjs/qss.js +63 -0
- package/build/cjs/qss.js.map +1 -0
- package/build/cjs/react/CatchBoundary.js +123 -0
- package/build/cjs/react/CatchBoundary.js.map +1 -0
- package/build/cjs/react/awaited.js +43 -0
- package/build/cjs/react/awaited.js.map +1 -0
- package/build/cjs/react/defer.js +37 -0
- package/build/cjs/react/defer.js.map +1 -0
- package/build/cjs/react.js +650 -0
- package/build/cjs/react.js.map +1 -0
- package/build/cjs/redirects.js +28 -0
- package/build/cjs/redirects.js.map +1 -0
- package/build/cjs/route.js +191 -0
- package/build/cjs/route.js.map +1 -0
- package/build/cjs/router.js +1085 -0
- package/build/cjs/router.js.map +1 -0
- package/build/cjs/routerConfig.js +209 -0
- package/build/cjs/routerConfig.js.map +1 -0
- package/build/cjs/scroll-restoration.js +202 -0
- package/build/cjs/scroll-restoration.js.map +1 -0
- package/build/cjs/searchParams.js +81 -0
- package/build/cjs/searchParams.js.map +1 -0
- package/build/cjs/src/CatchBoundary.js +126 -0
- package/build/cjs/src/CatchBoundary.js.map +1 -0
- package/build/cjs/src/Matches.js +235 -0
- package/build/cjs/src/Matches.js.map +1 -0
- package/build/cjs/src/RouterProvider.js +1051 -0
- package/build/cjs/src/RouterProvider.js.map +1 -0
- package/build/cjs/src/awaited.js +45 -0
- package/build/cjs/src/awaited.js.map +1 -0
- package/build/cjs/src/defer.js +39 -0
- package/build/cjs/src/defer.js.map +1 -0
- package/build/cjs/src/fileRoute.js +29 -0
- package/build/cjs/src/fileRoute.js.map +1 -0
- package/build/cjs/src/index.js +134 -0
- package/build/cjs/src/index.js.map +1 -0
- package/build/cjs/src/lazyRouteComponent.js +57 -0
- package/build/cjs/src/lazyRouteComponent.js.map +1 -0
- package/build/cjs/src/link.js +151 -0
- package/build/cjs/src/link.js.map +1 -0
- package/build/cjs/src/path.js +211 -0
- package/build/cjs/src/path.js.map +1 -0
- package/build/cjs/src/qss.js +65 -0
- package/build/cjs/src/qss.js.map +1 -0
- package/build/cjs/src/redirects.js +27 -0
- package/build/cjs/src/redirects.js.map +1 -0
- package/build/cjs/src/route.js +139 -0
- package/build/cjs/src/route.js.map +1 -0
- package/build/cjs/src/router.js +203 -0
- package/build/cjs/src/router.js.map +1 -0
- package/build/cjs/src/scroll-restoration.js +186 -0
- package/build/cjs/src/scroll-restoration.js.map +1 -0
- package/build/cjs/src/searchParams.js +83 -0
- package/build/cjs/src/searchParams.js.map +1 -0
- package/build/cjs/src/useBlocker.js +64 -0
- package/build/cjs/src/useBlocker.js.map +1 -0
- package/build/cjs/src/useNavigate.js +78 -0
- package/build/cjs/src/useNavigate.js.map +1 -0
- package/build/cjs/src/useParams.js +28 -0
- package/build/cjs/src/useParams.js.map +1 -0
- package/build/cjs/src/useSearch.js +27 -0
- package/build/cjs/src/useSearch.js.map +1 -0
- package/build/cjs/src/utils.js +230 -0
- package/build/cjs/src/utils.js.map +1 -0
- package/build/cjs/useBlocker.js +55 -0
- package/build/cjs/useBlocker.js.map +1 -0
- package/build/cjs/useNavigate.js +86 -0
- package/build/cjs/useNavigate.js.map +1 -0
- package/build/cjs/useParams.js +26 -0
- package/build/cjs/useParams.js.map +1 -0
- package/build/cjs/useSearch.js +25 -0
- package/build/cjs/useSearch.js.map +1 -0
- package/build/cjs/useStore.js +99 -0
- package/build/cjs/useStore.js.map +1 -0
- package/build/cjs/utils.js +241 -0
- package/build/cjs/utils.js.map +1 -0
- package/build/esm/index.js +2581 -337
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +3494 -2700
- package/build/stats-react.json +1134 -87
- package/build/types/CatchBoundary.d.ts +36 -0
- package/build/types/Matches.d.ts +64 -0
- package/build/types/RouteMatch.d.ts +23 -0
- package/build/types/RouterProvider.d.ts +35 -0
- package/build/types/awaited.d.ts +9 -0
- package/build/types/defer.d.ts +19 -0
- package/build/types/fileRoute.d.ts +38 -0
- package/build/types/history.d.ts +7 -0
- package/build/types/index.d.ts +911 -88
- package/build/types/injectHtml.d.ts +0 -0
- package/build/types/lazyRouteComponent.d.ts +2 -0
- package/build/types/link.d.ts +93 -0
- package/build/types/location.d.ts +12 -0
- package/build/types/path.d.ts +17 -0
- package/build/types/qss.d.ts +2 -0
- package/build/types/react/CatchBoundary.d.ts +33 -0
- package/build/types/react/awaited.d.ts +9 -0
- package/build/types/react/defer.d.ts +19 -0
- package/build/types/react.d.ts +141 -0
- package/build/types/redirects.d.ts +11 -0
- package/build/types/route.d.ts +283 -0
- package/build/types/routeInfo.d.ts +31 -0
- package/build/types/router.d.ts +186 -0
- package/build/types/scroll-restoration.d.ts +18 -0
- package/build/types/searchParams.d.ts +7 -0
- package/build/types/useBlocker.d.ts +9 -0
- package/build/types/useNavigate.d.ts +19 -0
- package/build/types/useParams.d.ts +7 -0
- package/build/types/useSearch.d.ts +7 -0
- package/build/types/useStore.d.ts +12 -0
- package/build/types/utils.d.ts +69 -0
- package/build/umd/index.development.js +2829 -1796
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +4 -24
- package/build/umd/index.production.js.map +1 -1
- package/package.json +9 -7
- package/src/CatchBoundary.tsx +101 -0
- package/src/Matches.tsx +423 -0
- package/src/RouterProvider.tsx +252 -0
- package/src/awaited.tsx +40 -0
- package/src/defer.ts +55 -0
- package/src/fileRoute.ts +152 -0
- package/src/history.ts +8 -0
- package/src/index.tsx +28 -747
- package/src/lazyRouteComponent.tsx +33 -0
- package/src/link.tsx +603 -0
- package/src/location.ts +13 -0
- package/src/path.ts +261 -0
- package/src/qss.ts +53 -0
- package/src/redirects.ts +39 -0
- package/src/route.ts +882 -0
- package/src/routeInfo.ts +84 -0
- package/src/router.ts +1671 -0
- package/src/scroll-restoration.tsx +230 -0
- package/src/searchParams.ts +79 -0
- package/src/useBlocker.tsx +27 -0
- package/src/useNavigate.tsx +111 -0
- package/src/useParams.tsx +25 -0
- package/src/useSearch.tsx +25 -0
- package/src/utils.ts +360 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router
|
|
2
|
+
* @tanstack/react-router/src/index.tsx
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) TanStack
|
|
5
5
|
*
|
|
@@ -9,13 +9,12 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
(function (global, factory) {
|
|
12
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('use-sync-external-store/shim
|
|
13
|
-
typeof define === 'function' && define.amd ? define(['exports', 'react', 'use-sync-external-store/shim
|
|
14
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React, global.
|
|
15
|
-
})(this, (function (exports, React,
|
|
12
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('use-sync-external-store/shim')) :
|
|
13
|
+
typeof define === 'function' && define.amd ? define(['exports', 'react', 'use-sync-external-store/shim'], factory) :
|
|
14
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React, global.require$$1));
|
|
15
|
+
})(this, (function (exports, React, require$$1) { 'use strict';
|
|
16
16
|
|
|
17
|
-
function
|
|
18
|
-
if (e && e.__esModule) return e;
|
|
17
|
+
function _interopNamespaceDefault(e) {
|
|
19
18
|
var n = Object.create(null);
|
|
20
19
|
if (e) {
|
|
21
20
|
Object.keys(e).forEach(function (k) {
|
|
@@ -28,147 +27,14 @@
|
|
|
28
27
|
}
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
|
-
n
|
|
30
|
+
n.default = e;
|
|
32
31
|
return Object.freeze(n);
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
var React__namespace = /*#__PURE__*/
|
|
36
|
-
|
|
37
|
-
function _extends() {
|
|
38
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
39
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
40
|
-
var source = arguments[i];
|
|
41
|
-
for (var key in source) {
|
|
42
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
43
|
-
target[key] = source[key];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return target;
|
|
48
|
-
};
|
|
49
|
-
return _extends.apply(this, arguments);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
var prefix = 'Invariant failed';
|
|
53
|
-
function invariant(condition, message) {
|
|
54
|
-
if (condition) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
var provided = typeof message === 'function' ? message() : message;
|
|
58
|
-
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
59
|
-
throw new Error(value);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function warning(condition, message) {
|
|
63
|
-
{
|
|
64
|
-
if (condition) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
var text = "Warning: " + message;
|
|
69
|
-
|
|
70
|
-
if (typeof console !== 'undefined') {
|
|
71
|
-
console.warn(text);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
throw Error(text);
|
|
76
|
-
} catch (x) {}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* store
|
|
82
|
-
*
|
|
83
|
-
* Copyright (c) TanStack
|
|
84
|
-
*
|
|
85
|
-
* This source code is licensed under the MIT license found in the
|
|
86
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
87
|
-
*
|
|
88
|
-
* @license MIT
|
|
89
|
-
*/
|
|
90
|
-
class Store {
|
|
91
|
-
listeners = new Set();
|
|
92
|
-
batching = false;
|
|
93
|
-
queue = [];
|
|
94
|
-
constructor(initialState, options) {
|
|
95
|
-
this.state = initialState;
|
|
96
|
-
this.options = options;
|
|
97
|
-
}
|
|
98
|
-
subscribe = listener => {
|
|
99
|
-
this.listeners.add(listener);
|
|
100
|
-
const unsub = this.options?.onSubscribe?.(listener, this);
|
|
101
|
-
return () => {
|
|
102
|
-
this.listeners.delete(listener);
|
|
103
|
-
unsub?.();
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
setState = updater => {
|
|
107
|
-
const previous = this.state;
|
|
108
|
-
this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
|
|
109
|
-
if (this.state === previous) return;
|
|
110
|
-
this.options?.onUpdate?.(this.state, previous);
|
|
111
|
-
this.queue.push(() => {
|
|
112
|
-
this.listeners.forEach(listener => listener(this.state, previous));
|
|
113
|
-
});
|
|
114
|
-
this.#flush();
|
|
115
|
-
};
|
|
116
|
-
#flush = () => {
|
|
117
|
-
if (this.batching) return;
|
|
118
|
-
this.queue.forEach(cb => cb());
|
|
119
|
-
this.queue = [];
|
|
120
|
-
};
|
|
121
|
-
batch = cb => {
|
|
122
|
-
this.batching = true;
|
|
123
|
-
cb();
|
|
124
|
-
this.batching = false;
|
|
125
|
-
this.#flush();
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
function shallow(objA, objB) {
|
|
129
|
-
if (Object.is(objA, objB)) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// if (objA instanceof Map && objB instanceof Map) {
|
|
137
|
-
// if (objA.size !== objB.size) return false
|
|
138
|
-
|
|
139
|
-
// for (const [key, value] of objA) {
|
|
140
|
-
// if (!Object.is(value, objB.get(key))) {
|
|
141
|
-
// return false
|
|
142
|
-
// }
|
|
143
|
-
// }
|
|
144
|
-
// return true
|
|
145
|
-
// }
|
|
146
|
-
|
|
147
|
-
// if (objA instanceof Set && objB instanceof Set) {
|
|
148
|
-
// if (objA.size !== objB.size) return false
|
|
149
|
-
|
|
150
|
-
// for (const value of objA) {
|
|
151
|
-
// if (!objB.has(value)) {
|
|
152
|
-
// return false
|
|
153
|
-
// }
|
|
154
|
-
// }
|
|
155
|
-
// return true
|
|
156
|
-
// }
|
|
157
|
-
|
|
158
|
-
const keysA = Object.keys(objA);
|
|
159
|
-
if (keysA.length !== Object.keys(objB).length) {
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
for (let i = 0; i < keysA.length; i++) {
|
|
163
|
-
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
34
|
+
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
169
35
|
|
|
170
36
|
/**
|
|
171
|
-
*
|
|
37
|
+
* @tanstack/history/src/index.ts
|
|
172
38
|
*
|
|
173
39
|
* Copyright (c) TanStack
|
|
174
40
|
*
|
|
@@ -177,11 +43,11 @@
|
|
|
177
43
|
*
|
|
178
44
|
* @license MIT
|
|
179
45
|
*/
|
|
180
|
-
|
|
181
46
|
// While the public API was clearly inspired by the "history" npm package,
|
|
182
47
|
// This implementation attempts to be more lightweight by
|
|
183
48
|
// making assumptions about the way TanStack Router works
|
|
184
49
|
|
|
50
|
+
const pushStateEvent = 'pushstate';
|
|
185
51
|
const popStateEvent = 'popstate';
|
|
186
52
|
const beforeUnloadEvent = 'beforeunload';
|
|
187
53
|
const beforeUnloadListener = event => {
|
|
@@ -195,124 +61,226 @@
|
|
|
195
61
|
});
|
|
196
62
|
};
|
|
197
63
|
function createHistory(opts) {
|
|
198
|
-
let
|
|
199
|
-
let
|
|
200
|
-
let listeners = new Set();
|
|
64
|
+
let location = opts.getLocation();
|
|
65
|
+
let subscribers = new Set();
|
|
201
66
|
let blockers = [];
|
|
202
|
-
let queue = [];
|
|
203
|
-
const tryFlush = () => {
|
|
204
|
-
if (blockers.length) {
|
|
205
|
-
blockers[0]?.(tryFlush, () => {
|
|
206
|
-
blockers = [];
|
|
207
|
-
stopBlocking();
|
|
208
|
-
});
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
while (queue.length) {
|
|
212
|
-
queue.shift()?.();
|
|
213
|
-
}
|
|
214
|
-
onUpdate();
|
|
215
|
-
};
|
|
216
|
-
const queueTask = task => {
|
|
217
|
-
queue.push(task);
|
|
218
|
-
tryFlush();
|
|
219
|
-
};
|
|
220
67
|
const onUpdate = () => {
|
|
221
|
-
|
|
222
|
-
|
|
68
|
+
location = opts.getLocation();
|
|
69
|
+
subscribers.forEach(subscriber => subscriber());
|
|
70
|
+
};
|
|
71
|
+
const tryNavigation = async task => {
|
|
72
|
+
if (typeof document !== 'undefined' && blockers.length) {
|
|
73
|
+
for (let blocker of blockers) {
|
|
74
|
+
const allowed = await blocker();
|
|
75
|
+
if (!allowed) {
|
|
76
|
+
opts.onBlocked?.(onUpdate);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
task();
|
|
223
82
|
};
|
|
224
83
|
return {
|
|
225
84
|
get location() {
|
|
226
|
-
return
|
|
85
|
+
return location;
|
|
227
86
|
},
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
unsub = opts.listener(onUpdate);
|
|
231
|
-
}
|
|
232
|
-
listeners.add(cb);
|
|
87
|
+
subscribe: cb => {
|
|
88
|
+
subscribers.add(cb);
|
|
233
89
|
return () => {
|
|
234
|
-
|
|
235
|
-
if (listeners.size === 0) {
|
|
236
|
-
unsub();
|
|
237
|
-
}
|
|
90
|
+
subscribers.delete(cb);
|
|
238
91
|
};
|
|
239
92
|
},
|
|
240
93
|
push: (path, state) => {
|
|
241
|
-
|
|
242
|
-
|
|
94
|
+
state = assignKey(state);
|
|
95
|
+
tryNavigation(() => {
|
|
96
|
+
opts.pushState(path, state, onUpdate);
|
|
243
97
|
});
|
|
244
98
|
},
|
|
245
99
|
replace: (path, state) => {
|
|
246
|
-
|
|
247
|
-
|
|
100
|
+
state = assignKey(state);
|
|
101
|
+
tryNavigation(() => {
|
|
102
|
+
opts.replaceState(path, state, onUpdate);
|
|
248
103
|
});
|
|
249
104
|
},
|
|
250
105
|
go: index => {
|
|
251
|
-
|
|
106
|
+
tryNavigation(() => {
|
|
252
107
|
opts.go(index);
|
|
253
108
|
});
|
|
254
109
|
},
|
|
255
110
|
back: () => {
|
|
256
|
-
|
|
111
|
+
tryNavigation(() => {
|
|
257
112
|
opts.back();
|
|
258
113
|
});
|
|
259
114
|
},
|
|
260
115
|
forward: () => {
|
|
261
|
-
|
|
116
|
+
tryNavigation(() => {
|
|
262
117
|
opts.forward();
|
|
263
118
|
});
|
|
264
119
|
},
|
|
265
120
|
createHref: str => opts.createHref(str),
|
|
266
|
-
block:
|
|
267
|
-
blockers.push(
|
|
121
|
+
block: blocker => {
|
|
122
|
+
blockers.push(blocker);
|
|
268
123
|
if (blockers.length === 1) {
|
|
269
124
|
addEventListener(beforeUnloadEvent, beforeUnloadListener, {
|
|
270
125
|
capture: true
|
|
271
126
|
});
|
|
272
127
|
}
|
|
273
128
|
return () => {
|
|
274
|
-
blockers = blockers.filter(b => b !==
|
|
129
|
+
blockers = blockers.filter(b => b !== blocker);
|
|
275
130
|
if (!blockers.length) {
|
|
276
131
|
stopBlocking();
|
|
277
132
|
}
|
|
278
133
|
};
|
|
279
|
-
}
|
|
134
|
+
},
|
|
135
|
+
flush: () => opts.flush?.(),
|
|
136
|
+
destroy: () => opts.destroy?.(),
|
|
137
|
+
notify: onUpdate
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function assignKey(state) {
|
|
141
|
+
if (!state) {
|
|
142
|
+
state = {};
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
...state,
|
|
146
|
+
key: createRandomKey()
|
|
280
147
|
};
|
|
281
148
|
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Creates a history object that can be used to interact with the browser's
|
|
152
|
+
* navigation. This is a lightweight API wrapping the browser's native methods.
|
|
153
|
+
* It is designed to work with TanStack Router, but could be used as a standalone API as well.
|
|
154
|
+
* IMPORTANT: This API implements history throttling via a microtask to prevent
|
|
155
|
+
* excessive calls to the history API. In some browsers, calling history.pushState or
|
|
156
|
+
* history.replaceState in quick succession can cause the browser to ignore subsequent
|
|
157
|
+
* calls. This API smooths out those differences and ensures that your application
|
|
158
|
+
* state will *eventually* match the browser state. In most cases, this is not a problem,
|
|
159
|
+
* but if you need to ensure that the browser state is up to date, you can use the
|
|
160
|
+
* `history.flush` method to immediately flush all pending state changes to the browser URL.
|
|
161
|
+
* @param opts
|
|
162
|
+
* @param opts.getHref A function that returns the current href (path + search + hash)
|
|
163
|
+
* @param opts.createHref A function that takes a path and returns a href (path + search + hash)
|
|
164
|
+
* @returns A history instance
|
|
165
|
+
*/
|
|
282
166
|
function createBrowserHistory(opts) {
|
|
283
|
-
const
|
|
167
|
+
const win = opts?.window ?? (typeof document !== 'undefined' ? window : undefined);
|
|
284
168
|
const createHref = opts?.createHref ?? (path => path);
|
|
285
|
-
const
|
|
286
|
-
|
|
169
|
+
const parseLocation = opts?.parseLocation ?? (() => parseHref(`${win.location.pathname}${win.location.search}${win.location.hash}`, win.history.state));
|
|
170
|
+
let currentLocation = parseLocation();
|
|
171
|
+
let rollbackLocation;
|
|
172
|
+
const getLocation = () => currentLocation;
|
|
173
|
+
let next;
|
|
174
|
+
|
|
175
|
+
// Because we are proactively updating the location
|
|
176
|
+
// in memory before actually updating the browser history,
|
|
177
|
+
// we need to track when we are doing this so we don't
|
|
178
|
+
// notify subscribers twice on the last update.
|
|
179
|
+
let tracking = true;
|
|
180
|
+
|
|
181
|
+
// We need to track the current scheduled update to prevent
|
|
182
|
+
// multiple updates from being scheduled at the same time.
|
|
183
|
+
let scheduled;
|
|
184
|
+
|
|
185
|
+
// This function is a wrapper to prevent any of the callback's
|
|
186
|
+
// side effects from causing a subscriber notification
|
|
187
|
+
const untrack = fn => {
|
|
188
|
+
tracking = false;
|
|
189
|
+
fn();
|
|
190
|
+
tracking = true;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// This function flushes the next update to the browser history
|
|
194
|
+
const flush = () => {
|
|
195
|
+
// Do not notify subscribers about this push/replace call
|
|
196
|
+
untrack(() => {
|
|
197
|
+
if (!next) return;
|
|
198
|
+
win.history[next.isPush ? 'pushState' : 'replaceState'](next.state, '', next.href);
|
|
199
|
+
// Reset the nextIsPush flag and clear the scheduled update
|
|
200
|
+
next = undefined;
|
|
201
|
+
scheduled = undefined;
|
|
202
|
+
rollbackLocation = undefined;
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// This function queues up a call to update the browser history
|
|
207
|
+
const queueHistoryAction = (type, destHref, state, onUpdate) => {
|
|
208
|
+
const href = createHref(destHref);
|
|
209
|
+
if (!scheduled) {
|
|
210
|
+
rollbackLocation = currentLocation;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Update the location in memory
|
|
214
|
+
currentLocation = parseHref(destHref, state);
|
|
215
|
+
|
|
216
|
+
// Keep track of the next location we need to flush to the URL
|
|
217
|
+
next = {
|
|
218
|
+
href,
|
|
219
|
+
state,
|
|
220
|
+
isPush: next?.isPush || type === 'push'
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// Notify subscribers
|
|
224
|
+
onUpdate();
|
|
225
|
+
if (!scheduled) {
|
|
226
|
+
// Schedule an update to the browser history
|
|
227
|
+
scheduled = Promise.resolve().then(() => flush());
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const onPushPop = () => {
|
|
231
|
+
currentLocation = parseLocation();
|
|
232
|
+
history.notify();
|
|
233
|
+
};
|
|
234
|
+
var originalPushState = win.history.pushState;
|
|
235
|
+
var originalReplaceState = win.history.replaceState;
|
|
236
|
+
const history = createHistory({
|
|
287
237
|
getLocation,
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
replaceState: (path, state) => {
|
|
301
|
-
window.history.replaceState({
|
|
302
|
-
...state,
|
|
303
|
-
key: createRandomKey()
|
|
304
|
-
}, '', createHref(path));
|
|
238
|
+
pushState: (href, state, onUpdate) => queueHistoryAction('push', href, state, onUpdate),
|
|
239
|
+
replaceState: (href, state, onUpdate) => queueHistoryAction('replace', href, state, onUpdate),
|
|
240
|
+
back: () => win.history.back(),
|
|
241
|
+
forward: () => win.history.forward(),
|
|
242
|
+
go: n => win.history.go(n),
|
|
243
|
+
createHref: href => createHref(href),
|
|
244
|
+
flush,
|
|
245
|
+
destroy: () => {
|
|
246
|
+
win.history.pushState = originalPushState;
|
|
247
|
+
win.history.replaceState = originalReplaceState;
|
|
248
|
+
win.removeEventListener(pushStateEvent, onPushPop);
|
|
249
|
+
win.removeEventListener(popStateEvent, onPushPop);
|
|
305
250
|
},
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
251
|
+
onBlocked: onUpdate => {
|
|
252
|
+
// If a navigation is blocked, we need to rollback the location
|
|
253
|
+
// that we optimistically updated in memory.
|
|
254
|
+
if (rollbackLocation && currentLocation !== rollbackLocation) {
|
|
255
|
+
currentLocation = rollbackLocation;
|
|
256
|
+
// Notify subscribers
|
|
257
|
+
onUpdate();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
310
260
|
});
|
|
261
|
+
win.addEventListener(pushStateEvent, onPushPop);
|
|
262
|
+
win.addEventListener(popStateEvent, onPushPop);
|
|
263
|
+
win.history.pushState = function () {
|
|
264
|
+
let res = originalPushState.apply(win.history, arguments);
|
|
265
|
+
if (tracking) history.notify();
|
|
266
|
+
return res;
|
|
267
|
+
};
|
|
268
|
+
win.history.replaceState = function () {
|
|
269
|
+
let res = originalReplaceState.apply(win.history, arguments);
|
|
270
|
+
if (tracking) history.notify();
|
|
271
|
+
return res;
|
|
272
|
+
};
|
|
273
|
+
return history;
|
|
311
274
|
}
|
|
312
|
-
function createHashHistory() {
|
|
275
|
+
function createHashHistory(opts) {
|
|
276
|
+
const win = opts?.window ?? (typeof document !== 'undefined' ? window : undefined);
|
|
313
277
|
return createBrowserHistory({
|
|
314
|
-
|
|
315
|
-
|
|
278
|
+
window: win,
|
|
279
|
+
parseLocation: () => {
|
|
280
|
+
const hashHref = win.location.hash.split('#').slice(1).join('#') ?? '/';
|
|
281
|
+
return parseHref(hashHref, win.history.state);
|
|
282
|
+
},
|
|
283
|
+
createHref: href => `${win.location.pathname}${win.location.search}#${href}`
|
|
316
284
|
});
|
|
317
285
|
}
|
|
318
286
|
function createMemoryHistory(opts = {
|
|
@@ -320,26 +288,19 @@
|
|
|
320
288
|
}) {
|
|
321
289
|
const entries = opts.initialEntries;
|
|
322
290
|
let index = opts.initialIndex ?? entries.length - 1;
|
|
323
|
-
let currentState = {
|
|
324
|
-
|
|
291
|
+
let currentState = {
|
|
292
|
+
key: createRandomKey()
|
|
293
|
+
};
|
|
294
|
+
const getLocation = () => parseHref(entries[index], currentState);
|
|
325
295
|
return createHistory({
|
|
326
296
|
getLocation,
|
|
327
|
-
listener: () => {
|
|
328
|
-
return () => {};
|
|
329
|
-
},
|
|
330
297
|
pushState: (path, state) => {
|
|
331
|
-
currentState =
|
|
332
|
-
...state,
|
|
333
|
-
key: createRandomKey()
|
|
334
|
-
};
|
|
298
|
+
currentState = state;
|
|
335
299
|
entries.push(path);
|
|
336
300
|
index++;
|
|
337
301
|
},
|
|
338
302
|
replaceState: (path, state) => {
|
|
339
|
-
currentState =
|
|
340
|
-
...state,
|
|
341
|
-
key: createRandomKey()
|
|
342
|
-
};
|
|
303
|
+
currentState = state;
|
|
343
304
|
entries[index] = path;
|
|
344
305
|
},
|
|
345
306
|
back: () => {
|
|
@@ -348,19 +309,21 @@
|
|
|
348
309
|
forward: () => {
|
|
349
310
|
index = Math.min(index + 1, entries.length - 1);
|
|
350
311
|
},
|
|
351
|
-
go: n =>
|
|
312
|
+
go: n => {
|
|
313
|
+
index = Math.min(Math.max(index + n, 0), entries.length - 1);
|
|
314
|
+
},
|
|
352
315
|
createHref: path => path
|
|
353
316
|
});
|
|
354
317
|
}
|
|
355
|
-
function
|
|
318
|
+
function parseHref(href, state) {
|
|
356
319
|
let hashIndex = href.indexOf('#');
|
|
357
320
|
let searchIndex = href.indexOf('?');
|
|
358
321
|
return {
|
|
359
322
|
href,
|
|
360
323
|
pathname: href.substring(0, hashIndex > 0 ? searchIndex > 0 ? Math.min(hashIndex, searchIndex) : hashIndex : searchIndex > 0 ? searchIndex : href.length),
|
|
361
|
-
hash: hashIndex > -1 ? href.substring(hashIndex
|
|
362
|
-
search: searchIndex > -1 ? href.
|
|
363
|
-
state
|
|
324
|
+
hash: hashIndex > -1 ? href.substring(hashIndex) : '',
|
|
325
|
+
search: searchIndex > -1 ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex) : '',
|
|
326
|
+
state: state || {}
|
|
364
327
|
};
|
|
365
328
|
}
|
|
366
329
|
|
|
@@ -369,98 +332,941 @@
|
|
|
369
332
|
return (Math.random() + 1).toString(36).substring(7);
|
|
370
333
|
}
|
|
371
334
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
335
|
+
var prefix = 'Invariant failed';
|
|
336
|
+
function invariant(condition, message) {
|
|
337
|
+
if (condition) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
var provided = typeof message === 'function' ? message() : message;
|
|
341
|
+
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
342
|
+
throw new Error(value);
|
|
377
343
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
344
|
+
|
|
345
|
+
function warning(condition, message) {
|
|
346
|
+
{
|
|
347
|
+
if (condition) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
var text = "Warning: " + message;
|
|
352
|
+
|
|
353
|
+
if (typeof console !== 'undefined') {
|
|
354
|
+
console.warn(text);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
throw Error(text);
|
|
359
|
+
} catch (x) {}
|
|
381
360
|
}
|
|
382
|
-
return updater;
|
|
383
|
-
}
|
|
384
|
-
function pick(parent, keys) {
|
|
385
|
-
return keys.reduce((obj, key) => {
|
|
386
|
-
obj[key] = parent[key];
|
|
387
|
-
return obj;
|
|
388
|
-
}, {});
|
|
389
361
|
}
|
|
390
362
|
|
|
363
|
+
var withSelector = {exports: {}};
|
|
364
|
+
|
|
365
|
+
var withSelector_development = {};
|
|
366
|
+
|
|
391
367
|
/**
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
368
|
+
* @license React
|
|
369
|
+
* use-sync-external-store-shim/with-selector.development.js
|
|
370
|
+
*
|
|
371
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
372
|
+
*
|
|
373
|
+
* This source code is licensed under the MIT license found in the
|
|
374
|
+
* LICENSE file in the root directory of this source tree.
|
|
396
375
|
*/
|
|
397
|
-
function replaceEqualDeep(prev, _next) {
|
|
398
|
-
if (prev === _next) {
|
|
399
|
-
return prev;
|
|
400
|
-
}
|
|
401
|
-
const next = _next;
|
|
402
|
-
const array = Array.isArray(prev) && Array.isArray(next);
|
|
403
|
-
if (array || isPlainObject(prev) && isPlainObject(next)) {
|
|
404
|
-
const prevSize = array ? prev.length : Object.keys(prev).length;
|
|
405
|
-
const nextItems = array ? next : Object.keys(next);
|
|
406
|
-
const nextSize = nextItems.length;
|
|
407
|
-
const copy = array ? [] : {};
|
|
408
|
-
let equalItems = 0;
|
|
409
|
-
for (let i = 0; i < nextSize; i++) {
|
|
410
|
-
const key = array ? i : nextItems[i];
|
|
411
|
-
copy[key] = replaceEqualDeep(prev[key], next[key]);
|
|
412
|
-
if (copy[key] === prev[key]) {
|
|
413
|
-
equalItems++;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
return prevSize === nextSize && equalItems === prevSize ? prev : copy;
|
|
417
|
-
}
|
|
418
|
-
return next;
|
|
419
|
-
}
|
|
420
376
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
377
|
+
var hasRequiredWithSelector_development;
|
|
378
|
+
|
|
379
|
+
function requireWithSelector_development () {
|
|
380
|
+
if (hasRequiredWithSelector_development) return withSelector_development;
|
|
381
|
+
hasRequiredWithSelector_development = 1;
|
|
382
|
+
|
|
383
|
+
{
|
|
384
|
+
(function() {
|
|
385
|
+
|
|
386
|
+
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
|
|
387
|
+
if (
|
|
388
|
+
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
|
|
389
|
+
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart ===
|
|
390
|
+
'function'
|
|
391
|
+
) {
|
|
392
|
+
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
|
|
393
|
+
}
|
|
394
|
+
var React$1 = React;
|
|
395
|
+
var shim = require$$1;
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* inlined Object.is polyfill to avoid requiring consumers ship their own
|
|
399
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
|
400
|
+
*/
|
|
401
|
+
function is(x, y) {
|
|
402
|
+
return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
|
|
403
|
+
;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
var objectIs = typeof Object.is === 'function' ? Object.is : is;
|
|
407
|
+
|
|
408
|
+
var useSyncExternalStore = shim.useSyncExternalStore;
|
|
409
|
+
|
|
410
|
+
// for CommonJS interop.
|
|
411
|
+
|
|
412
|
+
var useRef = React$1.useRef,
|
|
413
|
+
useEffect = React$1.useEffect,
|
|
414
|
+
useMemo = React$1.useMemo,
|
|
415
|
+
useDebugValue = React$1.useDebugValue; // Same as useSyncExternalStore, but supports selector and isEqual arguments.
|
|
416
|
+
|
|
417
|
+
function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
|
|
418
|
+
// Use this to track the rendered snapshot.
|
|
419
|
+
var instRef = useRef(null);
|
|
420
|
+
var inst;
|
|
421
|
+
|
|
422
|
+
if (instRef.current === null) {
|
|
423
|
+
inst = {
|
|
424
|
+
hasValue: false,
|
|
425
|
+
value: null
|
|
426
|
+
};
|
|
427
|
+
instRef.current = inst;
|
|
428
|
+
} else {
|
|
429
|
+
inst = instRef.current;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
var _useMemo = useMemo(function () {
|
|
433
|
+
// Track the memoized state using closure variables that are local to this
|
|
434
|
+
// memoized instance of a getSnapshot function. Intentionally not using a
|
|
435
|
+
// useRef hook, because that state would be shared across all concurrent
|
|
436
|
+
// copies of the hook/component.
|
|
437
|
+
var hasMemo = false;
|
|
438
|
+
var memoizedSnapshot;
|
|
439
|
+
var memoizedSelection;
|
|
440
|
+
|
|
441
|
+
var memoizedSelector = function (nextSnapshot) {
|
|
442
|
+
if (!hasMemo) {
|
|
443
|
+
// The first time the hook is called, there is no memoized result.
|
|
444
|
+
hasMemo = true;
|
|
445
|
+
memoizedSnapshot = nextSnapshot;
|
|
446
|
+
|
|
447
|
+
var _nextSelection = selector(nextSnapshot);
|
|
448
|
+
|
|
449
|
+
if (isEqual !== undefined) {
|
|
450
|
+
// Even if the selector has changed, the currently rendered selection
|
|
451
|
+
// may be equal to the new selection. We should attempt to reuse the
|
|
452
|
+
// current value if possible, to preserve downstream memoizations.
|
|
453
|
+
if (inst.hasValue) {
|
|
454
|
+
var currentSelection = inst.value;
|
|
455
|
+
|
|
456
|
+
if (isEqual(currentSelection, _nextSelection)) {
|
|
457
|
+
memoizedSelection = currentSelection;
|
|
458
|
+
return currentSelection;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
memoizedSelection = _nextSelection;
|
|
464
|
+
return _nextSelection;
|
|
465
|
+
} // We may be able to reuse the previous invocation's result.
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
// We may be able to reuse the previous invocation's result.
|
|
469
|
+
var prevSnapshot = memoizedSnapshot;
|
|
470
|
+
var prevSelection = memoizedSelection;
|
|
471
|
+
|
|
472
|
+
if (objectIs(prevSnapshot, nextSnapshot)) {
|
|
473
|
+
// The snapshot is the same as last time. Reuse the previous selection.
|
|
474
|
+
return prevSelection;
|
|
475
|
+
} // The snapshot has changed, so we need to compute a new selection.
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
// The snapshot has changed, so we need to compute a new selection.
|
|
479
|
+
var nextSelection = selector(nextSnapshot); // If a custom isEqual function is provided, use that to check if the data
|
|
480
|
+
// has changed. If it hasn't, return the previous selection. That signals
|
|
481
|
+
// to React that the selections are conceptually equal, and we can bail
|
|
482
|
+
// out of rendering.
|
|
483
|
+
|
|
484
|
+
// If a custom isEqual function is provided, use that to check if the data
|
|
485
|
+
// has changed. If it hasn't, return the previous selection. That signals
|
|
486
|
+
// to React that the selections are conceptually equal, and we can bail
|
|
487
|
+
// out of rendering.
|
|
488
|
+
if (isEqual !== undefined && isEqual(prevSelection, nextSelection)) {
|
|
489
|
+
return prevSelection;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
memoizedSnapshot = nextSnapshot;
|
|
493
|
+
memoizedSelection = nextSelection;
|
|
494
|
+
return nextSelection;
|
|
495
|
+
}; // Assigning this to a constant so that Flow knows it can't change.
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
// Assigning this to a constant so that Flow knows it can't change.
|
|
499
|
+
var maybeGetServerSnapshot = getServerSnapshot === undefined ? null : getServerSnapshot;
|
|
500
|
+
|
|
501
|
+
var getSnapshotWithSelector = function () {
|
|
502
|
+
return memoizedSelector(getSnapshot());
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
var getServerSnapshotWithSelector = maybeGetServerSnapshot === null ? undefined : function () {
|
|
506
|
+
return memoizedSelector(maybeGetServerSnapshot());
|
|
507
|
+
};
|
|
508
|
+
return [getSnapshotWithSelector, getServerSnapshotWithSelector];
|
|
509
|
+
}, [getSnapshot, getServerSnapshot, selector, isEqual]),
|
|
510
|
+
getSelection = _useMemo[0],
|
|
511
|
+
getServerSelection = _useMemo[1];
|
|
512
|
+
|
|
513
|
+
var value = useSyncExternalStore(subscribe, getSelection, getServerSelection);
|
|
514
|
+
useEffect(function () {
|
|
515
|
+
inst.hasValue = true;
|
|
516
|
+
inst.value = value;
|
|
517
|
+
}, [value]);
|
|
518
|
+
useDebugValue(value);
|
|
519
|
+
return value;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
withSelector_development.useSyncExternalStoreWithSelector = useSyncExternalStoreWithSelector;
|
|
523
|
+
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
|
|
524
|
+
if (
|
|
525
|
+
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
|
|
526
|
+
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop ===
|
|
527
|
+
'function'
|
|
528
|
+
) {
|
|
529
|
+
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error());
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
})();
|
|
533
|
+
}
|
|
534
|
+
return withSelector_development;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
{
|
|
538
|
+
withSelector.exports = requireWithSelector_development();
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
var withSelectorExports = withSelector.exports;
|
|
542
|
+
|
|
543
|
+
// src/index.ts
|
|
544
|
+
var Store = class {
|
|
545
|
+
constructor(initialState, options) {
|
|
546
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
547
|
+
this._batching = false;
|
|
548
|
+
this._flushing = 0;
|
|
549
|
+
this._nextPriority = null;
|
|
550
|
+
this.subscribe = (listener) => {
|
|
551
|
+
this.listeners.add(listener);
|
|
552
|
+
const unsub = this.options?.onSubscribe?.(listener, this);
|
|
553
|
+
return () => {
|
|
554
|
+
this.listeners.delete(listener);
|
|
555
|
+
unsub?.();
|
|
556
|
+
};
|
|
557
|
+
};
|
|
558
|
+
this.setState = (updater, opts) => {
|
|
559
|
+
const previous = this.state;
|
|
560
|
+
this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
|
|
561
|
+
const priority = opts?.priority ?? this.options?.defaultPriority ?? "high";
|
|
562
|
+
if (this._nextPriority === null) {
|
|
563
|
+
this._nextPriority = priority;
|
|
564
|
+
} else if (this._nextPriority === "high") {
|
|
565
|
+
this._nextPriority = priority;
|
|
566
|
+
} else {
|
|
567
|
+
this._nextPriority = this.options?.defaultPriority ?? "high";
|
|
568
|
+
}
|
|
569
|
+
this.options?.onUpdate?.({
|
|
570
|
+
priority: this._nextPriority
|
|
571
|
+
});
|
|
572
|
+
this._flush();
|
|
573
|
+
};
|
|
574
|
+
this._flush = () => {
|
|
575
|
+
if (this._batching)
|
|
576
|
+
return;
|
|
577
|
+
const flushId = ++this._flushing;
|
|
578
|
+
this.listeners.forEach((listener) => {
|
|
579
|
+
if (this._flushing !== flushId)
|
|
580
|
+
return;
|
|
581
|
+
listener({
|
|
582
|
+
priority: this._nextPriority ?? "high"
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
};
|
|
586
|
+
this.batch = (cb) => {
|
|
587
|
+
if (this._batching)
|
|
588
|
+
return cb();
|
|
589
|
+
this._batching = true;
|
|
590
|
+
cb();
|
|
591
|
+
this._batching = false;
|
|
592
|
+
this._flush();
|
|
593
|
+
};
|
|
594
|
+
this.state = initialState;
|
|
595
|
+
this.options = options;
|
|
425
596
|
}
|
|
597
|
+
};
|
|
426
598
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
599
|
+
// src/index.ts
|
|
600
|
+
function useStore(store, selector = (d) => d) {
|
|
601
|
+
const slice = withSelectorExports.useSyncExternalStoreWithSelector(
|
|
602
|
+
store.subscribe,
|
|
603
|
+
() => store.state,
|
|
604
|
+
() => store.state,
|
|
605
|
+
selector,
|
|
606
|
+
shallow$1
|
|
607
|
+
);
|
|
608
|
+
return slice;
|
|
609
|
+
}
|
|
610
|
+
function shallow$1(objA, objB) {
|
|
611
|
+
if (Object.is(objA, objB)) {
|
|
430
612
|
return true;
|
|
431
613
|
}
|
|
432
|
-
|
|
433
|
-
// If has modified prototype
|
|
434
|
-
const prot = ctor.prototype;
|
|
435
|
-
if (!hasObjectPrototype(prot)) {
|
|
614
|
+
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) {
|
|
436
615
|
return false;
|
|
437
616
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
|
617
|
+
const keysA = Object.keys(objA);
|
|
618
|
+
if (keysA.length !== Object.keys(objB).length) {
|
|
441
619
|
return false;
|
|
442
620
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
621
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
622
|
+
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function CatchBoundary(props) {
|
|
630
|
+
const errorComponent = props.errorComponent ?? ErrorComponent;
|
|
631
|
+
return /*#__PURE__*/React__namespace.createElement(CatchBoundaryImpl, {
|
|
632
|
+
getResetKey: props.getResetKey,
|
|
633
|
+
onCatch: props.onCatch,
|
|
634
|
+
children: ({
|
|
635
|
+
error
|
|
636
|
+
}) => {
|
|
637
|
+
if (error) {
|
|
638
|
+
return /*#__PURE__*/React__namespace.createElement(errorComponent, {
|
|
639
|
+
error
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
return props.children;
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
class CatchBoundaryImpl extends React__namespace.Component {
|
|
647
|
+
state = {
|
|
648
|
+
error: null
|
|
649
|
+
};
|
|
650
|
+
static getDerivedStateFromProps(props) {
|
|
651
|
+
return {
|
|
652
|
+
resetKey: props.getResetKey()
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
static getDerivedStateFromError(error) {
|
|
656
|
+
return {
|
|
657
|
+
error
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
componentDidUpdate(prevProps, prevState) {
|
|
661
|
+
if (prevState.error && prevState.resetKey !== this.state.resetKey) {
|
|
662
|
+
this.setState({
|
|
663
|
+
error: null
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
componentDidCatch(error) {
|
|
668
|
+
console.error(error);
|
|
669
|
+
this.props.onCatch?.(error);
|
|
670
|
+
}
|
|
671
|
+
render() {
|
|
672
|
+
return this.props.children(this.state);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function ErrorComponent({
|
|
676
|
+
error
|
|
677
|
+
}) {
|
|
678
|
+
const [show, setShow] = React__namespace.useState("development" !== 'production');
|
|
679
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
680
|
+
style: {
|
|
681
|
+
padding: '.5rem',
|
|
682
|
+
maxWidth: '100%'
|
|
683
|
+
}
|
|
684
|
+
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
685
|
+
style: {
|
|
686
|
+
display: 'flex',
|
|
687
|
+
alignItems: 'center',
|
|
688
|
+
gap: '.5rem'
|
|
689
|
+
}
|
|
690
|
+
}, /*#__PURE__*/React__namespace.createElement("strong", {
|
|
691
|
+
style: {
|
|
692
|
+
fontSize: '1rem'
|
|
693
|
+
}
|
|
694
|
+
}, "Something went wrong!"), /*#__PURE__*/React__namespace.createElement("button", {
|
|
695
|
+
style: {
|
|
696
|
+
appearance: 'none',
|
|
697
|
+
fontSize: '.6em',
|
|
698
|
+
border: '1px solid currentColor',
|
|
699
|
+
padding: '.1rem .2rem',
|
|
700
|
+
fontWeight: 'bold',
|
|
701
|
+
borderRadius: '.25rem'
|
|
702
|
+
},
|
|
703
|
+
onClick: () => setShow(d => !d)
|
|
704
|
+
}, show ? 'Hide Error' : 'Show Error')), /*#__PURE__*/React__namespace.createElement("div", {
|
|
705
|
+
style: {
|
|
706
|
+
height: '.25rem'
|
|
707
|
+
}
|
|
708
|
+
}), show ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("pre", {
|
|
709
|
+
style: {
|
|
710
|
+
fontSize: '.7em',
|
|
711
|
+
border: '1px solid red',
|
|
712
|
+
borderRadius: '.25rem',
|
|
713
|
+
padding: '.3rem',
|
|
714
|
+
color: 'red',
|
|
715
|
+
overflow: 'auto'
|
|
716
|
+
}
|
|
717
|
+
}, error.message ? /*#__PURE__*/React__namespace.createElement("code", null, error.message) : null)) : null);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// export type Expand<T> = T
|
|
721
|
+
|
|
722
|
+
// type Compute<T> = { [K in keyof T]: T[K] } | never
|
|
723
|
+
|
|
724
|
+
// type AllKeys<T> = T extends any ? keyof T : never
|
|
725
|
+
|
|
726
|
+
// export type MergeUnion<T, Keys extends keyof T = keyof T> = Compute<
|
|
727
|
+
// {
|
|
728
|
+
// [K in Keys]: T[Keys]
|
|
729
|
+
// } & {
|
|
730
|
+
// [K in AllKeys<T>]?: T extends any
|
|
731
|
+
// ? K extends keyof T
|
|
732
|
+
// ? T[K]
|
|
733
|
+
// : never
|
|
734
|
+
// : never
|
|
735
|
+
// }
|
|
736
|
+
// >
|
|
737
|
+
|
|
738
|
+
// // Sample types to merge
|
|
739
|
+
// type TypeA = {
|
|
740
|
+
// shared: string
|
|
741
|
+
// onlyInA: string
|
|
742
|
+
// nested: {
|
|
743
|
+
// shared: string
|
|
744
|
+
// aProp: string
|
|
745
|
+
// }
|
|
746
|
+
// array: string[]
|
|
747
|
+
// }
|
|
748
|
+
|
|
749
|
+
// type TypeB = {
|
|
750
|
+
// shared: number
|
|
751
|
+
// onlyInB: number
|
|
752
|
+
// nested: {
|
|
753
|
+
// shared: number
|
|
754
|
+
// bProp: number
|
|
755
|
+
// }
|
|
756
|
+
// array: number[]
|
|
757
|
+
// }
|
|
758
|
+
|
|
759
|
+
// type TypeC = {
|
|
760
|
+
// shared: boolean
|
|
761
|
+
// onlyInC: boolean
|
|
762
|
+
// nested: {
|
|
763
|
+
// shared: boolean
|
|
764
|
+
// cProp: boolean
|
|
765
|
+
// }
|
|
766
|
+
// array: boolean[]
|
|
767
|
+
// }
|
|
768
|
+
|
|
769
|
+
// type Test = Expand<Assign<TypeA, TypeB>>
|
|
770
|
+
|
|
771
|
+
// // Using DeepMerge to merge TypeA and TypeB
|
|
772
|
+
// type MergedType = Expand<AssignAll<[TypeA, TypeB, TypeC]>>
|
|
773
|
+
|
|
774
|
+
// from https://github.com/type-challenges/type-challenges/issues/737
|
|
775
|
+
|
|
776
|
+
//
|
|
777
|
+
|
|
778
|
+
const isServer = typeof document === 'undefined';
|
|
779
|
+
function last(arr) {
|
|
780
|
+
return arr[arr.length - 1];
|
|
781
|
+
}
|
|
782
|
+
function isFunction(d) {
|
|
783
|
+
return typeof d === 'function';
|
|
784
|
+
}
|
|
785
|
+
function functionalUpdate(updater, previous) {
|
|
786
|
+
if (isFunction(updater)) {
|
|
787
|
+
return updater(previous);
|
|
788
|
+
}
|
|
789
|
+
return updater;
|
|
790
|
+
}
|
|
791
|
+
function pick(parent, keys) {
|
|
792
|
+
return keys.reduce((obj, key) => {
|
|
793
|
+
obj[key] = parent[key];
|
|
794
|
+
return obj;
|
|
795
|
+
}, {});
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* This function returns `a` if `b` is deeply equal.
|
|
800
|
+
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
|
801
|
+
* This can be used for structural sharing between immutable JSON values for example.
|
|
802
|
+
* Do not use this with signals
|
|
803
|
+
*/
|
|
804
|
+
function replaceEqualDeep(prev, _next) {
|
|
805
|
+
if (prev === _next) {
|
|
806
|
+
return prev;
|
|
807
|
+
}
|
|
808
|
+
const next = _next;
|
|
809
|
+
const array = Array.isArray(prev) && Array.isArray(next);
|
|
810
|
+
if (array || isPlainObject(prev) && isPlainObject(next)) {
|
|
811
|
+
const prevSize = array ? prev.length : Object.keys(prev).length;
|
|
812
|
+
const nextItems = array ? next : Object.keys(next);
|
|
813
|
+
const nextSize = nextItems.length;
|
|
814
|
+
const copy = array ? [] : {};
|
|
815
|
+
let equalItems = 0;
|
|
816
|
+
for (let i = 0; i < nextSize; i++) {
|
|
817
|
+
const key = array ? i : nextItems[i];
|
|
818
|
+
copy[key] = replaceEqualDeep(prev[key], next[key]);
|
|
819
|
+
if (copy[key] === prev[key]) {
|
|
820
|
+
equalItems++;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return prevSize === nextSize && equalItems === prevSize ? prev : copy;
|
|
824
|
+
}
|
|
825
|
+
return next;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
|
829
|
+
function isPlainObject(o) {
|
|
830
|
+
if (!hasObjectPrototype(o)) {
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// If has modified constructor
|
|
835
|
+
const ctor = o.constructor;
|
|
836
|
+
if (typeof ctor === 'undefined') {
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// If has modified prototype
|
|
841
|
+
const prot = ctor.prototype;
|
|
842
|
+
if (!hasObjectPrototype(prot)) {
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// If constructor does not have an Object-specific method
|
|
847
|
+
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Most likely a plain Object
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
447
854
|
function hasObjectPrototype(o) {
|
|
448
855
|
return Object.prototype.toString.call(o) === '[object Object]';
|
|
449
856
|
}
|
|
450
|
-
function
|
|
857
|
+
function deepEqual(a, b, partial = false) {
|
|
451
858
|
if (a === b) {
|
|
452
859
|
return true;
|
|
453
860
|
}
|
|
454
861
|
if (typeof a !== typeof b) {
|
|
455
862
|
return false;
|
|
456
863
|
}
|
|
457
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
458
|
-
|
|
864
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
865
|
+
const aKeys = Object.keys(a);
|
|
866
|
+
const bKeys = Object.keys(b);
|
|
867
|
+
if (!partial && aKeys.length !== bKeys.length) {
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
return !bKeys.some(key => !(key in a) || !deepEqual(a[key], b[key], partial));
|
|
871
|
+
}
|
|
872
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
873
|
+
return !a.some((item, index) => !deepEqual(item, b[index], partial));
|
|
874
|
+
}
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
877
|
+
function useStableCallback(fn) {
|
|
878
|
+
const fnRef = React__namespace.useRef(fn);
|
|
879
|
+
fnRef.current = fn;
|
|
880
|
+
const ref = React__namespace.useRef((...args) => fnRef.current(...args));
|
|
881
|
+
return ref.current;
|
|
882
|
+
}
|
|
883
|
+
function shallow(objA, objB) {
|
|
884
|
+
if (Object.is(objA, objB)) {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
888
|
+
return false;
|
|
889
|
+
}
|
|
890
|
+
const keysA = Object.keys(objA);
|
|
891
|
+
if (keysA.length !== Object.keys(objB).length) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
895
|
+
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return true;
|
|
900
|
+
}
|
|
901
|
+
function useRouteContext(opts) {
|
|
902
|
+
return useMatch({
|
|
903
|
+
...opts,
|
|
904
|
+
select: match => opts?.select ? opts.select(match.context) : match.context
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
const useLayoutEffect$1 = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
|
|
908
|
+
function escapeJSON(jsonString) {
|
|
909
|
+
return jsonString.replace(/\\/g, '\\\\') // Escape backslashes
|
|
910
|
+
.replace(/'/g, "\\'") // Escape single quotes
|
|
911
|
+
.replace(/"/g, '\\"'); // Escape double quotes
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const matchContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
915
|
+
function Matches() {
|
|
916
|
+
const router = useRouter();
|
|
917
|
+
const matchId = useRouterState({
|
|
918
|
+
select: s => {
|
|
919
|
+
return getRenderedMatches(s)[0]?.id;
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
return /*#__PURE__*/React__namespace.createElement(matchContext.Provider, {
|
|
923
|
+
value: matchId
|
|
924
|
+
}, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
925
|
+
getResetKey: () => router.state.resolvedLocation.state?.key,
|
|
926
|
+
errorComponent: ErrorComponent,
|
|
927
|
+
onCatch: () => {
|
|
928
|
+
warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
|
|
929
|
+
}
|
|
930
|
+
}, matchId ? /*#__PURE__*/React__namespace.createElement(Match, {
|
|
931
|
+
matchId: matchId
|
|
932
|
+
}) : null));
|
|
933
|
+
}
|
|
934
|
+
function SafeFragment(props) {
|
|
935
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
|
|
936
|
+
}
|
|
937
|
+
function Match({
|
|
938
|
+
matchId
|
|
939
|
+
}) {
|
|
940
|
+
const router = useRouter();
|
|
941
|
+
const routeId = useRouterState({
|
|
942
|
+
select: s => getRenderedMatches(s).find(d => d.id === matchId)?.routeId
|
|
943
|
+
});
|
|
944
|
+
invariant(routeId, `Could not find routeId for matchId "${matchId}". Please file an issue!`);
|
|
945
|
+
const route = router.routesById[routeId];
|
|
946
|
+
const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent;
|
|
947
|
+
const pendingElement = PendingComponent ? /*#__PURE__*/React__namespace.createElement(PendingComponent, null) : null;
|
|
948
|
+
const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
|
|
949
|
+
const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? PendingComponent ?? route.options.component?.preload ?? route.options.pendingComponent?.preload ?? route.options.errorComponent?.preload ? React__namespace.Suspense : SafeFragment;
|
|
950
|
+
const ResolvedCatchBoundary = routeErrorComponent ? CatchBoundary : SafeFragment;
|
|
951
|
+
return /*#__PURE__*/React__namespace.createElement(matchContext.Provider, {
|
|
952
|
+
value: matchId
|
|
953
|
+
}, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
|
|
954
|
+
fallback: pendingElement
|
|
955
|
+
}, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
|
|
956
|
+
getResetKey: () => router.state.resolvedLocation.state?.key,
|
|
957
|
+
errorComponent: routeErrorComponent,
|
|
958
|
+
onCatch: () => {
|
|
959
|
+
warning(false, `Error in route match: ${matchId}`);
|
|
960
|
+
}
|
|
961
|
+
}, /*#__PURE__*/React__namespace.createElement(MatchInner, {
|
|
962
|
+
matchId: matchId,
|
|
963
|
+
pendingElement: pendingElement
|
|
964
|
+
}))));
|
|
965
|
+
}
|
|
966
|
+
function MatchInner({
|
|
967
|
+
matchId,
|
|
968
|
+
pendingElement
|
|
969
|
+
}) {
|
|
970
|
+
const router = useRouter();
|
|
971
|
+
const routeId = useRouterState({
|
|
972
|
+
select: s => getRenderedMatches(s).find(d => d.id === matchId)?.routeId
|
|
973
|
+
});
|
|
974
|
+
const route = router.routesById[routeId];
|
|
975
|
+
const match = useRouterState({
|
|
976
|
+
select: s => pick(getRenderedMatches(s).find(d => d.id === matchId), ['status', 'error', 'showPending', 'loadPromise'])
|
|
977
|
+
});
|
|
978
|
+
if (match.status === 'error') {
|
|
979
|
+
throw match.error;
|
|
980
|
+
}
|
|
981
|
+
if (match.status === 'pending') {
|
|
982
|
+
if (match.showPending) {
|
|
983
|
+
return pendingElement;
|
|
984
|
+
}
|
|
985
|
+
throw match.loadPromise;
|
|
986
|
+
}
|
|
987
|
+
if (match.status === 'success') {
|
|
988
|
+
let Comp = route.options.component ?? router.options.defaultComponent;
|
|
989
|
+
if (Comp) {
|
|
990
|
+
return /*#__PURE__*/React__namespace.createElement(Comp, null);
|
|
991
|
+
}
|
|
992
|
+
return /*#__PURE__*/React__namespace.createElement(Outlet, null);
|
|
993
|
+
}
|
|
994
|
+
invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
|
|
995
|
+
}
|
|
996
|
+
const Outlet = /*#__PURE__*/React__namespace.memo(function Outlet() {
|
|
997
|
+
const matchId = React__namespace.useContext(matchContext);
|
|
998
|
+
const childMatchId = useRouterState({
|
|
999
|
+
select: s => {
|
|
1000
|
+
const matches = getRenderedMatches(s);
|
|
1001
|
+
const index = matches.findIndex(d => d.id === matchId);
|
|
1002
|
+
return matches[index + 1]?.id;
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
if (!childMatchId) {
|
|
1006
|
+
return null;
|
|
1007
|
+
}
|
|
1008
|
+
return /*#__PURE__*/React__namespace.createElement(Match, {
|
|
1009
|
+
matchId: childMatchId
|
|
1010
|
+
});
|
|
1011
|
+
});
|
|
1012
|
+
function useMatchRoute() {
|
|
1013
|
+
useRouterState({
|
|
1014
|
+
select: s => [s.location, s.resolvedLocation]
|
|
1015
|
+
});
|
|
1016
|
+
const {
|
|
1017
|
+
matchRoute
|
|
1018
|
+
} = useRouter();
|
|
1019
|
+
return React__namespace.useCallback(opts => {
|
|
1020
|
+
const {
|
|
1021
|
+
pending,
|
|
1022
|
+
caseSensitive,
|
|
1023
|
+
...rest
|
|
1024
|
+
} = opts;
|
|
1025
|
+
return matchRoute(rest, {
|
|
1026
|
+
pending,
|
|
1027
|
+
caseSensitive
|
|
1028
|
+
});
|
|
1029
|
+
}, []);
|
|
1030
|
+
}
|
|
1031
|
+
function MatchRoute(props) {
|
|
1032
|
+
const matchRoute = useMatchRoute();
|
|
1033
|
+
const params = matchRoute(props);
|
|
1034
|
+
if (typeof props.children === 'function') {
|
|
1035
|
+
return props.children(params);
|
|
1036
|
+
}
|
|
1037
|
+
return !!params ? props.children : null;
|
|
1038
|
+
}
|
|
1039
|
+
function getRenderedMatches(state) {
|
|
1040
|
+
return state.pendingMatches?.some(d => d.showPending) ? state.pendingMatches : state.matches;
|
|
1041
|
+
}
|
|
1042
|
+
function useMatch(opts) {
|
|
1043
|
+
const router = useRouter();
|
|
1044
|
+
const nearestMatchId = React__namespace.useContext(matchContext);
|
|
1045
|
+
const nearestMatchRouteId = getRenderedMatches(router.state).find(d => d.id === nearestMatchId)?.routeId;
|
|
1046
|
+
const matchRouteId = (() => {
|
|
1047
|
+
const matches = getRenderedMatches(router.state);
|
|
1048
|
+
const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatchId);
|
|
1049
|
+
return match.routeId;
|
|
1050
|
+
})();
|
|
1051
|
+
if (opts?.strict ?? true) {
|
|
1052
|
+
invariant(nearestMatchRouteId == matchRouteId, `useMatch("${matchRouteId}") is being called in a component that is meant to render the '${nearestMatchRouteId}' route. Did you mean to 'useMatch("${matchRouteId}", { strict: false })' or 'useRoute("${matchRouteId}")' instead?`);
|
|
1053
|
+
}
|
|
1054
|
+
const matchSelection = useRouterState({
|
|
1055
|
+
select: state => {
|
|
1056
|
+
const match = getRenderedMatches(state).find(d => d.id === nearestMatchId);
|
|
1057
|
+
invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
|
|
1058
|
+
return opts?.select ? opts.select(match) : match;
|
|
1059
|
+
}
|
|
1060
|
+
});
|
|
1061
|
+
return matchSelection;
|
|
1062
|
+
}
|
|
1063
|
+
function useMatches(opts) {
|
|
1064
|
+
return useRouterState({
|
|
1065
|
+
select: state => {
|
|
1066
|
+
let matches = getRenderedMatches(state);
|
|
1067
|
+
return opts?.select ? opts.select(matches) : matches;
|
|
1068
|
+
}
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
function useParentMatches(opts) {
|
|
1072
|
+
const contextMatchId = React__namespace.useContext(matchContext);
|
|
1073
|
+
return useMatches({
|
|
1074
|
+
select: matches => {
|
|
1075
|
+
matches = matches.slice(matches.findIndex(d => d.id === contextMatchId));
|
|
1076
|
+
return opts?.select ? opts.select(matches) : matches;
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
function useLoaderDeps(opts) {
|
|
1081
|
+
return useMatch({
|
|
1082
|
+
...opts,
|
|
1083
|
+
select: s => {
|
|
1084
|
+
return typeof opts.select === 'function' ? opts.select(s?.loaderDeps) : s?.loaderDeps;
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
function useLoaderData(opts) {
|
|
1089
|
+
return useMatch({
|
|
1090
|
+
...opts,
|
|
1091
|
+
select: s => {
|
|
1092
|
+
return typeof opts.select === 'function' ? opts.select(s?.loaderData) : s?.loaderData;
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
exports.routerContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
1098
|
+
if (typeof document !== 'undefined') {
|
|
1099
|
+
if (window.__TSR_ROUTER_CONTEXT__) {
|
|
1100
|
+
exports.routerContext = window.__TSR_ROUTER_CONTEXT__;
|
|
1101
|
+
} else {
|
|
1102
|
+
window.__TSR_ROUTER_CONTEXT__ = exports.routerContext;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
function RouterProvider({
|
|
1106
|
+
router,
|
|
1107
|
+
...rest
|
|
1108
|
+
}) {
|
|
1109
|
+
// Allow the router to update options on the router instance
|
|
1110
|
+
router.update({
|
|
1111
|
+
...router.options,
|
|
1112
|
+
...rest,
|
|
1113
|
+
context: {
|
|
1114
|
+
...router.options.context,
|
|
1115
|
+
...rest?.context
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
const matches = router.options.InnerWrap ? /*#__PURE__*/React__namespace.createElement(router.options.InnerWrap, null, /*#__PURE__*/React__namespace.createElement(Matches, null)) : /*#__PURE__*/React__namespace.createElement(Matches, null);
|
|
1119
|
+
const provider = /*#__PURE__*/React__namespace.createElement(exports.routerContext.Provider, {
|
|
1120
|
+
value: router
|
|
1121
|
+
}, matches, /*#__PURE__*/React__namespace.createElement(Transitioner, null));
|
|
1122
|
+
if (router.options.Wrap) {
|
|
1123
|
+
return /*#__PURE__*/React__namespace.createElement(router.options.Wrap, null, provider);
|
|
1124
|
+
}
|
|
1125
|
+
return provider;
|
|
1126
|
+
}
|
|
1127
|
+
function Transitioner() {
|
|
1128
|
+
const router = useRouter();
|
|
1129
|
+
const routerState = useRouterState({
|
|
1130
|
+
select: s => pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning'])
|
|
1131
|
+
});
|
|
1132
|
+
const [isTransitioning, startReactTransition] = React__namespace.useTransition();
|
|
1133
|
+
router.startReactTransition = startReactTransition;
|
|
1134
|
+
React__namespace.useEffect(() => {
|
|
1135
|
+
if (isTransitioning) {
|
|
1136
|
+
router.__store.setState(s => ({
|
|
1137
|
+
...s,
|
|
1138
|
+
isTransitioning
|
|
1139
|
+
}));
|
|
1140
|
+
}
|
|
1141
|
+
}, [isTransitioning]);
|
|
1142
|
+
const tryLoad = () => {
|
|
1143
|
+
const apply = cb => {
|
|
1144
|
+
if (!routerState.isTransitioning) {
|
|
1145
|
+
startReactTransition(() => cb());
|
|
1146
|
+
} else {
|
|
1147
|
+
cb();
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
apply(() => {
|
|
1151
|
+
try {
|
|
1152
|
+
router.load();
|
|
1153
|
+
} catch (err) {
|
|
1154
|
+
console.error(err);
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
};
|
|
1158
|
+
useLayoutEffect$1(() => {
|
|
1159
|
+
const unsub = router.history.subscribe(() => {
|
|
1160
|
+
router.latestLocation = router.parseLocation(router.latestLocation);
|
|
1161
|
+
if (routerState.location !== router.latestLocation) {
|
|
1162
|
+
tryLoad();
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
const nextLocation = router.buildLocation({
|
|
1166
|
+
search: true,
|
|
1167
|
+
params: true,
|
|
1168
|
+
hash: true,
|
|
1169
|
+
state: true
|
|
1170
|
+
});
|
|
1171
|
+
if (routerState.location.href !== nextLocation.href) {
|
|
1172
|
+
router.commitLocation({
|
|
1173
|
+
...nextLocation,
|
|
1174
|
+
replace: true
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
return () => {
|
|
1178
|
+
unsub();
|
|
1179
|
+
};
|
|
1180
|
+
}, [router.history]);
|
|
1181
|
+
useLayoutEffect$1(() => {
|
|
1182
|
+
if (routerState.isTransitioning && !isTransitioning && !routerState.isLoading && routerState.resolvedLocation !== routerState.location) {
|
|
1183
|
+
router.emit({
|
|
1184
|
+
type: 'onResolved',
|
|
1185
|
+
fromLocation: routerState.resolvedLocation,
|
|
1186
|
+
toLocation: routerState.location,
|
|
1187
|
+
pathChanged: routerState.location.href !== routerState.resolvedLocation?.href
|
|
1188
|
+
});
|
|
1189
|
+
if (document.querySelector) {
|
|
1190
|
+
if (routerState.location.hash !== '') {
|
|
1191
|
+
const el = document.getElementById(routerState.location.hash);
|
|
1192
|
+
if (el) {
|
|
1193
|
+
el.scrollIntoView();
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
router.__store.setState(s => ({
|
|
1198
|
+
...s,
|
|
1199
|
+
isTransitioning: false,
|
|
1200
|
+
resolvedLocation: s.location
|
|
1201
|
+
}));
|
|
1202
|
+
}
|
|
1203
|
+
}, [routerState.isTransitioning, isTransitioning, routerState.isLoading, routerState.resolvedLocation, routerState.location]);
|
|
1204
|
+
useLayoutEffect$1(() => {
|
|
1205
|
+
if (!window.__TSR_DEHYDRATED__) {
|
|
1206
|
+
tryLoad();
|
|
1207
|
+
}
|
|
1208
|
+
}, []);
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
function getRouteMatch(state, id) {
|
|
1212
|
+
return [...state.cachedMatches, ...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
1213
|
+
}
|
|
1214
|
+
function useRouterState(opts) {
|
|
1215
|
+
const router = useRouter();
|
|
1216
|
+
return useStore(router.__store, opts?.select);
|
|
1217
|
+
}
|
|
1218
|
+
function useRouter() {
|
|
1219
|
+
const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || exports.routerContext : exports.routerContext;
|
|
1220
|
+
const value = React__namespace.useContext(resolvedContext);
|
|
1221
|
+
warning(value, 'useRouter must be used inside a <RouterProvider> component!');
|
|
1222
|
+
return value;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
function defer(_promise) {
|
|
1226
|
+
const promise = _promise;
|
|
1227
|
+
if (!promise.__deferredState) {
|
|
1228
|
+
promise.__deferredState = {
|
|
1229
|
+
uid: Math.random().toString(36).slice(2),
|
|
1230
|
+
status: 'pending'
|
|
1231
|
+
};
|
|
1232
|
+
const state = promise.__deferredState;
|
|
1233
|
+
promise.then(data => {
|
|
1234
|
+
state.status = 'success';
|
|
1235
|
+
state.data = data;
|
|
1236
|
+
}).catch(error => {
|
|
1237
|
+
state.status = 'error';
|
|
1238
|
+
state.error = error;
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
return promise;
|
|
1242
|
+
}
|
|
1243
|
+
function isDehydratedDeferred(obj) {
|
|
1244
|
+
return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
function useAwaited({
|
|
1248
|
+
promise
|
|
1249
|
+
}) {
|
|
1250
|
+
const router = useRouter();
|
|
1251
|
+
let state = promise.__deferredState;
|
|
1252
|
+
const key = `__TSR__DEFERRED__${state.uid}`;
|
|
1253
|
+
if (isDehydratedDeferred(promise)) {
|
|
1254
|
+
state = router.hydrateData(key);
|
|
1255
|
+
promise = Promise.resolve(state.data);
|
|
1256
|
+
promise.__deferredState = state;
|
|
1257
|
+
}
|
|
1258
|
+
if (state.status === 'pending') {
|
|
1259
|
+
throw new Promise(r => setTimeout(r, 1)).then(() => promise);
|
|
459
1260
|
}
|
|
460
|
-
if (
|
|
461
|
-
|
|
1261
|
+
if (state.status === 'error') {
|
|
1262
|
+
throw state.error;
|
|
462
1263
|
}
|
|
463
|
-
|
|
1264
|
+
router.dehydrateData(key, state);
|
|
1265
|
+
return [state.data];
|
|
1266
|
+
}
|
|
1267
|
+
function Await(props) {
|
|
1268
|
+
const awaited = useAwaited(props);
|
|
1269
|
+
return props.children(...awaited);
|
|
464
1270
|
}
|
|
465
1271
|
|
|
466
1272
|
function joinPaths(paths) {
|
|
@@ -554,45 +1360,59 @@
|
|
|
554
1360
|
}
|
|
555
1361
|
return segments;
|
|
556
1362
|
}
|
|
557
|
-
function interpolatePath(path, params,
|
|
1363
|
+
function interpolatePath(path, params, leaveWildcards = false) {
|
|
558
1364
|
const interpolatedPathSegments = parsePathname(path);
|
|
559
1365
|
return joinPaths(interpolatedPathSegments.map(segment => {
|
|
560
|
-
if (
|
|
561
|
-
|
|
1366
|
+
if (segment.type === 'wildcard') {
|
|
1367
|
+
const value = params[segment.value];
|
|
1368
|
+
if (leaveWildcards) return `${segment.value}${value ?? ''}`;
|
|
1369
|
+
return value;
|
|
562
1370
|
}
|
|
563
1371
|
if (segment.type === 'param') {
|
|
564
|
-
return params[segment.value.substring(1)] ?? '';
|
|
1372
|
+
return params[segment.value.substring(1)] ?? 'undefined';
|
|
565
1373
|
}
|
|
566
1374
|
return segment.value;
|
|
567
1375
|
}));
|
|
568
1376
|
}
|
|
569
1377
|
function matchPathname(basepath, currentPathname, matchLocation) {
|
|
570
1378
|
const pathParams = matchByPath(basepath, currentPathname, matchLocation);
|
|
571
|
-
// const searchMatched = matchBySearch(
|
|
1379
|
+
// const searchMatched = matchBySearch(location.search, matchLocation)
|
|
572
1380
|
|
|
573
1381
|
if (matchLocation.to && !pathParams) {
|
|
574
1382
|
return;
|
|
575
1383
|
}
|
|
576
1384
|
return pathParams ?? {};
|
|
577
1385
|
}
|
|
1386
|
+
function removeBasepath(basepath, pathname) {
|
|
1387
|
+
return basepath != '/' ? pathname.substring(basepath.length) : pathname;
|
|
1388
|
+
}
|
|
578
1389
|
function matchByPath(basepath, from, matchLocation) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
from = basepath != '/' ? from.substring(basepath.length) : from;
|
|
583
|
-
const baseSegments = parsePathname(from);
|
|
1390
|
+
// Remove the base path from the pathname
|
|
1391
|
+
from = removeBasepath(basepath, from);
|
|
1392
|
+
// Default to to $ (wildcard)
|
|
584
1393
|
const to = `${matchLocation.to ?? '$'}`;
|
|
1394
|
+
// Parse the from and to
|
|
1395
|
+
const baseSegments = parsePathname(from);
|
|
585
1396
|
const routeSegments = parsePathname(to);
|
|
586
|
-
if (
|
|
587
|
-
baseSegments.
|
|
1397
|
+
if (!from.startsWith('/')) {
|
|
1398
|
+
baseSegments.unshift({
|
|
1399
|
+
type: 'pathname',
|
|
1400
|
+
value: '/'
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
if (!to.startsWith('/')) {
|
|
1404
|
+
routeSegments.unshift({
|
|
1405
|
+
type: 'pathname',
|
|
1406
|
+
value: '/'
|
|
1407
|
+
});
|
|
588
1408
|
}
|
|
589
1409
|
const params = {};
|
|
590
1410
|
let isMatch = (() => {
|
|
591
1411
|
for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
|
|
592
1412
|
const baseSegment = baseSegments[i];
|
|
593
1413
|
const routeSegment = routeSegments[i];
|
|
594
|
-
const
|
|
595
|
-
const
|
|
1414
|
+
const isLastBaseSegment = i >= baseSegments.length - 1;
|
|
1415
|
+
const isLastRouteSegment = i >= routeSegments.length - 1;
|
|
596
1416
|
if (routeSegment) {
|
|
597
1417
|
if (routeSegment.type === 'wildcard') {
|
|
598
1418
|
if (baseSegment?.value) {
|
|
@@ -627,8 +1447,9 @@
|
|
|
627
1447
|
}
|
|
628
1448
|
}
|
|
629
1449
|
}
|
|
630
|
-
if (
|
|
631
|
-
|
|
1450
|
+
if (!isLastBaseSegment && isLastRouteSegment) {
|
|
1451
|
+
params['**'] = joinPaths(baseSegments.slice(i + 1).map(d => d.value));
|
|
1452
|
+
return !!matchLocation.fuzzy && routeSegment?.value !== '/';
|
|
632
1453
|
}
|
|
633
1454
|
}
|
|
634
1455
|
return true;
|
|
@@ -636,6 +1457,417 @@
|
|
|
636
1457
|
return isMatch ? params : undefined;
|
|
637
1458
|
}
|
|
638
1459
|
|
|
1460
|
+
function useParams(opts) {
|
|
1461
|
+
return useRouterState({
|
|
1462
|
+
select: state => {
|
|
1463
|
+
const params = last(state.matches)?.params;
|
|
1464
|
+
return opts?.select ? opts.select(params) : params;
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
function useSearch(opts) {
|
|
1470
|
+
return useMatch({
|
|
1471
|
+
...opts,
|
|
1472
|
+
select: match => {
|
|
1473
|
+
return opts?.select ? opts.select(match.search) : match.search;
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
const rootRouteId = '__root__';
|
|
1479
|
+
|
|
1480
|
+
// The parse type here allows a zod schema to be passed directly to the validator
|
|
1481
|
+
|
|
1482
|
+
class RouteApi {
|
|
1483
|
+
constructor({
|
|
1484
|
+
id
|
|
1485
|
+
}) {
|
|
1486
|
+
this.id = id;
|
|
1487
|
+
}
|
|
1488
|
+
useMatch = opts => {
|
|
1489
|
+
return useMatch({
|
|
1490
|
+
...opts,
|
|
1491
|
+
from: this.id
|
|
1492
|
+
});
|
|
1493
|
+
};
|
|
1494
|
+
useRouteContext = opts => {
|
|
1495
|
+
return useMatch({
|
|
1496
|
+
...opts,
|
|
1497
|
+
from: this.id,
|
|
1498
|
+
select: d => opts?.select ? opts.select(d.context) : d.context
|
|
1499
|
+
});
|
|
1500
|
+
};
|
|
1501
|
+
useSearch = opts => {
|
|
1502
|
+
return useSearch({
|
|
1503
|
+
...opts,
|
|
1504
|
+
from: this.id
|
|
1505
|
+
});
|
|
1506
|
+
};
|
|
1507
|
+
useParams = opts => {
|
|
1508
|
+
return useParams({
|
|
1509
|
+
...opts,
|
|
1510
|
+
from: this.id
|
|
1511
|
+
});
|
|
1512
|
+
};
|
|
1513
|
+
useLoaderDeps = opts => {
|
|
1514
|
+
return useLoaderDeps({
|
|
1515
|
+
...opts,
|
|
1516
|
+
from: this.id
|
|
1517
|
+
});
|
|
1518
|
+
};
|
|
1519
|
+
useLoaderData = opts => {
|
|
1520
|
+
return useLoaderData({
|
|
1521
|
+
...opts,
|
|
1522
|
+
from: this.id
|
|
1523
|
+
});
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
class Route {
|
|
1527
|
+
// Set up in this.init()
|
|
1528
|
+
|
|
1529
|
+
// customId!: TCustomId
|
|
1530
|
+
|
|
1531
|
+
// Optional
|
|
1532
|
+
|
|
1533
|
+
constructor(options) {
|
|
1534
|
+
this.options = options || {};
|
|
1535
|
+
this.isRoot = !options?.getParentRoute;
|
|
1536
|
+
invariant(!(options?.id && options?.path), `Route cannot have both an 'id' and a 'path' option.`);
|
|
1537
|
+
this.$$typeof = Symbol.for('react.memo');
|
|
1538
|
+
}
|
|
1539
|
+
init = opts => {
|
|
1540
|
+
this.originalIndex = opts.originalIndex;
|
|
1541
|
+
const options = this.options;
|
|
1542
|
+
const isRoot = !options?.path && !options?.id;
|
|
1543
|
+
this.parentRoute = this.options?.getParentRoute?.();
|
|
1544
|
+
if (isRoot) {
|
|
1545
|
+
this.path = rootRouteId;
|
|
1546
|
+
} else {
|
|
1547
|
+
invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
|
|
1548
|
+
}
|
|
1549
|
+
let path = isRoot ? rootRouteId : options.path;
|
|
1550
|
+
|
|
1551
|
+
// If the path is anything other than an index path, trim it up
|
|
1552
|
+
if (path && path !== '/') {
|
|
1553
|
+
path = trimPath(path);
|
|
1554
|
+
}
|
|
1555
|
+
const customId = options?.id || path;
|
|
1556
|
+
|
|
1557
|
+
// Strip the parentId prefix from the first level of children
|
|
1558
|
+
let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
|
|
1559
|
+
if (path === rootRouteId) {
|
|
1560
|
+
path = '/';
|
|
1561
|
+
}
|
|
1562
|
+
if (id !== rootRouteId) {
|
|
1563
|
+
id = joinPaths(['/', id]);
|
|
1564
|
+
}
|
|
1565
|
+
const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
|
|
1566
|
+
this.path = path;
|
|
1567
|
+
this.id = id;
|
|
1568
|
+
// this.customId = customId as TCustomId
|
|
1569
|
+
this.fullPath = fullPath;
|
|
1570
|
+
this.to = fullPath;
|
|
1571
|
+
};
|
|
1572
|
+
addChildren = children => {
|
|
1573
|
+
this.children = children;
|
|
1574
|
+
return this;
|
|
1575
|
+
};
|
|
1576
|
+
update = options => {
|
|
1577
|
+
Object.assign(this.options, options);
|
|
1578
|
+
return this;
|
|
1579
|
+
};
|
|
1580
|
+
useMatch = opts => {
|
|
1581
|
+
return useMatch({
|
|
1582
|
+
...opts,
|
|
1583
|
+
from: this.id
|
|
1584
|
+
});
|
|
1585
|
+
};
|
|
1586
|
+
useRouteContext = opts => {
|
|
1587
|
+
return useMatch({
|
|
1588
|
+
...opts,
|
|
1589
|
+
from: this.id,
|
|
1590
|
+
select: d => opts?.select ? opts.select(d.context) : d.context
|
|
1591
|
+
});
|
|
1592
|
+
};
|
|
1593
|
+
useSearch = opts => {
|
|
1594
|
+
return useSearch({
|
|
1595
|
+
...opts,
|
|
1596
|
+
from: this.id
|
|
1597
|
+
});
|
|
1598
|
+
};
|
|
1599
|
+
useParams = opts => {
|
|
1600
|
+
return useParams({
|
|
1601
|
+
...opts,
|
|
1602
|
+
from: this.id
|
|
1603
|
+
});
|
|
1604
|
+
};
|
|
1605
|
+
useLoaderDeps = opts => {
|
|
1606
|
+
return useLoaderDeps({
|
|
1607
|
+
...opts,
|
|
1608
|
+
from: this.id
|
|
1609
|
+
});
|
|
1610
|
+
};
|
|
1611
|
+
useLoaderData = opts => {
|
|
1612
|
+
return useLoaderData({
|
|
1613
|
+
...opts,
|
|
1614
|
+
from: this.id
|
|
1615
|
+
});
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
function rootRouteWithContext() {
|
|
1619
|
+
return options => {
|
|
1620
|
+
return new RootRoute(options);
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
class RootRoute extends Route {
|
|
1624
|
+
constructor(options) {
|
|
1625
|
+
super(options);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
function createRouteMask(opts) {
|
|
1629
|
+
return opts;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
//
|
|
1633
|
+
|
|
1634
|
+
class NotFoundRoute extends Route {
|
|
1635
|
+
constructor(options) {
|
|
1636
|
+
super({
|
|
1637
|
+
...options,
|
|
1638
|
+
id: '404'
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
class FileRoute {
|
|
1644
|
+
constructor(path) {
|
|
1645
|
+
this.path = path;
|
|
1646
|
+
}
|
|
1647
|
+
createRoute = options => {
|
|
1648
|
+
const route = new Route(options);
|
|
1649
|
+
route.isRoot = false;
|
|
1650
|
+
return route;
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
function lazyRouteComponent(importer, exportName) {
|
|
1655
|
+
let loadPromise;
|
|
1656
|
+
const load = () => {
|
|
1657
|
+
if (!loadPromise) {
|
|
1658
|
+
loadPromise = importer();
|
|
1659
|
+
}
|
|
1660
|
+
return loadPromise;
|
|
1661
|
+
};
|
|
1662
|
+
const lazyComp = /*#__PURE__*/React__namespace.lazy(async () => {
|
|
1663
|
+
const moduleExports = await load();
|
|
1664
|
+
const comp = moduleExports[exportName ?? 'default'];
|
|
1665
|
+
return {
|
|
1666
|
+
default: comp
|
|
1667
|
+
};
|
|
1668
|
+
});
|
|
1669
|
+
lazyComp.preload = load;
|
|
1670
|
+
return lazyComp;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
function _extends() {
|
|
1674
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
1675
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
1676
|
+
var source = arguments[i];
|
|
1677
|
+
for (var key in source) {
|
|
1678
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1679
|
+
target[key] = source[key];
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
return target;
|
|
1684
|
+
};
|
|
1685
|
+
return _extends.apply(this, arguments);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
const preloadWarning = 'Error preloading route! ☝️';
|
|
1689
|
+
function useLinkProps(options) {
|
|
1690
|
+
const router = useRouter();
|
|
1691
|
+
const matchPathname = useMatch({
|
|
1692
|
+
strict: false,
|
|
1693
|
+
select: s => s.pathname
|
|
1694
|
+
});
|
|
1695
|
+
const {
|
|
1696
|
+
// custom props
|
|
1697
|
+
children,
|
|
1698
|
+
target,
|
|
1699
|
+
activeProps = () => ({
|
|
1700
|
+
className: 'active'
|
|
1701
|
+
}),
|
|
1702
|
+
inactiveProps = () => ({}),
|
|
1703
|
+
activeOptions,
|
|
1704
|
+
disabled,
|
|
1705
|
+
hash,
|
|
1706
|
+
search,
|
|
1707
|
+
params,
|
|
1708
|
+
to,
|
|
1709
|
+
state,
|
|
1710
|
+
mask,
|
|
1711
|
+
preload: userPreload,
|
|
1712
|
+
preloadDelay: userPreloadDelay,
|
|
1713
|
+
replace,
|
|
1714
|
+
startTransition,
|
|
1715
|
+
resetScroll,
|
|
1716
|
+
// element props
|
|
1717
|
+
style,
|
|
1718
|
+
className,
|
|
1719
|
+
onClick,
|
|
1720
|
+
onFocus,
|
|
1721
|
+
onMouseEnter,
|
|
1722
|
+
onMouseLeave,
|
|
1723
|
+
onTouchStart,
|
|
1724
|
+
...rest
|
|
1725
|
+
} = options;
|
|
1726
|
+
|
|
1727
|
+
// If this link simply reloads the current route,
|
|
1728
|
+
// make sure it has a new key so it will trigger a data refresh
|
|
1729
|
+
|
|
1730
|
+
// If this `to` is a valid external URL, return
|
|
1731
|
+
// null for LinkUtils
|
|
1732
|
+
|
|
1733
|
+
const dest = {
|
|
1734
|
+
from: options.to ? matchPathname : undefined,
|
|
1735
|
+
...options
|
|
1736
|
+
};
|
|
1737
|
+
let type = 'internal';
|
|
1738
|
+
try {
|
|
1739
|
+
new URL(`${to}`);
|
|
1740
|
+
type = 'external';
|
|
1741
|
+
} catch {}
|
|
1742
|
+
if (type === 'external') {
|
|
1743
|
+
return {
|
|
1744
|
+
href: to
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
const next = router.buildLocation(dest);
|
|
1748
|
+
const preload = userPreload ?? router.options.defaultPreload;
|
|
1749
|
+
const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0;
|
|
1750
|
+
const isActive = useRouterState({
|
|
1751
|
+
select: s => {
|
|
1752
|
+
// Compare path/hash for matches
|
|
1753
|
+
const currentPathSplit = s.location.pathname.split('/');
|
|
1754
|
+
const nextPathSplit = next.pathname.split('/');
|
|
1755
|
+
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1756
|
+
// Combine the matches based on user router.options
|
|
1757
|
+
const pathTest = activeOptions?.exact ? s.location.pathname === next.pathname : pathIsFuzzyEqual;
|
|
1758
|
+
const hashTest = activeOptions?.includeHash ? s.location.hash === next.hash : true;
|
|
1759
|
+
const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(s.location.search, next.search, !activeOptions?.exact) : true;
|
|
1760
|
+
|
|
1761
|
+
// The final "active" test
|
|
1762
|
+
return pathTest && hashTest && searchTest;
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1765
|
+
|
|
1766
|
+
// The click handler
|
|
1767
|
+
const handleClick = e => {
|
|
1768
|
+
if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
|
|
1769
|
+
e.preventDefault();
|
|
1770
|
+
|
|
1771
|
+
// All is well? Navigate!
|
|
1772
|
+
router.commitLocation({
|
|
1773
|
+
...next,
|
|
1774
|
+
replace,
|
|
1775
|
+
resetScroll,
|
|
1776
|
+
startTransition
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
|
|
1781
|
+
// The click handler
|
|
1782
|
+
const handleFocus = e => {
|
|
1783
|
+
if (preload) {
|
|
1784
|
+
router.preloadRoute(dest).catch(err => {
|
|
1785
|
+
console.warn(err);
|
|
1786
|
+
console.warn(preloadWarning);
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
const handleTouchStart = e => {
|
|
1791
|
+
if (preload) {
|
|
1792
|
+
router.preloadRoute(dest).catch(err => {
|
|
1793
|
+
console.warn(err);
|
|
1794
|
+
console.warn(preloadWarning);
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
const handleEnter = e => {
|
|
1799
|
+
const target = e.target || {};
|
|
1800
|
+
if (preload) {
|
|
1801
|
+
if (target.preloadTimeout) {
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
target.preloadTimeout = setTimeout(() => {
|
|
1805
|
+
target.preloadTimeout = null;
|
|
1806
|
+
router.preloadRoute(dest).catch(err => {
|
|
1807
|
+
console.warn(err);
|
|
1808
|
+
console.warn(preloadWarning);
|
|
1809
|
+
});
|
|
1810
|
+
}, preloadDelay);
|
|
1811
|
+
}
|
|
1812
|
+
};
|
|
1813
|
+
const handleLeave = e => {
|
|
1814
|
+
const target = e.target || {};
|
|
1815
|
+
if (target.preloadTimeout) {
|
|
1816
|
+
clearTimeout(target.preloadTimeout);
|
|
1817
|
+
target.preloadTimeout = null;
|
|
1818
|
+
}
|
|
1819
|
+
};
|
|
1820
|
+
const composeHandlers = handlers => e => {
|
|
1821
|
+
if (e.persist) e.persist();
|
|
1822
|
+
handlers.filter(Boolean).forEach(handler => {
|
|
1823
|
+
if (e.defaultPrevented) return;
|
|
1824
|
+
handler(e);
|
|
1825
|
+
});
|
|
1826
|
+
};
|
|
1827
|
+
|
|
1828
|
+
// Get the active props
|
|
1829
|
+
const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
|
|
1830
|
+
|
|
1831
|
+
// Get the inactive props
|
|
1832
|
+
const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
|
|
1833
|
+
return {
|
|
1834
|
+
...resolvedActiveProps,
|
|
1835
|
+
...resolvedInactiveProps,
|
|
1836
|
+
...rest,
|
|
1837
|
+
href: disabled ? undefined : next.maskedLocation ? next.maskedLocation.href : next.href,
|
|
1838
|
+
onClick: composeHandlers([onClick, handleClick]),
|
|
1839
|
+
onFocus: composeHandlers([onFocus, handleFocus]),
|
|
1840
|
+
onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
|
|
1841
|
+
onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
|
|
1842
|
+
onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
|
|
1843
|
+
target,
|
|
1844
|
+
style: {
|
|
1845
|
+
...style,
|
|
1846
|
+
...resolvedActiveProps.style,
|
|
1847
|
+
...resolvedInactiveProps.style
|
|
1848
|
+
},
|
|
1849
|
+
className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
|
|
1850
|
+
...(disabled ? {
|
|
1851
|
+
role: 'link',
|
|
1852
|
+
'aria-disabled': true
|
|
1853
|
+
} : undefined),
|
|
1854
|
+
['data-status']: isActive ? 'active' : undefined
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
1858
|
+
const linkProps = useLinkProps(props);
|
|
1859
|
+
return /*#__PURE__*/React__namespace.createElement("a", _extends({
|
|
1860
|
+
ref: ref
|
|
1861
|
+
}, linkProps, {
|
|
1862
|
+
children: typeof props.children === 'function' ? props.children({
|
|
1863
|
+
isActive: linkProps['data-status'] === 'active'
|
|
1864
|
+
}) : props.children
|
|
1865
|
+
}));
|
|
1866
|
+
});
|
|
1867
|
+
function isCtrlEvent(e) {
|
|
1868
|
+
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
639
1871
|
// @ts-nocheck
|
|
640
1872
|
|
|
641
1873
|
// qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
|
|
@@ -665,8 +1897,7 @@
|
|
|
665
1897
|
var str = decodeURIComponent(mix);
|
|
666
1898
|
if (str === 'false') return false;
|
|
667
1899
|
if (str === 'true') return true;
|
|
668
|
-
|
|
669
|
-
return +str * 0 === 0 ? +str : str;
|
|
1900
|
+
return +str * 0 === 0 && +str + '' === str ? +str : str;
|
|
670
1901
|
}
|
|
671
1902
|
function decode(str) {
|
|
672
1903
|
var tmp,
|
|
@@ -685,1650 +1916,1452 @@
|
|
|
685
1916
|
return out;
|
|
686
1917
|
}
|
|
687
1918
|
|
|
688
|
-
|
|
689
|
-
class Route {
|
|
690
|
-
// Set up in this.init()
|
|
691
|
-
|
|
692
|
-
// customId!: TCustomId
|
|
693
|
-
|
|
694
|
-
// Optional
|
|
695
|
-
|
|
696
|
-
constructor(options) {
|
|
697
|
-
this.options = options || {};
|
|
698
|
-
this.isRoot = !options?.getParentRoute;
|
|
699
|
-
}
|
|
700
|
-
init = opts => {
|
|
701
|
-
this.originalIndex = opts.originalIndex;
|
|
702
|
-
this.router = opts.router;
|
|
703
|
-
const allOptions = this.options;
|
|
704
|
-
const isRoot = !allOptions?.path && !allOptions?.id;
|
|
705
|
-
this.parentRoute = this.options?.getParentRoute?.();
|
|
706
|
-
if (isRoot) {
|
|
707
|
-
this.path = rootRouteId;
|
|
708
|
-
} else {
|
|
709
|
-
invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
|
|
710
|
-
}
|
|
711
|
-
let path = isRoot ? rootRouteId : allOptions.path;
|
|
712
|
-
|
|
713
|
-
// If the path is anything other than an index path, trim it up
|
|
714
|
-
if (path && path !== '/') {
|
|
715
|
-
path = trimPath(path);
|
|
716
|
-
}
|
|
717
|
-
const customId = allOptions?.id || path;
|
|
718
|
-
|
|
719
|
-
// Strip the parentId prefix from the first level of children
|
|
720
|
-
let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
|
|
721
|
-
if (path === rootRouteId) {
|
|
722
|
-
path = '/';
|
|
723
|
-
}
|
|
724
|
-
if (id !== rootRouteId) {
|
|
725
|
-
id = joinPaths(['/', id]);
|
|
726
|
-
}
|
|
727
|
-
const fullPath = id === rootRouteId ? '/' : trimPathRight(joinPaths([this.parentRoute.fullPath, path]));
|
|
728
|
-
this.path = path;
|
|
729
|
-
this.id = id;
|
|
730
|
-
// this.customId = customId as TCustomId
|
|
731
|
-
this.fullPath = fullPath;
|
|
732
|
-
};
|
|
733
|
-
addChildren = children => {
|
|
734
|
-
this.children = children;
|
|
735
|
-
return this;
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
// generate = (
|
|
739
|
-
// options: Omit<
|
|
740
|
-
// RouteOptions<
|
|
741
|
-
// TParentRoute,
|
|
742
|
-
// TCustomId,
|
|
743
|
-
// TPath,
|
|
744
|
-
// InferFullSearchSchema<TParentRoute>,
|
|
745
|
-
// TSearchSchema,
|
|
746
|
-
// TFullSearchSchema,
|
|
747
|
-
// TParentRoute['__types']['allParams'],
|
|
748
|
-
// TParams,
|
|
749
|
-
// TAllParams,
|
|
750
|
-
// TParentContext,
|
|
751
|
-
// TAllParentContext,
|
|
752
|
-
// TRouteContext,
|
|
753
|
-
// TContext
|
|
754
|
-
// >,
|
|
755
|
-
// 'path'
|
|
756
|
-
// >,
|
|
757
|
-
// ) => {
|
|
758
|
-
// invariant(
|
|
759
|
-
// false,
|
|
760
|
-
// `route.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. `,
|
|
761
|
-
// )
|
|
762
|
-
// }
|
|
763
|
-
}
|
|
1919
|
+
// Detect if we're in the DOM
|
|
764
1920
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
1921
|
+
function redirect(opts) {
|
|
1922
|
+
opts.isRedirect = true;
|
|
1923
|
+
if (opts.throw) {
|
|
1924
|
+
throw opts;
|
|
768
1925
|
}
|
|
769
|
-
|
|
770
|
-
return options => new RootRoute(options);
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// const rootRoute = new RootRoute({
|
|
775
|
-
// validateSearch: () => null as unknown as { root?: boolean },
|
|
776
|
-
// })
|
|
777
|
-
|
|
778
|
-
// const aRoute = new Route({
|
|
779
|
-
// getParentRoute: () => rootRoute,
|
|
780
|
-
// path: 'a',
|
|
781
|
-
// validateSearch: () => null as unknown as { a?: string },
|
|
782
|
-
// })
|
|
783
|
-
|
|
784
|
-
// const bRoute = new Route({
|
|
785
|
-
// getParentRoute: () => aRoute,
|
|
786
|
-
// path: 'b',
|
|
787
|
-
// })
|
|
788
|
-
|
|
789
|
-
// const rootIsRoot = rootRoute.isRoot
|
|
790
|
-
// // ^?
|
|
791
|
-
// const aIsRoot = aRoute.isRoot
|
|
792
|
-
// // ^?
|
|
793
|
-
|
|
794
|
-
// const rId = rootRoute.id
|
|
795
|
-
// // ^?
|
|
796
|
-
// const aId = aRoute.id
|
|
797
|
-
// // ^?
|
|
798
|
-
// const bId = bRoute.id
|
|
799
|
-
// // ^?
|
|
800
|
-
|
|
801
|
-
// const rPath = rootRoute.fullPath
|
|
802
|
-
// // ^?
|
|
803
|
-
// const aPath = aRoute.fullPath
|
|
804
|
-
// // ^?
|
|
805
|
-
// const bPath = bRoute.fullPath
|
|
806
|
-
// // ^?
|
|
807
|
-
|
|
808
|
-
// const rSearch = rootRoute.__types.fullSearchSchema
|
|
809
|
-
// // ^?
|
|
810
|
-
// const aSearch = aRoute.__types.fullSearchSchema
|
|
811
|
-
// // ^?
|
|
812
|
-
// const bSearch = bRoute.__types.fullSearchSchema
|
|
813
|
-
// // ^?
|
|
814
|
-
|
|
815
|
-
// const config = rootRoute.addChildren([aRoute.addChildren([bRoute])])
|
|
816
|
-
// // ^?
|
|
817
|
-
|
|
818
|
-
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
819
|
-
const defaultStringifySearch = stringifySearchWith(JSON.stringify);
|
|
820
|
-
function parseSearchWith(parser) {
|
|
821
|
-
return searchStr => {
|
|
822
|
-
if (searchStr.substring(0, 1) === '?') {
|
|
823
|
-
searchStr = searchStr.substring(1);
|
|
824
|
-
}
|
|
825
|
-
let query = decode(searchStr);
|
|
826
|
-
|
|
827
|
-
// Try to parse any query params that might be json
|
|
828
|
-
for (let key in query) {
|
|
829
|
-
const value = query[key];
|
|
830
|
-
if (typeof value === 'string') {
|
|
831
|
-
try {
|
|
832
|
-
query[key] = parser(value);
|
|
833
|
-
} catch (err) {
|
|
834
|
-
//
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
return query;
|
|
839
|
-
};
|
|
1926
|
+
return opts;
|
|
840
1927
|
}
|
|
841
|
-
function
|
|
842
|
-
return
|
|
843
|
-
search = {
|
|
844
|
-
...search
|
|
845
|
-
};
|
|
846
|
-
if (search) {
|
|
847
|
-
Object.keys(search).forEach(key => {
|
|
848
|
-
const val = search[key];
|
|
849
|
-
if (typeof val === 'undefined' || val === undefined) {
|
|
850
|
-
delete search[key];
|
|
851
|
-
} else if (val && typeof val === 'object' && val !== null) {
|
|
852
|
-
try {
|
|
853
|
-
search[key] = stringify(val);
|
|
854
|
-
} catch (err) {
|
|
855
|
-
// silent
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
const searchStr = encode(search).toString();
|
|
861
|
-
return searchStr ? `?${searchStr}` : '';
|
|
862
|
-
};
|
|
1928
|
+
function isRedirect(obj) {
|
|
1929
|
+
return !!obj?.isRedirect;
|
|
863
1930
|
}
|
|
864
1931
|
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
search: d => ({
|
|
872
|
-
...(d ?? {}),
|
|
873
|
-
__data: {
|
|
874
|
-
matchId: routeMatch.id
|
|
875
|
-
}
|
|
876
|
-
})
|
|
877
|
-
});
|
|
878
|
-
const res = await fetch(next.href, {
|
|
879
|
-
method: 'GET',
|
|
880
|
-
signal: routeMatch.abortController.signal
|
|
881
|
-
});
|
|
882
|
-
if (res.ok) {
|
|
883
|
-
return res.json();
|
|
884
|
-
}
|
|
885
|
-
throw new Error('Failed to fetch match data');
|
|
886
|
-
};
|
|
887
|
-
class Router {
|
|
888
|
-
#unsubHistory;
|
|
889
|
-
startedLoadingAt = Date.now();
|
|
890
|
-
resolveNavigation = () => {};
|
|
891
|
-
constructor(options) {
|
|
892
|
-
this.options = {
|
|
893
|
-
defaultPreloadDelay: 50,
|
|
894
|
-
context: undefined,
|
|
895
|
-
...options,
|
|
896
|
-
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
897
|
-
parseSearch: options?.parseSearch ?? defaultParseSearch,
|
|
898
|
-
fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn
|
|
899
|
-
};
|
|
900
|
-
this.__store = new Store(getInitialRouterState(), {
|
|
901
|
-
onUpdate: state => {
|
|
902
|
-
this.state = state;
|
|
903
|
-
}
|
|
904
|
-
});
|
|
905
|
-
this.state = this.__store.state;
|
|
906
|
-
this.basepath = '';
|
|
907
|
-
this.update(options);
|
|
908
|
-
|
|
909
|
-
// Allow frameworks to hook into the router creation
|
|
910
|
-
this.options.Router?.(this);
|
|
911
|
-
const next = this.buildNext({
|
|
912
|
-
hash: true,
|
|
913
|
-
fromCurrent: true,
|
|
914
|
-
search: true,
|
|
915
|
-
state: true
|
|
916
|
-
});
|
|
917
|
-
if (this.state.latestLocation.href !== next.href) {
|
|
918
|
-
this.#commitLocation({
|
|
919
|
-
...next,
|
|
920
|
-
replace: true
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
reset = () => {
|
|
925
|
-
this.__store.setState(s => Object.assign(s, getInitialRouterState()));
|
|
926
|
-
};
|
|
927
|
-
mount = () => {
|
|
928
|
-
// Mount only does anything on the client
|
|
929
|
-
if (!isServer) {
|
|
930
|
-
// If the router matches are empty, start loading the matches
|
|
931
|
-
if (!this.state.currentMatches.length) {
|
|
932
|
-
this.safeLoad();
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
return () => {};
|
|
936
|
-
};
|
|
937
|
-
update = opts => {
|
|
938
|
-
Object.assign(this.options, opts);
|
|
939
|
-
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
940
|
-
if (this.#unsubHistory) {
|
|
941
|
-
this.#unsubHistory();
|
|
942
|
-
}
|
|
943
|
-
this.history = this.options.history ?? (isServer ? createMemoryHistory() : createBrowserHistory());
|
|
944
|
-
const parsedLocation = this.#parseLocation();
|
|
945
|
-
this.__store.setState(s => ({
|
|
946
|
-
...s,
|
|
947
|
-
latestLocation: parsedLocation,
|
|
948
|
-
currentLocation: parsedLocation
|
|
949
|
-
}));
|
|
950
|
-
this.#unsubHistory = this.history.listen(() => {
|
|
951
|
-
this.safeLoad({
|
|
952
|
-
next: this.#parseLocation(this.state.latestLocation)
|
|
953
|
-
});
|
|
954
|
-
});
|
|
955
|
-
}
|
|
956
|
-
const {
|
|
957
|
-
basepath,
|
|
958
|
-
routeTree
|
|
959
|
-
} = this.options;
|
|
960
|
-
this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
|
|
961
|
-
if (routeTree) {
|
|
962
|
-
this.routesById = {};
|
|
963
|
-
this.routeTree = this.#buildRouteTree(routeTree);
|
|
964
|
-
}
|
|
965
|
-
return this;
|
|
966
|
-
};
|
|
967
|
-
buildNext = opts => {
|
|
968
|
-
const next = this.#buildLocation(opts);
|
|
969
|
-
const __matches = this.matchRoutes(next.pathname);
|
|
970
|
-
return this.#buildLocation({
|
|
971
|
-
...opts,
|
|
972
|
-
__matches
|
|
973
|
-
});
|
|
974
|
-
};
|
|
975
|
-
cancelMatches = () => {
|
|
976
|
-
[...this.state.currentMatches, ...(this.state.pendingMatches || [])].forEach(match => {
|
|
977
|
-
match.cancel();
|
|
978
|
-
});
|
|
979
|
-
};
|
|
980
|
-
safeLoad = opts => {
|
|
981
|
-
this.load(opts).catch(err => {
|
|
982
|
-
console.warn(err);
|
|
983
|
-
invariant(false, 'Encountered an error during router.load()! ☝️.');
|
|
984
|
-
});
|
|
985
|
-
};
|
|
986
|
-
load = async opts => {
|
|
987
|
-
let now = Date.now();
|
|
988
|
-
const startedAt = now;
|
|
989
|
-
this.startedLoadingAt = startedAt;
|
|
990
|
-
|
|
991
|
-
// Cancel any pending matches
|
|
992
|
-
this.cancelMatches();
|
|
993
|
-
let matches;
|
|
994
|
-
this.__store.batch(() => {
|
|
995
|
-
if (opts?.next) {
|
|
996
|
-
// Ingest the new location
|
|
997
|
-
this.__store.setState(s => ({
|
|
998
|
-
...s,
|
|
999
|
-
latestLocation: opts.next
|
|
1000
|
-
}));
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
// Match the routes
|
|
1004
|
-
matches = this.matchRoutes(this.state.latestLocation.pathname, {
|
|
1005
|
-
strictParseParams: true
|
|
1006
|
-
});
|
|
1007
|
-
this.__store.setState(s => ({
|
|
1008
|
-
...s,
|
|
1009
|
-
status: 'pending',
|
|
1010
|
-
pendingMatches: matches,
|
|
1011
|
-
pendingLocation: this.state.latestLocation
|
|
1012
|
-
}));
|
|
1013
|
-
});
|
|
1014
|
-
|
|
1015
|
-
// Load the matches
|
|
1016
|
-
await this.loadMatches(matches, this.state.pendingLocation
|
|
1017
|
-
// opts
|
|
1018
|
-
);
|
|
1019
|
-
|
|
1020
|
-
if (this.startedLoadingAt !== startedAt) {
|
|
1021
|
-
// Ignore side-effects of outdated side-effects
|
|
1022
|
-
return this.navigationPromise;
|
|
1023
|
-
}
|
|
1024
|
-
const previousMatches = this.state.currentMatches;
|
|
1025
|
-
const exiting = [],
|
|
1026
|
-
staying = [];
|
|
1027
|
-
previousMatches.forEach(d => {
|
|
1028
|
-
if (matches.find(dd => dd.id === d.id)) {
|
|
1029
|
-
staying.push(d);
|
|
1030
|
-
} else {
|
|
1031
|
-
exiting.push(d);
|
|
1032
|
-
}
|
|
1033
|
-
});
|
|
1034
|
-
const entering = matches.filter(d => {
|
|
1035
|
-
return !previousMatches.find(dd => dd.id === d.id);
|
|
1036
|
-
});
|
|
1037
|
-
now = Date.now();
|
|
1038
|
-
exiting.forEach(d => {
|
|
1039
|
-
d.__onExit?.({
|
|
1040
|
-
params: d.params,
|
|
1041
|
-
search: d.state.routeSearch
|
|
1042
|
-
});
|
|
1043
|
-
|
|
1044
|
-
// Clear non-loading error states when match leaves
|
|
1045
|
-
if (d.state.status === 'error') {
|
|
1046
|
-
this.__store.setState(s => ({
|
|
1047
|
-
...s,
|
|
1048
|
-
status: 'idle',
|
|
1049
|
-
error: undefined
|
|
1050
|
-
}));
|
|
1051
|
-
}
|
|
1052
|
-
});
|
|
1053
|
-
staying.forEach(d => {
|
|
1054
|
-
d.route.options.onTransition?.({
|
|
1055
|
-
params: d.params,
|
|
1056
|
-
search: d.state.routeSearch
|
|
1057
|
-
});
|
|
1058
|
-
});
|
|
1059
|
-
entering.forEach(d => {
|
|
1060
|
-
d.__onExit = d.route.options.onLoaded?.({
|
|
1061
|
-
params: d.params,
|
|
1062
|
-
search: d.state.search
|
|
1063
|
-
});
|
|
1064
|
-
});
|
|
1065
|
-
const prevLocation = this.state.currentLocation;
|
|
1066
|
-
this.__store.setState(s => ({
|
|
1067
|
-
...s,
|
|
1068
|
-
status: 'idle',
|
|
1069
|
-
currentLocation: this.state.latestLocation,
|
|
1070
|
-
currentMatches: matches,
|
|
1071
|
-
pendingLocation: undefined,
|
|
1072
|
-
pendingMatches: undefined
|
|
1073
|
-
}));
|
|
1074
|
-
matches.forEach(match => {
|
|
1075
|
-
match.__commit();
|
|
1076
|
-
});
|
|
1077
|
-
if (prevLocation.href !== this.state.currentLocation.href) {
|
|
1078
|
-
this.options.onRouteChange?.();
|
|
1079
|
-
}
|
|
1080
|
-
this.resolveNavigation();
|
|
1081
|
-
};
|
|
1082
|
-
getRoute = id => {
|
|
1083
|
-
const route = this.routesById[id];
|
|
1084
|
-
invariant(route, `Route with id "${id}" not found`);
|
|
1085
|
-
return route;
|
|
1086
|
-
};
|
|
1087
|
-
loadRoute = async (navigateOpts = this.state.latestLocation) => {
|
|
1088
|
-
const next = this.buildNext(navigateOpts);
|
|
1089
|
-
const matches = this.matchRoutes(next.pathname, {
|
|
1090
|
-
strictParseParams: true
|
|
1091
|
-
});
|
|
1092
|
-
await this.loadMatches(matches, next);
|
|
1093
|
-
return matches;
|
|
1094
|
-
};
|
|
1095
|
-
preloadRoute = async (navigateOpts = this.state.latestLocation) => {
|
|
1096
|
-
const next = this.buildNext(navigateOpts);
|
|
1097
|
-
const matches = this.matchRoutes(next.pathname, {
|
|
1098
|
-
strictParseParams: true
|
|
1099
|
-
});
|
|
1100
|
-
await this.loadMatches(matches, next, {
|
|
1101
|
-
preload: true
|
|
1102
|
-
});
|
|
1103
|
-
return matches;
|
|
1104
|
-
};
|
|
1105
|
-
matchRoutes = (pathname, opts) => {
|
|
1106
|
-
const matches = [];
|
|
1107
|
-
if (!this.routeTree) {
|
|
1108
|
-
return matches;
|
|
1109
|
-
}
|
|
1110
|
-
const existingMatches = [...this.state.currentMatches, ...(this.state.pendingMatches ?? [])];
|
|
1111
|
-
const findInRouteTree = async routes => {
|
|
1112
|
-
const parentMatch = last(matches);
|
|
1113
|
-
let params = parentMatch?.params ?? {};
|
|
1114
|
-
const filteredRoutes = this.options.filterRoutes?.(routes) ?? routes;
|
|
1115
|
-
let matchingRoutes = [];
|
|
1116
|
-
const findMatchInRoutes = (parentRoutes, routes) => {
|
|
1117
|
-
routes.some(route => {
|
|
1118
|
-
const children = route.children;
|
|
1119
|
-
if (!route.path && children?.length) {
|
|
1120
|
-
return findMatchInRoutes([...matchingRoutes, route], children);
|
|
1121
|
-
}
|
|
1122
|
-
const fuzzy = !!(route.path !== '/' || children?.length);
|
|
1123
|
-
const matchParams = matchPathname(this.basepath, pathname, {
|
|
1124
|
-
to: route.fullPath,
|
|
1125
|
-
fuzzy,
|
|
1126
|
-
caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive
|
|
1127
|
-
});
|
|
1128
|
-
if (matchParams) {
|
|
1129
|
-
let parsedParams;
|
|
1130
|
-
try {
|
|
1131
|
-
parsedParams = route.options.parseParams?.(matchParams) ?? matchParams;
|
|
1132
|
-
} catch (err) {
|
|
1133
|
-
if (opts?.strictParseParams) {
|
|
1134
|
-
throw err;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
params = {
|
|
1138
|
-
...params,
|
|
1139
|
-
...parsedParams
|
|
1140
|
-
};
|
|
1141
|
-
}
|
|
1142
|
-
if (!!matchParams) {
|
|
1143
|
-
matchingRoutes = [...parentRoutes, route];
|
|
1144
|
-
}
|
|
1145
|
-
return !!matchingRoutes.length;
|
|
1146
|
-
});
|
|
1147
|
-
return !!matchingRoutes.length;
|
|
1148
|
-
};
|
|
1149
|
-
findMatchInRoutes([], filteredRoutes);
|
|
1150
|
-
if (!matchingRoutes.length) {
|
|
1151
|
-
return;
|
|
1152
|
-
}
|
|
1153
|
-
matchingRoutes.forEach(foundRoute => {
|
|
1154
|
-
const interpolatedPath = interpolatePath(foundRoute.path, params);
|
|
1155
|
-
const matchId = interpolatePath(foundRoute.id, params, true);
|
|
1156
|
-
const match = existingMatches.find(d => d.id === matchId) || new RouteMatch(this, foundRoute, {
|
|
1157
|
-
id: matchId,
|
|
1158
|
-
params,
|
|
1159
|
-
pathname: joinPaths([this.basepath, interpolatedPath])
|
|
1160
|
-
});
|
|
1161
|
-
matches.push(match);
|
|
1162
|
-
});
|
|
1163
|
-
const foundRoute = last(matchingRoutes);
|
|
1164
|
-
const foundChildren = foundRoute.children;
|
|
1165
|
-
if (foundChildren?.length) {
|
|
1166
|
-
findInRouteTree(foundChildren);
|
|
1167
|
-
}
|
|
1168
|
-
};
|
|
1169
|
-
findInRouteTree([this.routeTree]);
|
|
1170
|
-
return matches;
|
|
1171
|
-
};
|
|
1172
|
-
loadMatches = async (resolvedMatches, location, opts) => {
|
|
1173
|
-
let firstBadMatchIndex;
|
|
1174
|
-
|
|
1175
|
-
// Check each match middleware to see if the route can be accessed
|
|
1176
|
-
try {
|
|
1177
|
-
await Promise.all(resolvedMatches.map(async (match, index) => {
|
|
1178
|
-
try {
|
|
1179
|
-
await match.route.options.beforeLoad?.({
|
|
1180
|
-
router: this,
|
|
1181
|
-
match
|
|
1182
|
-
});
|
|
1183
|
-
} catch (err) {
|
|
1184
|
-
if (isRedirect(err)) {
|
|
1185
|
-
throw err;
|
|
1186
|
-
}
|
|
1187
|
-
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
1188
|
-
const errorHandler = match.route.options.onBeforeLoadError ?? match.route.options.onError;
|
|
1189
|
-
try {
|
|
1190
|
-
errorHandler?.(err);
|
|
1191
|
-
} catch (errorHandlerErr) {
|
|
1192
|
-
if (isRedirect(errorHandlerErr)) {
|
|
1193
|
-
throw errorHandlerErr;
|
|
1194
|
-
}
|
|
1195
|
-
match.__store.setState(s => ({
|
|
1196
|
-
...s,
|
|
1197
|
-
error: errorHandlerErr,
|
|
1198
|
-
status: 'error',
|
|
1199
|
-
updatedAt: Date.now()
|
|
1200
|
-
}));
|
|
1201
|
-
return;
|
|
1202
|
-
}
|
|
1203
|
-
match.__store.setState(s => ({
|
|
1204
|
-
...s,
|
|
1205
|
-
error: err,
|
|
1206
|
-
status: 'error',
|
|
1207
|
-
updatedAt: Date.now()
|
|
1208
|
-
}));
|
|
1209
|
-
}
|
|
1210
|
-
}));
|
|
1211
|
-
} catch (err) {
|
|
1212
|
-
if (isRedirect(err)) {
|
|
1213
|
-
if (!opts?.preload) {
|
|
1214
|
-
this.navigate(err);
|
|
1215
|
-
}
|
|
1216
|
-
return;
|
|
1217
|
-
}
|
|
1218
|
-
throw err; // we should never end up here
|
|
1932
|
+
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
1933
|
+
const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
|
|
1934
|
+
function parseSearchWith(parser) {
|
|
1935
|
+
return searchStr => {
|
|
1936
|
+
if (searchStr.substring(0, 1) === '?') {
|
|
1937
|
+
searchStr = searchStr.substring(1);
|
|
1219
1938
|
}
|
|
1939
|
+
let query = decode(searchStr);
|
|
1220
1940
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
const
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
if (parentMatch) {
|
|
1231
|
-
await parentMatch.__loadPromise;
|
|
1941
|
+
// Try to parse any query params that might be json
|
|
1942
|
+
for (let key in query) {
|
|
1943
|
+
const value = query[key];
|
|
1944
|
+
if (typeof value === 'string') {
|
|
1945
|
+
try {
|
|
1946
|
+
query[key] = parser(value);
|
|
1947
|
+
} catch (err) {
|
|
1948
|
+
//
|
|
1949
|
+
}
|
|
1232
1950
|
}
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
};
|
|
1236
|
-
reload = () => {
|
|
1237
|
-
this.navigate({
|
|
1238
|
-
fromCurrent: true,
|
|
1239
|
-
replace: true,
|
|
1240
|
-
search: true
|
|
1241
|
-
});
|
|
1951
|
+
}
|
|
1952
|
+
return query;
|
|
1242
1953
|
};
|
|
1243
|
-
|
|
1244
|
-
|
|
1954
|
+
}
|
|
1955
|
+
function stringifySearchWith(stringify, parser) {
|
|
1956
|
+
function stringifyValue(val) {
|
|
1957
|
+
if (typeof val === 'object' && val !== null) {
|
|
1958
|
+
try {
|
|
1959
|
+
return stringify(val);
|
|
1960
|
+
} catch (err) {
|
|
1961
|
+
// silent
|
|
1962
|
+
}
|
|
1963
|
+
} else if (typeof val === 'string' && typeof parser === 'function') {
|
|
1964
|
+
try {
|
|
1965
|
+
// Check if it's a valid parseable string.
|
|
1966
|
+
// If it is, then stringify it again.
|
|
1967
|
+
parser(val);
|
|
1968
|
+
return stringify(val);
|
|
1969
|
+
} catch (err) {
|
|
1970
|
+
// silent
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
return val;
|
|
1974
|
+
}
|
|
1975
|
+
return search => {
|
|
1976
|
+
search = {
|
|
1977
|
+
...search
|
|
1978
|
+
};
|
|
1979
|
+
if (search) {
|
|
1980
|
+
Object.keys(search).forEach(key => {
|
|
1981
|
+
const val = search[key];
|
|
1982
|
+
if (typeof val === 'undefined' || val === undefined) {
|
|
1983
|
+
delete search[key];
|
|
1984
|
+
} else {
|
|
1985
|
+
search[key] = stringifyValue(val);
|
|
1986
|
+
}
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
const searchStr = encode(search).toString();
|
|
1990
|
+
return searchStr ? `?${searchStr}` : '';
|
|
1245
1991
|
};
|
|
1246
|
-
|
|
1247
|
-
from,
|
|
1248
|
-
to = '',
|
|
1249
|
-
search,
|
|
1250
|
-
hash,
|
|
1251
|
-
replace,
|
|
1252
|
-
params
|
|
1253
|
-
}) => {
|
|
1254
|
-
// If this link simply reloads the current route,
|
|
1255
|
-
// make sure it has a new key so it will trigger a data refresh
|
|
1992
|
+
}
|
|
1256
1993
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1994
|
+
// import warning from 'tiny-warning'
|
|
1995
|
+
|
|
1996
|
+
//
|
|
1997
|
+
|
|
1998
|
+
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
1999
|
+
class Router {
|
|
2000
|
+
// Option-independent properties
|
|
2001
|
+
tempLocationKey = `${Math.round(Math.random() * 10000000)}`;
|
|
2002
|
+
resetNextScroll = true;
|
|
2003
|
+
navigateTimeout = null;
|
|
2004
|
+
latestLoadPromise = Promise.resolve();
|
|
2005
|
+
subscribers = new Set();
|
|
2006
|
+
injectedHtml = [];
|
|
2007
|
+
|
|
2008
|
+
// Must build in constructor
|
|
2009
|
+
|
|
2010
|
+
constructor(options) {
|
|
2011
|
+
this.update({
|
|
2012
|
+
defaultPreloadDelay: 50,
|
|
2013
|
+
defaultPendingMs: 1000,
|
|
2014
|
+
defaultPendingMinMs: 500,
|
|
2015
|
+
context: undefined,
|
|
2016
|
+
...options,
|
|
2017
|
+
stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
|
|
2018
|
+
parseSearch: options?.parseSearch ?? defaultParseSearch
|
|
1274
2019
|
});
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
// These are default implementations that can optionally be overridden
|
|
2023
|
+
// by the router provider once rendered. We provide these so that the
|
|
2024
|
+
// router can be used in a non-react environment if necessary
|
|
2025
|
+
startReactTransition = fn => fn();
|
|
2026
|
+
update = newOptions => {
|
|
2027
|
+
this.options = {
|
|
2028
|
+
...this.options,
|
|
2029
|
+
...newOptions
|
|
1280
2030
|
};
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
2031
|
+
this.basepath = `/${trimPath(newOptions.basepath ?? '') ?? ''}`;
|
|
2032
|
+
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
2033
|
+
this.history = this.options.history ?? (typeof document !== 'undefined' ? createBrowserHistory() : createMemoryHistory());
|
|
2034
|
+
this.latestLocation = this.parseLocation();
|
|
1285
2035
|
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
});
|
|
1290
|
-
if (!match) {
|
|
1291
|
-
return false;
|
|
2036
|
+
if (this.options.routeTree !== this.routeTree) {
|
|
2037
|
+
this.routeTree = this.options.routeTree;
|
|
2038
|
+
this.buildRouteTree();
|
|
1292
2039
|
}
|
|
1293
|
-
if (
|
|
1294
|
-
|
|
2040
|
+
if (!this.__store) {
|
|
2041
|
+
this.__store = new Store(getInitialRouterState(this.latestLocation), {
|
|
2042
|
+
onUpdate: () => {
|
|
2043
|
+
this.__store.state = {
|
|
2044
|
+
...this.state,
|
|
2045
|
+
status: this.state.isTransitioning || this.state.isLoading ? 'pending' : 'idle'
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
});
|
|
1295
2049
|
}
|
|
1296
|
-
return match;
|
|
1297
2050
|
};
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
replace
|
|
2051
|
+
get state() {
|
|
2052
|
+
return this.__store.state;
|
|
2053
|
+
}
|
|
2054
|
+
buildRouteTree = () => {
|
|
2055
|
+
this.routesById = {};
|
|
2056
|
+
this.routesByPath = {};
|
|
2057
|
+
const notFoundRoute = this.options.notFoundRoute;
|
|
2058
|
+
if (notFoundRoute) {
|
|
2059
|
+
notFoundRoute.init({
|
|
2060
|
+
originalIndex: 99999999999
|
|
2061
|
+
});
|
|
2062
|
+
this.routesById[notFoundRoute.id] = notFoundRoute;
|
|
2063
|
+
}
|
|
2064
|
+
const recurseRoutes = childRoutes => {
|
|
2065
|
+
childRoutes.forEach((childRoute, i) => {
|
|
2066
|
+
childRoute.init({
|
|
2067
|
+
originalIndex: i
|
|
2068
|
+
});
|
|
2069
|
+
const existingRoute = this.routesById[childRoute.id];
|
|
2070
|
+
invariant(!existingRoute, `Duplicate routes found with id: ${String(childRoute.id)}`);
|
|
2071
|
+
this.routesById[childRoute.id] = childRoute;
|
|
2072
|
+
if (!childRoute.isRoot && childRoute.path) {
|
|
2073
|
+
const trimmedFullPath = trimPathRight(childRoute.fullPath);
|
|
2074
|
+
if (!this.routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith('/')) {
|
|
2075
|
+
this.routesByPath[trimmedFullPath] = childRoute;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
const children = childRoute.children;
|
|
2079
|
+
if (children?.length) {
|
|
2080
|
+
recurseRoutes(children);
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
1331
2083
|
};
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
const currentPathSplit = this.state.currentLocation.pathname.split('/');
|
|
1338
|
-
const nextPathSplit = next.pathname.split('/');
|
|
1339
|
-
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1340
|
-
// Combine the matches based on user options
|
|
1341
|
-
const pathTest = activeOptions?.exact ? this.state.currentLocation.pathname === next.pathname : pathIsFuzzyEqual;
|
|
1342
|
-
const hashTest = activeOptions?.includeHash ? this.state.currentLocation.hash === next.hash : true;
|
|
1343
|
-
const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(this.state.currentLocation.search, next.search) : true;
|
|
1344
|
-
|
|
1345
|
-
// The final "active" test
|
|
1346
|
-
const isActive = pathTest && hashTest && searchTest;
|
|
1347
|
-
|
|
1348
|
-
// The click handler
|
|
1349
|
-
const handleClick = e => {
|
|
1350
|
-
if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
|
|
1351
|
-
e.preventDefault();
|
|
1352
|
-
|
|
1353
|
-
// All is well? Navigate!
|
|
1354
|
-
this.#commitLocation(nextOpts);
|
|
2084
|
+
recurseRoutes([this.routeTree]);
|
|
2085
|
+
const scoredRoutes = [];
|
|
2086
|
+
Object.values(this.routesById).forEach((d, i) => {
|
|
2087
|
+
if (d.isRoot || !d.path) {
|
|
2088
|
+
return;
|
|
1355
2089
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
if (preload) {
|
|
1361
|
-
this.preloadRoute(nextOpts).catch(err => {
|
|
1362
|
-
console.warn(err);
|
|
1363
|
-
console.warn('Error preloading route! ☝️');
|
|
1364
|
-
});
|
|
2090
|
+
const trimmed = trimPathLeft(d.fullPath);
|
|
2091
|
+
const parsed = parsePathname(trimmed);
|
|
2092
|
+
while (parsed.length > 1 && parsed[0]?.value === '/') {
|
|
2093
|
+
parsed.shift();
|
|
1365
2094
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
2095
|
+
const scores = parsed.map(d => {
|
|
2096
|
+
if (d.value === '/') {
|
|
2097
|
+
return 0.75;
|
|
2098
|
+
}
|
|
2099
|
+
if (d.type === 'param') {
|
|
2100
|
+
return 0.5;
|
|
2101
|
+
}
|
|
2102
|
+
if (d.type === 'wildcard') {
|
|
2103
|
+
return 0.25;
|
|
2104
|
+
}
|
|
2105
|
+
return 1;
|
|
1371
2106
|
});
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
2107
|
+
scoredRoutes.push({
|
|
2108
|
+
child: d,
|
|
2109
|
+
trimmed,
|
|
2110
|
+
parsed,
|
|
2111
|
+
index: i,
|
|
2112
|
+
scores
|
|
2113
|
+
});
|
|
2114
|
+
});
|
|
2115
|
+
this.flatRoutes = scoredRoutes.sort((a, b) => {
|
|
2116
|
+
const minLength = Math.min(a.scores.length, b.scores.length);
|
|
2117
|
+
|
|
2118
|
+
// Sort by min available score
|
|
2119
|
+
for (let i = 0; i < minLength; i++) {
|
|
2120
|
+
if (a.scores[i] !== b.scores[i]) {
|
|
2121
|
+
return b.scores[i] - a.scores[i];
|
|
1378
2122
|
}
|
|
1379
|
-
target.preloadTimeout = setTimeout(() => {
|
|
1380
|
-
target.preloadTimeout = null;
|
|
1381
|
-
this.preloadRoute(nextOpts).catch(err => {
|
|
1382
|
-
console.warn(err);
|
|
1383
|
-
console.warn('Error preloading route! ☝️');
|
|
1384
|
-
});
|
|
1385
|
-
}, preloadDelay);
|
|
1386
2123
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
2124
|
+
|
|
2125
|
+
// Sort by length of score
|
|
2126
|
+
if (a.scores.length !== b.scores.length) {
|
|
2127
|
+
return b.scores.length - a.scores.length;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
// Sort by min available parsed value
|
|
2131
|
+
for (let i = 0; i < minLength; i++) {
|
|
2132
|
+
if (a.parsed[i].value !== b.parsed[i].value) {
|
|
2133
|
+
return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
|
|
2134
|
+
}
|
|
1393
2135
|
}
|
|
2136
|
+
|
|
2137
|
+
// Sort by original index
|
|
2138
|
+
return a.index - b.index;
|
|
2139
|
+
}).map((d, i) => {
|
|
2140
|
+
d.child.rank = i;
|
|
2141
|
+
return d.child;
|
|
2142
|
+
});
|
|
2143
|
+
};
|
|
2144
|
+
subscribe = (eventType, fn) => {
|
|
2145
|
+
const listener = {
|
|
2146
|
+
eventType,
|
|
2147
|
+
fn
|
|
1394
2148
|
};
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
handleFocus,
|
|
1399
|
-
handleClick,
|
|
1400
|
-
handleEnter,
|
|
1401
|
-
handleLeave,
|
|
1402
|
-
handleTouchStart,
|
|
1403
|
-
isActive,
|
|
1404
|
-
disabled
|
|
2149
|
+
this.subscribers.add(listener);
|
|
2150
|
+
return () => {
|
|
2151
|
+
this.subscribers.delete(listener);
|
|
1405
2152
|
};
|
|
1406
2153
|
};
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
currentMatches: this.state.currentMatches.map(match => ({
|
|
1412
|
-
id: match.id,
|
|
1413
|
-
state: {
|
|
1414
|
-
status: match.state.status
|
|
1415
|
-
}
|
|
1416
|
-
}))
|
|
2154
|
+
emit = routerEvent => {
|
|
2155
|
+
this.subscribers.forEach(listener => {
|
|
2156
|
+
if (listener.eventType === routerEvent.type) {
|
|
2157
|
+
listener.fn(routerEvent);
|
|
1417
2158
|
}
|
|
1418
|
-
};
|
|
1419
|
-
};
|
|
1420
|
-
hydrate = dehydratedRouter => {
|
|
1421
|
-
this.__store.setState(s => {
|
|
1422
|
-
// Match the routes
|
|
1423
|
-
const currentMatches = this.matchRoutes(dehydratedRouter.state.latestLocation.pathname, {
|
|
1424
|
-
strictParseParams: true
|
|
1425
|
-
});
|
|
1426
|
-
currentMatches.forEach((match, index) => {
|
|
1427
|
-
const dehydratedMatch = dehydratedRouter.state.currentMatches[index];
|
|
1428
|
-
invariant(dehydratedMatch && dehydratedMatch.id === match.id, 'Oh no! There was a hydration mismatch when attempting to hydrate the state of the router! 😬');
|
|
1429
|
-
match.__store.setState(s => ({
|
|
1430
|
-
...s,
|
|
1431
|
-
...dehydratedMatch.state
|
|
1432
|
-
}));
|
|
1433
|
-
});
|
|
1434
|
-
return {
|
|
1435
|
-
...s,
|
|
1436
|
-
...dehydratedRouter.state,
|
|
1437
|
-
currentMatches
|
|
1438
|
-
};
|
|
1439
2159
|
});
|
|
1440
2160
|
};
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
routes.forEach((route, i) => {
|
|
1444
|
-
route.init({
|
|
1445
|
-
originalIndex: i,
|
|
1446
|
-
router: this
|
|
1447
|
-
});
|
|
1448
|
-
const existingRoute = this.routesById[route.id];
|
|
1449
|
-
invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
|
|
1450
|
-
this.routesById[route.id] = route;
|
|
1451
|
-
const children = route.children;
|
|
1452
|
-
if (children?.length) {
|
|
1453
|
-
recurseRoutes(children);
|
|
1454
|
-
route.children = children.map((d, i) => {
|
|
1455
|
-
const parsed = parsePathname(trimPathLeft(cleanPath(d.path ?? '/')));
|
|
1456
|
-
while (parsed.length > 1 && parsed[0]?.value === '/') {
|
|
1457
|
-
parsed.shift();
|
|
1458
|
-
}
|
|
1459
|
-
let score = 0;
|
|
1460
|
-
parsed.forEach((d, i) => {
|
|
1461
|
-
let modifier = 1;
|
|
1462
|
-
while (i--) {
|
|
1463
|
-
modifier *= 0.001;
|
|
1464
|
-
}
|
|
1465
|
-
if (d.type === 'pathname' && d.value !== '/') {
|
|
1466
|
-
score += 1 * modifier;
|
|
1467
|
-
} else if (d.type === 'param') {
|
|
1468
|
-
score += 2 * modifier;
|
|
1469
|
-
} else if (d.type === 'wildcard') {
|
|
1470
|
-
score += 3 * modifier;
|
|
1471
|
-
}
|
|
1472
|
-
});
|
|
1473
|
-
return {
|
|
1474
|
-
child: d,
|
|
1475
|
-
parsed,
|
|
1476
|
-
index: i,
|
|
1477
|
-
score
|
|
1478
|
-
};
|
|
1479
|
-
}).sort((a, b) => {
|
|
1480
|
-
if (a.score !== b.score) {
|
|
1481
|
-
return a.score - b.score;
|
|
1482
|
-
}
|
|
1483
|
-
return a.index - b.index;
|
|
1484
|
-
}).map(d => d.child);
|
|
1485
|
-
}
|
|
1486
|
-
});
|
|
1487
|
-
};
|
|
1488
|
-
recurseRoutes([routeTree]);
|
|
1489
|
-
const recurceCheckRoutes = (routes, parentRoute) => {
|
|
1490
|
-
routes.forEach(route => {
|
|
1491
|
-
if (route.isRoot) {
|
|
1492
|
-
invariant(!parentRoute, 'Root routes can only be used as the root of a route tree.');
|
|
1493
|
-
} else {
|
|
1494
|
-
invariant(parentRoute ? route.parentRoute === parentRoute : true, `Expected a route with path "${route.path}" to be passed to its parent route "${route.parentRoute?.id}" in an addChildren() call, but was instead passed as a child of the "${parentRoute?.id}" route.`);
|
|
1495
|
-
}
|
|
1496
|
-
if (route.children) {
|
|
1497
|
-
recurceCheckRoutes(route.children, route);
|
|
1498
|
-
}
|
|
1499
|
-
});
|
|
1500
|
-
};
|
|
1501
|
-
recurceCheckRoutes([routeTree], undefined);
|
|
1502
|
-
return routeTree;
|
|
2161
|
+
checkLatest = promise => {
|
|
2162
|
+
return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
|
|
1503
2163
|
};
|
|
1504
|
-
|
|
1505
|
-
|
|
2164
|
+
parseLocation = previousLocation => {
|
|
2165
|
+
const parse = ({
|
|
1506
2166
|
pathname,
|
|
1507
2167
|
search,
|
|
1508
2168
|
hash,
|
|
1509
2169
|
state
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
};
|
|
1521
|
-
};
|
|
1522
|
-
#buildLocation = (dest = {}) => {
|
|
1523
|
-
dest.fromCurrent = dest.fromCurrent ?? dest.to === '';
|
|
1524
|
-
const fromPathname = dest.fromCurrent ? this.state.latestLocation.pathname : dest.from ?? this.state.latestLocation.pathname;
|
|
1525
|
-
let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? ''}`);
|
|
1526
|
-
const fromMatches = this.matchRoutes(this.state.latestLocation.pathname, {
|
|
1527
|
-
strictParseParams: true
|
|
1528
|
-
});
|
|
1529
|
-
const prevParams = {
|
|
1530
|
-
...last(fromMatches)?.params
|
|
2170
|
+
}) => {
|
|
2171
|
+
const parsedSearch = this.options.parseSearch(search);
|
|
2172
|
+
return {
|
|
2173
|
+
pathname: pathname,
|
|
2174
|
+
searchStr: search,
|
|
2175
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
2176
|
+
hash: hash.split('#').reverse()[0] ?? '',
|
|
2177
|
+
href: `${pathname}${search}${hash}`,
|
|
2178
|
+
state: replaceEqualDeep(previousLocation?.state, state)
|
|
2179
|
+
};
|
|
1531
2180
|
};
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
2181
|
+
const location = parse(this.history.location);
|
|
2182
|
+
let {
|
|
2183
|
+
__tempLocation,
|
|
2184
|
+
__tempKey
|
|
2185
|
+
} = location.state;
|
|
2186
|
+
if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
|
|
2187
|
+
// Sync up the location keys
|
|
2188
|
+
const parsedTempLocation = parse(__tempLocation);
|
|
2189
|
+
parsedTempLocation.state.key = location.state.key;
|
|
2190
|
+
delete parsedTempLocation.state.__tempLocation;
|
|
2191
|
+
return {
|
|
2192
|
+
...parsedTempLocation,
|
|
2193
|
+
maskedLocation: location
|
|
2194
|
+
};
|
|
1540
2195
|
}
|
|
1541
|
-
|
|
1542
|
-
const preSearchFilters = dest.__matches?.map(match => match.route.options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1543
|
-
const postSearchFilters = dest.__matches?.map(match => match.route.options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
1544
|
-
|
|
1545
|
-
// Pre filters first
|
|
1546
|
-
const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), this.state.latestLocation.search) : this.state.latestLocation.search;
|
|
1547
|
-
|
|
1548
|
-
// Then the link/navigate function
|
|
1549
|
-
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
1550
|
-
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
1551
|
-
: preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
1552
|
-
: {};
|
|
1553
|
-
|
|
1554
|
-
// Then post filters
|
|
1555
|
-
const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1556
|
-
const search = replaceEqualDeep(this.state.latestLocation.search, postFilteredSearch);
|
|
1557
|
-
const searchStr = this.options.stringifySearch(search);
|
|
1558
|
-
let hash = dest.hash === true ? this.state.latestLocation.hash : functionalUpdate(dest.hash, this.state.latestLocation.hash);
|
|
1559
|
-
hash = hash ? `#${hash}` : '';
|
|
1560
|
-
const nextState = dest.state === true ? this.state.latestLocation.state : functionalUpdate(dest.state, this.state.latestLocation.state);
|
|
1561
|
-
return {
|
|
1562
|
-
pathname,
|
|
1563
|
-
search,
|
|
1564
|
-
searchStr,
|
|
1565
|
-
state: nextState,
|
|
1566
|
-
hash,
|
|
1567
|
-
href: this.history.createHref(`${pathname}${searchStr}${hash}`),
|
|
1568
|
-
key: dest.key
|
|
1569
|
-
};
|
|
2196
|
+
return location;
|
|
1570
2197
|
};
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
const id = '' + Date.now() + Math.random();
|
|
1574
|
-
if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
|
|
1575
|
-
let nextAction = 'replace';
|
|
1576
|
-
if (!location.replace) {
|
|
1577
|
-
nextAction = 'push';
|
|
1578
|
-
}
|
|
1579
|
-
const isSameUrl = this.state.latestLocation.href === next.href;
|
|
1580
|
-
if (isSameUrl && !next.key) {
|
|
1581
|
-
nextAction = 'replace';
|
|
1582
|
-
}
|
|
1583
|
-
const href = `${next.pathname}${next.searchStr}${next.hash ? `${next.hash}` : ''}`;
|
|
1584
|
-
this.history[nextAction === 'push' ? 'push' : 'replace'](href, {
|
|
1585
|
-
id,
|
|
1586
|
-
...next.state
|
|
1587
|
-
});
|
|
1588
|
-
return this.navigationPromise = new Promise(resolve => {
|
|
1589
|
-
const previousNavigationResolve = this.resolveNavigation;
|
|
1590
|
-
this.resolveNavigation = () => {
|
|
1591
|
-
previousNavigationResolve();
|
|
1592
|
-
resolve();
|
|
1593
|
-
};
|
|
1594
|
-
});
|
|
2198
|
+
resolvePathWithBase = (from, path) => {
|
|
2199
|
+
return resolvePath(this.basepath, from, cleanPath(path));
|
|
1595
2200
|
};
|
|
1596
|
-
|
|
2201
|
+
get looseRoutesById() {
|
|
2202
|
+
return this.routesById;
|
|
2203
|
+
}
|
|
2204
|
+
matchRoutes = (pathname, locationSearch, opts) => {
|
|
2205
|
+
let routeParams = {};
|
|
2206
|
+
let foundRoute = this.flatRoutes.find(route => {
|
|
2207
|
+
const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
|
|
2208
|
+
to: route.fullPath,
|
|
2209
|
+
caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
|
|
2210
|
+
fuzzy: true
|
|
2211
|
+
});
|
|
2212
|
+
if (matchedParams) {
|
|
2213
|
+
routeParams = matchedParams;
|
|
2214
|
+
return true;
|
|
2215
|
+
}
|
|
2216
|
+
return false;
|
|
2217
|
+
});
|
|
2218
|
+
let routeCursor = foundRoute || this.routesById['__root__'];
|
|
2219
|
+
let matchedRoutes = [routeCursor];
|
|
2220
|
+
|
|
2221
|
+
// Check to see if the route needs a 404 entry
|
|
2222
|
+
if (
|
|
2223
|
+
// If we found a route, and it's not an index route and we have left over path
|
|
2224
|
+
(foundRoute ? foundRoute.path !== '/' && routeParams['**'] :
|
|
2225
|
+
// Or if we didn't find a route and we have left over path
|
|
2226
|
+
trimPathRight(pathname)) &&
|
|
2227
|
+
// And we have a 404 route configured
|
|
2228
|
+
this.options.notFoundRoute) {
|
|
2229
|
+
matchedRoutes.push(this.options.notFoundRoute);
|
|
2230
|
+
}
|
|
2231
|
+
while (routeCursor?.parentRoute) {
|
|
2232
|
+
routeCursor = routeCursor.parentRoute;
|
|
2233
|
+
if (routeCursor) matchedRoutes.unshift(routeCursor);
|
|
2234
|
+
}
|
|
1597
2235
|
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
function getInitialRouterState() {
|
|
1601
|
-
return {
|
|
1602
|
-
status: 'idle',
|
|
1603
|
-
latestLocation: null,
|
|
1604
|
-
currentLocation: null,
|
|
1605
|
-
currentMatches: [],
|
|
1606
|
-
lastUpdated: Date.now()
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
function isCtrlEvent(e) {
|
|
1610
|
-
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
1611
|
-
}
|
|
1612
|
-
function redirect(opts) {
|
|
1613
|
-
opts.isRedirect = true;
|
|
1614
|
-
return opts;
|
|
1615
|
-
}
|
|
1616
|
-
function isRedirect(obj) {
|
|
1617
|
-
return !!obj?.isRedirect;
|
|
1618
|
-
}
|
|
2236
|
+
// Existing matches are matches that are already loaded along with
|
|
2237
|
+
// pending matches that are still loading
|
|
1619
2238
|
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
2239
|
+
const parseErrors = matchedRoutes.map(route => {
|
|
2240
|
+
let parsedParamsError;
|
|
2241
|
+
if (route.options.parseParams) {
|
|
2242
|
+
try {
|
|
2243
|
+
const parsedParams = route.options.parseParams(routeParams);
|
|
2244
|
+
// Add the parsed params to the accumulated params bag
|
|
2245
|
+
Object.assign(routeParams, parsedParams);
|
|
2246
|
+
} catch (err) {
|
|
2247
|
+
parsedParamsError = new PathParamError(err.message, {
|
|
2248
|
+
cause: err
|
|
2249
|
+
});
|
|
2250
|
+
if (opts?.throwOnError) {
|
|
2251
|
+
throw parsedParamsError;
|
|
2252
|
+
}
|
|
2253
|
+
return parsedParamsError;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
return;
|
|
2257
|
+
});
|
|
2258
|
+
const matches = [];
|
|
2259
|
+
matchedRoutes.forEach((route, index) => {
|
|
2260
|
+
// Take each matched route and resolve + validate its search params
|
|
2261
|
+
// This has to happen serially because each route's search params
|
|
2262
|
+
// can depend on the parent route's search params
|
|
2263
|
+
// It must also happen before we create the match so that we can
|
|
2264
|
+
// pass the search params to the route's potential key function
|
|
2265
|
+
// which is used to uniquely identify the route match in state
|
|
2266
|
+
|
|
2267
|
+
const parentMatch = matches[index - 1];
|
|
2268
|
+
const [preMatchSearch, searchError] = (() => {
|
|
2269
|
+
// Validate the search params and stabilize them
|
|
2270
|
+
const parentSearch = parentMatch?.search ?? locationSearch;
|
|
2271
|
+
try {
|
|
2272
|
+
const validator = typeof route.options.validateSearch === 'object' ? route.options.validateSearch.parse : route.options.validateSearch;
|
|
2273
|
+
let search = validator?.(parentSearch) ?? {};
|
|
2274
|
+
return [{
|
|
2275
|
+
...parentSearch,
|
|
2276
|
+
...search
|
|
2277
|
+
}, undefined];
|
|
2278
|
+
} catch (err) {
|
|
2279
|
+
const searchError = new SearchParamError(err.message, {
|
|
2280
|
+
cause: err
|
|
2281
|
+
});
|
|
2282
|
+
if (opts?.throwOnError) {
|
|
2283
|
+
throw searchError;
|
|
2284
|
+
}
|
|
2285
|
+
return [parentSearch, searchError];
|
|
2286
|
+
}
|
|
2287
|
+
})();
|
|
2288
|
+
|
|
2289
|
+
// This is where we need to call route.options.loaderDeps() to get any additional
|
|
2290
|
+
// deps that the route's loader function might need to run. We need to do this
|
|
2291
|
+
// before we create the match so that we can pass the deps to the route's
|
|
2292
|
+
// potential key function which is used to uniquely identify the route match in state
|
|
2293
|
+
|
|
2294
|
+
const loaderDeps = route.options.loaderDeps?.({
|
|
2295
|
+
search: preMatchSearch
|
|
2296
|
+
}) ?? '';
|
|
2297
|
+
const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : '';
|
|
2298
|
+
const interpolatedPath = interpolatePath(route.fullPath, routeParams);
|
|
2299
|
+
const matchId = interpolatePath(route.id, routeParams, true) + loaderDepsHash;
|
|
2300
|
+
|
|
2301
|
+
// Waste not, want not. If we already have a match for this route,
|
|
2302
|
+
// reuse it. This is important for layout routes, which might stick
|
|
2303
|
+
// around between navigation actions that only change leaf routes.
|
|
2304
|
+
const existingMatch = getRouteMatch(this.state, matchId);
|
|
2305
|
+
const cause = this.state.matches.find(d => d.id === matchId) ? 'stay' : 'enter';
|
|
2306
|
+
|
|
2307
|
+
// Create a fresh route match
|
|
2308
|
+
const hasLoaders = !!(route.options.loader || componentTypes.some(d => route.options[d]?.preload));
|
|
2309
|
+
const match = existingMatch ? {
|
|
2310
|
+
...existingMatch,
|
|
2311
|
+
cause
|
|
2312
|
+
} : {
|
|
2313
|
+
id: matchId,
|
|
2314
|
+
routeId: route.id,
|
|
2315
|
+
params: routeParams,
|
|
2316
|
+
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
2317
|
+
updatedAt: Date.now(),
|
|
1633
2318
|
search: {},
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
2319
|
+
searchError: undefined,
|
|
2320
|
+
status: hasLoaders ? 'pending' : 'success',
|
|
2321
|
+
showPending: false,
|
|
2322
|
+
isFetching: false,
|
|
2323
|
+
error: undefined,
|
|
2324
|
+
paramsError: parseErrors[index],
|
|
2325
|
+
loadPromise: Promise.resolve(),
|
|
2326
|
+
routeContext: undefined,
|
|
2327
|
+
context: undefined,
|
|
2328
|
+
abortController: new AbortController(),
|
|
2329
|
+
fetchCount: 0,
|
|
2330
|
+
cause,
|
|
2331
|
+
loaderDeps,
|
|
2332
|
+
invalid: false,
|
|
2333
|
+
preload: false
|
|
2334
|
+
};
|
|
2335
|
+
|
|
2336
|
+
// Regardless of whether we're reusing an existing match or creating
|
|
2337
|
+
// a new one, we need to update the match's search params
|
|
2338
|
+
match.search = replaceEqualDeep(match.search, preMatchSearch);
|
|
2339
|
+
// And also update the searchError if there is one
|
|
2340
|
+
match.searchError = searchError;
|
|
2341
|
+
matches.push(match);
|
|
1647
2342
|
});
|
|
1648
|
-
|
|
1649
|
-
this.__store.setState(s => ({
|
|
1650
|
-
...s,
|
|
1651
|
-
status: 'success'
|
|
1652
|
-
}));
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
#hasLoaders = () => {
|
|
1656
|
-
return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload));
|
|
2343
|
+
return matches;
|
|
1657
2344
|
};
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
routeSearch,
|
|
1661
|
-
search,
|
|
1662
|
-
context,
|
|
1663
|
-
routeContext
|
|
1664
|
-
} = this.#resolveInfo({
|
|
1665
|
-
location: this.router.state.currentLocation
|
|
1666
|
-
});
|
|
1667
|
-
this.context = context;
|
|
1668
|
-
this.routeContext = routeContext;
|
|
1669
|
-
this.__store.setState(s => ({
|
|
1670
|
-
...s,
|
|
1671
|
-
routeSearch: replaceEqualDeep(s.routeSearch, routeSearch),
|
|
1672
|
-
search: replaceEqualDeep(s.search, search)
|
|
1673
|
-
}));
|
|
2345
|
+
cancelMatch = id => {
|
|
2346
|
+
getRouteMatch(this.state, id)?.abortController?.abort();
|
|
1674
2347
|
};
|
|
1675
|
-
|
|
1676
|
-
this.
|
|
2348
|
+
cancelMatches = () => {
|
|
2349
|
+
this.state.pendingMatches?.forEach(match => {
|
|
2350
|
+
this.cancelMatch(match.id);
|
|
2351
|
+
});
|
|
1677
2352
|
};
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
const
|
|
1686
|
-
const
|
|
1687
|
-
|
|
1688
|
-
...parentSearchInfo.search,
|
|
1689
|
-
...routeSearch
|
|
2353
|
+
buildLocation = opts => {
|
|
2354
|
+
const build = (dest = {}, matches) => {
|
|
2355
|
+
const from = this.latestLocation;
|
|
2356
|
+
const fromSearch = (this.state.pendingMatches || this.state.matches).at(-1)?.search || from.search;
|
|
2357
|
+
const fromPathname = dest.from ?? from.pathname;
|
|
2358
|
+
let pathname = this.resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
|
|
2359
|
+
const fromMatches = this.matchRoutes(fromPathname, fromSearch);
|
|
2360
|
+
const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
|
|
2361
|
+
const prevParams = {
|
|
2362
|
+
...last(fromMatches)?.params
|
|
1690
2363
|
};
|
|
2364
|
+
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
2365
|
+
if (nextParams) {
|
|
2366
|
+
matches?.map(d => this.looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
2367
|
+
nextParams = {
|
|
2368
|
+
...nextParams,
|
|
2369
|
+
...fn(nextParams)
|
|
2370
|
+
};
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2373
|
+
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
2374
|
+
const preSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
2375
|
+
const postSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
|
|
2376
|
+
|
|
2377
|
+
// Pre filters first
|
|
2378
|
+
const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), fromSearch) : fromSearch;
|
|
2379
|
+
|
|
2380
|
+
// Then the link/navigate function
|
|
2381
|
+
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
2382
|
+
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
2383
|
+
: preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
2384
|
+
: {};
|
|
2385
|
+
|
|
2386
|
+
// Then post filters
|
|
2387
|
+
const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
2388
|
+
const search = replaceEqualDeep(fromSearch, postFilteredSearch);
|
|
2389
|
+
const searchStr = this.options.stringifySearch(search);
|
|
2390
|
+
const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
|
|
2391
|
+
const hashStr = hash ? `#${hash}` : '';
|
|
2392
|
+
let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
|
|
2393
|
+
nextState = replaceEqualDeep(from.state, nextState);
|
|
1691
2394
|
return {
|
|
1692
|
-
|
|
1693
|
-
search
|
|
2395
|
+
pathname,
|
|
2396
|
+
search,
|
|
2397
|
+
searchStr,
|
|
2398
|
+
state: nextState,
|
|
2399
|
+
hash,
|
|
2400
|
+
href: `${pathname}${searchStr}${hashStr}`,
|
|
2401
|
+
unmaskOnReload: dest.unmaskOnReload
|
|
1694
2402
|
};
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
|
|
2403
|
+
};
|
|
2404
|
+
const buildWithMatches = (dest = {}, maskedDest) => {
|
|
2405
|
+
let next = build(dest);
|
|
2406
|
+
let maskedNext = maskedDest ? build(maskedDest) : undefined;
|
|
2407
|
+
if (!maskedNext) {
|
|
2408
|
+
let params = {};
|
|
2409
|
+
let foundMask = this.options.routeMasks?.find(d => {
|
|
2410
|
+
const match = matchPathname(this.basepath, next.pathname, {
|
|
2411
|
+
to: d.from,
|
|
2412
|
+
caseSensitive: false,
|
|
2413
|
+
fuzzy: false
|
|
2414
|
+
});
|
|
2415
|
+
if (match) {
|
|
2416
|
+
params = match;
|
|
2417
|
+
return true;
|
|
2418
|
+
}
|
|
2419
|
+
return false;
|
|
2420
|
+
});
|
|
2421
|
+
if (foundMask) {
|
|
2422
|
+
foundMask = {
|
|
2423
|
+
...foundMask,
|
|
2424
|
+
from: interpolatePath(foundMask.from, params)
|
|
2425
|
+
};
|
|
2426
|
+
maskedDest = foundMask;
|
|
2427
|
+
maskedNext = build(maskedDest);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
const nextMatches = this.matchRoutes(next.pathname, next.search);
|
|
2431
|
+
const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
|
|
2432
|
+
const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
|
|
2433
|
+
const final = build(dest, nextMatches);
|
|
2434
|
+
if (maskedFinal) {
|
|
2435
|
+
final.maskedLocation = maskedFinal;
|
|
1698
2436
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
2437
|
+
return final;
|
|
2438
|
+
};
|
|
2439
|
+
if (opts.mask) {
|
|
2440
|
+
return buildWithMatches(opts, {
|
|
2441
|
+
...pick(opts, ['from']),
|
|
2442
|
+
...opts.mask
|
|
1703
2443
|
});
|
|
1704
|
-
error.code = 'INVALID_SEARCH_PARAMS';
|
|
1705
|
-
throw error;
|
|
1706
2444
|
}
|
|
2445
|
+
return buildWithMatches(opts);
|
|
1707
2446
|
};
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
2447
|
+
commitLocation = async ({
|
|
2448
|
+
startTransition,
|
|
2449
|
+
...next
|
|
2450
|
+
}) => {
|
|
2451
|
+
if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
|
|
2452
|
+
const isSameUrl = this.latestLocation.href === next.href;
|
|
2453
|
+
|
|
2454
|
+
// If the next urls are the same and we're not replacing,
|
|
2455
|
+
// do nothing
|
|
2456
|
+
if (!isSameUrl || !next.replace) {
|
|
2457
|
+
let {
|
|
2458
|
+
maskedLocation,
|
|
2459
|
+
...nextHistory
|
|
2460
|
+
} = next;
|
|
2461
|
+
if (maskedLocation) {
|
|
2462
|
+
nextHistory = {
|
|
2463
|
+
...maskedLocation,
|
|
2464
|
+
state: {
|
|
2465
|
+
...maskedLocation.state,
|
|
2466
|
+
__tempKey: undefined,
|
|
2467
|
+
__tempLocation: {
|
|
2468
|
+
...nextHistory,
|
|
2469
|
+
search: nextHistory.searchStr,
|
|
2470
|
+
state: {
|
|
2471
|
+
...nextHistory.state,
|
|
2472
|
+
__tempKey: undefined,
|
|
2473
|
+
__tempLocation: undefined,
|
|
2474
|
+
key: undefined
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
};
|
|
2479
|
+
if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
|
|
2480
|
+
nextHistory.state.__tempKey = this.tempLocationKey;
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
const apply = () => {
|
|
2484
|
+
this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
|
|
1729
2485
|
};
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
2486
|
+
if (startTransition ?? true) {
|
|
2487
|
+
this.startReactTransition(apply);
|
|
2488
|
+
} else {
|
|
2489
|
+
apply();
|
|
2490
|
+
}
|
|
1733
2491
|
}
|
|
2492
|
+
this.resetNextScroll = next.resetScroll ?? true;
|
|
2493
|
+
return this.latestLoadPromise;
|
|
2494
|
+
};
|
|
2495
|
+
buildAndCommitLocation = ({
|
|
2496
|
+
replace,
|
|
2497
|
+
resetScroll,
|
|
2498
|
+
startTransition,
|
|
2499
|
+
...rest
|
|
2500
|
+
} = {}) => {
|
|
2501
|
+
const location = this.buildLocation(rest);
|
|
2502
|
+
return this.commitLocation({
|
|
2503
|
+
...location,
|
|
2504
|
+
startTransition,
|
|
2505
|
+
replace,
|
|
2506
|
+
resetScroll
|
|
2507
|
+
});
|
|
1734
2508
|
};
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
2509
|
+
navigate = ({
|
|
2510
|
+
from,
|
|
2511
|
+
to = '',
|
|
2512
|
+
...rest
|
|
2513
|
+
}) => {
|
|
2514
|
+
// If this link simply reloads the current route,
|
|
2515
|
+
// make sure it has a new key so it will trigger a data refresh
|
|
2516
|
+
|
|
2517
|
+
// If this `to` is a valid external URL, return
|
|
2518
|
+
// null for LinkUtils
|
|
2519
|
+
const toString = String(to);
|
|
2520
|
+
const fromString = typeof from === 'undefined' ? from : String(from);
|
|
2521
|
+
let isExternal;
|
|
1738
2522
|
try {
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
2523
|
+
new URL(`${toString}`);
|
|
2524
|
+
isExternal = true;
|
|
2525
|
+
} catch (e) {}
|
|
2526
|
+
invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
|
|
2527
|
+
return this.buildAndCommitLocation({
|
|
2528
|
+
...rest,
|
|
2529
|
+
from: fromString,
|
|
2530
|
+
to: toString
|
|
2531
|
+
});
|
|
2532
|
+
};
|
|
2533
|
+
loadMatches = async ({
|
|
2534
|
+
checkLatest,
|
|
2535
|
+
matches,
|
|
2536
|
+
preload
|
|
2537
|
+
}) => {
|
|
2538
|
+
let latestPromise;
|
|
2539
|
+
let firstBadMatchIndex;
|
|
2540
|
+
const updateMatch = match => {
|
|
2541
|
+
// const isPreload = this.state.cachedMatches.find((d) => d.id === match.id)
|
|
2542
|
+
const isPending = this.state.pendingMatches?.find(d => d.id === match.id);
|
|
2543
|
+
const isMatched = this.state.matches.find(d => d.id === match.id);
|
|
2544
|
+
const matchesKey = isPending ? 'pendingMatches' : isMatched ? 'matches' : 'cachedMatches';
|
|
1747
2545
|
this.__store.setState(s => ({
|
|
1748
2546
|
...s,
|
|
1749
|
-
|
|
1750
|
-
error: err
|
|
2547
|
+
[matchesKey]: s[matchesKey]?.map(d => d.id === match.id ? match : d)
|
|
1751
2548
|
}));
|
|
2549
|
+
};
|
|
1752
2550
|
|
|
1753
|
-
|
|
1754
|
-
|
|
2551
|
+
// Check each match middleware to see if the route can be accessed
|
|
2552
|
+
try {
|
|
2553
|
+
for (let [index, match] of matches.entries()) {
|
|
2554
|
+
const parentMatch = matches[index - 1];
|
|
2555
|
+
const route = this.looseRoutesById[match.routeId];
|
|
2556
|
+
const abortController = new AbortController();
|
|
2557
|
+
const handleErrorAndRedirect = (err, code) => {
|
|
2558
|
+
err.routerCode = code;
|
|
2559
|
+
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
2560
|
+
if (isRedirect(err)) {
|
|
2561
|
+
throw err;
|
|
2562
|
+
}
|
|
2563
|
+
try {
|
|
2564
|
+
route.options.onError?.(err);
|
|
2565
|
+
} catch (errorHandlerErr) {
|
|
2566
|
+
err = errorHandlerErr;
|
|
2567
|
+
if (isRedirect(errorHandlerErr)) {
|
|
2568
|
+
throw errorHandlerErr;
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
matches[index] = match = {
|
|
2572
|
+
...match,
|
|
2573
|
+
error: err,
|
|
2574
|
+
status: 'error',
|
|
2575
|
+
updatedAt: Date.now(),
|
|
2576
|
+
abortController: new AbortController()
|
|
2577
|
+
};
|
|
2578
|
+
};
|
|
2579
|
+
try {
|
|
2580
|
+
if (match.paramsError) {
|
|
2581
|
+
handleErrorAndRedirect(match.paramsError, 'PARSE_PARAMS');
|
|
2582
|
+
}
|
|
2583
|
+
if (match.searchError) {
|
|
2584
|
+
handleErrorAndRedirect(match.searchError, 'VALIDATE_SEARCH');
|
|
2585
|
+
}
|
|
2586
|
+
const parentContext = parentMatch?.context ?? this.options.context ?? {};
|
|
2587
|
+
const beforeLoadContext = (await route.options.beforeLoad?.({
|
|
2588
|
+
search: match.search,
|
|
2589
|
+
abortController,
|
|
2590
|
+
params: match.params,
|
|
2591
|
+
preload: !!preload,
|
|
2592
|
+
context: parentContext,
|
|
2593
|
+
location: this.state.location,
|
|
2594
|
+
// TOOD: just expose state and router, etc
|
|
2595
|
+
navigate: opts => this.navigate({
|
|
2596
|
+
...opts,
|
|
2597
|
+
from: match.pathname
|
|
2598
|
+
}),
|
|
2599
|
+
buildLocation: this.buildLocation,
|
|
2600
|
+
cause: preload ? 'preload' : match.cause
|
|
2601
|
+
})) ?? {};
|
|
2602
|
+
if (isRedirect(beforeLoadContext)) {
|
|
2603
|
+
throw beforeLoadContext;
|
|
2604
|
+
}
|
|
2605
|
+
const context = {
|
|
2606
|
+
...parentContext,
|
|
2607
|
+
...beforeLoadContext
|
|
2608
|
+
};
|
|
2609
|
+
matches[index] = match = {
|
|
2610
|
+
...match,
|
|
2611
|
+
routeContext: replaceEqualDeep(match.routeContext, beforeLoadContext),
|
|
2612
|
+
context: replaceEqualDeep(match.context, context),
|
|
2613
|
+
abortController
|
|
2614
|
+
};
|
|
2615
|
+
} catch (err) {
|
|
2616
|
+
handleErrorAndRedirect(err, 'BEFORE_LOAD');
|
|
2617
|
+
break;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
} catch (err) {
|
|
2621
|
+
if (isRedirect(err)) {
|
|
2622
|
+
if (!preload) this.navigate(err);
|
|
2623
|
+
return matches;
|
|
2624
|
+
}
|
|
2625
|
+
throw err;
|
|
1755
2626
|
}
|
|
1756
|
-
const
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
2627
|
+
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
2628
|
+
const matchPromises = [];
|
|
2629
|
+
validResolvedMatches.forEach((match, index) => {
|
|
2630
|
+
matchPromises.push(new Promise(async resolve => {
|
|
2631
|
+
const parentMatchPromise = matchPromises[index - 1];
|
|
2632
|
+
const route = this.looseRoutesById[match.routeId];
|
|
2633
|
+
const handleErrorAndRedirect = err => {
|
|
2634
|
+
if (isRedirect(err)) {
|
|
2635
|
+
if (!preload) {
|
|
2636
|
+
this.navigate(err);
|
|
2637
|
+
}
|
|
2638
|
+
return true;
|
|
2639
|
+
}
|
|
2640
|
+
return false;
|
|
2641
|
+
};
|
|
2642
|
+
let loadPromise;
|
|
2643
|
+
matches[index] = match = {
|
|
2644
|
+
...match,
|
|
2645
|
+
showPending: false
|
|
2646
|
+
};
|
|
2647
|
+
let didShowPending = false;
|
|
2648
|
+
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
2649
|
+
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
2650
|
+
const shouldPending = !preload && pendingMs && (route.options.pendingComponent ?? this.options.defaultPendingComponent);
|
|
2651
|
+
const loaderContext = {
|
|
2652
|
+
params: match.params,
|
|
2653
|
+
deps: match.loaderDeps,
|
|
2654
|
+
preload: !!preload,
|
|
2655
|
+
parentMatchPromise,
|
|
2656
|
+
abortController: match.abortController,
|
|
2657
|
+
context: match.context,
|
|
2658
|
+
location: this.state.location,
|
|
2659
|
+
navigate: opts => this.navigate({
|
|
2660
|
+
...opts,
|
|
2661
|
+
from: match.pathname
|
|
2662
|
+
}),
|
|
2663
|
+
cause: preload ? 'preload' : match.cause
|
|
2664
|
+
};
|
|
2665
|
+
const fetch = async () => {
|
|
2666
|
+
if (match.isFetching) {
|
|
2667
|
+
loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
|
|
2668
|
+
} else {
|
|
2669
|
+
// If the user doesn't want the route to reload, just
|
|
2670
|
+
// resolve with the existing loader data
|
|
2671
|
+
|
|
2672
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2673
|
+
resolve();
|
|
2674
|
+
}
|
|
1762
2675
|
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
2676
|
+
// Otherwise, load the route
|
|
2677
|
+
matches[index] = match = {
|
|
2678
|
+
...match,
|
|
2679
|
+
isFetching: true,
|
|
2680
|
+
fetchCount: match.fetchCount + 1
|
|
2681
|
+
};
|
|
2682
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2683
|
+
const component = route.options[type];
|
|
2684
|
+
if (component?.preload) {
|
|
2685
|
+
await component.preload();
|
|
2686
|
+
}
|
|
2687
|
+
}));
|
|
2688
|
+
const loaderPromise = route.options.loader?.(loaderContext);
|
|
2689
|
+
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2690
|
+
}
|
|
2691
|
+
matches[index] = match = {
|
|
2692
|
+
...match,
|
|
2693
|
+
loadPromise
|
|
2694
|
+
};
|
|
2695
|
+
updateMatch(match);
|
|
2696
|
+
try {
|
|
2697
|
+
const loaderData = await loadPromise;
|
|
2698
|
+
if (latestPromise = checkLatest()) return await latestPromise;
|
|
2699
|
+
if (isRedirect(loaderData)) {
|
|
2700
|
+
if (handleErrorAndRedirect(loaderData)) return;
|
|
2701
|
+
}
|
|
2702
|
+
if (didShowPending && pendingMinMs) {
|
|
2703
|
+
await new Promise(r => setTimeout(r, pendingMinMs));
|
|
2704
|
+
}
|
|
2705
|
+
if (latestPromise = checkLatest()) return await latestPromise;
|
|
2706
|
+
matches[index] = match = {
|
|
2707
|
+
...match,
|
|
2708
|
+
error: undefined,
|
|
2709
|
+
status: 'success',
|
|
2710
|
+
isFetching: false,
|
|
2711
|
+
updatedAt: Date.now(),
|
|
2712
|
+
loaderData,
|
|
2713
|
+
loadPromise: undefined
|
|
2714
|
+
};
|
|
2715
|
+
} catch (error) {
|
|
2716
|
+
if (latestPromise = checkLatest()) return await latestPromise;
|
|
2717
|
+
if (handleErrorAndRedirect(error)) return;
|
|
2718
|
+
try {
|
|
2719
|
+
route.options.onError?.(error);
|
|
2720
|
+
} catch (onErrorError) {
|
|
2721
|
+
error = onErrorError;
|
|
2722
|
+
if (handleErrorAndRedirect(onErrorError)) return;
|
|
2723
|
+
}
|
|
2724
|
+
matches[index] = match = {
|
|
2725
|
+
...match,
|
|
2726
|
+
error,
|
|
2727
|
+
status: 'error',
|
|
2728
|
+
isFetching: false
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
updateMatch(match);
|
|
2732
|
+
};
|
|
1767
2733
|
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
2734
|
+
// This is where all of the stale-while-revalidate magic happens
|
|
2735
|
+
const age = Date.now() - match.updatedAt;
|
|
2736
|
+
let staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 30_000 // 30 seconds for preloads by default
|
|
2737
|
+
: route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
|
|
2738
|
+
|
|
2739
|
+
// Default to reloading the route all the time
|
|
2740
|
+
let shouldReload;
|
|
2741
|
+
const shouldReloadOption = route.options.shouldReload;
|
|
2742
|
+
|
|
2743
|
+
// Allow shouldReload to get the last say,
|
|
2744
|
+
// if provided.
|
|
2745
|
+
shouldReload = typeof shouldReloadOption === 'function' ? shouldReloadOption(loaderContext) : shouldReloadOption;
|
|
2746
|
+
matches[index] = match = {
|
|
2747
|
+
...match,
|
|
2748
|
+
preload: !!preload && !this.state.matches.find(d => d.id === match.id)
|
|
2749
|
+
};
|
|
2750
|
+
if (match.status !== 'success') {
|
|
2751
|
+
// If we need to potentially show the pending component,
|
|
2752
|
+
// start a timer to show it after the pendingMs
|
|
2753
|
+
if (shouldPending) {
|
|
2754
|
+
new Promise(r => setTimeout(r, pendingMs)).then(async () => {
|
|
2755
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
2756
|
+
didShowPending = true;
|
|
2757
|
+
matches[index] = match = {
|
|
2758
|
+
...match,
|
|
2759
|
+
showPending: true
|
|
2760
|
+
};
|
|
2761
|
+
updateMatch(match);
|
|
2762
|
+
resolve();
|
|
2763
|
+
});
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
// Critical Fetching, we need to await
|
|
2767
|
+
await fetch();
|
|
2768
|
+
} else if (match.invalid || (shouldReload ?? age > staleAge)) {
|
|
2769
|
+
// Background Fetching, no need to wait
|
|
2770
|
+
fetch();
|
|
2771
|
+
}
|
|
2772
|
+
resolve();
|
|
2773
|
+
}));
|
|
2774
|
+
});
|
|
2775
|
+
await Promise.all(matchPromises);
|
|
2776
|
+
return matches;
|
|
2777
|
+
};
|
|
2778
|
+
invalidate = () => {
|
|
2779
|
+
const invalidate = d => ({
|
|
2780
|
+
...d,
|
|
2781
|
+
invalid: true
|
|
2782
|
+
});
|
|
2783
|
+
this.__store.setState(s => ({
|
|
2784
|
+
...s,
|
|
2785
|
+
matches: s.matches.map(invalidate),
|
|
2786
|
+
cachedMatches: s.cachedMatches.map(invalidate),
|
|
2787
|
+
pendingMatches: s.pendingMatches?.map(invalidate)
|
|
2788
|
+
}));
|
|
2789
|
+
this.load();
|
|
2790
|
+
};
|
|
2791
|
+
load = async () => {
|
|
2792
|
+
const promise = new Promise(async (resolve, reject) => {
|
|
2793
|
+
const next = this.latestLocation;
|
|
2794
|
+
const prevLocation = this.state.resolvedLocation;
|
|
2795
|
+
const pathDidChange = prevLocation.href !== next.href;
|
|
1775
2796
|
let latestPromise;
|
|
1776
2797
|
|
|
1777
|
-
//
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
2798
|
+
// Cancel any pending matches
|
|
2799
|
+
this.cancelMatches();
|
|
2800
|
+
this.emit({
|
|
2801
|
+
type: 'onBeforeLoad',
|
|
2802
|
+
fromLocation: prevLocation,
|
|
2803
|
+
toLocation: next,
|
|
2804
|
+
pathChanged: pathDidChange
|
|
2805
|
+
});
|
|
2806
|
+
let pendingMatches;
|
|
2807
|
+
const previousMatches = this.state.matches;
|
|
2808
|
+
this.__store.batch(() => {
|
|
2809
|
+
this.cleanCache();
|
|
2810
|
+
|
|
2811
|
+
// Match the routes
|
|
2812
|
+
pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
2813
|
+
debug: true
|
|
2814
|
+
});
|
|
2815
|
+
|
|
2816
|
+
// Ingest the new matches
|
|
2817
|
+
// If a cached moved to pendingMatches, remove it from cachedMatches
|
|
1781
2818
|
this.__store.setState(s => ({
|
|
1782
2819
|
...s,
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
await Promise.all(componentTypes.map(async type => {
|
|
1791
|
-
const component = this.route.options[type];
|
|
1792
|
-
if (this[type]?.preload) {
|
|
1793
|
-
this[type] = await this.router.options.loadComponent(component);
|
|
1794
|
-
}
|
|
2820
|
+
isLoading: true,
|
|
2821
|
+
location: next,
|
|
2822
|
+
pendingMatches,
|
|
2823
|
+
cachedMatches: s.cachedMatches.filter(d => {
|
|
2824
|
+
return !pendingMatches.find(e => e.id === d.id);
|
|
2825
|
+
})
|
|
1795
2826
|
}));
|
|
1796
|
-
})();
|
|
1797
|
-
const dataPromise = Promise.resolve().then(() => {
|
|
1798
|
-
if (this.route.options.onLoad) {
|
|
1799
|
-
return this.route.options.onLoad({
|
|
1800
|
-
params: this.params,
|
|
1801
|
-
routeSearch,
|
|
1802
|
-
search,
|
|
1803
|
-
signal: this.abortController.signal,
|
|
1804
|
-
preload: !!opts?.preload,
|
|
1805
|
-
routeContext: routeContext,
|
|
1806
|
-
context: context
|
|
1807
|
-
});
|
|
1808
|
-
}
|
|
1809
|
-
return;
|
|
1810
2827
|
});
|
|
1811
2828
|
try {
|
|
1812
|
-
await Promise.all([componentsPromise, dataPromise]);
|
|
1813
|
-
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1814
|
-
this.__store.setState(s => ({
|
|
1815
|
-
...s,
|
|
1816
|
-
error: undefined,
|
|
1817
|
-
status: 'success',
|
|
1818
|
-
updatedAt: Date.now()
|
|
1819
|
-
}));
|
|
1820
|
-
} catch (err) {
|
|
1821
|
-
if (isRedirect(err)) {
|
|
1822
|
-
if (!opts?.preload) {
|
|
1823
|
-
this.router.navigate(err);
|
|
1824
|
-
}
|
|
1825
|
-
return;
|
|
1826
|
-
}
|
|
1827
|
-
const errorHandler = this.route.options.onLoadError ?? this.route.options.onError;
|
|
1828
2829
|
try {
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2830
|
+
// Load the matches
|
|
2831
|
+
await this.loadMatches({
|
|
2832
|
+
matches: pendingMatches,
|
|
2833
|
+
checkLatest: () => this.checkLatest(promise)
|
|
2834
|
+
});
|
|
2835
|
+
} catch (err) {
|
|
2836
|
+
// swallow this error, since we'll display the
|
|
2837
|
+
// errors on the route components
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
// Only apply the latest transition
|
|
2841
|
+
if (latestPromise = this.checkLatest(promise)) {
|
|
2842
|
+
return latestPromise;
|
|
2843
|
+
}
|
|
2844
|
+
const exitingMatches = previousMatches.filter(match => !pendingMatches.find(d => d.id === match.id));
|
|
2845
|
+
const enteringMatches = pendingMatches.filter(match => !previousMatches.find(d => d.id === match.id));
|
|
2846
|
+
const stayingMatches = previousMatches.filter(match => pendingMatches.find(d => d.id === match.id));
|
|
2847
|
+
|
|
2848
|
+
// Commit the pending matches. If a previous match was
|
|
2849
|
+
// removed, place it in the cachedMatches
|
|
2850
|
+
this.__store.batch(() => {
|
|
1837
2851
|
this.__store.setState(s => ({
|
|
1838
2852
|
...s,
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
2853
|
+
isLoading: false,
|
|
2854
|
+
matches: s.pendingMatches,
|
|
2855
|
+
pendingMatches: undefined,
|
|
2856
|
+
cachedMatches: [...s.cachedMatches, ...exitingMatches.filter(d => d.status !== 'error')]
|
|
1842
2857
|
}));
|
|
1843
|
-
|
|
2858
|
+
this.cleanCache();
|
|
2859
|
+
})
|
|
2860
|
+
|
|
2861
|
+
//
|
|
2862
|
+
;
|
|
2863
|
+
[[exitingMatches, 'onLeave'], [enteringMatches, 'onEnter'], [stayingMatches, 'onStay']].forEach(([matches, hook]) => {
|
|
2864
|
+
matches.forEach(match => {
|
|
2865
|
+
this.looseRoutesById[match.routeId].options[hook]?.(match);
|
|
2866
|
+
});
|
|
2867
|
+
});
|
|
2868
|
+
this.emit({
|
|
2869
|
+
type: 'onLoad',
|
|
2870
|
+
fromLocation: prevLocation,
|
|
2871
|
+
toLocation: next,
|
|
2872
|
+
pathChanged: pathDidChange
|
|
2873
|
+
});
|
|
2874
|
+
resolve();
|
|
2875
|
+
} catch (err) {
|
|
2876
|
+
// Only apply the latest transition
|
|
2877
|
+
if (latestPromise = this.checkLatest(promise)) {
|
|
2878
|
+
return latestPromise;
|
|
1844
2879
|
}
|
|
1845
|
-
|
|
1846
|
-
...s,
|
|
1847
|
-
error: err,
|
|
1848
|
-
status: 'error',
|
|
1849
|
-
updatedAt: Date.now()
|
|
1850
|
-
}));
|
|
1851
|
-
} finally {
|
|
1852
|
-
delete this.__loadPromise;
|
|
2880
|
+
reject(err);
|
|
1853
2881
|
}
|
|
1854
2882
|
});
|
|
1855
|
-
|
|
2883
|
+
this.latestLoadPromise = promise;
|
|
2884
|
+
return this.latestLoadPromise;
|
|
1856
2885
|
};
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
*
|
|
1868
|
-
* @license MIT
|
|
1869
|
-
*/
|
|
1870
|
-
|
|
1871
|
-
function useStore(store, selector = d => d, compareShallow) {
|
|
1872
|
-
const slice = withSelector.useSyncExternalStoreWithSelector(store.subscribe, () => store.state, () => store.state, selector, compareShallow ? shallow : undefined);
|
|
1873
|
-
return slice;
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
//
|
|
2886
|
+
cleanCache = () => {
|
|
2887
|
+
// This is where all of the garbage collection magic happens
|
|
2888
|
+
this.__store.setState(s => {
|
|
2889
|
+
return {
|
|
2890
|
+
...s,
|
|
2891
|
+
cachedMatches: s.cachedMatches.filter(d => {
|
|
2892
|
+
const route = this.looseRoutesById[d.routeId];
|
|
2893
|
+
if (!route.options.loader) {
|
|
2894
|
+
return false;
|
|
2895
|
+
}
|
|
1877
2896
|
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
}
|
|
2897
|
+
// If the route was preloaded, use the preloadGcTime
|
|
2898
|
+
// otherwise, use the gcTime
|
|
2899
|
+
const gcTime = (d.preload ? route.options.preloadGcTime ?? this.options.defaultPreloadGcTime : route.options.gcTime ?? this.options.defaultGcTime) ?? 5 * 60 * 1000;
|
|
2900
|
+
return d.status !== 'error' && Date.now() - d.updatedAt < gcTime;
|
|
2901
|
+
})
|
|
2902
|
+
};
|
|
2903
|
+
});
|
|
1885
2904
|
};
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
className,
|
|
1914
|
-
onClick,
|
|
1915
|
-
onFocus,
|
|
1916
|
-
onMouseEnter,
|
|
1917
|
-
onMouseLeave,
|
|
1918
|
-
onTouchStart,
|
|
1919
|
-
...rest
|
|
1920
|
-
} = options;
|
|
1921
|
-
const linkInfo = router.buildLink(options);
|
|
1922
|
-
if (linkInfo.type === 'external') {
|
|
1923
|
-
const {
|
|
1924
|
-
href
|
|
1925
|
-
} = linkInfo;
|
|
1926
|
-
return {
|
|
1927
|
-
href
|
|
2905
|
+
preloadRoute = async (navigateOpts = this.state.location) => {
|
|
2906
|
+
let next = this.buildLocation(navigateOpts);
|
|
2907
|
+
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
2908
|
+
throwOnError: true
|
|
2909
|
+
});
|
|
2910
|
+
const loadedMatchIds = Object.fromEntries([...this.state.matches, ...(this.state.pendingMatches ?? []), ...this.state.cachedMatches]?.map(d => [d.id, true]));
|
|
2911
|
+
this.__store.batch(() => {
|
|
2912
|
+
matches.forEach(match => {
|
|
2913
|
+
if (!loadedMatchIds[match.id]) {
|
|
2914
|
+
this.__store.setState(s => ({
|
|
2915
|
+
...s,
|
|
2916
|
+
cachedMatches: [...s.cachedMatches, match]
|
|
2917
|
+
}));
|
|
2918
|
+
}
|
|
2919
|
+
});
|
|
2920
|
+
});
|
|
2921
|
+
matches = await this.loadMatches({
|
|
2922
|
+
matches,
|
|
2923
|
+
preload: true,
|
|
2924
|
+
checkLatest: () => undefined
|
|
2925
|
+
});
|
|
2926
|
+
return matches;
|
|
2927
|
+
};
|
|
2928
|
+
matchRoute = (location, opts) => {
|
|
2929
|
+
location = {
|
|
2930
|
+
...location,
|
|
2931
|
+
to: location.to ? this.resolvePathWithBase(location.from || '', location.to) : undefined
|
|
1928
2932
|
};
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2933
|
+
const next = this.buildLocation(location);
|
|
2934
|
+
if (opts?.pending && this.state.status !== 'pending') {
|
|
2935
|
+
return false;
|
|
2936
|
+
}
|
|
2937
|
+
const baseLocation = opts?.pending ? this.latestLocation : this.state.resolvedLocation;
|
|
2938
|
+
if (!baseLocation) {
|
|
2939
|
+
return false;
|
|
2940
|
+
}
|
|
2941
|
+
const match = matchPathname(this.basepath, baseLocation.pathname, {
|
|
2942
|
+
...opts,
|
|
2943
|
+
to: next.pathname
|
|
2944
|
+
});
|
|
2945
|
+
if (!match) {
|
|
2946
|
+
return false;
|
|
2947
|
+
}
|
|
2948
|
+
if (match && (opts?.includeSearch ?? true)) {
|
|
2949
|
+
return deepEqual(baseLocation.search, next.search, true) ? match : false;
|
|
2950
|
+
}
|
|
2951
|
+
return match;
|
|
2952
|
+
};
|
|
2953
|
+
injectHtml = async html => {
|
|
2954
|
+
this.injectedHtml.push(html);
|
|
2955
|
+
};
|
|
2956
|
+
dehydrateData = (key, getData) => {
|
|
2957
|
+
if (typeof document === 'undefined') {
|
|
2958
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
2959
|
+
this.injectHtml(async () => {
|
|
2960
|
+
const id = `__TSR_DEHYDRATED__${strKey}`;
|
|
2961
|
+
const data = typeof getData === 'function' ? await getData() : getData;
|
|
2962
|
+
return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
|
|
2963
|
+
;(() => {
|
|
2964
|
+
var el = document.getElementById('${id}')
|
|
2965
|
+
el.parentElement.removeChild(el)
|
|
2966
|
+
})()
|
|
2967
|
+
</script>`;
|
|
1944
2968
|
});
|
|
1945
|
-
|
|
1946
|
-
handleClick(e);
|
|
2969
|
+
return () => this.hydrateData(key);
|
|
1947
2970
|
}
|
|
2971
|
+
return () => undefined;
|
|
1948
2972
|
};
|
|
1949
|
-
|
|
1950
|
-
if (
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
2973
|
+
hydrateData = key => {
|
|
2974
|
+
if (typeof document !== 'undefined') {
|
|
2975
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key);
|
|
2976
|
+
return window[`__TSR_DEHYDRATED__${strKey}`];
|
|
2977
|
+
}
|
|
2978
|
+
return undefined;
|
|
2979
|
+
};
|
|
2980
|
+
dehydrate = () => {
|
|
2981
|
+
return {
|
|
2982
|
+
state: {
|
|
2983
|
+
dehydratedMatches: this.state.matches.map(d => pick(d, ['id', 'status', 'updatedAt', 'loaderData']))
|
|
2984
|
+
}
|
|
2985
|
+
};
|
|
2986
|
+
};
|
|
2987
|
+
hydrate = async __do_not_use_server_ctx => {
|
|
2988
|
+
let _ctx = __do_not_use_server_ctx;
|
|
2989
|
+
// Client hydrates from window
|
|
2990
|
+
if (typeof document !== 'undefined') {
|
|
2991
|
+
_ctx = window.__TSR_DEHYDRATED__;
|
|
2992
|
+
}
|
|
2993
|
+
invariant(_ctx, 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?');
|
|
2994
|
+
const ctx = _ctx;
|
|
2995
|
+
this.dehydratedData = ctx.payload;
|
|
2996
|
+
this.options.hydrate?.(ctx.payload);
|
|
2997
|
+
const dehydratedState = ctx.router.state;
|
|
2998
|
+
let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
|
|
2999
|
+
const dehydratedMatch = dehydratedState.dehydratedMatches.find(d => d.id === match.id);
|
|
3000
|
+
invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
|
|
3001
|
+
if (dehydratedMatch) {
|
|
3002
|
+
return {
|
|
3003
|
+
...match,
|
|
3004
|
+
...dehydratedMatch
|
|
3005
|
+
};
|
|
3006
|
+
}
|
|
3007
|
+
return match;
|
|
3008
|
+
});
|
|
3009
|
+
this.__store.setState(s => {
|
|
3010
|
+
return {
|
|
3011
|
+
...s,
|
|
3012
|
+
matches: matches
|
|
3013
|
+
};
|
|
1954
3014
|
});
|
|
1955
3015
|
};
|
|
1956
3016
|
|
|
1957
|
-
//
|
|
1958
|
-
|
|
3017
|
+
// resolveMatchPromise = (matchId: string, key: string, value: any) => {
|
|
3018
|
+
// state.matches
|
|
3019
|
+
// .find((d) => d.id === matchId)
|
|
3020
|
+
// ?.__promisesByKey[key]?.resolve(value)
|
|
3021
|
+
// }
|
|
3022
|
+
}
|
|
1959
3023
|
|
|
1960
|
-
|
|
1961
|
-
|
|
3024
|
+
// A function that takes an import() argument which is a function and returns a new function that will
|
|
3025
|
+
// proxy arguments from the caller to the imported function, retaining all type
|
|
3026
|
+
// information along the way
|
|
3027
|
+
function lazyFn(fn, key) {
|
|
3028
|
+
return async (...args) => {
|
|
3029
|
+
const imported = await fn();
|
|
3030
|
+
return imported[key || 'default'](...args);
|
|
3031
|
+
};
|
|
3032
|
+
}
|
|
3033
|
+
class SearchParamError extends Error {}
|
|
3034
|
+
class PathParamError extends Error {}
|
|
3035
|
+
function getInitialRouterState(location) {
|
|
1962
3036
|
return {
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
onFocus: composeHandlers([onFocus, handleFocus]),
|
|
1969
|
-
onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
|
|
1970
|
-
onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
|
|
1971
|
-
onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
|
|
1972
|
-
target,
|
|
1973
|
-
style: {
|
|
1974
|
-
...style,
|
|
1975
|
-
...resolvedActiveProps.style,
|
|
1976
|
-
...resolvedInactiveProps.style
|
|
3037
|
+
isLoading: false,
|
|
3038
|
+
isTransitioning: false,
|
|
3039
|
+
status: 'idle',
|
|
3040
|
+
resolvedLocation: {
|
|
3041
|
+
...location
|
|
1977
3042
|
},
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
['data-status']: isActive ? 'active' : undefined
|
|
3043
|
+
location,
|
|
3044
|
+
matches: [],
|
|
3045
|
+
pendingMatches: [],
|
|
3046
|
+
cachedMatches: [],
|
|
3047
|
+
lastUpdated: Date.now()
|
|
1984
3048
|
};
|
|
1985
3049
|
}
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
3050
|
+
|
|
3051
|
+
const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
|
|
3052
|
+
const windowKey = 'window';
|
|
3053
|
+
const delimiter = '___';
|
|
3054
|
+
let weakScrolledElements = new WeakSet();
|
|
3055
|
+
const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
|
|
3056
|
+
let cache = sessionsStorage ? (() => {
|
|
3057
|
+
const storageKey = 'tsr-scroll-restoration-v2';
|
|
3058
|
+
const state = JSON.parse(window.sessionStorage.getItem(storageKey) || 'null') || {
|
|
3059
|
+
cached: {},
|
|
3060
|
+
next: {}
|
|
3061
|
+
};
|
|
3062
|
+
return {
|
|
3063
|
+
state,
|
|
3064
|
+
set: updater => {
|
|
3065
|
+
cache.state = functionalUpdate(updater, cache.state);
|
|
3066
|
+
window.sessionStorage.setItem(storageKey, JSON.stringify(cache.state));
|
|
3067
|
+
}
|
|
3068
|
+
};
|
|
3069
|
+
})() : undefined;
|
|
3070
|
+
const defaultGetKey = location => location.state.key;
|
|
3071
|
+
function useScrollRestoration(options) {
|
|
3072
|
+
const router = useRouter();
|
|
3073
|
+
useLayoutEffect(() => {
|
|
3074
|
+
const getKey = options?.getKey || defaultGetKey;
|
|
3075
|
+
const {
|
|
3076
|
+
history
|
|
3077
|
+
} = window;
|
|
3078
|
+
if (history.scrollRestoration) {
|
|
3079
|
+
history.scrollRestoration = 'manual';
|
|
3080
|
+
}
|
|
3081
|
+
const onScroll = event => {
|
|
3082
|
+
if (weakScrolledElements.has(event.target)) return;
|
|
3083
|
+
weakScrolledElements.add(event.target);
|
|
3084
|
+
let elementSelector = '';
|
|
3085
|
+
if (event.target === document || event.target === window) {
|
|
3086
|
+
elementSelector = windowKey;
|
|
3087
|
+
} else {
|
|
3088
|
+
const attrId = event.target.getAttribute('data-scroll-restoration-id');
|
|
3089
|
+
if (attrId) {
|
|
3090
|
+
elementSelector = `[data-scroll-restoration-id="${attrId}"]`;
|
|
3091
|
+
} else {
|
|
3092
|
+
elementSelector = getCssSelector(event.target);
|
|
2012
3093
|
}
|
|
2013
|
-
return component;
|
|
2014
3094
|
}
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
value: [undefined, ...currentMatches]
|
|
2031
|
-
}, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
2032
|
-
errorComponent: ErrorComponent,
|
|
2033
|
-
onCatch: () => {
|
|
2034
|
-
warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
|
|
3095
|
+
if (!cache.state.next[elementSelector]) {
|
|
3096
|
+
cache.set(c => ({
|
|
3097
|
+
...c,
|
|
3098
|
+
next: {
|
|
3099
|
+
...c.next,
|
|
3100
|
+
[elementSelector]: {
|
|
3101
|
+
scrollX: NaN,
|
|
3102
|
+
scrollY: NaN
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
}));
|
|
3106
|
+
}
|
|
3107
|
+
};
|
|
3108
|
+
if (typeof document !== 'undefined') {
|
|
3109
|
+
document.addEventListener('scroll', onScroll, true);
|
|
2035
3110
|
}
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
const resolvedRoute = router.getRoute(routeId);
|
|
2066
|
-
invariant(resolvedRoute, `Could not find a route for route "${routeId}"! Did you forget to add it to your route?`);
|
|
2067
|
-
return resolvedRoute;
|
|
2068
|
-
}
|
|
2069
|
-
function useSearch(opts) {
|
|
2070
|
-
const {
|
|
2071
|
-
track,
|
|
2072
|
-
...matchOpts
|
|
2073
|
-
} = opts;
|
|
2074
|
-
const match = useMatch(matchOpts);
|
|
2075
|
-
useStore(match.__store, d => opts?.track?.(d.search) ?? d.search, true);
|
|
2076
|
-
return match.state.search;
|
|
2077
|
-
}
|
|
2078
|
-
function useParams(opts) {
|
|
2079
|
-
const router = useRouterContext();
|
|
2080
|
-
useStore(router.__store, d => {
|
|
2081
|
-
const params = last(d.currentMatches)?.params;
|
|
2082
|
-
return opts?.track?.(params) ?? params;
|
|
2083
|
-
}, true);
|
|
2084
|
-
return last(router.state.currentMatches)?.params;
|
|
2085
|
-
}
|
|
2086
|
-
function useNavigate(defaultOpts) {
|
|
2087
|
-
const router = useRouterContext();
|
|
2088
|
-
return React__namespace.useCallback(opts => {
|
|
2089
|
-
return router.navigate({
|
|
2090
|
-
...defaultOpts,
|
|
2091
|
-
...opts
|
|
3111
|
+
const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
|
|
3112
|
+
if (event.pathChanged) {
|
|
3113
|
+
const restoreKey = getKey(event.fromLocation);
|
|
3114
|
+
for (const elementSelector in cache.state.next) {
|
|
3115
|
+
const entry = cache.state.next[elementSelector];
|
|
3116
|
+
if (elementSelector === windowKey) {
|
|
3117
|
+
entry.scrollX = window.scrollX || 0;
|
|
3118
|
+
entry.scrollY = window.scrollY || 0;
|
|
3119
|
+
} else if (elementSelector) {
|
|
3120
|
+
const element = document.querySelector(elementSelector);
|
|
3121
|
+
entry.scrollX = element?.scrollLeft || 0;
|
|
3122
|
+
entry.scrollY = element?.scrollTop || 0;
|
|
3123
|
+
}
|
|
3124
|
+
cache.set(c => {
|
|
3125
|
+
const next = {
|
|
3126
|
+
...c.next
|
|
3127
|
+
};
|
|
3128
|
+
delete next[elementSelector];
|
|
3129
|
+
return {
|
|
3130
|
+
...c,
|
|
3131
|
+
next,
|
|
3132
|
+
cached: {
|
|
3133
|
+
...c.cached,
|
|
3134
|
+
[[restoreKey, elementSelector].join(delimiter)]: entry
|
|
3135
|
+
}
|
|
3136
|
+
};
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
2092
3140
|
});
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
3141
|
+
const unsubOnResolved = router.subscribe('onResolved', event => {
|
|
3142
|
+
if (event.pathChanged) {
|
|
3143
|
+
if (!router.resetNextScroll) {
|
|
3144
|
+
return;
|
|
3145
|
+
}
|
|
3146
|
+
router.resetNextScroll = true;
|
|
3147
|
+
const getKey = options?.getKey || defaultGetKey;
|
|
3148
|
+
const restoreKey = getKey(event.toLocation);
|
|
3149
|
+
let windowRestored = false;
|
|
3150
|
+
for (const cacheKey in cache.state.cached) {
|
|
3151
|
+
const entry = cache.state.cached[cacheKey];
|
|
3152
|
+
const [key, elementSelector] = cacheKey.split(delimiter);
|
|
3153
|
+
if (key === restoreKey) {
|
|
3154
|
+
if (elementSelector === windowKey) {
|
|
3155
|
+
windowRestored = true;
|
|
3156
|
+
window.scrollTo(entry.scrollX, entry.scrollY);
|
|
3157
|
+
} else if (elementSelector) {
|
|
3158
|
+
const element = document.querySelector(elementSelector);
|
|
3159
|
+
if (element) {
|
|
3160
|
+
element.scrollLeft = entry.scrollX;
|
|
3161
|
+
element.scrollTop = entry.scrollY;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
if (!windowRestored) {
|
|
3167
|
+
window.scrollTo(0, 0);
|
|
3168
|
+
}
|
|
3169
|
+
cache.set(c => ({
|
|
3170
|
+
...c,
|
|
3171
|
+
next: {}
|
|
3172
|
+
}));
|
|
3173
|
+
weakScrolledElements = new WeakSet();
|
|
3174
|
+
}
|
|
2106
3175
|
});
|
|
3176
|
+
return () => {
|
|
3177
|
+
document.removeEventListener('scroll', onScroll);
|
|
3178
|
+
unsubOnBeforeLoad();
|
|
3179
|
+
unsubOnResolved();
|
|
3180
|
+
};
|
|
2107
3181
|
}, []);
|
|
2108
3182
|
}
|
|
2109
|
-
function
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
if (!params) {
|
|
2113
|
-
return null;
|
|
2114
|
-
}
|
|
2115
|
-
if (typeof props.children === 'function') {
|
|
2116
|
-
return props.children(params);
|
|
2117
|
-
}
|
|
2118
|
-
return params ? props.children : null;
|
|
2119
|
-
}
|
|
2120
|
-
function Outlet() {
|
|
2121
|
-
const matches = useMatches().slice(1);
|
|
2122
|
-
const match = matches[0];
|
|
2123
|
-
if (!match) {
|
|
2124
|
-
return null;
|
|
2125
|
-
}
|
|
2126
|
-
return /*#__PURE__*/React__namespace.createElement(SubOutlet, {
|
|
2127
|
-
matches: matches,
|
|
2128
|
-
match: match
|
|
2129
|
-
});
|
|
3183
|
+
function ScrollRestoration(props) {
|
|
3184
|
+
useScrollRestoration(props);
|
|
3185
|
+
return null;
|
|
2130
3186
|
}
|
|
2131
|
-
function
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
const ResolvedCatchBoundary = errorComponent ? CatchBoundary : SafeFragment;
|
|
2142
|
-
return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
|
|
2143
|
-
value: matches
|
|
2144
|
-
}, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
|
|
2145
|
-
fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, null)
|
|
2146
|
-
}, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
|
|
2147
|
-
key: match.route.id,
|
|
2148
|
-
errorComponent: errorComponent,
|
|
2149
|
-
onCatch: () => {
|
|
2150
|
-
warning(false, `Error in route match: ${match.id}`);
|
|
3187
|
+
function useElementScrollRestoration(options) {
|
|
3188
|
+
const router = useRouter();
|
|
3189
|
+
const getKey = options?.getKey || defaultGetKey;
|
|
3190
|
+
let elementSelector = '';
|
|
3191
|
+
if (options.id) {
|
|
3192
|
+
elementSelector = `[data-scroll-restoration-id="${options.id}"]`;
|
|
3193
|
+
} else {
|
|
3194
|
+
const element = options.getElement?.();
|
|
3195
|
+
if (!element) {
|
|
3196
|
+
return;
|
|
2151
3197
|
}
|
|
2152
|
-
|
|
2153
|
-
match: match
|
|
2154
|
-
}))));
|
|
2155
|
-
}
|
|
2156
|
-
function Inner(props) {
|
|
2157
|
-
const router = useRouterContext();
|
|
2158
|
-
if (props.match.state.status === 'error') {
|
|
2159
|
-
throw props.match.state.error;
|
|
2160
|
-
}
|
|
2161
|
-
if (props.match.state.status === 'success') {
|
|
2162
|
-
return /*#__PURE__*/React__namespace.createElement(props.match.component ?? router.options.defaultComponent ?? Outlet);
|
|
3198
|
+
elementSelector = getCssSelector(element);
|
|
2163
3199
|
}
|
|
2164
|
-
|
|
2165
|
-
|
|
3200
|
+
const restoreKey = getKey(router.latestLocation);
|
|
3201
|
+
const cacheKey = [restoreKey, elementSelector].join(delimiter);
|
|
3202
|
+
return cache.state.cached[cacheKey];
|
|
3203
|
+
}
|
|
3204
|
+
function getCssSelector(el) {
|
|
3205
|
+
let path = [],
|
|
3206
|
+
parent;
|
|
3207
|
+
while (parent = el.parentNode) {
|
|
3208
|
+
path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
|
|
3209
|
+
el = parent;
|
|
2166
3210
|
}
|
|
2167
|
-
|
|
2168
|
-
}
|
|
2169
|
-
function SafeFragment(props) {
|
|
2170
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
|
|
3211
|
+
return `${path.join(' > ')}`.toLowerCase();
|
|
2171
3212
|
}
|
|
2172
3213
|
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
class CatchBoundary extends React__namespace.Component {
|
|
2178
|
-
state = {
|
|
2179
|
-
error: false,
|
|
2180
|
-
info: undefined
|
|
2181
|
-
};
|
|
2182
|
-
componentDidCatch(error, info) {
|
|
2183
|
-
this.props.onCatch(error, info);
|
|
2184
|
-
console.error(error);
|
|
2185
|
-
this.setState({
|
|
2186
|
-
error,
|
|
2187
|
-
info
|
|
2188
|
-
});
|
|
2189
|
-
}
|
|
2190
|
-
render() {
|
|
2191
|
-
return /*#__PURE__*/React__namespace.createElement(CatchBoundaryInner, _extends({}, this.props, {
|
|
2192
|
-
errorState: this.state,
|
|
2193
|
-
reset: () => this.setState({})
|
|
2194
|
-
}));
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
function CatchBoundaryInner(props) {
|
|
2198
|
-
const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
|
|
2199
|
-
const router = useRouterContext();
|
|
2200
|
-
const errorComponent = props.errorComponent ?? ErrorComponent;
|
|
2201
|
-
const prevKeyRef = React__namespace.useRef('');
|
|
2202
|
-
React__namespace.useEffect(() => {
|
|
2203
|
-
if (activeErrorState) {
|
|
2204
|
-
if (router.state.currentLocation.key !== prevKeyRef.current) {
|
|
2205
|
-
setActiveErrorState({});
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
prevKeyRef.current = router.state.currentLocation.key;
|
|
2209
|
-
}, [activeErrorState, router.state.currentLocation.key]);
|
|
2210
|
-
React__namespace.useEffect(() => {
|
|
2211
|
-
if (props.errorState.error) {
|
|
2212
|
-
setActiveErrorState(props.errorState);
|
|
2213
|
-
}
|
|
2214
|
-
// props.reset()
|
|
2215
|
-
}, [props.errorState.error]);
|
|
2216
|
-
if (props.errorState.error && activeErrorState.error) {
|
|
2217
|
-
return /*#__PURE__*/React__namespace.createElement(errorComponent, activeErrorState);
|
|
2218
|
-
}
|
|
2219
|
-
return props.children;
|
|
2220
|
-
}
|
|
2221
|
-
function ErrorComponent({
|
|
2222
|
-
error
|
|
2223
|
-
}) {
|
|
2224
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
2225
|
-
style: {
|
|
2226
|
-
padding: '.5rem',
|
|
2227
|
-
maxWidth: '100%'
|
|
2228
|
-
}
|
|
2229
|
-
}, /*#__PURE__*/React__namespace.createElement("strong", {
|
|
2230
|
-
style: {
|
|
2231
|
-
fontSize: '1.2rem'
|
|
2232
|
-
}
|
|
2233
|
-
}, "Something went wrong!"), /*#__PURE__*/React__namespace.createElement("div", {
|
|
2234
|
-
style: {
|
|
2235
|
-
height: '.5rem'
|
|
2236
|
-
}
|
|
2237
|
-
}), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("pre", {
|
|
2238
|
-
style: {
|
|
2239
|
-
fontSize: '.7em',
|
|
2240
|
-
border: '1px solid red',
|
|
2241
|
-
borderRadius: '.25rem',
|
|
2242
|
-
padding: '.5rem',
|
|
2243
|
-
color: 'red',
|
|
2244
|
-
overflow: 'auto'
|
|
2245
|
-
}
|
|
2246
|
-
}, error.message ? /*#__PURE__*/React__namespace.createElement("code", null, error.message) : null)));
|
|
2247
|
-
}
|
|
2248
|
-
function useBlocker(message, condition = true) {
|
|
2249
|
-
const router = useRouter();
|
|
3214
|
+
function useBlocker(blockerFn, condition = true) {
|
|
3215
|
+
const {
|
|
3216
|
+
history
|
|
3217
|
+
} = useRouter();
|
|
2250
3218
|
React__namespace.useEffect(() => {
|
|
2251
3219
|
if (!condition) return;
|
|
2252
|
-
|
|
2253
|
-
if (window.confirm(message)) {
|
|
2254
|
-
unblock();
|
|
2255
|
-
retry();
|
|
2256
|
-
} else {
|
|
2257
|
-
cancel();
|
|
2258
|
-
}
|
|
2259
|
-
});
|
|
2260
|
-
return unblock;
|
|
3220
|
+
return history.block(blockerFn);
|
|
2261
3221
|
});
|
|
2262
3222
|
}
|
|
2263
3223
|
function Block({
|
|
2264
|
-
|
|
3224
|
+
blocker,
|
|
2265
3225
|
condition,
|
|
2266
3226
|
children
|
|
2267
3227
|
}) {
|
|
2268
|
-
useBlocker(
|
|
3228
|
+
useBlocker(blocker, condition);
|
|
2269
3229
|
return children ?? null;
|
|
2270
3230
|
}
|
|
2271
3231
|
|
|
3232
|
+
function useNavigate(defaultOpts) {
|
|
3233
|
+
const {
|
|
3234
|
+
navigate
|
|
3235
|
+
} = useRouter();
|
|
3236
|
+
const matchPathname = useMatch({
|
|
3237
|
+
strict: false,
|
|
3238
|
+
select: s => s.pathname
|
|
3239
|
+
});
|
|
3240
|
+
return React__namespace.useCallback(opts => {
|
|
3241
|
+
return navigate({
|
|
3242
|
+
from: opts?.to ? matchPathname : undefined,
|
|
3243
|
+
...defaultOpts,
|
|
3244
|
+
...opts
|
|
3245
|
+
});
|
|
3246
|
+
}, []);
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
// NOTE: I don't know of anyone using this. It's undocumented, so let's wait until someone needs it
|
|
3250
|
+
// export function typedNavigate<
|
|
3251
|
+
// TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
3252
|
+
// TDefaultFrom extends RoutePaths<TRouteTree> = '/',
|
|
3253
|
+
// >(navigate: (opts: NavigateOptions<any>) => Promise<void>) {
|
|
3254
|
+
// return navigate as <
|
|
3255
|
+
// TFrom extends RoutePaths<TRouteTree> = TDefaultFrom,
|
|
3256
|
+
// TTo extends string = '',
|
|
3257
|
+
// TMaskFrom extends RoutePaths<TRouteTree> = '/',
|
|
3258
|
+
// TMaskTo extends string = '',
|
|
3259
|
+
// >(
|
|
3260
|
+
// opts?: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
3261
|
+
// ) => Promise<void>
|
|
3262
|
+
// } //
|
|
3263
|
+
|
|
3264
|
+
function Navigate(props) {
|
|
3265
|
+
const {
|
|
3266
|
+
navigate
|
|
3267
|
+
} = useRouter();
|
|
3268
|
+
const match = useMatch({
|
|
3269
|
+
strict: false
|
|
3270
|
+
});
|
|
3271
|
+
React__namespace.useEffect(() => {
|
|
3272
|
+
navigate({
|
|
3273
|
+
from: props.to ? match.pathname : undefined,
|
|
3274
|
+
...props
|
|
3275
|
+
});
|
|
3276
|
+
}, []);
|
|
3277
|
+
return null;
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
exports.Await = Await;
|
|
2272
3281
|
exports.Block = Block;
|
|
3282
|
+
exports.CatchBoundary = CatchBoundary;
|
|
3283
|
+
exports.CatchBoundaryImpl = CatchBoundaryImpl;
|
|
2273
3284
|
exports.ErrorComponent = ErrorComponent;
|
|
3285
|
+
exports.FileRoute = FileRoute;
|
|
2274
3286
|
exports.Link = Link;
|
|
3287
|
+
exports.Match = Match;
|
|
2275
3288
|
exports.MatchRoute = MatchRoute;
|
|
3289
|
+
exports.Matches = Matches;
|
|
2276
3290
|
exports.Navigate = Navigate;
|
|
3291
|
+
exports.NotFoundRoute = NotFoundRoute;
|
|
2277
3292
|
exports.Outlet = Outlet;
|
|
2278
|
-
exports.
|
|
3293
|
+
exports.PathParamError = PathParamError;
|
|
2279
3294
|
exports.RootRoute = RootRoute;
|
|
2280
3295
|
exports.Route = Route;
|
|
2281
|
-
exports.
|
|
3296
|
+
exports.RouteApi = RouteApi;
|
|
2282
3297
|
exports.Router = Router;
|
|
2283
3298
|
exports.RouterProvider = RouterProvider;
|
|
3299
|
+
exports.ScrollRestoration = ScrollRestoration;
|
|
3300
|
+
exports.SearchParamError = SearchParamError;
|
|
2284
3301
|
exports.cleanPath = cleanPath;
|
|
3302
|
+
exports.componentTypes = componentTypes;
|
|
2285
3303
|
exports.createBrowserHistory = createBrowserHistory;
|
|
2286
3304
|
exports.createHashHistory = createHashHistory;
|
|
3305
|
+
exports.createHistory = createHistory;
|
|
2287
3306
|
exports.createMemoryHistory = createMemoryHistory;
|
|
3307
|
+
exports.createRouteMask = createRouteMask;
|
|
2288
3308
|
exports.decode = decode;
|
|
2289
|
-
exports.
|
|
3309
|
+
exports.deepEqual = deepEqual;
|
|
2290
3310
|
exports.defaultParseSearch = defaultParseSearch;
|
|
2291
3311
|
exports.defaultStringifySearch = defaultStringifySearch;
|
|
3312
|
+
exports.defer = defer;
|
|
2292
3313
|
exports.encode = encode;
|
|
3314
|
+
exports.escapeJSON = escapeJSON;
|
|
2293
3315
|
exports.functionalUpdate = functionalUpdate;
|
|
3316
|
+
exports.getInitialRouterState = getInitialRouterState;
|
|
3317
|
+
exports.getRouteMatch = getRouteMatch;
|
|
2294
3318
|
exports.interpolatePath = interpolatePath;
|
|
2295
3319
|
exports.invariant = invariant;
|
|
3320
|
+
exports.isDehydratedDeferred = isDehydratedDeferred;
|
|
2296
3321
|
exports.isPlainObject = isPlainObject;
|
|
2297
3322
|
exports.isRedirect = isRedirect;
|
|
3323
|
+
exports.isServer = isServer;
|
|
2298
3324
|
exports.joinPaths = joinPaths;
|
|
2299
3325
|
exports.last = last;
|
|
2300
|
-
exports.
|
|
3326
|
+
exports.lazyFn = lazyFn;
|
|
3327
|
+
exports.lazyRouteComponent = lazyRouteComponent;
|
|
2301
3328
|
exports.matchByPath = matchByPath;
|
|
3329
|
+
exports.matchContext = matchContext;
|
|
2302
3330
|
exports.matchPathname = matchPathname;
|
|
2303
|
-
exports.matchesContext = matchesContext;
|
|
2304
3331
|
exports.parsePathname = parsePathname;
|
|
2305
3332
|
exports.parseSearchWith = parseSearchWith;
|
|
2306
|
-
exports.partialDeepEqual = partialDeepEqual;
|
|
2307
3333
|
exports.pick = pick;
|
|
2308
3334
|
exports.redirect = redirect;
|
|
3335
|
+
exports.removeBasepath = removeBasepath;
|
|
2309
3336
|
exports.replaceEqualDeep = replaceEqualDeep;
|
|
2310
3337
|
exports.resolvePath = resolvePath;
|
|
2311
3338
|
exports.rootRouteId = rootRouteId;
|
|
2312
|
-
exports.
|
|
3339
|
+
exports.rootRouteWithContext = rootRouteWithContext;
|
|
3340
|
+
exports.shallow = shallow;
|
|
2313
3341
|
exports.stringifySearchWith = stringifySearchWith;
|
|
2314
3342
|
exports.trimPath = trimPath;
|
|
2315
3343
|
exports.trimPathLeft = trimPathLeft;
|
|
2316
3344
|
exports.trimPathRight = trimPathRight;
|
|
3345
|
+
exports.useAwaited = useAwaited;
|
|
2317
3346
|
exports.useBlocker = useBlocker;
|
|
3347
|
+
exports.useElementScrollRestoration = useElementScrollRestoration;
|
|
3348
|
+
exports.useLayoutEffect = useLayoutEffect$1;
|
|
2318
3349
|
exports.useLinkProps = useLinkProps;
|
|
3350
|
+
exports.useLoaderData = useLoaderData;
|
|
3351
|
+
exports.useLoaderDeps = useLoaderDeps;
|
|
2319
3352
|
exports.useMatch = useMatch;
|
|
2320
3353
|
exports.useMatchRoute = useMatchRoute;
|
|
2321
3354
|
exports.useMatches = useMatches;
|
|
2322
3355
|
exports.useNavigate = useNavigate;
|
|
2323
3356
|
exports.useParams = useParams;
|
|
2324
|
-
exports.
|
|
3357
|
+
exports.useParentMatches = useParentMatches;
|
|
3358
|
+
exports.useRouteContext = useRouteContext;
|
|
2325
3359
|
exports.useRouter = useRouter;
|
|
2326
|
-
exports.
|
|
3360
|
+
exports.useRouterState = useRouterState;
|
|
3361
|
+
exports.useScrollRestoration = useScrollRestoration;
|
|
2327
3362
|
exports.useSearch = useSearch;
|
|
2328
|
-
exports.
|
|
3363
|
+
exports.useStableCallback = useStableCallback;
|
|
2329
3364
|
exports.warning = warning;
|
|
2330
3365
|
|
|
2331
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2332
|
-
|
|
2333
3366
|
}));
|
|
2334
3367
|
//# sourceMappingURL=index.development.js.map
|