clear-react-router 1.0.16 → 1.0.18
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/dist/index.js +402 -404
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,440 +1,438 @@
|
|
|
1
|
-
import { Suspense
|
|
1
|
+
import { Suspense, createContext, lazy, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
//#region \0rolldown/runtime.js
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region context/RouterContext.ts
|
|
6
|
+
var ActionsContext = createContext({});
|
|
7
|
+
var DataContext = createContext({});
|
|
8
|
+
var NavigationContext = createContext({});
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region ../../node_modules/react/cjs/react-jsx-runtime.production.js
|
|
11
|
+
/**
|
|
12
|
+
* @license React
|
|
13
|
+
* react-jsx-runtime.production.js
|
|
14
|
+
*
|
|
15
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
16
|
+
*
|
|
17
|
+
* This source code is licensed under the MIT license found in the
|
|
18
|
+
* LICENSE file in the root directory of this source tree.
|
|
19
|
+
*/
|
|
20
|
+
var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
21
|
+
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element");
|
|
22
|
+
function jsxProd(type, config, maybeKey) {
|
|
23
|
+
var key = null;
|
|
24
|
+
void 0 !== maybeKey && (key = "" + maybeKey);
|
|
25
|
+
void 0 !== config.key && (key = "" + config.key);
|
|
26
|
+
if ("key" in config) {
|
|
27
|
+
maybeKey = {};
|
|
28
|
+
for (var propName in config) "key" !== propName && (maybeKey[propName] = config[propName]);
|
|
29
|
+
} else maybeKey = config;
|
|
30
|
+
config = maybeKey.ref;
|
|
31
|
+
return {
|
|
32
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
33
|
+
type,
|
|
34
|
+
key,
|
|
35
|
+
ref: void 0 !== config ? config : null,
|
|
36
|
+
props: maybeKey
|
|
18
37
|
};
|
|
19
38
|
}
|
|
20
|
-
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
case b: return "Profiler";
|
|
30
|
-
case y: return "StrictMode";
|
|
31
|
-
case w: return "Suspense";
|
|
32
|
-
case T: return "SuspenseList";
|
|
33
|
-
case O: return "Activity";
|
|
34
|
-
}
|
|
35
|
-
if (typeof e == "object") switch (typeof e.tag == "number" && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), e.$$typeof) {
|
|
36
|
-
case _: return "Portal";
|
|
37
|
-
case S: return e.displayName || "Context";
|
|
38
|
-
case x: return (e._context.displayName || "Context") + ".Consumer";
|
|
39
|
-
case C:
|
|
40
|
-
var n = e.render;
|
|
41
|
-
return e = e.displayName, e ||= (e = n.displayName || n.name || "", e === "" ? "ForwardRef" : "ForwardRef(" + e + ")"), e;
|
|
42
|
-
case E: return n = e.displayName || null, n === null ? t(e.type) || "Memo" : n;
|
|
43
|
-
case D:
|
|
44
|
-
n = e._payload, e = e._init;
|
|
45
|
-
try {
|
|
46
|
-
return t(e(n));
|
|
47
|
-
} catch {}
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
function n(e) {
|
|
52
|
-
return "" + e;
|
|
53
|
-
}
|
|
54
|
-
function r(e) {
|
|
55
|
-
try {
|
|
56
|
-
n(e);
|
|
57
|
-
var t = !1;
|
|
58
|
-
} catch {
|
|
59
|
-
t = !0;
|
|
60
|
-
}
|
|
61
|
-
if (t) {
|
|
62
|
-
t = console;
|
|
63
|
-
var r = t.error, i = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
|
|
64
|
-
return r.call(t, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", i), n(e);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function i(e) {
|
|
68
|
-
if (e === v) return "<>";
|
|
69
|
-
if (typeof e == "object" && e && e.$$typeof === D) return "<...>";
|
|
70
|
-
try {
|
|
71
|
-
var n = t(e);
|
|
72
|
-
return n ? "<" + n + ">" : "<...>";
|
|
73
|
-
} catch {
|
|
74
|
-
return "<...>";
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function a() {
|
|
78
|
-
var e = A.A;
|
|
79
|
-
return e === null ? null : e.getOwner();
|
|
80
|
-
}
|
|
81
|
-
function o() {
|
|
82
|
-
return Error("react-stack-top-frame");
|
|
83
|
-
}
|
|
84
|
-
function s(e) {
|
|
85
|
-
if (j.call(e, "key")) {
|
|
86
|
-
var t = Object.getOwnPropertyDescriptor(e, "key").get;
|
|
87
|
-
if (t && t.isReactWarning) return !1;
|
|
88
|
-
}
|
|
89
|
-
return e.key !== void 0;
|
|
90
|
-
}
|
|
91
|
-
function c(e, t) {
|
|
92
|
-
function n() {
|
|
93
|
-
P || (P = !0, console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", t));
|
|
94
|
-
}
|
|
95
|
-
n.isReactWarning = !0, Object.defineProperty(e, "key", {
|
|
96
|
-
get: n,
|
|
97
|
-
configurable: !0
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
function l() {
|
|
101
|
-
var e = t(this.type);
|
|
102
|
-
return F[e] || (F[e] = !0, console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")), e = this.props.ref, e === void 0 ? null : e;
|
|
103
|
-
}
|
|
104
|
-
function d(e, t, n, r, i, a) {
|
|
105
|
-
var o = n.ref;
|
|
106
|
-
return e = {
|
|
107
|
-
$$typeof: g,
|
|
108
|
-
type: e,
|
|
109
|
-
key: t,
|
|
110
|
-
props: n,
|
|
111
|
-
_owner: r
|
|
112
|
-
}, (o === void 0 ? null : o) === null ? Object.defineProperty(e, "ref", {
|
|
113
|
-
enumerable: !1,
|
|
114
|
-
value: null
|
|
115
|
-
}) : Object.defineProperty(e, "ref", {
|
|
116
|
-
enumerable: !1,
|
|
117
|
-
get: l
|
|
118
|
-
}), e._store = {}, Object.defineProperty(e._store, "validated", {
|
|
119
|
-
configurable: !1,
|
|
120
|
-
enumerable: !1,
|
|
121
|
-
writable: !0,
|
|
122
|
-
value: 0
|
|
123
|
-
}), Object.defineProperty(e, "_debugInfo", {
|
|
124
|
-
configurable: !1,
|
|
125
|
-
enumerable: !1,
|
|
126
|
-
writable: !0,
|
|
127
|
-
value: null
|
|
128
|
-
}), Object.defineProperty(e, "_debugStack", {
|
|
129
|
-
configurable: !1,
|
|
130
|
-
enumerable: !1,
|
|
131
|
-
writable: !0,
|
|
132
|
-
value: i
|
|
133
|
-
}), Object.defineProperty(e, "_debugTask", {
|
|
134
|
-
configurable: !1,
|
|
135
|
-
enumerable: !1,
|
|
136
|
-
writable: !0,
|
|
137
|
-
value: a
|
|
138
|
-
}), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
|
|
139
|
-
}
|
|
140
|
-
function f(e, n, i, o, l, u) {
|
|
141
|
-
var f = n.children;
|
|
142
|
-
if (f !== void 0) if (o) if (M(f)) {
|
|
143
|
-
for (o = 0; o < f.length; o++) p(f[o]);
|
|
144
|
-
Object.freeze && Object.freeze(f);
|
|
145
|
-
} else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");
|
|
146
|
-
else p(f);
|
|
147
|
-
if (j.call(n, "key")) {
|
|
148
|
-
f = t(e);
|
|
149
|
-
var m = Object.keys(n).filter(function(e) {
|
|
150
|
-
return e !== "key";
|
|
151
|
-
});
|
|
152
|
-
o = 0 < m.length ? "{key: someKey, " + m.join(": ..., ") + ": ...}" : "{key: someKey}", R[f + o] || (m = 0 < m.length ? "{" + m.join(": ..., ") + ": ...}" : "{}", console.error("A props object containing a \"key\" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />", o, f, m, f), R[f + o] = !0);
|
|
153
|
-
}
|
|
154
|
-
if (f = null, i !== void 0 && (r(i), f = "" + i), s(n) && (r(n.key), f = "" + n.key), "key" in n) for (var h in i = {}, n) h !== "key" && (i[h] = n[h]);
|
|
155
|
-
else i = n;
|
|
156
|
-
return f && c(i, typeof e == "function" ? e.displayName || e.name || "Unknown" : e), d(e, f, i, a(), l, u);
|
|
157
|
-
}
|
|
158
|
-
function p(e) {
|
|
159
|
-
m(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e && e.$$typeof === D && (e._payload.status === "fulfilled" ? m(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
|
|
160
|
-
}
|
|
161
|
-
function m(e) {
|
|
162
|
-
return typeof e == "object" && !!e && e.$$typeof === g;
|
|
163
|
-
}
|
|
164
|
-
var h = u("react"), g = Symbol.for("react.transitional.element"), _ = Symbol.for("react.portal"), v = Symbol.for("react.fragment"), y = Symbol.for("react.strict_mode"), b = Symbol.for("react.profiler"), x = Symbol.for("react.consumer"), S = Symbol.for("react.context"), C = Symbol.for("react.forward_ref"), w = Symbol.for("react.suspense"), T = Symbol.for("react.suspense_list"), E = Symbol.for("react.memo"), D = Symbol.for("react.lazy"), O = Symbol.for("react.activity"), k = Symbol.for("react.client.reference"), A = h.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, j = Object.prototype.hasOwnProperty, M = Array.isArray, N = console.createTask ? console.createTask : function() {
|
|
165
|
-
return null;
|
|
166
|
-
};
|
|
167
|
-
h = { react_stack_bottom_frame: function(e) {
|
|
168
|
-
return e();
|
|
169
|
-
} };
|
|
170
|
-
var P, F = {}, I = h.react_stack_bottom_frame.bind(h, o)(), L = N(i(o)), R = {};
|
|
171
|
-
e.Fragment = v, e.jsx = function(e, t, n) {
|
|
172
|
-
var r = 1e4 > A.recentlyCreatedOwnerStacks++;
|
|
173
|
-
return f(e, t, n, !1, r ? Error("react-stack-top-frame") : I, r ? N(i(e)) : L);
|
|
174
|
-
}, e.jsxs = function(e, t, n) {
|
|
175
|
-
var r = 1e4 > A.recentlyCreatedOwnerStacks++;
|
|
176
|
-
return f(e, t, n, !0, r ? Error("react-stack-top-frame") : I, r ? N(i(e)) : L);
|
|
177
|
-
};
|
|
178
|
-
})();
|
|
179
|
-
})), g = (/* @__PURE__ */ l(((e, t) => {
|
|
180
|
-
process.env.NODE_ENV === "production" ? t.exports = m() : t.exports = h();
|
|
181
|
-
})))(), _ = ({ children: e, setContext: t, context: n, updateBlockedRoute: r, updateLocation: i, location: a, params: o, prefetchLoader: s, loaderCache: c, blockerState: l }) => /* @__PURE__ */ (0, g.jsx)(d.Provider, {
|
|
182
|
-
value: {
|
|
183
|
-
updateLocation: i,
|
|
184
|
-
updateBlockedRoute: r,
|
|
185
|
-
prefetchLoader: s,
|
|
186
|
-
setContext: t
|
|
187
|
-
},
|
|
188
|
-
children: /* @__PURE__ */ (0, g.jsx)(f.Provider, {
|
|
39
|
+
exports.jsx = jsxProd;
|
|
40
|
+
}));
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region provider/RouterProvider.tsx
|
|
43
|
+
var import_jsx_runtime = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
44
|
+
module.exports = require_react_jsx_runtime_production();
|
|
45
|
+
})))();
|
|
46
|
+
var RouterProvider = ({ children, setContext, context, updateBlockedRoute, updateLocation, location, params, prefetchLoader, loaderCache, blockerState }) => {
|
|
47
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActionsContext.Provider, {
|
|
189
48
|
value: {
|
|
190
|
-
|
|
191
|
-
|
|
49
|
+
updateLocation,
|
|
50
|
+
updateBlockedRoute,
|
|
51
|
+
prefetchLoader,
|
|
52
|
+
setContext
|
|
192
53
|
},
|
|
193
|
-
children: /* @__PURE__ */ (0,
|
|
54
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataContext.Provider, {
|
|
194
55
|
value: {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
location: a
|
|
56
|
+
context,
|
|
57
|
+
loaderCache
|
|
198
58
|
},
|
|
199
|
-
children:
|
|
59
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigationContext.Provider, {
|
|
60
|
+
value: {
|
|
61
|
+
blockerState,
|
|
62
|
+
params,
|
|
63
|
+
location
|
|
64
|
+
},
|
|
65
|
+
children
|
|
66
|
+
})
|
|
200
67
|
})
|
|
201
|
-
})
|
|
202
|
-
}), v = (t, r) => {
|
|
203
|
-
let i = n(() => t().then((e) => ({ default: e.default || e })));
|
|
204
|
-
return () => /* @__PURE__ */ (0, g.jsx)(e, {
|
|
205
|
-
fallback: typeof r == "function" ? r() : r || null,
|
|
206
|
-
children: /* @__PURE__ */ (0, g.jsx)(i, {})
|
|
207
68
|
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region utils/createLazyComponent.tsx
|
|
72
|
+
var createLazyComponent = (importFn, fallback) => {
|
|
73
|
+
const LazyComp = lazy(() => importFn().then((module) => ({ default: module.default || module })));
|
|
74
|
+
return () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Suspense, {
|
|
75
|
+
fallback: typeof fallback === "function" ? fallback() : fallback || null,
|
|
76
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LazyComp, {})
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region utils/utils.ts
|
|
81
|
+
var isLazy = (el) => typeof el.element === "function" && el.element.toString().includes("import(");
|
|
82
|
+
var parseClientRouteItem = (el, parentParams = [], parentPath = "") => {
|
|
83
|
+
const currentParamsList = el.path.match(/:[^/]+/g);
|
|
84
|
+
const normalizedSplitPath = el.path.replaceAll(/:[^/]+(\/|$)/g, "").split("/").filter(Boolean);
|
|
85
|
+
const splitPath = el.path.split("/");
|
|
86
|
+
const currentParams = currentParamsList ? [...parentParams, ...currentParamsList.map((param, index) => ({
|
|
87
|
+
key: normalizedSplitPath[index],
|
|
88
|
+
value: param.slice(1)
|
|
89
|
+
}))] : parentParams;
|
|
90
|
+
const path = currentParams.length ? `${parentPath}${splitPath.slice(0, splitPath.length - 1).join("/")}` : el.path;
|
|
91
|
+
const resolvedElement = isLazy(el) ? createLazyComponent(el.element, el.fallback) : el.element;
|
|
213
92
|
return [{
|
|
214
|
-
...
|
|
215
|
-
path
|
|
216
|
-
params:
|
|
217
|
-
element:
|
|
218
|
-
}, ...
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
93
|
+
...el,
|
|
94
|
+
path,
|
|
95
|
+
params: currentParams,
|
|
96
|
+
element: resolvedElement
|
|
97
|
+
}, ...el.children?.flatMap((child) => parseClientRouteItem(child, currentParams, path)) || []];
|
|
98
|
+
};
|
|
99
|
+
var createRouter = (clientList) => clientList.flatMap((el) => parseClientRouteItem(el, []));
|
|
100
|
+
var getParamsObject = (params) => {
|
|
101
|
+
const { pathname } = window.location;
|
|
102
|
+
const split = pathname.split("/");
|
|
103
|
+
return (params || []).map((el) => ({
|
|
104
|
+
index: split.findIndex((item) => item === el.key),
|
|
105
|
+
value: el.value
|
|
106
|
+
})).reduce((acc, cur) => ({
|
|
107
|
+
...acc,
|
|
108
|
+
[cur.value]: split[cur.index + 1]
|
|
227
109
|
}), {});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
110
|
+
};
|
|
111
|
+
var parseWindowLocation = (location) => ({
|
|
112
|
+
pathname: location.pathname,
|
|
113
|
+
search: location.search
|
|
114
|
+
});
|
|
115
|
+
var comparePaths = (el, pathname) => {
|
|
116
|
+
const splitElementPath = el.path.split("/").filter(Boolean);
|
|
117
|
+
const paramsLength = el.params ? Object.keys(el.params).length : 0;
|
|
118
|
+
const splitPathname = pathname.split("/").filter(Boolean);
|
|
119
|
+
return splitElementPath.every((item, index) => item === splitPathname[index + (index ? 1 : 0)]) && splitPathname.length === splitElementPath.length + paramsLength;
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region hooks/useLatest.ts
|
|
123
|
+
var useLatest = (value) => {
|
|
124
|
+
const ref = useRef(value);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
ref.current = value;
|
|
127
|
+
}, [value]);
|
|
128
|
+
return ref;
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region hooks/useHandleNavigation.ts
|
|
132
|
+
var isRedirect = (error) => typeof error === "object" && error !== null && error.cause === "redirect";
|
|
133
|
+
var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache }) => {
|
|
134
|
+
const [blockedRoute, setBlockedRoute] = useState({
|
|
241
135
|
from: "",
|
|
242
136
|
to: ""
|
|
243
|
-
})
|
|
137
|
+
});
|
|
138
|
+
const prevPathname = useRef("");
|
|
139
|
+
const setNextLocationRef = useLatest(useCallback(async (nextLocation) => {
|
|
244
140
|
try {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
141
|
+
const nextItem = routeList.find((el) => comparePaths(el, nextLocation.pathname));
|
|
142
|
+
if (nextItem?.beforeLoad) await nextItem?.beforeLoad(context);
|
|
143
|
+
setLocation(nextLocation);
|
|
144
|
+
if (nextLocation.pathname !== window.location.pathname) {
|
|
145
|
+
history.pushState(null, "", nextLocation.pathname);
|
|
146
|
+
prevPathname.current = nextLocation.pathname;
|
|
147
|
+
}
|
|
148
|
+
await revalidateCache(nextItem);
|
|
149
|
+
if (nextItem?.afterLoad) await nextItem?.afterLoad(context);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
const redirect = error;
|
|
152
|
+
if (!isRedirect(redirect)) return redirect;
|
|
153
|
+
history.replaceState(null, "", redirect.url);
|
|
154
|
+
setLocation({
|
|
155
|
+
pathname: redirect.url,
|
|
156
|
+
search: redirect.search
|
|
254
157
|
});
|
|
255
158
|
}
|
|
256
159
|
}, [
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
]))
|
|
262
|
-
|
|
263
|
-
from
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
} : (e === "process" && f.current({ pathname: n.to }), !n.from && !n.to ? n : {
|
|
268
|
-
from: "",
|
|
269
|
-
to: ""
|
|
270
|
-
})), [f]), m = r(async (e) => {
|
|
271
|
-
l.from ? u((t) => ({
|
|
272
|
-
...t,
|
|
273
|
-
to: e.pathname
|
|
274
|
-
})) : await f.current(e);
|
|
275
|
-
}, [l.from, f]);
|
|
276
|
-
return a(() => {
|
|
277
|
-
let e = async (e) => {
|
|
278
|
-
let t = C(e.target.location);
|
|
279
|
-
d.current === l.from ? (u({
|
|
280
|
-
from: d.current,
|
|
281
|
-
to: t.pathname
|
|
282
|
-
}), history.replaceState(null, "", d.current)) : f.current(t);
|
|
160
|
+
context,
|
|
161
|
+
revalidateCache,
|
|
162
|
+
routeList,
|
|
163
|
+
setLocation
|
|
164
|
+
]));
|
|
165
|
+
const updateBlockedRoute = useCallback(({ type, payload = "" }) => setBlockedRoute((prevState) => {
|
|
166
|
+
if (prevState.from === payload && type === "charge") return prevState;
|
|
167
|
+
if (payload && prevState.from !== payload && type === "charge") return {
|
|
168
|
+
...prevState,
|
|
169
|
+
from: payload
|
|
283
170
|
};
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}, [
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}), {}));
|
|
310
|
-
try {
|
|
311
|
-
a(!1);
|
|
312
|
-
let t = await e?.loader();
|
|
313
|
-
u.current = {
|
|
314
|
-
...u.current,
|
|
315
|
-
[e.path]: Date.now()
|
|
316
|
-
}, d({
|
|
317
|
-
key: e.path,
|
|
318
|
-
value: t
|
|
171
|
+
if (type === "reset") return {
|
|
172
|
+
...prevState,
|
|
173
|
+
to: ""
|
|
174
|
+
};
|
|
175
|
+
if (type === "process") setNextLocationRef.current({ pathname: prevState.to });
|
|
176
|
+
if (!prevState.from && !prevState.to) return prevState;
|
|
177
|
+
return {
|
|
178
|
+
from: "",
|
|
179
|
+
to: ""
|
|
180
|
+
};
|
|
181
|
+
}), [setNextLocationRef]);
|
|
182
|
+
const updateLocation = useCallback(async (nextLocation) => {
|
|
183
|
+
if (blockedRoute.from) setBlockedRoute((prevState) => ({
|
|
184
|
+
...prevState,
|
|
185
|
+
to: nextLocation.pathname
|
|
186
|
+
}));
|
|
187
|
+
else await setNextLocationRef.current(nextLocation);
|
|
188
|
+
}, [blockedRoute.from, setNextLocationRef]);
|
|
189
|
+
useEffect(() => {
|
|
190
|
+
const handler = async (event) => {
|
|
191
|
+
const newLocation = parseWindowLocation(event.target.location);
|
|
192
|
+
if (prevPathname.current === blockedRoute.from) {
|
|
193
|
+
setBlockedRoute({
|
|
194
|
+
from: prevPathname.current,
|
|
195
|
+
to: newLocation.pathname
|
|
319
196
|
});
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
197
|
+
history.replaceState(null, "", prevPathname.current);
|
|
198
|
+
} else setNextLocationRef.current(newLocation);
|
|
199
|
+
};
|
|
200
|
+
window.addEventListener("popstate", handler);
|
|
201
|
+
return () => window.removeEventListener("popstate", handler);
|
|
202
|
+
}, [blockedRoute.from, setNextLocationRef]);
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
const currentLocation = parseWindowLocation(window.location);
|
|
205
|
+
setNextLocationRef.current(currentLocation);
|
|
206
|
+
prevPathname.current = currentLocation.pathname;
|
|
207
|
+
}, [setNextLocationRef]);
|
|
208
|
+
return {
|
|
209
|
+
blockerState: useMemo(() => {
|
|
210
|
+
if (blockedRoute.from && blockedRoute.to) return "blocked";
|
|
211
|
+
if (blockedRoute.from) return "charged";
|
|
212
|
+
return "unblocked";
|
|
213
|
+
}, [blockedRoute]),
|
|
214
|
+
updateLocation,
|
|
215
|
+
updateBlockedRoute
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region hooks/useLoader.ts
|
|
220
|
+
var useLoader = (routeList) => {
|
|
221
|
+
const [loaderCache, setLoaderCache] = useState({});
|
|
222
|
+
const [loaderError, setLoaderError] = useState(false);
|
|
223
|
+
const [isLoadingMap, setIsLoadingMap] = useState({});
|
|
224
|
+
const cacheTimestampsRef = useRef({});
|
|
225
|
+
const updateCache = useCallback(({ key, value }) => setLoaderCache((prevState) => ({
|
|
226
|
+
...prevState,
|
|
227
|
+
[key]: value
|
|
228
|
+
})), []);
|
|
229
|
+
const isCacheItemFresh = useCallback((routeItem) => {
|
|
230
|
+
if (!routeItem) return true;
|
|
231
|
+
const currentCacheTimestamp = cacheTimestampsRef.current[routeItem.path];
|
|
232
|
+
return Boolean(currentCacheTimestamp && Date.now() - currentCacheTimestamp < (routeItem.staleTime || 0));
|
|
233
|
+
}, []);
|
|
234
|
+
const revalidateCache = useCallback(async (routeItem) => {
|
|
235
|
+
if (!routeItem?.loader) return;
|
|
236
|
+
if (isCacheItemFresh(routeItem)) return;
|
|
237
|
+
setIsLoadingMap((prev) => ({
|
|
238
|
+
...prev,
|
|
239
|
+
[routeItem.path]: true
|
|
240
|
+
}));
|
|
241
|
+
setLoaderCache((prevState) => Object.keys(prevState).filter((el) => el !== routeItem.path).reduce((acc, cur) => ({
|
|
242
|
+
...acc,
|
|
243
|
+
[cur]: prevState[cur]
|
|
244
|
+
}), {}));
|
|
245
|
+
try {
|
|
246
|
+
setLoaderError(false);
|
|
247
|
+
const result = await routeItem?.loader();
|
|
248
|
+
cacheTimestampsRef.current = {
|
|
249
|
+
...cacheTimestampsRef.current,
|
|
250
|
+
[routeItem.path]: Date.now()
|
|
251
|
+
};
|
|
252
|
+
updateCache({
|
|
253
|
+
key: routeItem.path,
|
|
254
|
+
value: result
|
|
255
|
+
});
|
|
256
|
+
} catch {
|
|
257
|
+
setLoaderError(true);
|
|
258
|
+
} finally {
|
|
259
|
+
setIsLoadingMap((prev) => ({
|
|
260
|
+
...prev,
|
|
261
|
+
[routeItem.path]: false
|
|
262
|
+
}));
|
|
328
263
|
}
|
|
329
|
-
}, [
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
264
|
+
}, [isCacheItemFresh, updateCache]);
|
|
265
|
+
const prefetchLoader = useCallback(async (pathname) => {
|
|
266
|
+
const item = routeList.find((el) => comparePaths(el, pathname));
|
|
267
|
+
if (item) await revalidateCache(item);
|
|
268
|
+
}, [revalidateCache, routeList]);
|
|
333
269
|
return {
|
|
334
|
-
loaderCache:
|
|
335
|
-
loaderError
|
|
336
|
-
prefetchLoader
|
|
337
|
-
revalidateCache
|
|
338
|
-
isLoading:
|
|
270
|
+
loaderCache: loaderCache[window.location.pathname],
|
|
271
|
+
loaderError,
|
|
272
|
+
prefetchLoader,
|
|
273
|
+
revalidateCache,
|
|
274
|
+
isLoading: isLoadingMap[window.location.pathname]
|
|
339
275
|
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
276
|
+
};
|
|
277
|
+
//#endregion
|
|
278
|
+
//#region utils/renderElement.tsx
|
|
279
|
+
var renderElement = (Component) => {
|
|
280
|
+
if (!Component) return null;
|
|
281
|
+
return typeof Component === "function" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, {}) : Component;
|
|
282
|
+
};
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region components/Router.tsx
|
|
285
|
+
var PAGE_NOT_FOUND = "error 404. Page not found";
|
|
286
|
+
var ALL_LOCATIONS = "*";
|
|
287
|
+
var Router = ({ routeList, context: initialContext = {} }) => {
|
|
288
|
+
const [location, setLocation] = useState(parseWindowLocation(window.location));
|
|
289
|
+
const [context, setContext] = useState(initialContext);
|
|
290
|
+
const routeItem = useMemo(() => routeList.find((el) => el.path === ALL_LOCATIONS || comparePaths(el, location.pathname)), [location.pathname, routeList]);
|
|
291
|
+
const { loaderError, loaderCache, prefetchLoader, revalidateCache, isLoading } = useLoader(routeList);
|
|
292
|
+
const { blockerState, updateLocation, updateBlockedRoute } = useHandleNavigation({
|
|
293
|
+
setLocation,
|
|
294
|
+
routeList,
|
|
295
|
+
context,
|
|
296
|
+
revalidateCache
|
|
297
|
+
});
|
|
298
|
+
const params = useMemo(() => routeItem?.params ? getParamsObject(routeItem.params) : {}, [routeItem]);
|
|
299
|
+
const providerProps = useMemo(() => ({
|
|
300
|
+
location,
|
|
301
|
+
updateLocation,
|
|
302
|
+
params,
|
|
303
|
+
loaderCache,
|
|
304
|
+
prefetchLoader,
|
|
305
|
+
updateBlockedRoute,
|
|
306
|
+
blockerState,
|
|
307
|
+
context,
|
|
308
|
+
setContext
|
|
356
309
|
}), [
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
310
|
+
blockerState,
|
|
311
|
+
loaderCache,
|
|
312
|
+
location,
|
|
313
|
+
params,
|
|
314
|
+
prefetchLoader,
|
|
315
|
+
context,
|
|
316
|
+
updateBlockedRoute,
|
|
317
|
+
updateLocation
|
|
365
318
|
]);
|
|
366
|
-
|
|
367
|
-
...
|
|
368
|
-
children:
|
|
369
|
-
}) : l ? /* @__PURE__ */ (0, g.jsx)(_, {
|
|
370
|
-
...b,
|
|
371
|
-
children: k(s?.errorElement)
|
|
372
|
-
}) : /* @__PURE__ */ (0, g.jsx)(_, {
|
|
373
|
-
...b,
|
|
374
|
-
children: k(s?.element) || A
|
|
319
|
+
if (routeItem?.loader && !loaderError && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RouterProvider, {
|
|
320
|
+
...providerProps,
|
|
321
|
+
children: renderElement(routeItem?.loaderFallback)
|
|
375
322
|
});
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
return
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
323
|
+
if (loaderError) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RouterProvider, {
|
|
324
|
+
...providerProps,
|
|
325
|
+
children: renderElement(routeItem?.errorElement)
|
|
326
|
+
});
|
|
327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RouterProvider, {
|
|
328
|
+
...providerProps,
|
|
329
|
+
children: renderElement(routeItem?.element) || PAGE_NOT_FOUND
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
//#endregion
|
|
333
|
+
//#region hooks/useServiceContext.ts
|
|
334
|
+
var useNavigationState = () => {
|
|
335
|
+
const context = useContext(NavigationContext);
|
|
336
|
+
if (!Object.keys(context).length) throw new Error("useNavigationState must be used within Router component");
|
|
337
|
+
return context;
|
|
338
|
+
};
|
|
339
|
+
var useRouterActions = () => {
|
|
340
|
+
const context = useContext(ActionsContext);
|
|
341
|
+
if (!Object.keys(context).length) throw new Error("useRouterActions must be used within Router component");
|
|
342
|
+
return context;
|
|
343
|
+
};
|
|
344
|
+
var useRouterData = () => {
|
|
345
|
+
const context = useContext(DataContext);
|
|
346
|
+
if (!Object.keys(context).length) throw new Error("useRouterData must be used within Router component");
|
|
347
|
+
return context;
|
|
348
|
+
};
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region hooks/useNavigate.ts
|
|
351
|
+
var useNavigate = () => {
|
|
352
|
+
const { updateLocation } = useRouterActions();
|
|
353
|
+
return useCallback(async (arg) => arg === -1 ? history.go(-1) : await updateLocation(arg), [updateLocation]);
|
|
354
|
+
};
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region components/Link.tsx
|
|
357
|
+
var Link = ({ children, to, prefetch = true }) => {
|
|
358
|
+
const { prefetchLoader } = useRouterActions();
|
|
359
|
+
const navigate = useNavigate();
|
|
360
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
|
|
394
361
|
style: { cursor: "pointer" },
|
|
395
|
-
onClick: () =>
|
|
396
|
-
onMouseOver: () =>
|
|
397
|
-
children
|
|
362
|
+
onClick: () => navigate({ pathname: to }),
|
|
363
|
+
onMouseOver: () => prefetch && prefetchLoader(to),
|
|
364
|
+
children
|
|
398
365
|
});
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
return
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
366
|
+
};
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region hooks/useParams.ts
|
|
369
|
+
var useParams = () => {
|
|
370
|
+
const { params } = useNavigationState();
|
|
371
|
+
return params;
|
|
372
|
+
};
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region hooks/useLocation.ts
|
|
375
|
+
var useLocation = () => {
|
|
376
|
+
return useNavigationState().location;
|
|
377
|
+
};
|
|
378
|
+
//#endregion
|
|
379
|
+
//#region hooks/useLoaderState.ts
|
|
380
|
+
var useLoaderState = () => {
|
|
381
|
+
const { loaderCache } = useRouterData();
|
|
382
|
+
return loaderCache;
|
|
383
|
+
};
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region hooks/useBlocker.ts
|
|
386
|
+
var useBlocker = (blockerFn) => {
|
|
387
|
+
const { location: { pathname }, blockerState } = useNavigationState();
|
|
388
|
+
const { updateBlockedRoute } = useRouterActions();
|
|
389
|
+
const shouldBlock = blockerFn();
|
|
390
|
+
useEffect(() => updateBlockedRoute(shouldBlock ? {
|
|
408
391
|
type: "charge",
|
|
409
|
-
payload:
|
|
392
|
+
payload: pathname
|
|
410
393
|
} : { type: "unblock" }), [
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
])
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
394
|
+
shouldBlock,
|
|
395
|
+
pathname,
|
|
396
|
+
updateBlockedRoute
|
|
397
|
+
]);
|
|
398
|
+
return {
|
|
399
|
+
state: blockerState,
|
|
400
|
+
process: () => updateBlockedRoute({ type: "process" }),
|
|
401
|
+
reset: () => updateBlockedRoute({ type: "reset" })
|
|
418
402
|
};
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
403
|
+
};
|
|
404
|
+
//#endregion
|
|
405
|
+
//#region hooks/useBeforeUnload.ts
|
|
406
|
+
var useBeforeUnload = (callback) => {
|
|
407
|
+
useEffect(() => {
|
|
408
|
+
const handler = (event) => {
|
|
409
|
+
if (!callback) return;
|
|
410
|
+
event.preventDefault();
|
|
411
|
+
callback();
|
|
423
412
|
};
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
},
|
|
427
|
-
|
|
413
|
+
window.addEventListener("beforeunload", handler);
|
|
414
|
+
return () => window.removeEventListener("beforeunload", handler);
|
|
415
|
+
}, [callback]);
|
|
416
|
+
};
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region hooks/useRouterContext.ts
|
|
419
|
+
var useRouterContext = () => {
|
|
420
|
+
const { context } = useRouterData();
|
|
421
|
+
const { setContext } = useRouterActions();
|
|
428
422
|
return {
|
|
429
|
-
context
|
|
430
|
-
setContext
|
|
423
|
+
context,
|
|
424
|
+
setContext
|
|
431
425
|
};
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
426
|
+
};
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region utils/redirect.ts
|
|
429
|
+
var redirect = (url, search) => {
|
|
430
|
+
const error = /* @__PURE__ */ new Error();
|
|
431
|
+
error.cause = "redirect";
|
|
432
|
+
throw Object.assign(error, {
|
|
433
|
+
url,
|
|
434
|
+
search: search || ""
|
|
437
435
|
});
|
|
438
436
|
};
|
|
439
437
|
//#endregion
|
|
440
|
-
export {
|
|
438
|
+
export { Link, Router, createRouter, redirect, useBeforeUnload, useBlocker, useLoaderState, useLocation, useNavigate, useParams, useRouterContext };
|
package/package.json
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clear-react-router",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"description": "A lightweight, type-safe routing library for React applications",
|
|
5
5
|
"author": "Andrew Bubnov",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
6
|
"scripts": {
|
|
10
7
|
"build": "vite build && tsc --emitDeclarationOnly"
|
|
11
8
|
},
|
|
@@ -31,6 +28,9 @@
|
|
|
31
28
|
],
|
|
32
29
|
"license": "MIT",
|
|
33
30
|
"type": "module",
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"module": "./dist/index.js",
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
34
|
"exports": {
|
|
35
35
|
".": {
|
|
36
36
|
"types": "./dist/index.d.ts",
|