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 CHANGED
@@ -76,7 +76,7 @@ const App = cc(() => {
76
76
  <div>
77
77
  <nav>
78
78
  <Link href="/">Home</Link>
79
- <NavLink href="/about" activeClass="active">
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 `initialPath`.
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 href="/users" activeClass="active" class="nav">
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
 
@@ -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
- export interface LinkProps {
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 interface NavLinkProps extends LinkProps {
23
- activeClass?: string;
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
- constructor(routes, initialPath) {
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, initialPath) {
421
- return new Router(routes, initialPath);
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/component";
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: '<a href="" class="" target="" download="" rel="" onclick="" onmouseenter=""><!--s:0--></a>',
554
- slots: [{
555
- path: [],
556
- type: "attr",
557
- name: "href"
558
- }, {
559
- path: [],
560
- type: "attr",
561
- name: "class"
562
- }, {
563
- path: [],
564
- type: "attr",
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: '<a href="" class="" target="" download="" rel="" onclick="" onmouseenter=""><!--s:0--></a>',
589
- slots: [{
590
- path: [],
591
- type: "attr",
592
- name: "href"
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: "<div>404 - Page not found</div>",
624
- slots: []
625
- };
626
- var _$tmpl_3 = {
627
- html: "<div>Loading...</div>",
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
- href,
649
- prefetch = true,
650
- class: cls,
651
- children,
652
- target,
653
- download,
654
- rel
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
- return _$createTemplate(_$tmpl_0, [href, cls, target, downloadAttr(download), rel, (e) => {
658
- onLinkClick(e, href, router, {
659
- target,
660
- download
661
- });
662
- }, () => {
663
- if (prefetch)
664
- router.prefetch(href);
665
- }, children]);
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
- var NavLink = cc(({
668
- href,
669
- prefetch = true,
670
- activeClass = "active",
671
- class: cls,
672
- children,
673
- target,
674
- download,
675
- rel
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 className = computed2(() => router.path === href || router.path.startsWith(href + "/") ? `${cls ?? ""} ${activeClass}`.trim() : cls ?? "");
679
- return _$createTemplate(_$tmpl_1, [href, className, target, downloadAttr(download), rel, (e) => {
680
- onLinkClick(e, href, router, {
681
- target,
682
- download
683
- });
684
- }, () => {
685
- if (prefetch)
686
- router.prefetch(href);
687
- }, children]);
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 DefaultNotFound = cc(() => _$createTemplate(_$tmpl_2, []));
690
- var DefaultLoading = cc(() => _$createTemplate(_$tmpl_3, []));
691
- var DefaultError = cc(() => _$createTemplate(_$tmpl_4, []));
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=D61DE7C0A6BF0E7964756E2164756E21
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
- "import { _$createTemplate } from \"sinwan/renderer\";\nconst _$tmpl_0 = {\n html: \"<a href=\\\"\\\" class=\\\"\\\" target=\\\"\\\" download=\\\"\\\" rel=\\\"\\\" onclick=\\\"\\\" onmouseenter=\\\"\\\"><!--s:0--></a>\",\n slots: [{\n path: [],\n type: \"attr\",\n name: \"href\"\n }, {\n path: [],\n type: \"attr\",\n name: \"class\"\n }, {\n path: [],\n type: \"attr\",\n name: \"target\"\n }, {\n path: [],\n type: \"attr\",\n name: \"download\"\n }, {\n path: [],\n type: \"attr\",\n name: \"rel\"\n }, {\n path: [],\n type: \"event\",\n name: \"onclick\"\n }, {\n path: [],\n type: \"event\",\n name: \"onmouseenter\"\n }, {\n path: [0],\n type: \"child\"\n }]\n};\nconst _$tmpl_1 = {\n html: \"<a href=\\\"\\\" class=\\\"\\\" target=\\\"\\\" download=\\\"\\\" rel=\\\"\\\" onclick=\\\"\\\" onmouseenter=\\\"\\\"><!--s:0--></a>\",\n slots: [{\n path: [],\n type: \"attr\",\n name: \"href\"\n }, {\n path: [],\n type: \"attr\",\n name: \"class\"\n }, {\n path: [],\n type: \"attr\",\n name: \"target\"\n }, {\n path: [],\n type: \"attr\",\n name: \"download\"\n }, {\n path: [],\n type: \"attr\",\n name: \"rel\"\n }, {\n path: [],\n type: \"event\",\n name: \"onclick\"\n }, {\n path: [],\n type: \"event\",\n name: \"onmouseenter\"\n }, {\n path: [0],\n type: \"child\"\n }]\n};\nconst _$tmpl_2 = {\n html: \"<div>404 - Page not found</div>\",\n slots: []\n};\nconst _$tmpl_3 = {\n html: \"<div>Loading...</div>\",\n slots: []\n};\nconst _$tmpl_4 = {\n html: \"<div>Failed to load page</div>\",\n slots: []\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 */\n\nimport { cc } from \"sinwan/component\";\nimport { Key } from \"sinwan/component\";\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\nexport interface LinkProps {\n href: string;\n prefetch?: boolean;\n class?: string;\n children?: SinwanNode;\n target?: string;\n download?: string | boolean;\n rel?: string;\n}\nfunction onLinkClick(event: MouseEvent, href: string, router: Router, options: LinkInterceptOptions): void {\n if (!shouldInterceptLinkClick(event, href, router.path, options)) return;\n event.preventDefault();\n router.navigate(href);\n}\nfunction downloadAttr(download: string | boolean | undefined): string | undefined {\n if (download === undefined || download === false) return undefined;\n if (download === true) return \"\";\n return 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>(({\n href,\n prefetch = true,\n class: cls,\n children,\n target,\n download,\n rel\n}) => {\n const router = useRouter();\n return _$createTemplate(_$tmpl_0, [href, cls, target, downloadAttr(download), rel, (e: MouseEvent) => {\n onLinkClick(e, href, router, {\n target,\n download\n });\n }, () => {\n if (prefetch) router.prefetch(href);\n }, children]);\n});\n\n// ─── NavLink ───────────────────────────────────────────────\n\nexport interface NavLinkProps extends LinkProps {\n activeClass?: string;\n}\n\n/**\n * NavLink — Link with active state styling.\n * Uses the router from context.\n */\nexport const NavLink = cc<NavLinkProps>(({\n href,\n prefetch = true,\n activeClass = \"active\",\n class: cls,\n children,\n target,\n download,\n rel\n}) => {\n const router = useRouter();\n const className = computed(() => router.path === href || router.path.startsWith(href + \"/\") ? `${cls ?? \"\"} ${activeClass}`.trim() : cls ?? \"\");\n return _$createTemplate(_$tmpl_1, [href, className, target, downloadAttr(download), rel, (e: MouseEvent) => {\n onLinkClick(e, href, router, {\n target,\n download\n });\n }, () => {\n if (prefetch) router.prefetch(href);\n }, children]);\n});\n\n// ─── RouterOutlet ──────────────────────────────────────────\n\nexport interface RouterOutletProps {\n fallback?: SinwanComponent;\n notFound?: SinwanComponent;\n error?: SinwanComponent<{\n error?: unknown;\n }>;\n /** Depth of this outlet (0 = top-level, 1 = nested in parent route). */\n depth?: number;\n}\nconst DefaultNotFound = cc(() => _$createTemplate(_$tmpl_2, []));\nconst DefaultLoading = cc(() => _$createTemplate(_$tmpl_3, []));\nconst DefaultError = cc<{\n error?: unknown;\n}>(() => _$createTemplate(_$tmpl_4, []));\nfunction resolveOutletNode(matched: MatchedRoute, router: Router, fallback: SinwanComponent, errorComp: SinwanComponent<{\n error?: unknown;\n}>): SinwanNode {\n const route = matched.route;\n if (!isLazyComponent(route.component)) {\n const Comp = route.component;\n return <Comp />;\n }\n const cacheKey = matched.matchedPath;\n const state = router.peekLazy(cacheKey);\n if (state.status === \"ready\") {\n const Comp = state.component;\n return <Comp />;\n }\n if (state.status === \"error\") {\n const ErrorView = errorComp;\n return <ErrorView error={state.error} />;\n }\n router.ensureLazy(cacheKey, route.component);\n const Fallback = fallback;\n return <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>(({\n fallback,\n notFound,\n error,\n depth = 0\n}) => {\n const router = useRouter();\n const Fallback = fallback ?? DefaultLoading;\n const NotFound = notFound ?? DefaultNotFound;\n const ErrorView = error ?? DefaultError;\n return <Key when={() => computeOutletKey(router, depth)}>\n {() => {\n const matched = getMatchAtDepth(router.matched, depth);\n if (!matched) {\n if (depth > 0) return null;\n return <NotFound />;\n }\n return resolveOutletNode(matched, router, Fallback, ErrorView);\n }}\n </Key>;\n});",
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 */\n\nimport { cc, provide, onDispose } from \"sinwan/component\";\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 } from \"./types.ts\";\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 = Omit<RouteDefinition, \"children\"> & {\n children?: RouteDefinition | RouteDefinition[] | SinwanNode;\n};\nexport interface RoutesProps {\n children?: SinwanNode;\n fallback?: SinwanComponent;\n notFound?: SinwanComponent;\n error?: SinwanComponent<{\n error?: unknown;\n }>;\n initialPath?: string;\n}\nfunction isElementLike(value: unknown): value is SinwanElement {\n return value != null && typeof value === \"object\" && \"tag\" in value;\n}\nfunction routePropsRecord(props: RouteProps): Record<string, unknown> {\n const record: Record<string, unknown> = {\n path: props.path,\n component: props.component\n };\n if (props.meta !== undefined) record.meta = props.meta;\n if (props.children !== undefined) record.children = props.children;\n return record;\n}\n\n/** Marker for a single route. Same props as `RouteDefinition`. */\nexport function Route(props: RouteProps): SinwanElement {\n return {\n tag: ROUTE_TYPE,\n props: routePropsRecord(props),\n children: []\n };\n}\nexport function isRouteElement(value: unknown): value is SinwanElement {\n if (!isElementLike(value)) return false;\n return value.tag === ROUTE_TYPE || value.tag === Route;\n}\nfunction isRouteDefinition(value: unknown): value is RouteDefinition {\n if (value == null || typeof value !== \"object\") return false;\n if (\"tag\" in value) return false;\n const rec = value as {\n path?: unknown;\n component?: unknown;\n };\n return typeof rec.path === \"string\" && rec.component != null;\n}\nfunction flattenNodes(node: unknown): unknown[] {\n if (node == null || typeof node === \"boolean\") return [];\n if (Array.isArray(node)) {\n const out: unknown[] = [];\n for (const child of node) {\n out.push(...flattenNodes(child));\n }\n return out;\n }\n if (isElementLike(node) && node.tag === \"\") {\n const fromKids = flattenNodes(node.children);\n if (fromKids.length > 0) return fromKids;\n return flattenNodes(node.props.children);\n }\n return [node];\n}\nfunction nestedDefinitions(source: unknown): RouteDefinition[] | undefined {\n if (source == null) return undefined;\n if (Array.isArray(source) && source.length > 0 && isRouteDefinition(source[0])) {\n const defs: RouteDefinition[] = [];\n for (const item of source) {\n if (isRouteDefinition(item)) defs.push(item);\n }\n return defs.length > 0 ? defs : undefined;\n }\n if (isRouteDefinition(source)) return [source];\n const collected = collectRouteDefinitions(source);\n return collected.length > 0 ? collected : undefined;\n}\nfunction routeNodeToDefinition(node: unknown): RouteDefinition | null {\n if (isRouteDefinition(node)) {\n const def: RouteDefinition = {\n path: node.path,\n component: node.component\n };\n if (node.meta) def.meta = node.meta;\n if (node.children && node.children.length > 0) def.children = node.children;\n return def;\n }\n if (!isRouteElement(node)) return null;\n const props = node.props;\n const path = props.path;\n const component = props.component;\n if (typeof path !== \"string\" || component == null) return null;\n const def: RouteDefinition = {\n path,\n component: component as RouteComponent\n };\n const meta = props.meta;\n if (meta != null && typeof meta === \"object\") {\n def.meta = meta as Record<string, unknown>;\n }\n const nested = nestedDefinitions(props.children ?? node.children);\n if (nested) def.children = nested;\n return def;\n}\n\n/** Walk JSX children (and fragments) into native `RouteDefinition[]`. */\nexport function collectRouteDefinitions(children: unknown): RouteDefinition[] {\n const defs: RouteDefinition[] = [];\n for (const node of flattenNodes(children)) {\n const def = routeNodeToDefinition(node);\n if (def) defs.push(def);\n }\n return defs;\n}\n\n/** Non-route siblings (nav, layout) to render beside the outlet. */\nexport function layoutNodes(children: unknown): SinwanNode[] {\n const out: SinwanNode[] = [];\n for (const node of flattenNodes(children)) {\n if (isRouteElement(node) || isRouteDefinition(node)) continue;\n out.push(node as SinwanNode);\n }\n return 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>(({\n children,\n fallback,\n notFound,\n error,\n initialPath\n}) => {\n const router = createRouter(collectRouteDefinitions(children), initialPath);\n provide(RouterKey, router);\n onDispose(() => {\n router.dispose();\n });\n const outlet = <RouterOutlet fallback={fallback} notFound={notFound} error={error} />;\n const layout = layoutNodes(children);\n if (layout.length === 0) return outlet;\n return <>\n {layout}\n {outlet}\n </>;\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": "D61DE7C0A6BF0E7964756E2164756E21",
14
+ "mappings": "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",
15
+ "debugId": "1D4F3C960149F76864756E2164756E21",
15
16
  "names": []
16
17
  }
@@ -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
- constructor(routes: RouteDefinition[], initialPath?: string);
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
- /** Create a router instance. */
75
- export declare function createRouter(routes: RouteDefinition[], initialPath?: string): Router;
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;
@@ -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.2",
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": ">=1.3.3 <2.0.0"
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": "^0.2.5",
47
- "happy-dom": "^20.9.0",
48
- "typescript": "^5"
47
+ "bun-plugin-sinwan": ">=1.0.0 <2.0.0",
48
+ "happy-dom": "^20.14.5"
49
49
  }
50
- }
50
+ }