sinwan-router 1.0.2 → 1.1.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/README.md +27 -6
- package/dist/components.d.ts +29 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +335 -162
- package/dist/index.js.map +7 -6
- package/dist/jsx-routes.d.ts +2 -1
- package/dist/router.d.ts +18 -4
- package/dist/scroll.d.ts +9 -0
- package/dist/types.d.ts +24 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ const App = cc(() => {
|
|
|
76
76
|
<div>
|
|
77
77
|
<nav>
|
|
78
78
|
<Link href="/">Home</Link>
|
|
79
|
-
<NavLink href="/about"
|
|
79
|
+
<NavLink href="/about" class={({ isActive }) => (isActive ? "active" : undefined)}>
|
|
80
80
|
About
|
|
81
81
|
</NavLink>
|
|
82
82
|
</nav>
|
|
@@ -111,7 +111,7 @@ const App = cc(() => (
|
|
|
111
111
|
));
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
`Routes` collects `<Route>` children into a router, provides `RouterKey` to layout siblings (`Link`, `NavLink`), and renders a `<RouterOutlet />`. Put links **inside** `<Routes>` — they need that context. You can still pass `fallback`, `notFound`, `error`, and `
|
|
114
|
+
`Routes` collects `<Route>` children into a router, provides `RouterKey` to layout siblings (`Link`, `NavLink`), and renders a `<RouterOutlet />`. Put links **inside** `<Routes>` — they need that context. You can still pass `fallback`, `notFound`, `error`, `initialPath`, and `scroll`.
|
|
115
115
|
|
|
116
116
|
## Routes
|
|
117
117
|
|
|
@@ -156,6 +156,24 @@ router.dispose();
|
|
|
156
156
|
|
|
157
157
|
`prefetch` and `RouterOutlet` share the same instance cache. `dispose()` removes the `popstate` listener and drops that cache.
|
|
158
158
|
|
|
159
|
+
### Scroll after navigation
|
|
160
|
+
|
|
161
|
+
By default the router leaves the window scroll alone (`scroll: "preserve"`). For a site where each page should open at the top, use `scroll: "top"`:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
const router = createRouter(routes, { scroll: "top" });
|
|
165
|
+
// or
|
|
166
|
+
<Routes scroll="top">…</Routes>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- `navigate()` (and so `Link`, `NavLink`, `useNavigate`) scrolls the window to the top.
|
|
170
|
+
- An href with a hash (`/products#pricing`) scrolls to the element with that id once the route has rendered, waiting for lazy routes. Use `scroll-margin-top` on the target to clear a sticky header.
|
|
171
|
+
- The hash of the first page load is revealed the same way.
|
|
172
|
+
- Back and forward keep the browser's own scroll restoration.
|
|
173
|
+
- `navigate(to, { scroll: false })` skips one navigation, for example a query-param tab switch.
|
|
174
|
+
|
|
175
|
+
`createRouter(routes, "/path")` still sets the initial path; `createRouter(routes, { initialPath: "/path" })` is the same.
|
|
176
|
+
|
|
159
177
|
```tsx
|
|
160
178
|
<Link href="/users/1" class="nav">
|
|
161
179
|
Profile
|
|
@@ -165,12 +183,15 @@ router.dispose();
|
|
|
165
183
|
Docs
|
|
166
184
|
</Link>
|
|
167
185
|
|
|
168
|
-
<NavLink
|
|
186
|
+
<NavLink
|
|
187
|
+
href="/users"
|
|
188
|
+
class={({ isActive }) => (isActive ? "nav active" : "nav")}
|
|
189
|
+
>
|
|
169
190
|
Users
|
|
170
191
|
</NavLink>
|
|
171
192
|
```
|
|
172
193
|
|
|
173
|
-
`NavLink` is active on an exact match or a nested prefix (`/users` matches `/users/42`). Prefetch on hover is on by default; pass `prefetch={false}` to disable.
|
|
194
|
+
`NavLink` is active on an exact match or a nested prefix (`/users` matches `/users/42`). Pass `class={({ isActive }) => …}` to choose active vs idle styles (avoids Tailwind utility clashes). With no `class` prop, active links get `"active"` for CSS selectors. Prefetch on hover is on by default; pass `prefetch={false}` to disable.
|
|
174
195
|
|
|
175
196
|
## Outlet
|
|
176
197
|
|
|
@@ -183,7 +204,7 @@ router.dispose();
|
|
|
183
204
|
| ----------- | -------------------------------------------------------------------- |
|
|
184
205
|
| `depth` | `0` is the root match; `1` is the first nested child, and so on |
|
|
185
206
|
| `fallback` | Shown while a lazy import is in flight |
|
|
186
|
-
| `notFound` | Shown at depth `0` when nothing matches; nested outlets render nothing |
|
|
207
|
+
| `notFound` | Shown at depth `0` when nothing matches; nested outlets render nothing. Omit to use the built-in styled 404 (path + home link). |
|
|
187
208
|
| `error` | Shown when a lazy import rejects (`{ error?: unknown }` props) |
|
|
188
209
|
|
|
189
210
|
Put `<RouterOutlet depth={1} />` inside a parent layout to render the child.
|
|
@@ -213,7 +234,7 @@ navigate("/about", { replace: true });
|
|
|
213
234
|
## Features
|
|
214
235
|
|
|
215
236
|
- Radix-tree matcher: `createRadixTree`, `radixInsert`, `radixSearch`, `buildPath`, `normalizePath`
|
|
216
|
-
- Router: `createRouter`, `navigate`, `prefetch`, `resolveComponent`, `dispose`, `lazy` / `isLazyComponent`
|
|
237
|
+
- Router: `createRouter` (`initialPath`, `scroll`), `navigate`, `prefetch`, `resolveComponent`, `dispose`, `lazy` / `isLazyComponent`
|
|
217
238
|
- Components: `Link`, `NavLink`, `RouterOutlet`, `Routes`, `Route`
|
|
218
239
|
- Hooks: `useRouter`, `useParams`, `useSearchParams`, `useRoute`, `useNavigate`, `usePath`, `RouterKey`
|
|
219
240
|
|
package/dist/components.d.ts
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* The router instance must be provided via provide(RouterKey, router).
|
|
6
6
|
*/
|
|
7
7
|
import type { SinwanComponent, SinwanNode } from "sinwan/component";
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Anchor props for client navigation. Extra keys (data-*, aria-*, ref,
|
|
10
|
+
* mouse/focus handlers) are forwarded so Slot / asChild parents can merge
|
|
11
|
+
* onto the real `<a>` (e.g. SidebarMenuButton tooltip).
|
|
12
|
+
*/
|
|
13
|
+
export type LinkProps = {
|
|
9
14
|
href: string;
|
|
10
15
|
prefetch?: boolean;
|
|
11
16
|
class?: string;
|
|
@@ -13,15 +18,34 @@ export interface LinkProps {
|
|
|
13
18
|
target?: string;
|
|
14
19
|
download?: string | boolean;
|
|
15
20
|
rel?: string;
|
|
16
|
-
|
|
21
|
+
onclick?: (event: MouseEvent) => void;
|
|
22
|
+
onmouseenter?: (event: MouseEvent) => void;
|
|
23
|
+
} & Record<string, unknown>;
|
|
17
24
|
/**
|
|
18
25
|
* Link — client-side navigation anchor.
|
|
19
26
|
* Uses the router from context (provide(RouterKey, router)).
|
|
20
27
|
*/
|
|
21
28
|
export declare const Link: SinwanComponent<LinkProps>;
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
}
|
|
29
|
+
export type NavLinkClassOptions = {
|
|
30
|
+
isActive: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type NavLinkClassFunction = (options: NavLinkClassOptions) => string | false | null | undefined;
|
|
33
|
+
export type NavLinkProps = {
|
|
34
|
+
href: string;
|
|
35
|
+
prefetch?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Static class string, or a callback that receives `{ isActive }` so
|
|
38
|
+
* active/inactive styles never share conflicting Tailwind utilities.
|
|
39
|
+
* When omitted, active links get the class `"active"` (CSS templates).
|
|
40
|
+
*/
|
|
41
|
+
class?: string | NavLinkClassFunction;
|
|
42
|
+
children?: SinwanNode;
|
|
43
|
+
target?: string;
|
|
44
|
+
download?: string | boolean;
|
|
45
|
+
rel?: string;
|
|
46
|
+
onclick?: (event: MouseEvent) => void;
|
|
47
|
+
onmouseenter?: (event: MouseEvent) => void;
|
|
48
|
+
} & Record<string, unknown>;
|
|
25
49
|
/**
|
|
26
50
|
* NavLink — Link with active state styling.
|
|
27
51
|
* Uses the router from context.
|
package/dist/index.d.ts
CHANGED
|
@@ -32,8 +32,8 @@ export { createRouter, Router, isLazyComponent, lazy } from "./router.ts";
|
|
|
32
32
|
export { createRadixTree, radixInsert, radixSearch, buildPath, normalizePath, extractSearchParams, } from "./matcher.ts";
|
|
33
33
|
export type { RadixNode, RouteData, MatchResult } from "./matcher.ts";
|
|
34
34
|
export { Link, NavLink, RouterOutlet } from "./components.tsx";
|
|
35
|
-
export type { LinkProps, NavLinkProps, RouterOutletProps, } from "./components.tsx";
|
|
35
|
+
export type { LinkProps, NavLinkProps, NavLinkClassOptions, NavLinkClassFunction, RouterOutletProps, } from "./components.tsx";
|
|
36
36
|
export { Route, Routes, collectRouteDefinitions, isRouteElement, layoutNodes, } from "./jsx-routes.tsx";
|
|
37
37
|
export type { RouteProps, RoutesProps } from "./jsx-routes.tsx";
|
|
38
38
|
export { useRouter, useParams, useSearchParams, useRoute, useNavigate, usePath, RouterKey, } from "./hooks.ts";
|
|
39
|
-
export type { RouteDefinition, RouteComponent, LazyComponent, MatchedRoute, NavigateOptions, RouterContextValue, LazyPeek, } from "./types.ts";
|
|
39
|
+
export type { RouteDefinition, RouteComponent, LazyComponent, MatchedRoute, NavigateOptions, RouterOptions, RouterScroll, RouterContextValue, LazyPeek, } from "./types.ts";
|
package/dist/index.js
CHANGED
|
@@ -190,6 +190,24 @@ function buildPath(pattern, params = {}) {
|
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
// src/scroll.ts
|
|
194
|
+
function hashFromHref(href) {
|
|
195
|
+
const index = href.indexOf("#");
|
|
196
|
+
return index === -1 ? "" : href.slice(index + 1);
|
|
197
|
+
}
|
|
198
|
+
function findHashTarget(doc, hash) {
|
|
199
|
+
let id = hash;
|
|
200
|
+
try {
|
|
201
|
+
id = decodeURIComponent(hash);
|
|
202
|
+
} catch {}
|
|
203
|
+
return doc.getElementById(id);
|
|
204
|
+
}
|
|
205
|
+
function nextFrame(win) {
|
|
206
|
+
return new Promise((resolve) => {
|
|
207
|
+
win.requestAnimationFrame(() => resolve());
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
193
211
|
// src/router.ts
|
|
194
212
|
function hasTrueFlag(value, key) {
|
|
195
213
|
return key in value && value[key] === true;
|
|
@@ -220,7 +238,11 @@ class Router {
|
|
|
220
238
|
lazyInflight = new Map;
|
|
221
239
|
_lazyTick;
|
|
222
240
|
popstateHandler = null;
|
|
223
|
-
|
|
241
|
+
scroll;
|
|
242
|
+
scrollToken = 0;
|
|
243
|
+
constructor(routes, options = {}) {
|
|
244
|
+
const { initialPath, scroll = "preserve" } = typeof options === "string" ? { initialPath: options } : options;
|
|
245
|
+
this.scroll = scroll;
|
|
224
246
|
this.tree = createRadixTree();
|
|
225
247
|
this.routeList = [];
|
|
226
248
|
this._lazyTick = signal(0);
|
|
@@ -264,6 +286,11 @@ class Router {
|
|
|
264
286
|
this._searchParams.value = extractSearchParams(url);
|
|
265
287
|
};
|
|
266
288
|
window.addEventListener("popstate", this.popstateHandler);
|
|
289
|
+
if (this.scroll === "top") {
|
|
290
|
+
const initialHash = hashFromHref(window.location.hash);
|
|
291
|
+
if (initialHash)
|
|
292
|
+
this.revealHash(initialHash);
|
|
293
|
+
}
|
|
267
294
|
}
|
|
268
295
|
}
|
|
269
296
|
insertRoute(route, parentPath, parentChain = []) {
|
|
@@ -351,6 +378,35 @@ class Router {
|
|
|
351
378
|
}
|
|
352
379
|
this._path.value = normalized;
|
|
353
380
|
this._searchParams.value = extractSearchParams(to);
|
|
381
|
+
if (options.scroll !== false)
|
|
382
|
+
this.applyScroll(to);
|
|
383
|
+
}
|
|
384
|
+
applyScroll(to) {
|
|
385
|
+
if (this.scroll !== "top" || typeof window === "undefined")
|
|
386
|
+
return;
|
|
387
|
+
this.scrollToken++;
|
|
388
|
+
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
|
389
|
+
const hash = hashFromHref(to);
|
|
390
|
+
if (hash)
|
|
391
|
+
this.revealHash(hash);
|
|
392
|
+
}
|
|
393
|
+
revealHash(hash) {
|
|
394
|
+
const token = ++this.scrollToken;
|
|
395
|
+
this.whenRouteRendered().then(() => {
|
|
396
|
+
if (token !== this.scrollToken)
|
|
397
|
+
return;
|
|
398
|
+
findHashTarget(window.document, hash)?.scrollIntoView();
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
async whenRouteRendered() {
|
|
402
|
+
const loads = [];
|
|
403
|
+
for (let m = this._matched.value ?? undefined;m; m = m.parent) {
|
|
404
|
+
if (isLazyComponent(m.route.component)) {
|
|
405
|
+
loads.push(this.resolveComponent(m.route));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
await Promise.allSettled(loads);
|
|
409
|
+
await nextFrame(window);
|
|
354
410
|
}
|
|
355
411
|
prefetch(path) {
|
|
356
412
|
if (typeof window === "undefined")
|
|
@@ -404,6 +460,7 @@ class Router {
|
|
|
404
460
|
window.removeEventListener("popstate", this.popstateHandler);
|
|
405
461
|
this.popstateHandler = null;
|
|
406
462
|
}
|
|
463
|
+
this.scrollToken++;
|
|
407
464
|
this.lazyCache.clear();
|
|
408
465
|
this.lazyErrors.clear();
|
|
409
466
|
this.lazyInflight.clear();
|
|
@@ -417,13 +474,13 @@ function joinPaths(parent, child) {
|
|
|
417
474
|
return "/" + relativeChild;
|
|
418
475
|
return parent + "/" + relativeChild;
|
|
419
476
|
}
|
|
420
|
-
function createRouter(routes,
|
|
421
|
-
return new Router(routes,
|
|
477
|
+
function createRouter(routes, options) {
|
|
478
|
+
return new Router(routes, options);
|
|
422
479
|
}
|
|
423
480
|
// src/components.tsx
|
|
424
|
-
import { _$createTemplate } from "sinwan/renderer";
|
|
425
|
-
import { cc } from "sinwan/component";
|
|
426
|
-
import { Key } from "sinwan/
|
|
481
|
+
import { _$createTemplate } from "sinwan/renderer/web";
|
|
482
|
+
import { cc, getRawProps } from "sinwan/component";
|
|
483
|
+
import { Key } from "sinwan/control-flow";
|
|
427
484
|
import { computed as computed2 } from "sinwan/reactivity";
|
|
428
485
|
|
|
429
486
|
// src/hooks.ts
|
|
@@ -550,87 +607,53 @@ function computeOutletKey(router, depth) {
|
|
|
550
607
|
// src/components.tsx
|
|
551
608
|
import { jsxDEV } from "sinwan/jsx-dev-runtime";
|
|
552
609
|
var _$tmpl_0 = {
|
|
553
|
-
html: '<
|
|
554
|
-
slots: [
|
|
555
|
-
path: [],
|
|
556
|
-
type: "attr",
|
|
557
|
-
name: "
|
|
558
|
-
|
|
559
|
-
path: [],
|
|
560
|
-
type: "
|
|
561
|
-
name: "
|
|
562
|
-
|
|
563
|
-
path: [],
|
|
564
|
-
|
|
565
|
-
name: "target"
|
|
566
|
-
}, {
|
|
567
|
-
path: [],
|
|
568
|
-
type: "attr",
|
|
569
|
-
name: "download"
|
|
570
|
-
}, {
|
|
571
|
-
path: [],
|
|
572
|
-
type: "attr",
|
|
573
|
-
name: "rel"
|
|
574
|
-
}, {
|
|
575
|
-
path: [],
|
|
576
|
-
type: "event",
|
|
577
|
-
name: "onclick"
|
|
578
|
-
}, {
|
|
579
|
-
path: [],
|
|
580
|
-
type: "event",
|
|
581
|
-
name: "onmouseenter"
|
|
582
|
-
}, {
|
|
583
|
-
path: [0],
|
|
584
|
-
type: "child"
|
|
585
|
-
}]
|
|
610
|
+
html: '<div role="main" aria-labelledby="sinwan-router-not-found-title" style=""><div style=""><p aria-hidden="true" style="">404</p><h1 id="sinwan-router-not-found-title" style="">Page not found</h1><p style="">No route matches<!--s:0--><code style=""></code>.</p><!--s:2--></div></div>',
|
|
611
|
+
slots: [
|
|
612
|
+
{ path: [], type: "attr", name: "style" },
|
|
613
|
+
{ path: [0], type: "attr", name: "style" },
|
|
614
|
+
{ path: [0, 0], type: "attr", name: "style" },
|
|
615
|
+
{ path: [0, 1], type: "attr", name: "style" },
|
|
616
|
+
{ path: [0, 2], type: "attr", name: "style" },
|
|
617
|
+
{ path: [0, 2, 1], type: "child" },
|
|
618
|
+
{ path: [0, 2, 2], type: "attr", name: "style" },
|
|
619
|
+
{ path: [0, 2, 2], type: "child" },
|
|
620
|
+
{ path: [0, 3], type: "child" }
|
|
621
|
+
]
|
|
586
622
|
};
|
|
587
623
|
var _$tmpl_1 = {
|
|
588
|
-
html: '<
|
|
589
|
-
slots: [
|
|
590
|
-
path: [],
|
|
591
|
-
type: "attr",
|
|
592
|
-
|
|
593
|
-
}, {
|
|
594
|
-
path: [],
|
|
595
|
-
type: "attr",
|
|
596
|
-
name: "class"
|
|
597
|
-
}, {
|
|
598
|
-
path: [],
|
|
599
|
-
type: "attr",
|
|
600
|
-
name: "target"
|
|
601
|
-
}, {
|
|
602
|
-
path: [],
|
|
603
|
-
type: "attr",
|
|
604
|
-
name: "download"
|
|
605
|
-
}, {
|
|
606
|
-
path: [],
|
|
607
|
-
type: "attr",
|
|
608
|
-
name: "rel"
|
|
609
|
-
}, {
|
|
610
|
-
path: [],
|
|
611
|
-
type: "event",
|
|
612
|
-
name: "onclick"
|
|
613
|
-
}, {
|
|
614
|
-
path: [],
|
|
615
|
-
type: "event",
|
|
616
|
-
name: "onmouseenter"
|
|
617
|
-
}, {
|
|
618
|
-
path: [0],
|
|
619
|
-
type: "child"
|
|
620
|
-
}]
|
|
624
|
+
html: '<div role="status" aria-live="polite" style=""><div style="">Loading...</div></div>',
|
|
625
|
+
slots: [
|
|
626
|
+
{ path: [], type: "attr", name: "style" },
|
|
627
|
+
{ path: [0], type: "attr", name: "style" }
|
|
628
|
+
]
|
|
621
629
|
};
|
|
622
630
|
var _$tmpl_2 = {
|
|
623
|
-
html:
|
|
624
|
-
slots: [
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
slots: []
|
|
629
|
-
};
|
|
630
|
-
var _$tmpl_4 = {
|
|
631
|
-
html: "<div>Failed to load page</div>",
|
|
632
|
-
slots: []
|
|
631
|
+
html: '<div role="alert" style=""><div style="">Failed to load page</div></div>',
|
|
632
|
+
slots: [
|
|
633
|
+
{ path: [], type: "attr", name: "style" },
|
|
634
|
+
{ path: [0], type: "attr", name: "style" }
|
|
635
|
+
]
|
|
633
636
|
};
|
|
637
|
+
var LINK_OWN_KEYS = new Set([
|
|
638
|
+
"href",
|
|
639
|
+
"prefetch",
|
|
640
|
+
"class",
|
|
641
|
+
"children",
|
|
642
|
+
"target",
|
|
643
|
+
"download",
|
|
644
|
+
"rel",
|
|
645
|
+
"onclick",
|
|
646
|
+
"onmouseenter"
|
|
647
|
+
]);
|
|
648
|
+
function linkPassthrough(props) {
|
|
649
|
+
const raw = getRawProps(props);
|
|
650
|
+
const rest = {};
|
|
651
|
+
for (const key of Object.keys(raw)) {
|
|
652
|
+
if (!LINK_OWN_KEYS.has(key))
|
|
653
|
+
rest[key] = raw[key];
|
|
654
|
+
}
|
|
655
|
+
return rest;
|
|
656
|
+
}
|
|
634
657
|
function onLinkClick(event, href, router, options) {
|
|
635
658
|
if (!shouldInterceptLinkClick(event, href, router.path, options))
|
|
636
659
|
return;
|
|
@@ -644,51 +667,220 @@ function downloadAttr(download) {
|
|
|
644
667
|
return "";
|
|
645
668
|
return download;
|
|
646
669
|
}
|
|
647
|
-
var Link = cc(({
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
670
|
+
var Link = cc((props) => {
|
|
671
|
+
const {
|
|
672
|
+
href,
|
|
673
|
+
prefetch = true,
|
|
674
|
+
class: cls,
|
|
675
|
+
children,
|
|
676
|
+
target,
|
|
677
|
+
download,
|
|
678
|
+
rel,
|
|
679
|
+
onclick,
|
|
680
|
+
onmouseenter
|
|
681
|
+
} = props;
|
|
656
682
|
const router = useRouter();
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
683
|
+
const rest = linkPassthrough(props);
|
|
684
|
+
return /* @__PURE__ */ jsxDEV("a", {
|
|
685
|
+
...rest,
|
|
686
|
+
href,
|
|
687
|
+
class: cls,
|
|
688
|
+
target,
|
|
689
|
+
download: downloadAttr(download),
|
|
690
|
+
rel,
|
|
691
|
+
onclick: (e) => {
|
|
692
|
+
onLinkClick(e, href, router, { target, download });
|
|
693
|
+
onclick?.(e);
|
|
694
|
+
},
|
|
695
|
+
onmouseenter: (e) => {
|
|
696
|
+
if (prefetch)
|
|
697
|
+
router.prefetch(href);
|
|
698
|
+
onmouseenter?.(e);
|
|
699
|
+
},
|
|
700
|
+
children
|
|
701
|
+
}, undefined, false, undefined, this);
|
|
666
702
|
});
|
|
667
|
-
|
|
668
|
-
href
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
703
|
+
function isNavLinkActive(path, href) {
|
|
704
|
+
return path === href || path.startsWith(href + "/");
|
|
705
|
+
}
|
|
706
|
+
function resolveNavLinkClass(cls, isActive) {
|
|
707
|
+
if (typeof cls === "function") {
|
|
708
|
+
return (cls({ isActive }) || "").trim();
|
|
709
|
+
}
|
|
710
|
+
if (cls != null && cls !== "") {
|
|
711
|
+
return cls;
|
|
712
|
+
}
|
|
713
|
+
return isActive ? "active" : "";
|
|
714
|
+
}
|
|
715
|
+
var NavLink = cc((props) => {
|
|
716
|
+
const {
|
|
717
|
+
href,
|
|
718
|
+
prefetch = true,
|
|
719
|
+
class: cls,
|
|
720
|
+
children,
|
|
721
|
+
target,
|
|
722
|
+
download,
|
|
723
|
+
rel,
|
|
724
|
+
onclick,
|
|
725
|
+
onmouseenter
|
|
726
|
+
} = props;
|
|
677
727
|
const router = useRouter();
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
728
|
+
const rest = linkPassthrough(props);
|
|
729
|
+
const className = computed2(() => resolveNavLinkClass(cls, isNavLinkActive(router.path, href)));
|
|
730
|
+
return /* @__PURE__ */ jsxDEV("a", {
|
|
731
|
+
...rest,
|
|
732
|
+
href,
|
|
733
|
+
class: className,
|
|
734
|
+
target,
|
|
735
|
+
download: downloadAttr(download),
|
|
736
|
+
rel,
|
|
737
|
+
onclick: (e) => {
|
|
738
|
+
onLinkClick(e, href, router, { target, download });
|
|
739
|
+
onclick?.(e);
|
|
740
|
+
},
|
|
741
|
+
onmouseenter: (e) => {
|
|
742
|
+
if (prefetch)
|
|
743
|
+
router.prefetch(href);
|
|
744
|
+
onmouseenter?.(e);
|
|
745
|
+
},
|
|
746
|
+
children
|
|
747
|
+
}, undefined, false, undefined, this);
|
|
748
|
+
});
|
|
749
|
+
var creditBlue = {
|
|
750
|
+
background: "oklch(0.98 0.004 250)",
|
|
751
|
+
foreground: "oklch(0.18 0.03 255)",
|
|
752
|
+
primary: "oklch(0.55 0.22 262)",
|
|
753
|
+
primaryForeground: "oklch(0.98 0.01 250)",
|
|
754
|
+
secondary: "oklch(0.9 0.04 262)",
|
|
755
|
+
secondaryForeground: "oklch(0.3 0.09 262)",
|
|
756
|
+
tertiary: "oklch(0.72 0.14 230)",
|
|
757
|
+
muted: "oklch(0.96 0.006 250)",
|
|
758
|
+
mutedForeground: "oklch(0.5 0.02 255)",
|
|
759
|
+
card: "oklch(1 0 0)",
|
|
760
|
+
border: "oklch(0.9 0.01 255)",
|
|
761
|
+
radius: "0.625rem",
|
|
762
|
+
ambientBackground: [
|
|
763
|
+
"radial-gradient(110% 85% at 0% 0%, oklch(0.72 0.14 230 / 0.08), transparent 60%)",
|
|
764
|
+
"radial-gradient(110% 85% at 100% 0%, oklch(0.55 0.22 262 / 0.07), transparent 60%)",
|
|
765
|
+
"radial-gradient(110% 85% at 100% 100%, oklch(0.72 0.14 230 / 0.08), transparent 60%)",
|
|
766
|
+
"radial-gradient(110% 85% at 0% 100%, oklch(0.55 0.22 262 / 0.06), transparent 60%)",
|
|
767
|
+
"oklch(0.98 0.004 250)"
|
|
768
|
+
].join(", "),
|
|
769
|
+
brandGradient: "linear-gradient(150deg, oklch(0.72 0.14 230) 10%, oklch(0.55 0.22 262) 100%)"
|
|
770
|
+
};
|
|
771
|
+
var defaultNotFoundShellStyle = {
|
|
772
|
+
minHeight: "100vh",
|
|
773
|
+
display: "flex",
|
|
774
|
+
alignItems: "center",
|
|
775
|
+
justifyContent: "center",
|
|
776
|
+
padding: "2.5rem 1.25rem",
|
|
777
|
+
boxSizing: "border-box",
|
|
778
|
+
background: creditBlue.ambientBackground,
|
|
779
|
+
color: creditBlue.foreground,
|
|
780
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
781
|
+
};
|
|
782
|
+
var defaultNotFoundCardStyle = {
|
|
783
|
+
maxWidth: "28rem",
|
|
784
|
+
width: "100%",
|
|
785
|
+
textAlign: "center",
|
|
786
|
+
padding: "2.25rem 1.75rem",
|
|
787
|
+
borderRadius: "calc(0.625rem * 1.4)",
|
|
788
|
+
background: creditBlue.card,
|
|
789
|
+
border: `1px solid ${creditBlue.border}`,
|
|
790
|
+
boxShadow: "0 18px 50px oklch(0.55 0.22 262 / 0.08)"
|
|
791
|
+
};
|
|
792
|
+
var defaultNotFoundCodeStyle = {
|
|
793
|
+
display: "inline-block",
|
|
794
|
+
margin: "0 0.15em",
|
|
795
|
+
padding: "0.12em 0.4em",
|
|
796
|
+
borderRadius: "calc(0.625rem * 0.6)",
|
|
797
|
+
background: creditBlue.muted,
|
|
798
|
+
color: creditBlue.secondaryForeground,
|
|
799
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
|
800
|
+
fontSize: "0.88em",
|
|
801
|
+
wordBreak: "break-all"
|
|
802
|
+
};
|
|
803
|
+
var defaultNotFoundLinkStyle = {
|
|
804
|
+
display: "inline-block",
|
|
805
|
+
padding: "0.65rem 1.2rem",
|
|
806
|
+
borderRadius: creditBlue.radius,
|
|
807
|
+
background: creditBlue.brandGradient,
|
|
808
|
+
color: creditBlue.primaryForeground,
|
|
809
|
+
textDecoration: "none",
|
|
810
|
+
fontSize: "0.9rem",
|
|
811
|
+
fontWeight: 600,
|
|
812
|
+
letterSpacing: "0.01em",
|
|
813
|
+
boxShadow: "0 8px 20px oklch(0.55 0.22 262 / 0.28)"
|
|
814
|
+
};
|
|
815
|
+
var DefaultNotFound = cc(() => {
|
|
816
|
+
const router = useRouter();
|
|
817
|
+
return _$createTemplate(_$tmpl_0, [
|
|
818
|
+
defaultNotFoundShellStyle,
|
|
819
|
+
defaultNotFoundCardStyle,
|
|
820
|
+
{
|
|
821
|
+
margin: "0 0 0.85rem",
|
|
822
|
+
fontSize: "clamp(3.5rem, 12vw, 5rem)",
|
|
823
|
+
fontWeight: 700,
|
|
824
|
+
letterSpacing: "-0.06em",
|
|
825
|
+
lineHeight: 1,
|
|
826
|
+
background: creditBlue.brandGradient,
|
|
827
|
+
backgroundClip: "text",
|
|
828
|
+
WebkitBackgroundClip: "text",
|
|
829
|
+
color: "transparent"
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
margin: "0 0 0.75rem",
|
|
833
|
+
fontSize: "1.5rem",
|
|
834
|
+
fontWeight: 600,
|
|
835
|
+
letterSpacing: "-0.02em",
|
|
836
|
+
color: creditBlue.foreground
|
|
837
|
+
},
|
|
838
|
+
{
|
|
839
|
+
margin: "0 0 1.75rem",
|
|
840
|
+
fontSize: "0.95rem",
|
|
841
|
+
lineHeight: 1.55,
|
|
842
|
+
color: creditBlue.mutedForeground
|
|
843
|
+
},
|
|
844
|
+
" ",
|
|
845
|
+
defaultNotFoundCodeStyle,
|
|
846
|
+
() => router.path,
|
|
847
|
+
/* @__PURE__ */ jsxDEV(Link, {
|
|
848
|
+
href: "/",
|
|
849
|
+
style: defaultNotFoundLinkStyle,
|
|
850
|
+
children: "Back to home"
|
|
851
|
+
}, undefined, false, undefined, this)
|
|
852
|
+
]);
|
|
688
853
|
});
|
|
689
|
-
var
|
|
690
|
-
|
|
691
|
-
|
|
854
|
+
var defaultStatusShellStyle = {
|
|
855
|
+
minHeight: "100vh",
|
|
856
|
+
display: "flex",
|
|
857
|
+
alignItems: "center",
|
|
858
|
+
justifyContent: "center",
|
|
859
|
+
padding: "2rem 1.25rem",
|
|
860
|
+
boxSizing: "border-box",
|
|
861
|
+
background: creditBlue.ambientBackground,
|
|
862
|
+
color: creditBlue.foreground,
|
|
863
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
864
|
+
};
|
|
865
|
+
var defaultStatusCardStyle = {
|
|
866
|
+
padding: "1.25rem 1.5rem",
|
|
867
|
+
borderRadius: creditBlue.radius,
|
|
868
|
+
background: creditBlue.card,
|
|
869
|
+
border: `1px solid ${creditBlue.border}`,
|
|
870
|
+
color: creditBlue.secondaryForeground,
|
|
871
|
+
fontSize: "0.95rem",
|
|
872
|
+
fontWeight: 500,
|
|
873
|
+
boxShadow: "0 12px 32px oklch(0.55 0.22 262 / 0.06)"
|
|
874
|
+
};
|
|
875
|
+
var DefaultLoading = cc(() => _$createTemplate(_$tmpl_1, [defaultStatusShellStyle, defaultStatusCardStyle]));
|
|
876
|
+
var DefaultError = cc(() => _$createTemplate(_$tmpl_2, [
|
|
877
|
+
defaultStatusShellStyle,
|
|
878
|
+
{
|
|
879
|
+
...defaultStatusCardStyle,
|
|
880
|
+
borderColor: "oklch(0.55 0.22 262 / 0.35)",
|
|
881
|
+
color: creditBlue.foreground
|
|
882
|
+
}
|
|
883
|
+
]));
|
|
692
884
|
function resolveOutletNode(matched, router, fallback, errorComp) {
|
|
693
885
|
const route = matched.route;
|
|
694
886
|
if (!isLazyComponent(route.component)) {
|
|
@@ -711,30 +903,26 @@ function resolveOutletNode(matched, router, fallback, errorComp) {
|
|
|
711
903
|
const Fallback = fallback;
|
|
712
904
|
return /* @__PURE__ */ jsxDEV(Fallback, {}, undefined, false, undefined, this);
|
|
713
905
|
}
|
|
714
|
-
var RouterOutlet = cc(({
|
|
715
|
-
fallback,
|
|
716
|
-
notFound,
|
|
717
|
-
error,
|
|
718
|
-
depth = 0
|
|
719
|
-
}) => {
|
|
906
|
+
var RouterOutlet = cc((props) => {
|
|
720
907
|
const router = useRouter();
|
|
721
|
-
const Fallback = fallback ?? DefaultLoading;
|
|
722
|
-
const NotFound = notFound ?? DefaultNotFound;
|
|
723
|
-
const ErrorView = error ?? DefaultError;
|
|
908
|
+
const Fallback = () => props.fallback ?? DefaultLoading;
|
|
909
|
+
const NotFound = props.notFound ?? DefaultNotFound;
|
|
910
|
+
const ErrorView = () => props.error ?? DefaultError;
|
|
724
911
|
return /* @__PURE__ */ jsxDEV(Key, {
|
|
725
|
-
when: () => computeOutletKey(router, depth),
|
|
726
|
-
children: () => {
|
|
727
|
-
const matched = getMatchAtDepth(router.matched, depth);
|
|
912
|
+
when: () => computeOutletKey(router, props.depth === undefined ? 0 : props.depth),
|
|
913
|
+
children: (_identity) => {
|
|
914
|
+
const matched = getMatchAtDepth(router.matched, props.depth === undefined ? 0 : props.depth);
|
|
728
915
|
if (!matched) {
|
|
729
|
-
if (depth > 0)
|
|
916
|
+
if ((props.depth === undefined ? 0 : props.depth) > 0)
|
|
730
917
|
return null;
|
|
731
918
|
return /* @__PURE__ */ jsxDEV(NotFound, {}, undefined, false, undefined, this);
|
|
732
919
|
}
|
|
733
|
-
return resolveOutletNode(matched, router, Fallback, ErrorView);
|
|
920
|
+
return resolveOutletNode(matched, router, Fallback(), ErrorView());
|
|
734
921
|
}
|
|
735
922
|
}, undefined, false, undefined, this);
|
|
736
923
|
});
|
|
737
924
|
// src/jsx-routes.tsx
|
|
925
|
+
import { unwrap as _$unwrap } from "sinwan/reactivity";
|
|
738
926
|
import { cc as cc2, provide, onDispose } from "sinwan/component";
|
|
739
927
|
import { jsxDEV as jsxDEV2, Fragment } from "sinwan/jsx-dev-runtime";
|
|
740
928
|
var ROUTE_TYPE = Symbol.for("sinwan.router.Route");
|
|
@@ -742,10 +930,7 @@ function isElementLike(value) {
|
|
|
742
930
|
return value != null && typeof value === "object" && "tag" in value;
|
|
743
931
|
}
|
|
744
932
|
function routePropsRecord(props) {
|
|
745
|
-
const record = {
|
|
746
|
-
path: props.path,
|
|
747
|
-
component: props.component
|
|
748
|
-
};
|
|
933
|
+
const record = { path: props.path, component: props.component };
|
|
749
934
|
if (props.meta !== undefined)
|
|
750
935
|
record.meta = props.meta;
|
|
751
936
|
if (props.children !== undefined)
|
|
@@ -808,10 +993,7 @@ function nestedDefinitions(source) {
|
|
|
808
993
|
}
|
|
809
994
|
function routeNodeToDefinition(node) {
|
|
810
995
|
if (isRouteDefinition(node)) {
|
|
811
|
-
const def = {
|
|
812
|
-
path: node.path,
|
|
813
|
-
component: node.component
|
|
814
|
-
};
|
|
996
|
+
const def = { path: node.path, component: node.component };
|
|
815
997
|
if (node.meta)
|
|
816
998
|
def.meta = node.meta;
|
|
817
999
|
if (node.children && node.children.length > 0)
|
|
@@ -825,10 +1007,7 @@ function routeNodeToDefinition(node) {
|
|
|
825
1007
|
const component = props.component;
|
|
826
1008
|
if (typeof path !== "string" || component == null)
|
|
827
1009
|
return null;
|
|
828
|
-
const def = {
|
|
829
|
-
path,
|
|
830
|
-
component
|
|
831
|
-
};
|
|
1010
|
+
const def = { path, component };
|
|
832
1011
|
const meta = props.meta;
|
|
833
1012
|
if (meta != null && typeof meta === "object") {
|
|
834
1013
|
def.meta = meta;
|
|
@@ -856,24 +1035,18 @@ function layoutNodes(children) {
|
|
|
856
1035
|
}
|
|
857
1036
|
return out;
|
|
858
1037
|
}
|
|
859
|
-
var Routes = cc2(({
|
|
860
|
-
children,
|
|
861
|
-
fallback,
|
|
862
|
-
notFound,
|
|
863
|
-
error,
|
|
864
|
-
initialPath
|
|
865
|
-
}) => {
|
|
866
|
-
const router = createRouter(collectRouteDefinitions(children), initialPath);
|
|
1038
|
+
var Routes = cc2((props) => {
|
|
1039
|
+
const router = createRouter(collectRouteDefinitions(props.children), { initialPath: props.initialPath, scroll: props.scroll });
|
|
867
1040
|
provide(RouterKey, router);
|
|
868
1041
|
onDispose(() => {
|
|
869
1042
|
router.dispose();
|
|
870
1043
|
});
|
|
871
1044
|
const outlet = /* @__PURE__ */ jsxDEV2(RouterOutlet, {
|
|
872
|
-
fallback,
|
|
873
|
-
notFound,
|
|
874
|
-
error
|
|
1045
|
+
fallback: () => _$unwrap(props).fallback,
|
|
1046
|
+
notFound: () => _$unwrap(props).notFound,
|
|
1047
|
+
error: () => _$unwrap(props).error
|
|
875
1048
|
}, undefined, false, undefined, this);
|
|
876
|
-
const layout = layoutNodes(children);
|
|
1049
|
+
const layout = layoutNodes(props.children);
|
|
877
1050
|
if (layout.length === 0)
|
|
878
1051
|
return outlet;
|
|
879
1052
|
return /* @__PURE__ */ jsxDEV2(Fragment, {
|
|
@@ -911,5 +1084,5 @@ export {
|
|
|
911
1084
|
useSearchParams
|
|
912
1085
|
};
|
|
913
1086
|
|
|
914
|
-
//# debugId=
|
|
1087
|
+
//# debugId=1D4F3C960149F76864756E2164756E21
|
|
915
1088
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/router.ts", "../src/matcher.ts", "../src/components.tsx", "../src/hooks.ts", "../src/link-nav.ts", "../src/outlet.ts", "../src/jsx-routes.tsx"],
|
|
3
|
+
"sources": ["../src/router.ts", "../src/matcher.ts", "../src/scroll.ts", "../src/components.tsx", "../src/hooks.ts", "../src/link-nav.ts", "../src/outlet.ts", "../src/jsx-routes.tsx"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Sinwan Router — Core Router\n *\n * Manages route state, navigation, and matching using Sinwan's reactivity.\n * Uses a radix tree for O(depth) route lookups — no regex compilation.\n * SSR-safe: all DOM access is guarded by `typeof window` checks.\n */\n\nimport { signal, computed } from \"sinwan/reactivity\";\nimport type { Signal, Computed } from \"sinwan/reactivity\";\nimport type { SinwanComponent } from \"sinwan/component\";\nimport type {\n RouteDefinition,\n MatchedRoute,\n NavigateOptions,\n LazyComponent,\n LazyPeek,\n} from \"./types.ts\";\nimport {\n createRadixTree,\n radixInsert,\n radixSearch,\n normalizePath,\n extractSearchParams,\n type RadixNode,\n} from \"./matcher.ts\";\n\nfunction hasTrueFlag(value: object, key: string): boolean {\n return key in value && (value as Record<string, unknown>)[key] === true;\n}\n\n/**\n * True for explicit `lazy()` factories, `_SinwanLazy` brands, and zero-arg\n * `() => import(...)` loaders. `cc` components and functions that take props\n * are not treated as lazy importers.\n */\nexport function isLazyComponent(comp: unknown): comp is LazyComponent {\n if (typeof comp !== \"function\") return false;\n if (hasTrueFlag(comp, \"_SinwanComponent\")) return false;\n if (hasTrueFlag(comp, \"_SinwanLazy\")) return true;\n return comp.length === 0;\n}\n\n/** Mark a dynamic import factory as a lazy route component. */\nexport function lazy(\n loader: () => Promise<{ default: SinwanComponent }>,\n): LazyComponent {\n const factory = (): Promise<{ default: SinwanComponent }> => loader();\n return Object.assign(factory, { _SinwanLazy: true as const });\n}\n\n/** Internal leaf data stored in the radix tree. */\ninterface LeafData {\n route: RouteDefinition;\n fullPattern: string;\n /** Chain of (route, fullPattern) pairs from root to this leaf. */\n chain: { route: RouteDefinition; fullPattern: string }[];\n [key: string]: unknown;\n}\n\n/** The core router instance. */\nexport class Router {\n private readonly tree: RadixNode;\n private readonly routeList: RouteDefinition[];\n private readonly _path: Signal<string>;\n private readonly _searchParams: Signal<URLSearchParams>;\n private readonly _matched: Computed<MatchedRoute | null>;\n private readonly _params: Computed<Record<string, string>>;\n private readonly lazyCache = new Map<string, SinwanComponent>();\n private readonly lazyErrors = new Map<string, unknown>();\n private readonly lazyInflight = new Map<string, Promise<SinwanComponent>>();\n private readonly _lazyTick: Signal<number>;\n private popstateHandler: (() => void) | null = null;\n\n constructor(routes: RouteDefinition[], initialPath?: string) {\n this.tree = createRadixTree();\n this.routeList = [];\n this._lazyTick = signal(0);\n\n // Insert all routes (including nested) into the radix tree.\n // Static segments are inserted first so they're checked before\n // param segments during search (insertion order within siblings\n // determines search order, and static children are always checked\n // first in searchNode regardless).\n for (const route of routes) {\n this.insertRoute(route, \"\");\n }\n\n const startPath =\n initialPath ??\n (typeof window !== \"undefined\"\n ? window.location.pathname + window.location.search\n : \"/\");\n\n this._path = signal(normalizePath(startPath));\n this._searchParams = signal(extractSearchParams(startPath));\n\n this._matched = computed(() => {\n const path = normalizePath(this._path.value);\n const result = radixSearch(this.tree, path);\n if (!result) return null;\n\n const leaf = result.data as LeafData;\n const params = result.params;\n\n // Build the matched route chain (parent → child).\n // The returned matched route is the deepest (leaf) match,\n // with `parent` pointing up the chain to the root.\n let parent: MatchedRoute | undefined;\n let matched: MatchedRoute | undefined;\n for (let i = 0; i < leaf.chain.length; i++) {\n const entry = leaf.chain[i]!;\n const m: MatchedRoute = {\n route: entry.route,\n params,\n path,\n matchedPath: entry.fullPattern,\n parent: i > 0 ? parent : undefined,\n };\n parent = m;\n matched = m; // last one is the deepest\n }\n return matched ?? null;\n });\n\n this._params = computed(() => {\n const matched = this._matched.value;\n return matched ? matched.params : {};\n });\n\n // Listen to popstate on the client\n if (typeof window !== \"undefined\") {\n this.popstateHandler = () => {\n const url = window.location.pathname + window.location.search;\n this._path.value = normalizePath(url);\n this._searchParams.value = extractSearchParams(url);\n };\n window.addEventListener(\"popstate\", this.popstateHandler);\n }\n }\n\n /** Recursively insert a route and its children into the tree. */\n private insertRoute(\n route: RouteDefinition,\n parentPath: string,\n parentChain: { route: RouteDefinition; fullPattern: string }[] = [],\n ): void {\n const fullPattern = joinPaths(parentPath, route.path);\n const chain = [...parentChain, { route, fullPattern }];\n const leafData: LeafData = { route, fullPattern, chain };\n\n radixInsert(this.tree, fullPattern, leafData);\n this.routeList.push(route);\n\n if (route.children) {\n for (const child of route.children) {\n this.insertRoute(child, fullPattern, chain);\n }\n }\n }\n\n private bumpLazyTick(): void {\n this._lazyTick.value = this._lazyTick.value + 1;\n }\n\n /** Reactive counter bumped when a lazy load succeeds or fails. */\n get lazyTick(): number {\n return this._lazyTick.value;\n }\n\n /** Current load snapshot for a lazy cache key (pattern). */\n peekLazy(cacheKey: string): LazyPeek {\n const cached = this.lazyCache.get(cacheKey);\n if (cached) return { status: \"ready\", component: cached };\n if (this.lazyInflight.has(cacheKey)) return { status: \"loading\" };\n if (this.lazyErrors.has(cacheKey)) {\n return { status: \"error\", error: this.lazyErrors.get(cacheKey) };\n }\n return { status: \"idle\" };\n }\n\n /**\n * Start a lazy import if needed. Does not retry a stored error\n * (the outlet keeps showing the error UI until navigation or prefetch).\n */\n ensureLazy(cacheKey: string, loader: LazyComponent): void {\n const state = this.peekLazy(cacheKey);\n if (state.status !== \"idle\") return;\n this.startLazyLoad(cacheKey, loader);\n }\n\n private startLazyLoad(\n cacheKey: string,\n loader: LazyComponent,\n ): Promise<SinwanComponent> {\n this.lazyErrors.delete(cacheKey);\n const pending = loader()\n .then((mod) => {\n this.lazyCache.set(cacheKey, mod.default);\n this.lazyErrors.delete(cacheKey);\n this.bumpLazyTick();\n return mod.default;\n })\n .catch((err: unknown) => {\n this.lazyErrors.set(cacheKey, err);\n this.bumpLazyTick();\n throw err;\n })\n .finally(() => {\n this.lazyInflight.delete(cacheKey);\n });\n this.lazyInflight.set(cacheKey, pending);\n pending.catch(() => {\n /* prefetch / outlet consume errors via peekLazy */\n });\n return pending;\n }\n\n /** Current URL path (reactive). */\n get path(): string {\n return this._path.value;\n }\n\n /** Current path signal (for fine-grained reactivity). */\n get pathSignal(): Signal<string> {\n return this._path;\n }\n\n /** Current matched route (reactive). */\n get matched(): MatchedRoute | null {\n return this._matched.value;\n }\n\n /** Current matched route computed (for fine-grained reactivity). */\n get matchedComputed(): Computed<MatchedRoute | null> {\n return this._matched;\n }\n\n /** Current route parameters (reactive). */\n get params(): Record<string, string> {\n return this._params.value;\n }\n\n /** Current search params (reactive). */\n get searchParams(): URLSearchParams {\n return this._searchParams.value;\n }\n\n /** All registered routes. */\n get routes(): RouteDefinition[] {\n return this.routeList;\n }\n\n /** Navigate to a new path. */\n navigate(to: string, options: NavigateOptions = {}): void {\n const normalized = normalizePath(to);\n\n if (typeof window !== \"undefined\") {\n if (options.replace) {\n window.history.replaceState(options.state ?? {}, \"\", to);\n } else {\n window.history.pushState(options.state ?? {}, \"\", to);\n }\n }\n\n this._path.value = normalized;\n this._searchParams.value = extractSearchParams(to);\n }\n\n /** Prefetch a route's lazy component into this router's cache. */\n prefetch(path: string): void {\n if (typeof window === \"undefined\") return;\n\n const normalized = normalizePath(path);\n const result = radixSearch(this.tree, normalized);\n if (!result) return;\n\n const leaf = result.data as LeafData;\n const route = leaf.route;\n if (!isLazyComponent(route.component)) return;\n\n const cacheKey = leaf.fullPattern;\n const state = this.peekLazy(cacheKey);\n if (state.status === \"ready\" || state.status === \"loading\") return;\n this.startLazyLoad(cacheKey, route.component);\n }\n\n /** Resolve a lazy component, using this instance's cache if available. */\n async resolveComponent(\n route: RouteDefinition,\n ): Promise<SinwanComponent> {\n if (!isLazyComponent(route.component)) {\n return route.component;\n }\n\n const cacheKey = this.findFullPattern(route) ?? route.path;\n const cached = this.lazyCache.get(cacheKey);\n if (cached) return cached;\n\n const inflight = this.lazyInflight.get(cacheKey);\n if (inflight) return inflight;\n\n return this.startLazyLoad(cacheKey, route.component);\n }\n\n /** Find the full pattern for a route. */\n private findFullPattern(route: RouteDefinition): string | undefined {\n return this.searchForRoute(this.tree, route, \"\");\n }\n\n private searchForRoute(\n node: RadixNode,\n target: RouteDefinition,\n pathSoFar: string,\n ): string | undefined {\n if (node.route) {\n const leaf = node.route as LeafData;\n if (leaf.route === target) return leaf.fullPattern;\n }\n for (const child of node.children) {\n const seg = child.isParam\n ? \"/:\" + child.paramName\n : child.isWildcard\n ? \"/*\"\n : \"/\" + child.prefix;\n const found = this.searchForRoute(child, target, pathSoFar + seg);\n if (found) return found;\n }\n return undefined;\n }\n\n /** Clean up event listeners and drop this instance's lazy cache. */\n dispose(): void {\n if (this.popstateHandler && typeof window !== \"undefined\") {\n window.removeEventListener(\"popstate\", this.popstateHandler);\n this.popstateHandler = null;\n }\n this.lazyCache.clear();\n this.lazyErrors.clear();\n this.lazyInflight.clear();\n }\n}\n\n/** Join parent and child paths. */\nfunction joinPaths(parent: string, child: string): string {\n if (child === \"/\") return parent || \"/\";\n // Strip leading slash from child so it's always relative\n const relativeChild = child.startsWith(\"/\") ? child.slice(1) : child;\n if (parent === \"/\" || parent === \"\") return \"/\" + relativeChild;\n return parent + \"/\" + relativeChild;\n}\n\n/** Create a router instance. */\nexport function createRouter(\n routes: RouteDefinition[],\n initialPath?: string,\n): Router {\n return new Router(routes, initialPath);\n}\n",
|
|
5
|
+
"/**\n * Sinwan Router — Core Router\n *\n * Manages route state, navigation, and matching using Sinwan's reactivity.\n * Uses a radix tree for O(depth) route lookups — no regex compilation.\n * SSR-safe: all DOM access is guarded by `typeof window` checks.\n */\n\nimport { signal, computed } from \"sinwan/reactivity\";\nimport type { Signal, Computed } from \"sinwan/reactivity\";\nimport type { SinwanComponent } from \"sinwan/component\";\nimport type {\n RouteDefinition,\n MatchedRoute,\n NavigateOptions,\n LazyComponent,\n LazyPeek,\n RouterOptions,\n RouterScroll,\n} from \"./types.ts\";\nimport {\n createRadixTree,\n radixInsert,\n radixSearch,\n normalizePath,\n extractSearchParams,\n type RadixNode,\n} from \"./matcher.ts\";\nimport { findHashTarget, hashFromHref, nextFrame } from \"./scroll.ts\";\n\nfunction hasTrueFlag(value: object, key: string): boolean {\n return key in value && (value as Record<string, unknown>)[key] === true;\n}\n\n/**\n * True for explicit `lazy()` factories, `_SinwanLazy` brands, and zero-arg\n * `() => import(...)` loaders. `cc` components and functions that take props\n * are not treated as lazy importers.\n */\nexport function isLazyComponent(comp: unknown): comp is LazyComponent {\n if (typeof comp !== \"function\") return false;\n if (hasTrueFlag(comp, \"_SinwanComponent\")) return false;\n if (hasTrueFlag(comp, \"_SinwanLazy\")) return true;\n return comp.length === 0;\n}\n\n/** Mark a dynamic import factory as a lazy route component. */\nexport function lazy(\n loader: () => Promise<{ default: SinwanComponent }>,\n): LazyComponent {\n const factory = (): Promise<{ default: SinwanComponent }> => loader();\n return Object.assign(factory, { _SinwanLazy: true as const });\n}\n\n/** Internal leaf data stored in the radix tree. */\ninterface LeafData {\n route: RouteDefinition;\n fullPattern: string;\n /** Chain of (route, fullPattern) pairs from root to this leaf. */\n chain: { route: RouteDefinition; fullPattern: string }[];\n [key: string]: unknown;\n}\n\n/** The core router instance. */\nexport class Router {\n private readonly tree: RadixNode;\n private readonly routeList: RouteDefinition[];\n private readonly _path: Signal<string>;\n private readonly _searchParams: Signal<URLSearchParams>;\n private readonly _matched: Computed<MatchedRoute | null>;\n private readonly _params: Computed<Record<string, string>>;\n private readonly lazyCache = new Map<string, SinwanComponent>();\n private readonly lazyErrors = new Map<string, unknown>();\n private readonly lazyInflight = new Map<string, Promise<SinwanComponent>>();\n private readonly _lazyTick: Signal<number>;\n private popstateHandler: (() => void) | null = null;\n private readonly scroll: RouterScroll;\n /** Bumped per navigation so a stale pending hash reveal is dropped. */\n private scrollToken = 0;\n\n /**\n * @param options Router options, or the initial path (1.0 signature).\n */\n constructor(routes: RouteDefinition[], options: string | RouterOptions = {}) {\n const { initialPath, scroll = \"preserve\" }: RouterOptions =\n typeof options === \"string\" ? { initialPath: options } : options;\n this.scroll = scroll;\n this.tree = createRadixTree();\n this.routeList = [];\n this._lazyTick = signal(0);\n\n // Insert all routes (including nested) into the radix tree.\n // Static segments are inserted first so they're checked before\n // param segments during search (insertion order within siblings\n // determines search order, and static children are always checked\n // first in searchNode regardless).\n for (const route of routes) {\n this.insertRoute(route, \"\");\n }\n\n const startPath =\n initialPath ??\n (typeof window !== \"undefined\"\n ? window.location.pathname + window.location.search\n : \"/\");\n\n this._path = signal(normalizePath(startPath));\n this._searchParams = signal(extractSearchParams(startPath));\n\n this._matched = computed(() => {\n const path = normalizePath(this._path.value);\n const result = radixSearch(this.tree, path);\n if (!result) return null;\n\n const leaf = result.data as LeafData;\n const params = result.params;\n\n // Build the matched route chain (parent → child).\n // The returned matched route is the deepest (leaf) match,\n // with `parent` pointing up the chain to the root.\n let parent: MatchedRoute | undefined;\n let matched: MatchedRoute | undefined;\n for (let i = 0; i < leaf.chain.length; i++) {\n const entry = leaf.chain[i]!;\n const m: MatchedRoute = {\n route: entry.route,\n params,\n path,\n matchedPath: entry.fullPattern,\n parent: i > 0 ? parent : undefined,\n };\n parent = m;\n matched = m; // last one is the deepest\n }\n return matched ?? null;\n });\n\n this._params = computed(() => {\n const matched = this._matched.value;\n return matched ? matched.params : {};\n });\n\n // Listen to popstate on the client\n if (typeof window !== \"undefined\") {\n this.popstateHandler = () => {\n const url = window.location.pathname + window.location.search;\n this._path.value = normalizePath(url);\n this._searchParams.value = extractSearchParams(url);\n };\n window.addEventListener(\"popstate\", this.popstateHandler);\n\n if (this.scroll === \"top\") {\n const initialHash = hashFromHref(window.location.hash);\n if (initialHash) this.revealHash(initialHash);\n }\n }\n }\n\n /** Recursively insert a route and its children into the tree. */\n private insertRoute(\n route: RouteDefinition,\n parentPath: string,\n parentChain: { route: RouteDefinition; fullPattern: string }[] = [],\n ): void {\n const fullPattern = joinPaths(parentPath, route.path);\n const chain = [...parentChain, { route, fullPattern }];\n const leafData: LeafData = { route, fullPattern, chain };\n\n radixInsert(this.tree, fullPattern, leafData);\n this.routeList.push(route);\n\n if (route.children) {\n for (const child of route.children) {\n this.insertRoute(child, fullPattern, chain);\n }\n }\n }\n\n private bumpLazyTick(): void {\n this._lazyTick.value = this._lazyTick.value + 1;\n }\n\n /** Reactive counter bumped when a lazy load succeeds or fails. */\n get lazyTick(): number {\n return this._lazyTick.value;\n }\n\n /** Current load snapshot for a lazy cache key (pattern). */\n peekLazy(cacheKey: string): LazyPeek {\n const cached = this.lazyCache.get(cacheKey);\n if (cached) return { status: \"ready\", component: cached };\n if (this.lazyInflight.has(cacheKey)) return { status: \"loading\" };\n if (this.lazyErrors.has(cacheKey)) {\n return { status: \"error\", error: this.lazyErrors.get(cacheKey) };\n }\n return { status: \"idle\" };\n }\n\n /**\n * Start a lazy import if needed. Does not retry a stored error\n * (the outlet keeps showing the error UI until navigation or prefetch).\n */\n ensureLazy(cacheKey: string, loader: LazyComponent): void {\n const state = this.peekLazy(cacheKey);\n if (state.status !== \"idle\") return;\n this.startLazyLoad(cacheKey, loader);\n }\n\n private startLazyLoad(\n cacheKey: string,\n loader: LazyComponent,\n ): Promise<SinwanComponent> {\n this.lazyErrors.delete(cacheKey);\n const pending = loader()\n .then((mod) => {\n this.lazyCache.set(cacheKey, mod.default);\n this.lazyErrors.delete(cacheKey);\n this.bumpLazyTick();\n return mod.default;\n })\n .catch((err: unknown) => {\n this.lazyErrors.set(cacheKey, err);\n this.bumpLazyTick();\n throw err;\n })\n .finally(() => {\n this.lazyInflight.delete(cacheKey);\n });\n this.lazyInflight.set(cacheKey, pending);\n pending.catch(() => {\n /* prefetch / outlet consume errors via peekLazy */\n });\n return pending;\n }\n\n /** Current URL path (reactive). */\n get path(): string {\n return this._path.value;\n }\n\n /** Current path signal (for fine-grained reactivity). */\n get pathSignal(): Signal<string> {\n return this._path;\n }\n\n /** Current matched route (reactive). */\n get matched(): MatchedRoute | null {\n return this._matched.value;\n }\n\n /** Current matched route computed (for fine-grained reactivity). */\n get matchedComputed(): Computed<MatchedRoute | null> {\n return this._matched;\n }\n\n /** Current route parameters (reactive). */\n get params(): Record<string, string> {\n return this._params.value;\n }\n\n /** Current search params (reactive). */\n get searchParams(): URLSearchParams {\n return this._searchParams.value;\n }\n\n /** All registered routes. */\n get routes(): RouteDefinition[] {\n return this.routeList;\n }\n\n /** Navigate to a new path. */\n navigate(to: string, options: NavigateOptions = {}): void {\n const normalized = normalizePath(to);\n\n if (typeof window !== \"undefined\") {\n if (options.replace) {\n window.history.replaceState(options.state ?? {}, \"\", to);\n } else {\n window.history.pushState(options.state ?? {}, \"\", to);\n }\n }\n\n this._path.value = normalized;\n this._searchParams.value = extractSearchParams(to);\n if (options.scroll !== false) this.applyScroll(to);\n }\n\n /** `scroll: \"top\"`: jump to the top, then to the `#hash` target once rendered. */\n private applyScroll(to: string): void {\n if (this.scroll !== \"top\" || typeof window === \"undefined\") return;\n this.scrollToken++;\n window.scrollTo({ top: 0, left: 0, behavior: \"instant\" });\n const hash = hashFromHref(to);\n if (hash) this.revealHash(hash);\n }\n\n private revealHash(hash: string): void {\n const token = ++this.scrollToken;\n void this.whenRouteRendered().then(() => {\n if (token !== this.scrollToken) return;\n findHashTarget(window.document, hash)?.scrollIntoView();\n });\n }\n\n /** Waits for the matched chain's lazy components, then one frame for the DOM. */\n private async whenRouteRendered(): Promise<void> {\n const loads: Promise<SinwanComponent>[] = [];\n for (let m = this._matched.value ?? undefined; m; m = m.parent) {\n if (isLazyComponent(m.route.component)) {\n loads.push(this.resolveComponent(m.route));\n }\n }\n await Promise.allSettled(loads);\n await nextFrame(window);\n }\n\n /** Prefetch a route's lazy component into this router's cache. */\n prefetch(path: string): void {\n if (typeof window === \"undefined\") return;\n\n const normalized = normalizePath(path);\n const result = radixSearch(this.tree, normalized);\n if (!result) return;\n\n const leaf = result.data as LeafData;\n const route = leaf.route;\n if (!isLazyComponent(route.component)) return;\n\n const cacheKey = leaf.fullPattern;\n const state = this.peekLazy(cacheKey);\n if (state.status === \"ready\" || state.status === \"loading\") return;\n this.startLazyLoad(cacheKey, route.component);\n }\n\n /** Resolve a lazy component, using this instance's cache if available. */\n async resolveComponent(\n route: RouteDefinition,\n ): Promise<SinwanComponent> {\n if (!isLazyComponent(route.component)) {\n return route.component;\n }\n\n const cacheKey = this.findFullPattern(route) ?? route.path;\n const cached = this.lazyCache.get(cacheKey);\n if (cached) return cached;\n\n const inflight = this.lazyInflight.get(cacheKey);\n if (inflight) return inflight;\n\n return this.startLazyLoad(cacheKey, route.component);\n }\n\n /** Find the full pattern for a route. */\n private findFullPattern(route: RouteDefinition): string | undefined {\n return this.searchForRoute(this.tree, route, \"\");\n }\n\n private searchForRoute(\n node: RadixNode,\n target: RouteDefinition,\n pathSoFar: string,\n ): string | undefined {\n if (node.route) {\n const leaf = node.route as LeafData;\n if (leaf.route === target) return leaf.fullPattern;\n }\n for (const child of node.children) {\n const seg = child.isParam\n ? \"/:\" + child.paramName\n : child.isWildcard\n ? \"/*\"\n : \"/\" + child.prefix;\n const found = this.searchForRoute(child, target, pathSoFar + seg);\n if (found) return found;\n }\n return undefined;\n }\n\n /** Clean up event listeners and drop this instance's lazy cache. */\n dispose(): void {\n if (this.popstateHandler && typeof window !== \"undefined\") {\n window.removeEventListener(\"popstate\", this.popstateHandler);\n this.popstateHandler = null;\n }\n this.scrollToken++;\n this.lazyCache.clear();\n this.lazyErrors.clear();\n this.lazyInflight.clear();\n }\n}\n\n/** Join parent and child paths. */\nfunction joinPaths(parent: string, child: string): string {\n if (child === \"/\") return parent || \"/\";\n // Strip leading slash from child so it's always relative\n const relativeChild = child.startsWith(\"/\") ? child.slice(1) : child;\n if (parent === \"/\" || parent === \"\") return \"/\" + relativeChild;\n return parent + \"/\" + relativeChild;\n}\n\n/**\n * Create a router instance.\n * @param options Router options, or the initial path (1.0 signature).\n */\nexport function createRouter(\n routes: RouteDefinition[],\n options?: string | RouterOptions,\n): Router {\n return new Router(routes, options);\n}\n",
|
|
6
6
|
"/**\n * Sinwan Router — Radix Tree Path Matching\n *\n * Segment-by-segment trie matching for O(depth) lookups.\n * No regex compilation — static segments are matched by direct\n * string comparison, params by position, and wildcards capture\n * the remaining path.\n *\n * Architecture mirrors the sinwan-engine HTTPRouter radix tree:\n * - Static children checked first (fast path)\n * - Param children checked second\n * - Wildcard children checked last (catch-all)\n */\n\n// ─── Radix Node ────────────────────────────────────────────\n\nexport interface RadixNode {\n /** Literal segment prefix, or `:param` / `*` marker. */\n prefix: string;\n /** Child nodes. */\n children: RadixNode[];\n /** Whether this node is a `:param` segment. */\n isParam: boolean;\n /** Param name (without the `:`). */\n paramName: string;\n /** Whether this node is a `*` wildcard. */\n isWildcard: boolean;\n /** Route data attached at this node (set at leaf). */\n route: RouteData | null;\n}\n\n/** Arbitrary data attached to a matched leaf node. */\nexport interface RouteData {\n [key: string]: unknown;\n}\n\nfunction createNode(prefix: string): RadixNode {\n return {\n prefix,\n children: [],\n isParam: prefix.startsWith(\":\"),\n paramName: prefix.startsWith(\":\") ? prefix.slice(1) : \"\",\n isWildcard: prefix === \"*\" || prefix.startsWith(\"*\"),\n route: null,\n };\n}\n\n// ─── Path Utilities ────────────────────────────────────────\n\n/**\n * Normalize a URL path: ensure leading slash, strip trailing slash\n * (except for root), and strip hash/query.\n */\nexport function normalizePath(path: string): string {\n // Strip query and hash\n const qIdx = path.indexOf(\"?\");\n if (qIdx !== -1) path = path.slice(0, qIdx);\n const hIdx = path.indexOf(\"#\");\n if (hIdx !== -1) path = path.slice(0, hIdx);\n\n // Ensure leading slash\n if (!path.startsWith(\"/\")) path = \"/\" + path;\n\n // Strip trailing slash (except root)\n if (path.length > 1 && path.endsWith(\"/\")) {\n path = path.slice(0, -1);\n }\n\n return path;\n}\n\n/** Split a path into segments, filtering empty strings. */\nfunction splitSegments(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n}\n\n/** Extract the search params from a URL string. */\nexport function extractSearchParams(path: string): URLSearchParams {\n const qIdx = path.indexOf(\"?\");\n if (qIdx === -1) return new URLSearchParams();\n return new URLSearchParams(path.slice(qIdx + 1));\n}\n\n// ─── Radix Insert ──────────────────────────────────────────\n\n/**\n * Insert a route into the radix tree.\n *\n * @param root The root node.\n * @param pattern Path pattern like `/users/:id` or `/files/*path`.\n * @param data Arbitrary data to attach at the leaf.\n */\nexport function radixInsert(\n root: RadixNode,\n pattern: string,\n data: RouteData,\n): void {\n const segments = splitSegments(normalizePath(pattern));\n insertNode(root, segments, 0, data);\n}\n\nfunction insertNode(\n node: RadixNode,\n segments: string[],\n depth: number,\n data: RouteData,\n): void {\n if (depth === segments.length) {\n node.route = data;\n return;\n }\n\n const seg = segments[depth];\n if (seg === undefined) return;\n\n // Wildcard child\n if (seg === \"*\" || seg.startsWith(\"*\")) {\n const existing = node.children.find((c) => c.isWildcard);\n if (existing) {\n insertNode(existing, segments, depth + 1, data);\n return;\n }\n const wc = createNode(seg);\n node.children.push(wc);\n insertNode(wc, segments, depth + 1, data);\n return;\n }\n\n // Param child\n if (seg.startsWith(\":\")) {\n const paramName = seg.slice(1);\n for (const child of node.children) {\n if (child.isParam && child.paramName === paramName) {\n insertNode(child, segments, depth + 1, data);\n return;\n }\n }\n const pc = createNode(seg);\n node.children.push(pc);\n insertNode(pc, segments, depth + 1, data);\n return;\n }\n\n // Static child\n for (const child of node.children) {\n if (child.isParam || child.isWildcard) continue;\n if (child.prefix === seg) {\n insertNode(child, segments, depth + 1, data);\n return;\n }\n }\n\n const sc = createNode(seg);\n node.children.push(sc);\n insertNode(sc, segments, depth + 1, data);\n}\n\n// ─── Radix Search ──────────────────────────────────────────\n\n/** Result of a radix search. */\nexport interface MatchResult {\n /** The data attached to the matched leaf node. */\n data: RouteData;\n /** Extracted path parameters. */\n params: Record<string, string>;\n /** The full pattern that was matched. */\n matchedPath: string;\n}\n\n/**\n * Search the radix tree for a matching route.\n *\n * Static segments are checked first (fast path), then param\n * segments, then wildcard segments (catch-all).\n *\n * @returns `MatchResult` if found, `null` otherwise.\n */\nexport function radixSearch(root: RadixNode, path: string): MatchResult | null {\n const segments = splitSegments(normalizePath(path));\n const params: Record<string, string> = Object.create(null);\n const result = searchNode(root, segments, 0, params, \"\");\n if (!result) return null;\n return result;\n}\n\nfunction searchNode(\n node: RadixNode,\n segments: string[],\n depth: number,\n params: Record<string, string>,\n pathSoFar: string,\n): MatchResult | null {\n // Reached the end of the path — check if this node has a route\n if (depth === segments.length) {\n if (node.route) {\n return {\n data: node.route,\n params: copyParams(params),\n matchedPath: pathSoFar,\n };\n }\n // Check for trailing wildcard (matches empty rest)\n for (const child of node.children) {\n if (child.isWildcard && child.route) {\n const paramName = child.prefix === \"*\" ? \"\" : child.prefix.slice(1);\n if (paramName) {\n params[paramName] = \"\";\n } else {\n params[\"_wildcard\"] = \"\";\n }\n return {\n data: child.route,\n params: copyParams(params),\n matchedPath: pathSoFar + \"/*\",\n };\n }\n }\n return null;\n }\n\n const seg = segments[depth];\n if (seg === undefined) return null;\n\n // 1) Static children (fast path)\n for (const child of node.children) {\n if (child.isParam || child.isWildcard) continue;\n if (child.prefix !== seg) continue;\n const found = searchNode(\n child,\n segments,\n depth + 1,\n params,\n pathSoFar + \"/\" + child.prefix,\n );\n if (found) return found;\n }\n\n // 2) Param children\n for (const child of node.children) {\n if (!child.isParam) continue;\n params[child.paramName] = decodeURIComponent(seg);\n const found = searchNode(\n child,\n segments,\n depth + 1,\n params,\n pathSoFar + \"/:\" + child.paramName,\n );\n if (found) return found;\n delete params[child.paramName];\n }\n\n // 3) Wildcard children (catch-all)\n for (const child of node.children) {\n if (!child.isWildcard) continue;\n if (!child.route) continue;\n const rest = wildcardValue(segments, depth);\n // Extract param name: \"*\" → \"_wildcard\", \"*path\" → \"path\"\n const paramName = child.prefix === \"*\" ? \"\" : child.prefix.slice(1);\n if (paramName) {\n params[paramName] = rest;\n } else {\n params[\"_wildcard\"] = rest;\n }\n return {\n data: child.route,\n params: copyParams(params),\n matchedPath: pathSoFar + \"/*\",\n };\n }\n\n return null;\n}\n\n/** Build the wildcard value from remaining segments. */\nfunction wildcardValue(segments: string[], depth: number): string {\n let rest = \"\";\n for (let i = depth; i < segments.length; i += 1) {\n const seg = segments[i];\n if (seg === undefined || seg === \"\") continue;\n if (rest === \"\") rest = seg;\n else rest += \"/\" + seg;\n }\n return rest;\n}\n\n/** Fast key-by-key copy of params. */\nfunction copyParams(src: Record<string, string>): Record<string, string> {\n const dst: Record<string, string> = Object.create(null);\n for (const key in src) dst[key] = src[key]!;\n return dst;\n}\n\n// ─── Radix Tree Factory ────────────────────────────────────\n\n/** Create a new empty radix tree root. */\nexport function createRadixTree(): RadixNode {\n return createNode(\"\");\n}\n\n// ─── Build Path (still useful for programmatic URL construction) ─\n\n/**\n * Build a path from a pattern and params.\n *\n * @example\n * ```ts\n * buildPath(\"/users/:id\", { id: \"42\" }); // \"/users/42\"\n * ```\n */\nexport function buildPath(\n pattern: string,\n params: Record<string, string> = {},\n): string {\n return pattern.replace(/:(\\w+)/g, (_match, name: string) => {\n const value = params[name];\n if (value === undefined) {\n throw new Error(`Missing param \"${name}\" for pattern \"${pattern}\"`);\n }\n return encodeURIComponent(value);\n });\n}\n",
|
|
7
|
-
"
|
|
7
|
+
"/**\n * Sinwan Router — scroll helpers for the `scroll: \"top\"` option.\n */\n\n/** The fragment of an href or `location.hash`, without `#` (`\"\"` when none). */\nexport function hashFromHref(href: string): string {\n const index = href.indexOf(\"#\");\n return index === -1 ? \"\" : href.slice(index + 1);\n}\n\n/** The element a URL fragment points at, by id (percent-decoded when valid). */\nexport function findHashTarget(\n doc: Pick<Document, \"getElementById\">,\n hash: string,\n): HTMLElement | null {\n let id = hash;\n try {\n id = decodeURIComponent(hash);\n } catch {\n // Malformed escape: look the raw fragment up instead.\n }\n return doc.getElementById(id);\n}\n\n/** Resolves on the next animation frame, after pending DOM updates paint. */\nexport function nextFrame(win: Pick<Window, \"requestAnimationFrame\">): Promise<void> {\n return new Promise((resolve) => {\n win.requestAnimationFrame(() => resolve());\n });\n}\n",
|
|
8
|
+
"import { _$createTemplate } from \"sinwan/renderer/web\";\n\nconst _$tmpl_0 = {\n\thtml: \"<div role=\\\"main\\\" aria-labelledby=\\\"sinwan-router-not-found-title\\\" style=\\\"\\\"><div style=\\\"\\\"><p aria-hidden=\\\"true\\\" style=\\\"\\\">404</p><h1 id=\\\"sinwan-router-not-found-title\\\" style=\\\"\\\">Page not found</h1><p style=\\\"\\\">No route matches<!--s:0--><code style=\\\"\\\"></code>.</p><!--s:2--></div></div>\",\n\tslots: [\n\t\t{ path: [], type: \"attr\", name: \"style\" },\n\t\t{ path: [0], type: \"attr\", name: \"style\" },\n\t\t{ path: [0, 0], type: \"attr\", name: \"style\" },\n\t\t{ path: [0, 1], type: \"attr\", name: \"style\" },\n\t\t{ path: [0, 2], type: \"attr\", name: \"style\" },\n\t\t{ path: [0, 2, 1], type: \"child\" },\n\t\t{ path: [0, 2, 2], type: \"attr\", name: \"style\" },\n\t\t{ path: [0, 2, 2], type: \"child\" },\n\t\t{ path: [0, 3], type: \"child\" }\n\t]\n};\n\nconst _$tmpl_1 = {\n\thtml: \"<div role=\\\"status\\\" aria-live=\\\"polite\\\" style=\\\"\\\"><div style=\\\"\\\">Loading...</div></div>\",\n\tslots: [\n\t\t{ path: [], type: \"attr\", name: \"style\" },\n\t\t{ path: [0], type: \"attr\", name: \"style\" }\n\t]\n};\n\nconst _$tmpl_2 = {\n\thtml: \"<div role=\\\"alert\\\" style=\\\"\\\"><div style=\\\"\\\">Failed to load page</div></div>\",\n\tslots: [\n\t\t{ path: [], type: \"attr\", name: \"style\" },\n\t\t{ path: [0], type: \"attr\", name: \"style\" }\n\t]\n};\n\n/**\n * Sinwan Router — Components\n *\n * Link, NavLink, and RouterOutlet that use useRouter() internally.\n * The router instance must be provided via provide(RouterKey, router).\n */\nimport { cc, getRawProps } from \"sinwan/component\";\n\nimport { Key } from \"sinwan/control-flow\";\nimport type { SinwanComponent, SinwanNode } from \"sinwan/component\";\nimport { computed } from \"sinwan/reactivity\";\nimport { useRouter } from \"./hooks.ts\";\nimport { isLazyComponent } from \"./router.ts\";\nimport type { Router } from \"./router.ts\";\nimport type { MatchedRoute } from \"./types.ts\";\nimport { shouldInterceptLinkClick, type LinkInterceptOptions } from \"./link-nav.ts\";\nimport { computeOutletKey, getMatchAtDepth } from \"./outlet.ts\";\n\n// ─── Link ──────────────────────────────────────────────────\n/**\n * Anchor props for client navigation. Extra keys (data-*, aria-*, ref,\n * mouse/focus handlers) are forwarded so Slot / asChild parents can merge\n * onto the real `<a>` (e.g. SidebarMenuButton tooltip).\n */\nexport type LinkProps = \n\t{ \n\t\thref: string;\n\t\tprefetch?: boolean;\n\t\tclass?: string;\n\t\tchildren?: SinwanNode;\n\t\ttarget?: string;\n\t\tdownload?: string | boolean;\n\t\trel?: string;\n\t\tonclick?: (event: MouseEvent) => void;\n\t\tonmouseenter?: (event: MouseEvent) => void\n\t } &\n\tRecord<string, unknown>;\n\nconst LINK_OWN_KEYS = new Set([\n\t\"href\",\n\t\"prefetch\",\n\t\"class\",\n\t\"children\",\n\t\"target\",\n\t\"download\",\n\t\"rel\",\n\t\"onclick\",\n\t\"onmouseenter\"\n]);\n\nfunction linkPassthrough(props: LinkProps): Record<string, unknown> {\n\tconst raw = getRawProps(props) as Record<string, unknown>;\n\tconst rest: Record<string, unknown> = {};\n\n\tfor (const key of Object.keys(raw)) {\n\t\tif (!LINK_OWN_KEYS.has(key)) rest[key] = raw[key];\n\t}\n\n\treturn rest;\n}\n\nfunction onLinkClick(\n\tevent: MouseEvent,\n\thref: string,\n\trouter: Router,\n\toptions: LinkInterceptOptions\n): void {\n\tif (!shouldInterceptLinkClick(event, href, router.path, options)) return;\n\n\tevent.preventDefault();\n\trouter.navigate(href);\n}\n\nfunction downloadAttr(download: string | boolean | undefined): string | undefined {\n\tif (download === undefined || download === false) return undefined;\n\tif (download === true) return \"\";\n\n\treturn download;\n}\n\n/**\n * Link — client-side navigation anchor.\n * Uses the router from context (provide(RouterKey, router)).\n */\nexport const Link = cc<LinkProps>((props) => {\n\tconst {\n\t\thref,\n\t\tprefetch = true,\n\t\tclass: cls,\n\t\tchildren,\n\t\ttarget,\n\t\tdownload,\n\t\trel,\n\t\tonclick,\n\t\tonmouseenter\n\t} = props;\n\n\tconst router = useRouter();\n\tconst rest = linkPassthrough(props);\n\n\treturn (<a {...rest} href={href} class={cls} target={target} download={downloadAttr(download)} rel={rel} onclick={(e: MouseEvent) => {\n\t\tonLinkClick(e, href, router, { target, download });\n\t\tonclick?.(e);\n\t}} onmouseenter={(e: MouseEvent) => {\n\t\tif (prefetch) router.prefetch(href);\n\n\t\tonmouseenter?.(e);\n\t}}>\n {children}\n </a>);\n});\n\n// ─── NavLink ───────────────────────────────────────────────\nexport type NavLinkClassOptions = { isActive: boolean };\n\nexport type NavLinkClassFunction = (options: NavLinkClassOptions) => string | false | null | undefined;\n\nexport type NavLinkProps = \n\t{ \n\t\thref: string;\n\t\tprefetch?: boolean;\n\t\t/**\n\t\t * Static class string, or a callback that receives `{ isActive }` so\n\t\t * active/inactive styles never share conflicting Tailwind utilities.\n\t\t * When omitted, active links get the class `\"active\"` (CSS templates).\n\t\t */\n\t\tclass?: string | NavLinkClassFunction;\n\t\tchildren?: SinwanNode;\n\t\ttarget?: string;\n\t\tdownload?: string | boolean;\n\t\trel?: string;\n\t\tonclick?: (event: MouseEvent) => void;\n\t\tonmouseenter?: (event: MouseEvent) => void\n\t } &\n\tRecord<string, unknown>;\n\nfunction isNavLinkActive(path: string, href: string): boolean {\n\treturn path === href || path.startsWith(href + \"/\");\n}\n\nfunction resolveNavLinkClass(\n\tcls: string | NavLinkClassFunction | undefined,\n\tisActive: boolean\n): string {\n\tif (typeof cls === \"function\") {\n\t\treturn (cls({ isActive }) || \"\").trim();\n\t}\n\n\tif (cls != null && cls !== \"\") {\n\t\treturn cls;\n\t}\n\n\treturn isActive ? \"active\" : \"\";\n}\n\n/**\n * NavLink — Link with active state styling.\n * Uses the router from context.\n */\nexport const NavLink = cc<NavLinkProps>((props) => {\n\tconst {\n\t\thref,\n\t\tprefetch = true,\n\t\tclass: cls,\n\t\tchildren,\n\t\ttarget,\n\t\tdownload,\n\t\trel,\n\t\tonclick,\n\t\tonmouseenter\n\t} = props;\n\n\tconst router = useRouter();\n\tconst rest = linkPassthrough(props as LinkProps);\n\tconst className = computed(() => resolveNavLinkClass(cls, isNavLinkActive(router.path, href)));\n\n\treturn (<a {...rest} href={href} class={className} target={target} download={downloadAttr(download)} rel={rel} onclick={(e: MouseEvent) => {\n\t\tonLinkClick(e, href, router, { target, download });\n\t\tonclick?.(e);\n\t}} onmouseenter={(e: MouseEvent) => {\n\t\tif (prefetch) router.prefetch(href);\n\n\t\tonmouseenter?.(e);\n\t}}>\n {children}\n </a>);\n});\n\n// ─── RouterOutlet ──────────────────────────────────────────\nexport interface RouterOutletProps {\n\tfallback?: SinwanComponent;\n\tnotFound?: SinwanComponent;\n\terror?: SinwanComponent<{ error?: unknown }>;\n\t/** Depth of this outlet (0 = top-level, 1 = nested in parent route). */ depth?: number\n}\n\n/** Credit Blue palette (sinwan-ui default) — inline so the router needs no CSS import. */ const creditBlue = {\n\tbackground: \"oklch(0.98 0.004 250)\",\n\tforeground: \"oklch(0.18 0.03 255)\",\n\tprimary: \"oklch(0.55 0.22 262)\",\n\tprimaryForeground: \"oklch(0.98 0.01 250)\",\n\tsecondary: \"oklch(0.9 0.04 262)\",\n\tsecondaryForeground: \"oklch(0.3 0.09 262)\",\n\ttertiary: \"oklch(0.72 0.14 230)\",\n\tmuted: \"oklch(0.96 0.006 250)\",\n\tmutedForeground: \"oklch(0.5 0.02 255)\",\n\tcard: \"oklch(1 0 0)\",\n\tborder: \"oklch(0.9 0.01 255)\",\n\tradius: \"0.625rem\",\n\tambientBackground: [\n\t\t\"radial-gradient(110% 85% at 0% 0%, oklch(0.72 0.14 230 / 0.08), transparent 60%)\",\n\t\t\"radial-gradient(110% 85% at 100% 0%, oklch(0.55 0.22 262 / 0.07), transparent 60%)\",\n\t\t\"radial-gradient(110% 85% at 100% 100%, oklch(0.72 0.14 230 / 0.08), transparent 60%)\",\n\t\t\"radial-gradient(110% 85% at 0% 100%, oklch(0.55 0.22 262 / 0.06), transparent 60%)\",\n\t\t\"oklch(0.98 0.004 250)\"\n\t].join(\", \"),\n\tbrandGradient: \"linear-gradient(150deg, oklch(0.72 0.14 230) 10%, oklch(0.55 0.22 262) 100%)\"\n} as const;\n\nconst defaultNotFoundShellStyle = {\n\tminHeight: \"100vh\",\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n\tpadding: \"2.5rem 1.25rem\",\n\tboxSizing: \"border-box\",\n\tbackground: creditBlue.ambientBackground,\n\tcolor: creditBlue.foreground,\n\tfontFamily: 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif'\n} as const;\n\nconst defaultNotFoundCardStyle = {\n\tmaxWidth: \"28rem\",\n\twidth: \"100%\",\n\ttextAlign: \"center\",\n\tpadding: \"2.25rem 1.75rem\",\n\tborderRadius: \"calc(0.625rem * 1.4)\",\n\tbackground: creditBlue.card,\n\tborder: `1px solid ${creditBlue.border}`,\n\tboxShadow: \"0 18px 50px oklch(0.55 0.22 262 / 0.08)\"\n} as const;\n\nconst defaultNotFoundCodeStyle = {\n\tdisplay: \"inline-block\",\n\tmargin: \"0 0.15em\",\n\tpadding: \"0.12em 0.4em\",\n\tborderRadius: \"calc(0.625rem * 0.6)\",\n\tbackground: creditBlue.muted,\n\tcolor: creditBlue.secondaryForeground,\n\tfontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\n\tfontSize: \"0.88em\",\n\twordBreak: \"break-all\"\n} as const;\n\nconst defaultNotFoundLinkStyle = {\n\tdisplay: \"inline-block\",\n\tpadding: \"0.65rem 1.2rem\",\n\tborderRadius: creditBlue.radius,\n\tbackground: creditBlue.brandGradient,\n\tcolor: creditBlue.primaryForeground,\n\ttextDecoration: \"none\",\n\tfontSize: \"0.9rem\",\n\tfontWeight: 600,\n\tletterSpacing: \"0.01em\",\n\tboxShadow: \"0 8px 20px oklch(0.55 0.22 262 / 0.28)\"\n} as const;\n\n/** Built-in 404 when `notFound` is omitted from `RouterOutlet` / `Routes`. */ const DefaultNotFound = cc(() => {\n\tconst router = useRouter();\n\n\treturn (_$createTemplate(_$tmpl_0, [\n\t\tdefaultNotFoundShellStyle,\n\t\tdefaultNotFoundCardStyle,\n\t\t{\n\t\t\tmargin: \"0 0 0.85rem\",\n\t\t\tfontSize: \"clamp(3.5rem, 12vw, 5rem)\",\n\t\t\tfontWeight: 700,\n\t\t\tletterSpacing: \"-0.06em\",\n\t\t\tlineHeight: 1,\n\t\t\tbackground: creditBlue.brandGradient,\n\t\t\tbackgroundClip: \"text\",\n\t\t\tWebkitBackgroundClip: \"text\",\n\t\t\tcolor: \"transparent\"\n\t\t},\n\n\t\t{\n\t\t\tmargin: \"0 0 0.75rem\",\n\t\t\tfontSize: \"1.5rem\",\n\t\t\tfontWeight: 600,\n\t\t\tletterSpacing: \"-0.02em\",\n\t\t\tcolor: creditBlue.foreground\n\t\t},\n\n\t\t{\n\t\t\tmargin: \"0 0 1.75rem\",\n\t\t\tfontSize: \"0.95rem\",\n\t\t\tlineHeight: 1.55,\n\t\t\tcolor: creditBlue.mutedForeground\n\t\t},\n\t\t\" \",\n\t\tdefaultNotFoundCodeStyle,\n\t\t() => router.path,\n\t\t<Link href=\"/\" style={defaultNotFoundLinkStyle}>\n Back to home\n </Link>\n\t]));\n});\n\nconst defaultStatusShellStyle = {\n\tminHeight: \"100vh\",\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n\tpadding: \"2rem 1.25rem\",\n\tboxSizing: \"border-box\",\n\tbackground: creditBlue.ambientBackground,\n\tcolor: creditBlue.foreground,\n\tfontFamily: 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif'\n} as const;\n\nconst defaultStatusCardStyle = {\n\tpadding: \"1.25rem 1.5rem\",\n\tborderRadius: creditBlue.radius,\n\tbackground: creditBlue.card,\n\tborder: `1px solid ${creditBlue.border}`,\n\tcolor: creditBlue.secondaryForeground,\n\tfontSize: \"0.95rem\",\n\tfontWeight: 500,\n\tboxShadow: \"0 12px 32px oklch(0.55 0.22 262 / 0.06)\"\n} as const;\n\nconst DefaultLoading = cc(() => (_$createTemplate(_$tmpl_1, [defaultStatusShellStyle, defaultStatusCardStyle])));\n\nconst DefaultError = cc<{ error?: unknown }>(() => (_$createTemplate(_$tmpl_2, [\n\tdefaultStatusShellStyle,\n\t{\n\t\t...defaultStatusCardStyle,\n\t\tborderColor: \"oklch(0.55 0.22 262 / 0.35)\",\n\t\tcolor: creditBlue.foreground\n\t}\n])));\n\nfunction resolveOutletNode(\n\tmatched: MatchedRoute,\n\trouter: Router,\n\tfallback: SinwanComponent,\n\terrorComp: SinwanComponent<{ error?: unknown }>\n): SinwanNode {\n\tconst route = matched.route;\n\n\tif (!isLazyComponent(route.component)) {\n\t\tconst Comp = route.component;\n\n\t\treturn <Comp />;\n\t}\n\n\tconst cacheKey = matched.matchedPath;\n\tconst state = router.peekLazy(cacheKey);\n\n\tif (state.status === \"ready\") {\n\t\tconst Comp = state.component;\n\n\t\treturn <Comp />;\n\t}\n\n\tif (state.status === \"error\") {\n\t\tconst ErrorView = errorComp;\n\n\t\treturn <ErrorView error={state.error} />;\n\t}\n\n\trouter.ensureLazy(cacheKey, route.component);\n\n\tconst Fallback = fallback;\n\n\treturn <Fallback />;\n}\n\n/**\n * RouterOutlet — renders the matched route's component at a given depth.\n * For nested routes, place a <RouterOutlet /> inside the parent component.\n * Uses the router from context.\n */\nexport const RouterOutlet = cc<RouterOutletProps>((props) => {\n\tconst router = useRouter();\n\tconst Fallback = () => props.fallback ?? DefaultLoading;\n\tconst NotFound = props.notFound ?? DefaultNotFound;\n\tconst ErrorView = () => props.error ?? DefaultError;\n\n\t// Arity ≥ 1: Key remount render-prop (not a reactive SinwanNode getter).\n\t// Zero-arity `() =>` remounts the layout on every `matched` change.\n\treturn (<Key when={() => computeOutletKey(router, props.depth === void 0 ? 0 : props.depth)}>\n {(_identity) => {\n\t\t\tconst matched = getMatchAtDepth(router.matched, props.depth === void 0 ? 0 : props.depth);\n\n\t\t\tif (!matched) {\n\t\t\t\tif ((props.depth === void 0 ? 0 : props.depth) > 0) return null;\n\n\t\t\t\treturn <NotFound />;\n\t\t\t}\n\n\t\t\treturn resolveOutletNode(matched, router, Fallback(), ErrorView());\n\t\t}}\n </Key>);\n});",
|
|
8
9
|
"/**\n * Sinwan Router — Hooks\n *\n * Reactive hooks for accessing router state inside components.\n * Must be called within a component that has a Router in context.\n */\n\nimport { inject } from \"sinwan/component\";\nimport type { InjectionKey } from \"sinwan/component\";\nimport type { Router } from \"./router.ts\";\nimport type { RouterContextValue, NavigateOptions } from \"./types.ts\";\n\n/** Injection key for the router instance. */\nexport const RouterKey: InjectionKey<Router> = Symbol(\"sinwan.router\");\n\n/**\n * Access the router instance.\n *\n * @example\n * ```tsx\n * const router = useRouter();\n * router.navigate(\"/about\");\n * ```\n */\nexport function useRouter(): Router {\n const router = inject(RouterKey);\n if (!router) {\n throw new Error(\"useRouter() called outside of a Router provider.\");\n }\n return router;\n}\n\n/**\n * Get the current route parameters.\n *\n * @example\n * ```tsx\n * const params = useParams();\n * console.log(params.id); // \"42\" for /users/42\n * ```\n */\nexport function useParams(): Record<string, string> {\n return useRouter().params;\n}\n\n/**\n * Get the current search params (query string).\n *\n * @example\n * ```tsx\n * const searchParams = useSearchParams();\n * console.log(searchParams.get(\"q\")); // \"hello\" for /search?q=hello\n * ```\n */\nexport function useSearchParams(): URLSearchParams {\n return useRouter().searchParams;\n}\n\n/**\n * Get the current matched route.\n *\n * @example\n * ```tsx\n * const route = useRoute();\n * if (route) {\n * console.log(route.path, route.params);\n * }\n * ```\n */\nexport function useRoute() {\n return useRouter().matched;\n}\n\n/**\n * Get a navigate function.\n *\n * @example\n * ```tsx\n * const navigate = useNavigate();\n * navigate(\"/users/42\");\n * navigate(\"/login\", { replace: true });\n * ```\n */\nexport function useNavigate(): (to: string, options?: NavigateOptions) => void {\n const router = useRouter();\n return router.navigate.bind(router);\n}\n\n/**\n * Get the current path.\n *\n * @example\n * ```tsx\n * const path = usePath();\n * console.log(path); // \"/users/42\"\n * ```\n */\nexport function usePath(): string {\n return useRouter().path;\n}\n",
|
|
9
10
|
"/**\n * Link click interception.\n */\n\n/** Fields read from a click event to decide client-side navigation. */\nexport interface LinkClickEvent {\n button: number;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n defaultPrevented: boolean;\n}\n\nexport interface LinkInterceptOptions {\n target?: string;\n download?: string | boolean;\n}\n\n/** True when the href should be left to the browser (other origin or scheme). */\nexport function isExternalHref(href: string): boolean {\n if (href.startsWith(\"//\")) return true;\n const colon = href.indexOf(\":\");\n if (colon <= 0) return false;\n const slash = href.indexOf(\"/\");\n if (slash !== -1 && slash < colon) return false;\n return true;\n}\n\n/** True when the href is an in-page hash (no path change). */\nexport function isHashOnlyHref(href: string, currentPath: string): boolean {\n if (href.startsWith(\"#\")) return true;\n const hashIdx = href.indexOf(\"#\");\n if (hashIdx === -1) return false;\n const beforeHash = href.slice(0, hashIdx);\n if (beforeHash === \"\") return true;\n const qIdx = beforeHash.indexOf(\"?\");\n const pathPart = qIdx === -1 ? beforeHash : beforeHash.slice(0, qIdx);\n if (pathPart === \"\" || pathPart === \".\") return true;\n const normalized =\n pathPart.startsWith(\"/\") ? pathPart : \"/\" + pathPart;\n const stripped =\n normalized.length > 1 && normalized.endsWith(\"/\")\n ? normalized.slice(0, -1)\n : normalized;\n return stripped === currentPath;\n}\n\n/** Whether this click should be handled by the client router. */\nexport function shouldInterceptLinkClick(\n event: LinkClickEvent,\n href: string,\n currentPath: string,\n options: LinkInterceptOptions = {},\n): boolean {\n if (event.defaultPrevented) return false;\n if (event.button !== 0) return false;\n if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {\n return false;\n }\n if (options.target != null && options.target !== \"\" && options.target !== \"_self\") {\n return false;\n }\n if (options.download !== undefined && options.download !== false) {\n return false;\n }\n if (isExternalHref(href)) return false;\n if (isHashOnlyHref(href, currentPath)) return false;\n return true;\n}\n",
|
|
10
11
|
"/**\n * Nested-outlet matching and Key identity.\n */\n\nimport { isLazyComponent } from \"./router.ts\";\nimport type { Router } from \"./router.ts\";\nimport type { MatchedRoute } from \"./types.ts\";\n\n/**\n * Walk the matched route chain to a specific depth.\n * depth=0 → root match, depth=1 → first child, etc.\n */\nexport function getMatchAtDepth(\n matched: MatchedRoute | null,\n depth: number,\n): MatchedRoute | null {\n if (!matched) return null;\n let current: MatchedRoute | undefined = matched;\n const chain: MatchedRoute[] = [];\n while (current) {\n chain.unshift(current);\n current = current.parent;\n }\n return chain[depth] ?? null;\n}\n\n/**\n * Stable identity for a match at one outlet depth.\n * Parent layouts ignore child param changes; param routes include their values.\n */\nexport function routeIdentity(matched: MatchedRoute): string {\n const pattern = matched.matchedPath;\n if (pattern.includes(\"*\")) {\n return matched.path;\n }\n let concrete = pattern;\n for (const key of Object.keys(matched.params)) {\n const value = matched.params[key];\n if (value === undefined) continue;\n concrete = concrete.replace(\":\" + key, encodeURIComponent(value));\n }\n if (concrete.includes(\":\")) {\n return matched.path;\n }\n return concrete;\n}\n\nfunction lazyStatusSuffix(router: Router, matched: MatchedRoute): string {\n if (!isLazyComponent(matched.route.component)) return \"sync\";\n const state = router.peekLazy(matched.matchedPath);\n return state.status;\n}\n\n/**\n * Key value for `<Key>` at an outlet depth.\n * Reads `lazyTick` so load completion re-evaluates without a same-path navigate.\n * Unchanged identities do not remount parent layouts.\n */\nexport function computeOutletKey(router: Router, depth: number): string {\n void router.lazyTick;\n const matched = getMatchAtDepth(router.matched, depth);\n if (!matched) {\n return depth > 0 ? `__empty:${depth}` : \"__notfound__\";\n }\n return `${routeIdentity(matched)}:${lazyStatusSuffix(router, matched)}`;\n}\n",
|
|
11
|
-
"/**\n * JSX <Routes> / <Route> — the same fields as RouteDefinition.\n */\
|
|
12
|
+
"import { unwrap as _$unwrap } from \"sinwan/reactivity\";\n\n/**\n * JSX <Routes> / <Route> — the same fields as RouteDefinition.\n */\nimport { cc, provide, onDispose } from \"sinwan/component\";\n\nimport type { SinwanComponent, SinwanElement, SinwanNode } from \"sinwan/component\";\nimport { createRouter } from \"./router.ts\";\nimport { RouterOutlet } from \"./components.tsx\";\nimport { RouterKey } from \"./hooks.ts\";\nimport type { RouteComponent, RouteDefinition, RouterOptions, RouterScroll } from \"./types.ts\";\n\nexport const ROUTE_TYPE = Symbol.for(\"sinwan.router.Route\");\n\n/**\n * JSX props match {@link RouteDefinition}.\n * `children` may be nested `<Route>` elements or a `RouteDefinition[]`.\n */\nexport type RouteProps = \n\tOmit<RouteDefinition, \"children\"> &\n\t{ children?: RouteDefinition | RouteDefinition[] | SinwanNode };\n\nexport interface RoutesProps {\n\tchildren?: SinwanNode;\n\tfallback?: SinwanComponent;\n\tnotFound?: SinwanComponent;\n\terror?: SinwanComponent<{ error?: unknown }>;\n\tinitialPath?: string;\n\tscroll?: RouterScroll\n}\n\nfunction isElementLike(value: unknown): value is SinwanElement {\n\treturn value != null && typeof value === \"object\" && \"tag\" in value;\n}\n\nfunction routePropsRecord(props: RouteProps): Record<string, unknown> {\n\tconst record: Record<string, unknown> = { path: props.path, component: props.component };\n\n\tif (props.meta !== undefined) record.meta = props.meta;\n\tif (props.children !== undefined) record.children = props.children;\n\n\treturn record;\n}\n\n/** Marker for a single route. Same props as `RouteDefinition`. */ export function Route(props: RouteProps): SinwanElement {\n\treturn {\n\t\ttag: ROUTE_TYPE,\n\t\tprops: routePropsRecord(props),\n\t\tchildren: []\n\t};\n}\n\nexport function isRouteElement(value: unknown): value is SinwanElement {\n\tif (!isElementLike(value)) return false;\n\n\treturn value.tag === ROUTE_TYPE || value.tag === Route;\n}\n\nfunction isRouteDefinition(value: unknown): value is RouteDefinition {\n\tif (value == null || typeof value !== \"object\") return false;\n\tif (\"tag\" in value) return false;\n\n\tconst rec = value as { path?: unknown; component?: unknown };\n\n\treturn typeof rec.path === \"string\" && rec.component != null;\n}\n\nfunction flattenNodes(node: unknown): unknown[] {\n\tif (node == null || typeof node === \"boolean\") return [];\n\n\tif (Array.isArray(node)) {\n\t\tconst out: unknown[] = [];\n\n\t\tfor (const child of node) {\n\t\t\tout.push(...flattenNodes(child));\n\t\t}\n\n\t\treturn out;\n\t}\n\n\tif (isElementLike(node) && node.tag === \"\") {\n\t\tconst fromKids = flattenNodes(node.children);\n\n\t\tif (fromKids.length > 0) return fromKids;\n\n\t\treturn flattenNodes(node.props.children);\n\t}\n\n\treturn [node];\n}\n\nfunction nestedDefinitions(source: unknown): RouteDefinition[] | undefined {\n\tif (source == null) return undefined;\n\n\tif (Array.isArray(source) && source.length > 0 && isRouteDefinition(source[0])) {\n\t\tconst defs: RouteDefinition[] = [];\n\n\t\tfor (const item of source) {\n\t\t\tif (isRouteDefinition(item)) defs.push(item);\n\t\t}\n\n\t\treturn defs.length > 0 ? defs : undefined;\n\t}\n\n\tif (isRouteDefinition(source)) return [source];\n\n\tconst collected = collectRouteDefinitions(source);\n\n\treturn collected.length > 0 ? collected : undefined;\n}\n\nfunction routeNodeToDefinition(node: unknown): RouteDefinition | null {\n\tif (isRouteDefinition(node)) {\n\t\tconst def: RouteDefinition = { path: node.path, component: node.component };\n\n\t\tif (node.meta) def.meta = node.meta;\n\t\tif (node.children && node.children.length > 0) def.children = node.children;\n\n\t\treturn def;\n\t}\n\n\tif (!isRouteElement(node)) return null;\n\n\tconst props = node.props;\n\tconst path = props.path;\n\tconst component = props.component;\n\n\tif (typeof path !== \"string\" || component == null) return null;\n\n\tconst def: RouteDefinition = { path, component: component as RouteComponent };\n\tconst meta = props.meta;\n\n\tif (meta != null && typeof meta === \"object\") {\n\t\tdef.meta = meta as Record<string, unknown>;\n\t}\n\n\tconst nested = nestedDefinitions(props.children ?? node.children);\n\n\tif (nested) def.children = nested;\n\n\treturn def;\n}\n\n/** Walk JSX children (and fragments) into native `RouteDefinition[]`. */ export function collectRouteDefinitions(children: unknown): RouteDefinition[] {\n\tconst defs: RouteDefinition[] = [];\n\n\tfor (const node of flattenNodes(children)) {\n\t\tconst def = routeNodeToDefinition(node);\n\n\t\tif (def) defs.push(def);\n\t}\n\n\treturn defs;\n}\n\n/** Non-route siblings (nav, layout) to render beside the outlet. */ export function layoutNodes(children: unknown): SinwanNode[] {\n\tconst out: SinwanNode[] = [];\n\n\tfor (const node of flattenNodes(children)) {\n\t\tif (isRouteElement(node) || isRouteDefinition(node)) continue;\n\n\t\tout.push(node as SinwanNode);\n\t}\n\n\treturn out;\n}\n\n/**\n * Declarative JSX router. Builds a `Router` from `<Route>` children\n * (same fields as `RouteDefinition`), provides `RouterKey` to layout\n * siblings such as `<NavLink>`, and renders a `<RouterOutlet />`.\n */\nexport const Routes = cc<RoutesProps>((props) => {\n\tconst router = createRouter(collectRouteDefinitions(props.children), { initialPath: props.initialPath, scroll: props.scroll });\n\n\tprovide(RouterKey, router);\n\n\tonDispose(() => {\n\t\trouter.dispose();\n\t});\n\n\tconst outlet = (<RouterOutlet fallback={() => _$unwrap(props).fallback} notFound={() => _$unwrap(props).notFound} error={() => _$unwrap(props).error} />);\n\tconst layout = layoutNodes(props.children);\n\n\tif (layout.length === 0) return outlet;\n\n\treturn (<>\n {layout}\n {outlet}\n </>);\n});"
|
|
12
13
|
],
|
|
13
|
-
"mappings": "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",
|
|
14
|
-
"debugId": "
|
|
14
|
+
"mappings": "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",
|
|
15
|
+
"debugId": "1D4F3C960149F76864756E2164756E21",
|
|
15
16
|
"names": []
|
|
16
17
|
}
|
package/dist/jsx-routes.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* JSX <Routes> / <Route> — the same fields as RouteDefinition.
|
|
3
3
|
*/
|
|
4
4
|
import type { SinwanComponent, SinwanElement, SinwanNode } from "sinwan/component";
|
|
5
|
-
import type { RouteDefinition } from "./types.ts";
|
|
5
|
+
import type { RouteDefinition, RouterScroll } from "./types.ts";
|
|
6
6
|
export declare const ROUTE_TYPE: unique symbol;
|
|
7
7
|
/**
|
|
8
8
|
* JSX props match {@link RouteDefinition}.
|
|
@@ -19,6 +19,7 @@ export interface RoutesProps {
|
|
|
19
19
|
error?: unknown;
|
|
20
20
|
}>;
|
|
21
21
|
initialPath?: string;
|
|
22
|
+
scroll?: RouterScroll;
|
|
22
23
|
}
|
|
23
24
|
/** Marker for a single route. Same props as `RouteDefinition`. */
|
|
24
25
|
export declare function Route(props: RouteProps): SinwanElement;
|
package/dist/router.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Signal, Computed } from "sinwan/reactivity";
|
|
9
9
|
import type { SinwanComponent } from "sinwan/component";
|
|
10
|
-
import type { RouteDefinition, MatchedRoute, NavigateOptions, LazyComponent, LazyPeek } from "./types.ts";
|
|
10
|
+
import type { RouteDefinition, MatchedRoute, NavigateOptions, LazyComponent, LazyPeek, RouterOptions } from "./types.ts";
|
|
11
11
|
/**
|
|
12
12
|
* True for explicit `lazy()` factories, `_SinwanLazy` brands, and zero-arg
|
|
13
13
|
* `() => import(...)` loaders. `cc` components and functions that take props
|
|
@@ -31,7 +31,13 @@ export declare class Router {
|
|
|
31
31
|
private readonly lazyInflight;
|
|
32
32
|
private readonly _lazyTick;
|
|
33
33
|
private popstateHandler;
|
|
34
|
-
|
|
34
|
+
private readonly scroll;
|
|
35
|
+
/** Bumped per navigation so a stale pending hash reveal is dropped. */
|
|
36
|
+
private scrollToken;
|
|
37
|
+
/**
|
|
38
|
+
* @param options Router options, or the initial path (1.0 signature).
|
|
39
|
+
*/
|
|
40
|
+
constructor(routes: RouteDefinition[], options?: string | RouterOptions);
|
|
35
41
|
/** Recursively insert a route and its children into the tree. */
|
|
36
42
|
private insertRoute;
|
|
37
43
|
private bumpLazyTick;
|
|
@@ -61,6 +67,11 @@ export declare class Router {
|
|
|
61
67
|
get routes(): RouteDefinition[];
|
|
62
68
|
/** Navigate to a new path. */
|
|
63
69
|
navigate(to: string, options?: NavigateOptions): void;
|
|
70
|
+
/** `scroll: "top"`: jump to the top, then to the `#hash` target once rendered. */
|
|
71
|
+
private applyScroll;
|
|
72
|
+
private revealHash;
|
|
73
|
+
/** Waits for the matched chain's lazy components, then one frame for the DOM. */
|
|
74
|
+
private whenRouteRendered;
|
|
64
75
|
/** Prefetch a route's lazy component into this router's cache. */
|
|
65
76
|
prefetch(path: string): void;
|
|
66
77
|
/** Resolve a lazy component, using this instance's cache if available. */
|
|
@@ -71,5 +82,8 @@ export declare class Router {
|
|
|
71
82
|
/** Clean up event listeners and drop this instance's lazy cache. */
|
|
72
83
|
dispose(): void;
|
|
73
84
|
}
|
|
74
|
-
/**
|
|
75
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Create a router instance.
|
|
87
|
+
* @param options Router options, or the initial path (1.0 signature).
|
|
88
|
+
*/
|
|
89
|
+
export declare function createRouter(routes: RouteDefinition[], options?: string | RouterOptions): Router;
|
package/dist/scroll.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sinwan Router — scroll helpers for the `scroll: "top"` option.
|
|
3
|
+
*/
|
|
4
|
+
/** The fragment of an href or `location.hash`, without `#` (`""` when none). */
|
|
5
|
+
export declare function hashFromHref(href: string): string;
|
|
6
|
+
/** The element a URL fragment points at, by id (percent-decoded when valid). */
|
|
7
|
+
export declare function findHashTarget(doc: Pick<Document, "getElementById">, hash: string): HTMLElement | null;
|
|
8
|
+
/** Resolves on the next animation frame, after pending DOM updates paint. */
|
|
9
|
+
export declare function nextFrame(win: Pick<Window, "requestAnimationFrame">): Promise<void>;
|
package/dist/types.d.ts
CHANGED
|
@@ -40,6 +40,30 @@ export interface NavigateOptions {
|
|
|
40
40
|
replace?: boolean;
|
|
41
41
|
/** Optional state object to associate with the history entry. */
|
|
42
42
|
state?: unknown;
|
|
43
|
+
/**
|
|
44
|
+
* Set to `false` to skip the router's `scroll` handling for this one
|
|
45
|
+
* navigation (for example, a query-param tab switch).
|
|
46
|
+
*/
|
|
47
|
+
scroll?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Window scroll after client navigation.
|
|
51
|
+
* - `"preserve"`: leave the scroll position alone (default).
|
|
52
|
+
* - `"top"`: scroll to the top, or to the element named by the URL `#hash`
|
|
53
|
+
* once the route has rendered (lazy routes included).
|
|
54
|
+
*/
|
|
55
|
+
export type RouterScroll = "preserve" | "top";
|
|
56
|
+
/** Options for `createRouter` / `new Router`. */
|
|
57
|
+
export interface RouterOptions {
|
|
58
|
+
/** Starting path. Defaults to `window.location` on the client, `/` on the server. */
|
|
59
|
+
initialPath?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Window scroll after `navigate()` (Link, NavLink, `useNavigate`).
|
|
62
|
+
* With `"top"`, the hash of the first page load is revealed too.
|
|
63
|
+
* Back/forward keep the browser's own scroll restoration.
|
|
64
|
+
* @default "preserve"
|
|
65
|
+
*/
|
|
66
|
+
scroll?: RouterScroll;
|
|
43
67
|
}
|
|
44
68
|
/** The router context value provided to descendant components. */
|
|
45
69
|
export interface RouterContextValue {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sinwan-router",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Client-side router for Sinwan apps — declarative route matching, params, lazy loading, and prefetching built on Sinwan's reactivity system.",
|
|
5
5
|
"author": "Mohammed Ben Cheikh",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"typecheck": "bunx tsc -p tsconfig.json"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"sinwan": ">=
|
|
42
|
+
"sinwan": ">=2.0.0 <3.0.0",
|
|
43
|
+
"typescript": ">=5.0.0 <8.0.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@types/bun": "latest",
|
|
46
|
-
"bun-plugin-sinwan": "
|
|
47
|
-
"happy-dom": "^20.
|
|
48
|
-
"typescript": "^5"
|
|
47
|
+
"bun-plugin-sinwan": ">=1.0.0 <2.0.0",
|
|
48
|
+
"happy-dom": "^20.14.5"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|