@ripetchor/r-router 1.0.0 → 1.0.1
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/README.md +168 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.js +149 -143
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1 +1,168 @@
|
|
|
1
|
-
#
|
|
1
|
+
# R-Router
|
|
2
|
+
|
|
3
|
+
HistoryAPI router.
|
|
4
|
+
|
|
5
|
+
**WARNING**: This router is primarily intended for personal use. It may contain bugs or unexpected behavior. Use at your own risk.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { createRouter, RouterOutlet, RouteContext } from '@ripetchor/r-router';
|
|
11
|
+
|
|
12
|
+
const routes = [
|
|
13
|
+
{
|
|
14
|
+
path: '/',
|
|
15
|
+
component: () => {
|
|
16
|
+
const div = document.createElement('div');
|
|
17
|
+
div.textContent = 'Home';
|
|
18
|
+
return div;
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
path: '/user/:id',
|
|
23
|
+
component: (ctx: RouteContext) => {
|
|
24
|
+
const div = document.createElement('div');
|
|
25
|
+
div.textContent = `User ID: ${ctx.params.id}`;
|
|
26
|
+
return div;
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
path: '/about',
|
|
31
|
+
loadComponent: async () => {
|
|
32
|
+
const { default: About } = await import('./About');
|
|
33
|
+
return About();
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
path: '/old-path',
|
|
38
|
+
redirectTo: '/new-path',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
path: '*',
|
|
42
|
+
component: () => {
|
|
43
|
+
const div = document.createElement('div');
|
|
44
|
+
div.textContent = '404 Not Found';
|
|
45
|
+
return div;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const router = createRouter(routes, { defaultTitle: 'My App' });
|
|
51
|
+
|
|
52
|
+
async function init() {
|
|
53
|
+
const outlet: RouterOutlet = await router.initialize();
|
|
54
|
+
|
|
55
|
+
const header = document.createElement('header');
|
|
56
|
+
const nav = document.createElement('nav');
|
|
57
|
+
const links = [
|
|
58
|
+
{ text: 'Home', path: '/' },
|
|
59
|
+
{ text: 'About', path: '/about' },
|
|
60
|
+
{ text: 'User', path: '/user/1' },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
links.forEach((link) => {
|
|
64
|
+
const a = document.createElement('a');
|
|
65
|
+
a.href = link.path;
|
|
66
|
+
a.textContent = link.text;
|
|
67
|
+
a.addEventListener('click', (e) => {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
router.push(link.path);
|
|
70
|
+
});
|
|
71
|
+
nav.appendChild(a);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
header.appendChild(nav);
|
|
75
|
+
|
|
76
|
+
const footer = document.createElement('footer');
|
|
77
|
+
|
|
78
|
+
document.body.appendChild(header);
|
|
79
|
+
document.body.appendChild(outlet);
|
|
80
|
+
document.body.appendChild(footer);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
init();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## API
|
|
87
|
+
|
|
88
|
+
### `createRouter(routes: Route[], options?: RouterOptions): Router`
|
|
89
|
+
|
|
90
|
+
Creates a router instance.
|
|
91
|
+
|
|
92
|
+
- `routes`: Array of route definitions.
|
|
93
|
+
- `options`:
|
|
94
|
+
- `defaultTitle`: Fallback document title.
|
|
95
|
+
- `globalErrorComponent`: Custom error component.
|
|
96
|
+
- `sortRoutesBySpecificity`: Sort routes by specificity (default: `true`).
|
|
97
|
+
- `ignoreSameLocation`: Skip same-path navigation (default: `true`).
|
|
98
|
+
|
|
99
|
+
#### `initialize(): Promise<RouterOutlet>`
|
|
100
|
+
|
|
101
|
+
Sets up popstate listener, navigates to current path, returns root `RouterOutlet`(web-component). Throws an error if it has been initialized.
|
|
102
|
+
|
|
103
|
+
#### `push(path: string, state?: unknown): Promise<void>`
|
|
104
|
+
|
|
105
|
+
Navigates, adding to history.
|
|
106
|
+
|
|
107
|
+
#### `replace(path: string, state?: unknown): Promise<void>`
|
|
108
|
+
|
|
109
|
+
Navigates, replacing history entry.
|
|
110
|
+
|
|
111
|
+
### Route Types
|
|
112
|
+
|
|
113
|
+
- `SyncRoute`: Returns `HTMLElement` via `component(ctx: RouteContext)`.
|
|
114
|
+
- `AsyncRoute`: Returns `Promise<HTMLElement>` via `loadComponent(ctx: RouteContext)`.
|
|
115
|
+
- `RedirectRoute`: Redirects via `redirectTo`.
|
|
116
|
+
|
|
117
|
+
#### `Route.beforeEnter`
|
|
118
|
+
|
|
119
|
+
Runs before navigation. Return `false` to cancel, string to redirect, or `true` to proceed.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
{
|
|
123
|
+
path: '/protected',
|
|
124
|
+
beforeEnter: [(ctx: RouteContext) => isAuthenticated() ? true : '/login'],
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `Route.afterEnter`
|
|
129
|
+
|
|
130
|
+
Runs after navigation.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
{
|
|
134
|
+
path: '/dashboard',
|
|
135
|
+
afterEnter: [(ctx: RouteContext) => console.log('Entered dashboard')],
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Error Handling
|
|
140
|
+
|
|
141
|
+
Use `errorComponent` in routes or `globalErrorComponent` in options.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const routes = [
|
|
145
|
+
{
|
|
146
|
+
path: '*',
|
|
147
|
+
errorComponent: (error, ctx) => {
|
|
148
|
+
const div = document.createElement('div');
|
|
149
|
+
div.textContent = `Error: ${error.message}`;
|
|
150
|
+
return div;
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
// or
|
|
156
|
+
|
|
157
|
+
const router = createRouter(routes, {
|
|
158
|
+
globalErrorComponent: (error) => {
|
|
159
|
+
const div = document.createElement('div');
|
|
160
|
+
div.textContent = 'Global Error';
|
|
161
|
+
return div;
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ declare interface BaseRoute {
|
|
|
11
11
|
title?: string | ((ctx: RouteContext) => string);
|
|
12
12
|
beforeEnter?: BeforeEnterHook[];
|
|
13
13
|
afterEnter?: AfterEnterHook[];
|
|
14
|
-
errorComponent?(error:
|
|
14
|
+
errorComponent?(error: Error, ctx: RouteContext | null): HTMLElement;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export declare type BeforeEnterHook = (ctx: RouteContext) => boolean | string | Promise<boolean | string>;
|
|
@@ -26,7 +26,7 @@ declare interface RedirectRoute extends BaseRoute {
|
|
|
26
26
|
|
|
27
27
|
export declare type Route = SyncRoute | AsyncRoute | RedirectRoute;
|
|
28
28
|
|
|
29
|
-
declare interface RouteContext {
|
|
29
|
+
export declare interface RouteContext {
|
|
30
30
|
from: string | null;
|
|
31
31
|
to: string;
|
|
32
32
|
params: Record<string, string>;
|
|
@@ -38,9 +38,9 @@ export declare class Router {
|
|
|
38
38
|
private readonly routerController;
|
|
39
39
|
private initialized;
|
|
40
40
|
private navigationController;
|
|
41
|
-
private readonly
|
|
41
|
+
private readonly routeMatchers;
|
|
42
42
|
private readonly options;
|
|
43
|
-
private readonly
|
|
43
|
+
private readonly outlet;
|
|
44
44
|
private currentPath;
|
|
45
45
|
constructor(routes: Route[], options?: RouterOptions);
|
|
46
46
|
initialize(): Promise<Readonly<RouterOutlet>>;
|
|
@@ -52,7 +52,7 @@ export declare class Router {
|
|
|
52
52
|
|
|
53
53
|
declare interface RouterOptions {
|
|
54
54
|
defaultTitle?: string;
|
|
55
|
-
globalErrorComponent?: (error:
|
|
55
|
+
globalErrorComponent?: (error: Error) => HTMLElement;
|
|
56
56
|
sortRoutesBySpecificity?: boolean;
|
|
57
57
|
ignoreSameLocation?: boolean;
|
|
58
58
|
}
|
|
@@ -71,4 +71,6 @@ declare interface SyncRoute extends BaseRoute {
|
|
|
71
71
|
loadComponent?(): Promise<HTMLElement>;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
export declare function withAbortSignal<T>(fn: () => Promise<T>, signal: AbortSignal): Promise<T>;
|
|
75
|
+
|
|
74
76
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
function P(t, e) {
|
|
2
|
-
const
|
|
3
|
-
|
|
2
|
+
const o = document.createElement("div");
|
|
3
|
+
o.style.cssText = `
|
|
4
4
|
position: fixed;
|
|
5
5
|
inset: 0;
|
|
6
6
|
background-color: rgba(0, 0, 0, 0.5);
|
|
@@ -11,8 +11,8 @@ function P(t, e) {
|
|
|
11
11
|
backdrop-filter: blur(4px);
|
|
12
12
|
animation: fadeIn 0.25s ease;
|
|
13
13
|
`;
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const n = document.createElement("div");
|
|
15
|
+
n.style.cssText = `
|
|
16
16
|
position: relative;
|
|
17
17
|
max-width: 80dvh;
|
|
18
18
|
width: 100%;
|
|
@@ -81,101 +81,115 @@ function P(t, e) {
|
|
|
81
81
|
}, l.onmouseleave = () => {
|
|
82
82
|
l.style.opacity = "0.7";
|
|
83
83
|
}, l.onclick = () => {
|
|
84
|
-
|
|
84
|
+
o.remove();
|
|
85
85
|
}, f.onmouseenter = () => {
|
|
86
86
|
f.style.backgroundColor = "var(--button-bg-hover)";
|
|
87
87
|
}, f.onmouseleave = () => {
|
|
88
88
|
f.style.backgroundColor = "var(--button-bg)";
|
|
89
89
|
}, f.onclick = () => {
|
|
90
90
|
location.reload();
|
|
91
|
-
},
|
|
91
|
+
}, o.appendChild(n), n.append(l, r, i, a), t.stack && n.append(d), n.append(f);
|
|
92
92
|
const g = (u) => {
|
|
93
|
-
u.key === "Escape" &&
|
|
93
|
+
u.key === "Escape" && o.remove();
|
|
94
94
|
};
|
|
95
95
|
window.addEventListener("keydown", g);
|
|
96
96
|
const w = new MutationObserver(() => {
|
|
97
|
-
document.body.contains(
|
|
97
|
+
document.body.contains(o) || (window.removeEventListener("keydown", g), w.disconnect());
|
|
98
98
|
});
|
|
99
99
|
w.observe(document.body, { childList: !0 });
|
|
100
100
|
const y = () => {
|
|
101
101
|
const u = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
102
|
-
|
|
102
|
+
n.style.setProperty("--bg", u ? "#2b2b2b" : "#fff"), n.style.setProperty("--text", u ? "#eee" : "#222"), n.style.setProperty("--accent", u ? "#ff6b6b" : "#e74c3c"), n.style.setProperty(
|
|
103
103
|
"--code-bg",
|
|
104
104
|
u ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)"
|
|
105
|
-
),
|
|
105
|
+
), n.style.setProperty("--button-bg", u ? "#3498db55" : "#3498db"), n.style.setProperty(
|
|
106
106
|
"--button-bg-hover",
|
|
107
107
|
u ? "#3498db88" : "#2980b9"
|
|
108
|
-
),
|
|
108
|
+
), n.style.setProperty("--button-text", "#fff");
|
|
109
109
|
};
|
|
110
110
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", y), y();
|
|
111
111
|
const b = document.createElement("style");
|
|
112
112
|
return b.textContent = `
|
|
113
113
|
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
114
114
|
@keyframes scaleIn { from { transform: scale(0.95); opacity: 0; } to { transform: scale(1); opacity: 1; } }
|
|
115
|
-
`, document.head.appendChild(b),
|
|
115
|
+
`, document.head.appendChild(b), o;
|
|
116
116
|
}
|
|
117
|
-
function
|
|
118
|
-
|
|
117
|
+
async function p(t, e) {
|
|
118
|
+
if (e.aborted)
|
|
119
|
+
throw new DOMException("Aborted", "AbortError");
|
|
120
|
+
return new Promise((o, n) => {
|
|
121
|
+
const r = () => n(new DOMException("Aborted", "AbortError"));
|
|
122
|
+
e.addEventListener("abort", r), t().then(o).catch(n).finally(() => {
|
|
123
|
+
e.removeEventListener("abort", r);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
119
126
|
}
|
|
120
|
-
function
|
|
121
|
-
const
|
|
122
|
-
|
|
127
|
+
function k(t) {
|
|
128
|
+
const e = typeof t == "string" ? t : "Unknown error";
|
|
129
|
+
return t instanceof Error ? t : new Error(e);
|
|
130
|
+
}
|
|
131
|
+
function T(t, e, o) {
|
|
132
|
+
t.title ? document.title = typeof t.title == "function" ? t.title(e) : t.title : document.title = o ?? "";
|
|
133
|
+
}
|
|
134
|
+
function m(t, e, o) {
|
|
135
|
+
const n = e ?? null;
|
|
136
|
+
switch (o) {
|
|
123
137
|
case "push":
|
|
124
|
-
window.history.pushState(
|
|
138
|
+
window.history.pushState(n, "", t);
|
|
125
139
|
break;
|
|
126
140
|
case "replace":
|
|
127
|
-
window.history.replaceState(
|
|
141
|
+
window.history.replaceState(n, "", t);
|
|
128
142
|
break;
|
|
129
143
|
}
|
|
130
144
|
}
|
|
131
|
-
function
|
|
145
|
+
function L(t, e) {
|
|
132
146
|
t.replaceChildren(e);
|
|
133
147
|
}
|
|
134
|
-
function h(t, e,
|
|
135
|
-
const i =
|
|
136
|
-
t.replaceChildren(
|
|
148
|
+
function h(t, e, o, n, r) {
|
|
149
|
+
const i = k(e), a = o?.errorComponent?.(i, n) ?? r?.(i) ?? P(i, n);
|
|
150
|
+
t.replaceChildren(a);
|
|
137
151
|
}
|
|
138
152
|
const A = "*";
|
|
139
|
-
function
|
|
153
|
+
function z({ path: t }) {
|
|
140
154
|
return t.includes(":");
|
|
141
155
|
}
|
|
142
156
|
function x(t) {
|
|
143
157
|
const [, e] = t.split("?");
|
|
144
158
|
return new URLSearchParams(e || "");
|
|
145
159
|
}
|
|
146
|
-
function
|
|
160
|
+
function S({ path: t }) {
|
|
147
161
|
const e = t.replace(
|
|
148
162
|
/:([^/]+)/g,
|
|
149
|
-
(
|
|
163
|
+
(o, n) => `(?<${n}>[^/]+)`
|
|
150
164
|
);
|
|
151
165
|
return new RegExp(`^${e}$`);
|
|
152
166
|
}
|
|
153
|
-
function
|
|
154
|
-
const e =
|
|
167
|
+
function $(t) {
|
|
168
|
+
const e = S(t);
|
|
155
169
|
return {
|
|
156
170
|
route: t,
|
|
157
171
|
redirectTo: t.redirectTo || null,
|
|
158
|
-
match(
|
|
159
|
-
const
|
|
160
|
-
return e.test(
|
|
172
|
+
match(o) {
|
|
173
|
+
const n = o.split("?")[0];
|
|
174
|
+
return e.test(n);
|
|
161
175
|
},
|
|
162
|
-
getParams(
|
|
163
|
-
return e.exec(
|
|
176
|
+
getParams(o) {
|
|
177
|
+
return e.exec(o)?.groups ?? {};
|
|
164
178
|
},
|
|
165
179
|
getQuery: x
|
|
166
180
|
};
|
|
167
181
|
}
|
|
168
|
-
function
|
|
182
|
+
function M({ path: t }) {
|
|
169
183
|
return t === A ? new RegExp("^.*$") : new RegExp(`^${t}$`);
|
|
170
184
|
}
|
|
171
|
-
function
|
|
172
|
-
const e =
|
|
185
|
+
function W(t) {
|
|
186
|
+
const e = M(t);
|
|
173
187
|
return {
|
|
174
188
|
route: t,
|
|
175
189
|
redirectTo: t.redirectTo || null,
|
|
176
|
-
match(
|
|
177
|
-
const
|
|
178
|
-
return e.test(
|
|
190
|
+
match(o) {
|
|
191
|
+
const n = o.split("?")[0];
|
|
192
|
+
return e.test(n);
|
|
179
193
|
},
|
|
180
194
|
getParams() {
|
|
181
195
|
return {};
|
|
@@ -183,30 +197,30 @@ function I(t) {
|
|
|
183
197
|
getQuery: x
|
|
184
198
|
};
|
|
185
199
|
}
|
|
186
|
-
function
|
|
187
|
-
return
|
|
200
|
+
function U(t) {
|
|
201
|
+
return z(t) ? $(t) : W(t);
|
|
188
202
|
}
|
|
189
|
-
function
|
|
190
|
-
for (let
|
|
191
|
-
if (e[
|
|
192
|
-
return e[
|
|
203
|
+
function B(t, e) {
|
|
204
|
+
for (let o = 0; o < e.length; o++)
|
|
205
|
+
if (e[o].match(t))
|
|
206
|
+
return e[o];
|
|
193
207
|
return null;
|
|
194
208
|
}
|
|
195
|
-
async function
|
|
196
|
-
return typeof t.component == "function" ? t.component(e) : typeof t.loadComponent == "function" ? await t.loadComponent(e) : new Error("Failed to get component for route");
|
|
209
|
+
async function H(t, e) {
|
|
210
|
+
return typeof t.component == "function" ? t.component(e) : typeof t.loadComponent == "function" ? await t.loadComponent(e) : new Error("Failed to get component for route: " + t.path);
|
|
197
211
|
}
|
|
198
|
-
async function
|
|
199
|
-
const
|
|
200
|
-
if (!(!
|
|
201
|
-
for (const
|
|
202
|
-
await
|
|
212
|
+
async function I(t, e) {
|
|
213
|
+
const o = t.afterEnter;
|
|
214
|
+
if (!(!o || o.length === 0))
|
|
215
|
+
for (const n of o)
|
|
216
|
+
await n(e);
|
|
203
217
|
}
|
|
204
|
-
async function
|
|
205
|
-
const
|
|
206
|
-
if (!
|
|
218
|
+
async function O(t, e) {
|
|
219
|
+
const o = t.beforeEnter;
|
|
220
|
+
if (!o || o.length === 0)
|
|
207
221
|
return null;
|
|
208
|
-
for (const
|
|
209
|
-
const r = await
|
|
222
|
+
for (const n of o) {
|
|
223
|
+
const r = await n(e);
|
|
210
224
|
if (r === !1 || typeof r == "string")
|
|
211
225
|
return r;
|
|
212
226
|
}
|
|
@@ -215,42 +229,32 @@ async function H(t, e) {
|
|
|
215
229
|
function E(t) {
|
|
216
230
|
return t instanceof DOMException && t.name === "AbortError";
|
|
217
231
|
}
|
|
218
|
-
class C extends HTMLElement {
|
|
219
|
-
constructor(e) {
|
|
220
|
-
super(), this.setAttribute("outlet-id", e.outletId);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
customElements.define("router-outlet", C);
|
|
224
|
-
async function m(t, e) {
|
|
225
|
-
if (e.aborted)
|
|
226
|
-
throw new DOMException("Aborted", "AbortError");
|
|
227
|
-
return new Promise((n, o) => {
|
|
228
|
-
const r = () => o(new DOMException("Aborted", "AbortError"));
|
|
229
|
-
e.addEventListener("abort", r), t().then(n).catch(o).finally(() => {
|
|
230
|
-
e.removeEventListener("abort", r);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
232
|
function v(t) {
|
|
235
233
|
const e = t.split("/").filter(Boolean);
|
|
236
234
|
if (e.length === 0)
|
|
237
235
|
return 0;
|
|
238
|
-
let
|
|
239
|
-
for (let
|
|
240
|
-
const r = e[
|
|
241
|
-
r === "*" ?
|
|
236
|
+
let o = 0;
|
|
237
|
+
for (let n = 0; n < e.length; n++) {
|
|
238
|
+
const r = e[n];
|
|
239
|
+
r === "*" ? o -= 100 : r.startsWith(":") ? o += 5 : o += 10;
|
|
242
240
|
}
|
|
243
|
-
return
|
|
241
|
+
return o += e.length * 0.1, o;
|
|
244
242
|
}
|
|
245
|
-
function
|
|
246
|
-
return t.toSorted((e,
|
|
243
|
+
function D(t) {
|
|
244
|
+
return t.toSorted((e, o) => v(o.path) - v(e.path));
|
|
247
245
|
}
|
|
248
|
-
function
|
|
246
|
+
function Q(t, e) {
|
|
249
247
|
if (t === null)
|
|
250
248
|
return !1;
|
|
251
|
-
const
|
|
252
|
-
return !(
|
|
249
|
+
const o = new URL(t, location.origin), n = new URL(e, location.origin);
|
|
250
|
+
return !(o.pathname !== n.pathname || o.search !== n.search);
|
|
251
|
+
}
|
|
252
|
+
class C extends HTMLElement {
|
|
253
|
+
constructor(e) {
|
|
254
|
+
super(), this.setAttribute("outlet-id", e.outletId);
|
|
255
|
+
}
|
|
253
256
|
}
|
|
257
|
+
customElements.define("router-outlet", C);
|
|
254
258
|
function R(t) {
|
|
255
259
|
if (typeof t != "string")
|
|
256
260
|
throw new Error(`Path must be a string, got ${typeof t}`);
|
|
@@ -271,16 +275,16 @@ function R(t) {
|
|
|
271
275
|
`Path contains invalid characters: "${e.join("")}" in "${t}"`
|
|
272
276
|
);
|
|
273
277
|
}
|
|
274
|
-
function
|
|
278
|
+
function _(t) {
|
|
275
279
|
const e = /* @__PURE__ */ new Set();
|
|
276
|
-
for (let
|
|
277
|
-
const
|
|
278
|
-
if (e.has(
|
|
279
|
-
throw new Error(`Duplicate root route path: "${
|
|
280
|
-
e.add(
|
|
280
|
+
for (let o = 0; o < t.length; o++) {
|
|
281
|
+
const n = t[o].path;
|
|
282
|
+
if (e.has(n))
|
|
283
|
+
throw new Error(`Duplicate root route path: "${n}"`);
|
|
284
|
+
e.add(n);
|
|
281
285
|
}
|
|
282
286
|
}
|
|
283
|
-
function
|
|
287
|
+
function q(t) {
|
|
284
288
|
if (!(t.redirectTo === null || t.redirectTo == null) && typeof t.redirectTo == "string") {
|
|
285
289
|
const e = t.redirectTo;
|
|
286
290
|
if (R(e), e === t.path)
|
|
@@ -289,74 +293,75 @@ function _(t) {
|
|
|
289
293
|
throw new Error('Catch-all route "*" cannot have a redirect');
|
|
290
294
|
}
|
|
291
295
|
}
|
|
292
|
-
function
|
|
293
|
-
const e = typeof t.redirectTo == "string",
|
|
294
|
-
if (e && (
|
|
296
|
+
function F(t) {
|
|
297
|
+
const e = typeof t.redirectTo == "string", o = typeof t.component == "function", n = typeof t.loadComponent == "function";
|
|
298
|
+
if (e && (o || n))
|
|
295
299
|
throw new Error(
|
|
296
300
|
`Redirect route "${t.path}" must not define components`
|
|
297
301
|
);
|
|
298
|
-
if (
|
|
302
|
+
if (o && n)
|
|
299
303
|
throw new Error(
|
|
300
304
|
`Route "${t.path}" cannot have both component and loadComponent`
|
|
301
305
|
);
|
|
302
|
-
if (!e && !
|
|
306
|
+
if (!e && !o && !n)
|
|
303
307
|
throw new Error(
|
|
304
308
|
`Route "${t.path}" must define either "component" or "loadComponent"`
|
|
305
309
|
);
|
|
306
310
|
}
|
|
307
|
-
function F(t) {
|
|
308
|
-
R(t.path), _(t), q(t);
|
|
309
|
-
}
|
|
310
311
|
function j(t) {
|
|
311
|
-
|
|
312
|
+
R(t.path), q(t), F(t);
|
|
313
|
+
}
|
|
314
|
+
function K(t) {
|
|
315
|
+
_(t);
|
|
312
316
|
for (let e = 0; e < t.length; e++) {
|
|
313
|
-
const
|
|
314
|
-
|
|
317
|
+
const o = t[e];
|
|
318
|
+
j(o);
|
|
315
319
|
}
|
|
316
320
|
}
|
|
317
|
-
class
|
|
321
|
+
class Z {
|
|
318
322
|
routerController = new AbortController();
|
|
319
323
|
initialized = !1;
|
|
320
324
|
navigationController = null;
|
|
321
|
-
|
|
325
|
+
routeMatchers = [];
|
|
322
326
|
options;
|
|
323
|
-
|
|
327
|
+
outlet = new C({ outletId: "root" });
|
|
324
328
|
currentPath = null;
|
|
325
|
-
constructor(e,
|
|
326
|
-
|
|
329
|
+
constructor(e, o) {
|
|
330
|
+
K(e), this.options = {
|
|
327
331
|
defaultTitle: document.title,
|
|
328
332
|
sortRoutesBySpecificity: !0,
|
|
329
|
-
|
|
333
|
+
ignoreSameLocation: !0,
|
|
334
|
+
...o
|
|
330
335
|
};
|
|
331
|
-
const
|
|
332
|
-
this.
|
|
336
|
+
const n = this.options.sortRoutesBySpecificity ? D(e) : e;
|
|
337
|
+
this.routeMatchers = n.map(U);
|
|
333
338
|
}
|
|
334
339
|
async initialize() {
|
|
335
340
|
if (this.initialized)
|
|
336
341
|
throw new Error("Router already initialized");
|
|
337
|
-
const e = async (
|
|
342
|
+
const e = async (n) => {
|
|
338
343
|
const r = window.location.pathname + window.location.search;
|
|
339
|
-
await this.navigate(r,
|
|
344
|
+
await this.navigate(r, n.state, "none");
|
|
340
345
|
};
|
|
341
346
|
window.addEventListener(
|
|
342
347
|
"popstate",
|
|
343
|
-
(
|
|
344
|
-
e(
|
|
348
|
+
(n) => {
|
|
349
|
+
e(n).catch(console.error);
|
|
345
350
|
},
|
|
346
351
|
{ signal: this.routerController.signal }
|
|
347
352
|
);
|
|
348
|
-
const
|
|
349
|
-
return await this.navigate(
|
|
353
|
+
const o = window.location.pathname + window.location.search;
|
|
354
|
+
return await this.navigate(o, null, "none"), this.initialized = !0, this.outlet;
|
|
350
355
|
}
|
|
351
356
|
destroy() {
|
|
352
357
|
if (!this.initialized)
|
|
353
358
|
throw new Error("Router not initialized");
|
|
354
359
|
this.routerController.abort(), this.navigationController && (this.navigationController.abort(), this.navigationController = null), this.initialized = !1;
|
|
355
360
|
}
|
|
356
|
-
async navigate(e,
|
|
361
|
+
async navigate(e, o, n, r = 0) {
|
|
357
362
|
if (r > 5) {
|
|
358
363
|
h(
|
|
359
|
-
this.
|
|
364
|
+
this.outlet,
|
|
360
365
|
new Error("Too many redirects"),
|
|
361
366
|
null,
|
|
362
367
|
null,
|
|
@@ -364,10 +369,10 @@ class K {
|
|
|
364
369
|
);
|
|
365
370
|
return;
|
|
366
371
|
}
|
|
367
|
-
if (this.options.ignoreSameLocation &&
|
|
372
|
+
if (this.options.ignoreSameLocation && Q(this.currentPath, e))
|
|
368
373
|
return;
|
|
369
374
|
this.navigationController && (this.navigationController.abort("navigation canceled"), this.navigationController = null), this.navigationController = new AbortController();
|
|
370
|
-
const i = this.navigationController.signal, a =
|
|
375
|
+
const i = this.navigationController.signal, a = B(e, this.routeMatchers), s = {
|
|
371
376
|
from: this.currentPath,
|
|
372
377
|
to: e,
|
|
373
378
|
params: a?.getParams(e) ?? {},
|
|
@@ -376,8 +381,8 @@ class K {
|
|
|
376
381
|
};
|
|
377
382
|
try {
|
|
378
383
|
if (!a) {
|
|
379
|
-
|
|
380
|
-
this.
|
|
384
|
+
m(e, o, n), h(
|
|
385
|
+
this.outlet,
|
|
381
386
|
new Error('Route not found. Add "*" catch-all route'),
|
|
382
387
|
null,
|
|
383
388
|
s,
|
|
@@ -386,32 +391,32 @@ class K {
|
|
|
386
391
|
return;
|
|
387
392
|
}
|
|
388
393
|
if (a.redirectTo) {
|
|
389
|
-
await this.navigate(a.redirectTo,
|
|
394
|
+
await this.navigate(a.redirectTo, o, "replace", r + 1);
|
|
390
395
|
return;
|
|
391
396
|
}
|
|
392
397
|
if (i.aborted)
|
|
393
398
|
return;
|
|
394
|
-
const c = await
|
|
395
|
-
() =>
|
|
399
|
+
const c = await p(
|
|
400
|
+
() => O(a.route, s),
|
|
396
401
|
i
|
|
397
402
|
);
|
|
398
403
|
if (c === !1)
|
|
399
404
|
return;
|
|
400
405
|
if (typeof c == "string") {
|
|
401
|
-
await this.navigate(c,
|
|
406
|
+
await this.navigate(c, o, "replace", r + 1);
|
|
402
407
|
return;
|
|
403
408
|
}
|
|
404
409
|
if (i.aborted)
|
|
405
410
|
return;
|
|
406
|
-
const d = await
|
|
407
|
-
() =>
|
|
411
|
+
const d = await p(
|
|
412
|
+
() => H(a.route, s),
|
|
408
413
|
i
|
|
409
414
|
);
|
|
410
415
|
if (d instanceof Error) {
|
|
411
416
|
if (E(d))
|
|
412
417
|
return;
|
|
413
|
-
|
|
414
|
-
this.
|
|
418
|
+
m(e, o, n), h(
|
|
419
|
+
this.outlet,
|
|
415
420
|
d,
|
|
416
421
|
a.route,
|
|
417
422
|
s,
|
|
@@ -421,12 +426,12 @@ class K {
|
|
|
421
426
|
}
|
|
422
427
|
if (i.aborted)
|
|
423
428
|
return;
|
|
424
|
-
|
|
429
|
+
L(this.outlet, d), m(e, o, n), T(a.route, s, this.options.defaultTitle), this.currentPath = e, await p(() => I(a.route, s), i);
|
|
425
430
|
} catch (c) {
|
|
426
431
|
if (E(c))
|
|
427
432
|
return;
|
|
428
433
|
h(
|
|
429
|
-
this.
|
|
434
|
+
this.outlet,
|
|
430
435
|
c instanceof Error ? c : new Error("Unknown error"),
|
|
431
436
|
a?.route ?? null,
|
|
432
437
|
s,
|
|
@@ -436,25 +441,26 @@ class K {
|
|
|
436
441
|
this.navigationController?.signal === i && (this.navigationController = null);
|
|
437
442
|
}
|
|
438
443
|
}
|
|
439
|
-
async push(e,
|
|
444
|
+
async push(e, o) {
|
|
440
445
|
try {
|
|
441
|
-
await this.navigate(e,
|
|
442
|
-
} catch (
|
|
443
|
-
console.error("[Router.push] Error:",
|
|
446
|
+
await this.navigate(e, o, "push");
|
|
447
|
+
} catch (n) {
|
|
448
|
+
console.error("[Router.push] Error:", n);
|
|
444
449
|
}
|
|
445
450
|
}
|
|
446
|
-
async replace(e,
|
|
451
|
+
async replace(e, o) {
|
|
447
452
|
try {
|
|
448
|
-
await this.navigate(e,
|
|
449
|
-
} catch (
|
|
450
|
-
console.error("[Router.replace] Error:",
|
|
453
|
+
await this.navigate(e, o, "replace");
|
|
454
|
+
} catch (n) {
|
|
455
|
+
console.error("[Router.replace] Error:", n);
|
|
451
456
|
}
|
|
452
457
|
}
|
|
453
458
|
}
|
|
454
|
-
function
|
|
455
|
-
return new
|
|
459
|
+
function J(t, e) {
|
|
460
|
+
return new Z(t, e);
|
|
456
461
|
}
|
|
457
462
|
export {
|
|
458
|
-
|
|
459
|
-
|
|
463
|
+
Z as Router,
|
|
464
|
+
J as createRouter,
|
|
465
|
+
p as withAbortSignal
|
|
460
466
|
};
|