@studiolambda/router 0.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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/matcher-CSJ3hjzA.cjs +2 -0
  4. package/dist/matcher-CSJ3hjzA.cjs.map +1 -0
  5. package/dist/matcher-XNPYU-tD.js +69 -0
  6. package/dist/matcher-XNPYU-tD.js.map +1 -0
  7. package/dist/router.cjs +1 -0
  8. package/dist/router.js +2 -0
  9. package/dist/router_react.cjs +6 -0
  10. package/dist/router_react.cjs.map +1 -0
  11. package/dist/router_react.js +506 -0
  12. package/dist/router_react.js.map +1 -0
  13. package/dist/src/react/ExampleMain.d.ts +7 -0
  14. package/dist/src/react/components/Link.d.ts +91 -0
  15. package/dist/src/react/components/Middlewares.d.ts +28 -0
  16. package/dist/src/react/components/NotFound.d.ts +6 -0
  17. package/dist/src/react/components/Router.d.ts +81 -0
  18. package/dist/src/react/context/MatcherContext.d.ts +12 -0
  19. package/dist/src/react/context/NavigationContext.d.ts +11 -0
  20. package/dist/src/react/context/NavigationSignalContext.d.ts +7 -0
  21. package/dist/src/react/context/NavigationTypeContext.d.ts +6 -0
  22. package/dist/src/react/context/PathnameContext.d.ts +10 -0
  23. package/dist/src/react/context/PropsContext.d.ts +10 -0
  24. package/dist/src/react/context/TransitionContext.d.ts +19 -0
  25. package/dist/src/react/createRouter.d.ts +187 -0
  26. package/dist/src/react/example.d.ts +1 -0
  27. package/dist/src/react/examples/Auth.d.ts +11 -0
  28. package/dist/src/react/examples/HelloWorld.d.ts +5 -0
  29. package/dist/src/react/examples/Other.d.ts +6 -0
  30. package/dist/src/react/examples/User.d.ts +6 -0
  31. package/dist/src/react/extractPathname.d.ts +17 -0
  32. package/dist/src/react/hooks/useActiveLinkProps.d.ts +73 -0
  33. package/dist/src/react/hooks/useBack.d.ts +47 -0
  34. package/dist/src/react/hooks/useForward.d.ts +47 -0
  35. package/dist/src/react/hooks/useIsPending.d.ts +29 -0
  36. package/dist/src/react/hooks/useNavigate.d.ts +10 -0
  37. package/dist/src/react/hooks/useNavigation.d.ts +13 -0
  38. package/dist/src/react/hooks/useNavigationEvents.d.ts +43 -0
  39. package/dist/src/react/hooks/useNavigationHandlers.d.ts +47 -0
  40. package/dist/src/react/hooks/useNavigationSignal.d.ts +13 -0
  41. package/dist/src/react/hooks/useNavigationType.d.ts +12 -0
  42. package/dist/src/react/hooks/useNextMatch.d.ts +26 -0
  43. package/dist/src/react/hooks/useParams.d.ts +19 -0
  44. package/dist/src/react/hooks/usePathname.d.ts +23 -0
  45. package/dist/src/react/hooks/usePrefetch.d.ts +27 -0
  46. package/dist/src/react/hooks/usePrefetchEffect.d.ts +69 -0
  47. package/dist/src/react/hooks/useSearchParams.d.ts +58 -0
  48. package/dist/src/react/index.d.ts +31 -0
  49. package/dist/src/react/navigation/createMemoryNavigation.d.ts +52 -0
  50. package/dist/src/react/router.d.ts +139 -0
  51. package/dist/src/react/test-helpers.d.ts +50 -0
  52. package/dist/src/router/index.d.ts +1 -0
  53. package/dist/src/router/matcher.d.ts +127 -0
  54. package/package.json +107 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Erik C. Forés
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # Lambda Router
2
+
3
+ > Lightweight, isomorphic and framework agnostic router for modern UIs
4
+
5
+ Lambda Router is a client-side routing library designed for single-page applications. It provides a core URL pattern matcher that works in any JavaScript environment, plus a full-featured React integration with components, hooks, and navigation management.
6
+
7
+ ## Documentation
8
+
9
+ Find out about the project and discover the features at the [Documentation](https://lambda.studio/router/getting-started/)
10
+
11
+ ## Installation
12
+
13
+ ```
14
+ npm i @studiolambda/router
15
+ ```
@@ -0,0 +1,2 @@
1
+ function e(e){let t=e?.root??{children:new Map};function n(e,n){let r=e.split(`/`).filter(Boolean),i=t;for(let e of r){if(e.startsWith(`*`)){let t=e.length>1?e.slice(1):`*`;i.wildcard||={children:new Map,name:t},i=i.wildcard;continue}if(e.startsWith(`:`)){let t=e.slice(1);i.child||={children:new Map,name:t},i=i.child;continue}let t=i.children.get(e);t||(t={children:new Map},i.children.set(e,t)),i=t}i.handler=n}function r(e){let n=e.split(`/`).filter(Boolean);function r(e,t,i){if(t===n.length)return e.handler?{handler:e.handler,params:i}:null;let a=n[t],o=e.children.get(a);if(o){let e=r(o,t+1,i);if(e)return e}if(e.child&&e.child.name){let n=r(e.child,t+1,{...i,[e.child.name]:a});if(n)return n}if(e.wildcard&&e.wildcard.name&&e.wildcard.handler){let r=n.slice(t).join(`/`);return{handler:e.wildcard.handler,params:{...i,[e.wildcard.name]:r}}}return null}return r(t,0,{})}return{register:n,match:r}}Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return e}});
2
+ //# sourceMappingURL=matcher-CSJ3hjzA.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matcher-CSJ3hjzA.cjs","names":[],"sources":["../src/router/matcher.ts"],"sourcesContent":["/**\n * Describes a route matcher that maps URL path patterns to\n * handlers. Supports static segments, dynamic `:param`\n * segments, and wildcard `*param` segments with a trie-based\n * lookup.\n *\n * @typeParam T - The handler type associated with each route.\n */\nexport interface Matcher<T> {\n /**\n * Registers a route pattern with a corresponding handler.\n * Patterns use `/`-separated segments where `:name` denotes\n * a dynamic parameter (e.g. `/user/:id/posts`) and `*name`\n * denotes a wildcard that captures the rest of the path\n * (e.g. `/files/*path`). A bare `*` captures into a param\n * named `'*'`.\n *\n * @param pattern - The URL path pattern to register.\n * @param handler - The handler to associate with this pattern.\n */\n readonly register: (pattern: string, handler: T) => void\n\n /**\n * Attempts to match a URL path against registered routes.\n * Static segments take priority over dynamic ones, which\n * take priority over wildcard segments. Returns the matched\n * handler and extracted parameters, or `null` if no route\n * matches.\n *\n * @param path - The URL path to match (e.g. `/user/42`).\n * @returns The resolved match with handler and params, or null.\n */\n readonly match: (path: string) => Resolved<T> | null\n}\n\n/**\n * The result of a successful route match. Contains the handler\n * registered for the matched pattern and a record of extracted\n * dynamic parameters.\n *\n * @typeParam T - The handler type associated with the route.\n */\nexport interface Resolved<T> {\n /**\n * The handler that was registered for the matched route pattern.\n */\n readonly handler: T\n\n /**\n * Dynamic path parameters extracted from the URL. Keys are the\n * parameter names from the pattern (without the `:` prefix),\n * values are the corresponding URL segments.\n *\n * @example\n * Pattern `/user/:id` matched against `/user/42`\n * produces `{ id: \"42\" }`.\n */\n readonly params: Record<string, string>\n}\n\n/**\n * Configuration options for creating a new matcher instance.\n *\n * @typeParam T - The handler type associated with each route.\n */\nexport interface Options<T> {\n /**\n * An existing trie root node to use instead of creating\n * an empty one. Useful for pre-built or shared route trees.\n */\n readonly root?: Node<T>\n}\n\n/**\n * A node in the route-matching trie. Each node represents a\n * single URL path segment and may hold a handler (indicating\n * a complete route), static children (keyed by segment string),\n * a single dynamic child (for `:param` segments), and/or a\n * wildcard child (for `*param` segments that capture the rest\n * of the path).\n *\n * @typeParam T - The handler type associated with each route.\n */\nexport interface Node<T> {\n /**\n * Map of static child segments. Each key is a literal path\n * segment string (e.g. `\"user\"`, `\"posts\"`).\n */\n readonly children: Map<string, Node<T>>\n\n /**\n * The handler registered at this node, or `undefined` if\n * this node is only an intermediate segment in a longer\n * pattern.\n */\n handler?: T\n\n /**\n * The single dynamic child node for `:param` segments.\n * Only one dynamic segment is allowed per trie level.\n */\n child?: Node<T>\n\n /**\n * The parameter name for this dynamic segment (without the\n * `:` prefix). Only set on nodes created from `:param`\n * patterns.\n */\n readonly name?: string\n\n /**\n * The wildcard child node for `*param` segments. Captures\n * all remaining path segments into a single parameter.\n * Only one wildcard is allowed per trie level and it must\n * be the last segment in the pattern.\n */\n wildcard?: Node<T>\n}\n\n/**\n * Creates a new trie-based route matcher. Routes are registered\n * with patterns containing static segments, dynamic (`:param`)\n * segments, and wildcard (`*param`) segments. Matching\n * prioritises static segments over dynamic ones, and dynamic\n * over wildcards, performing a depth-first search through the\n * trie.\n *\n * Wildcard segments capture all remaining path segments into a\n * single parameter joined by `/`. A bare `*` captures into\n * a param named `'*'`. Wildcards must be the last segment\n * in a pattern.\n *\n * @typeParam T - The handler type associated with each route.\n * @param options - Optional configuration with a pre-built root node.\n * @returns A matcher instance with `register` and `match` methods.\n */\nexport function createMatcher<T>(options?: Options<T>): Matcher<T> {\n const root: Node<T> = options?.root ?? { children: new Map() }\n\n /**\n * Registers a route pattern by walking/creating trie nodes\n * for each segment and attaching the handler at the leaf.\n * Wildcard segments (`*param`) create a terminal wildcard\n * node — no further segments are allowed after a wildcard.\n *\n * @param pattern - The URL path pattern to register.\n * @param handler - The handler to store at the leaf node.\n */\n function register(pattern: string, handler: T) {\n const segments = pattern.split('/').filter(Boolean)\n let node = root\n\n for (const segment of segments) {\n if (segment.startsWith('*')) {\n const name = segment.length > 1 ? segment.slice(1) : '*'\n\n if (!node.wildcard) {\n node.wildcard = { children: new Map(), name }\n }\n\n node = node.wildcard\n continue\n }\n\n if (segment.startsWith(':')) {\n const name = segment.slice(1)\n\n if (!node.child) {\n node.child = { children: new Map(), name }\n }\n\n node = node.child\n continue\n }\n\n let next = node.children.get(segment)\n\n if (!next) {\n next = { children: new Map() }\n node.children.set(segment, next)\n }\n\n node = next\n }\n\n node.handler = handler\n }\n\n /**\n * Matches a URL path against the trie by splitting it into\n * segments and performing a depth-first search. Static\n * children are tried before the dynamic child, and dynamic\n * before the wildcard, at each level.\n *\n * @param path - The URL path to match.\n * @returns The resolved handler and params, or null.\n */\n function match(path: string): Resolved<T> | null {\n const segments = path.split('/').filter(Boolean)\n\n /**\n * Recursively searches the trie for a matching route.\n * Tries the static child first (exact segment match),\n * then falls back to the dynamic child, and finally\n * to the wildcard child which captures all remaining\n * segments.\n *\n * @param node - The current trie node being examined.\n * @param index - The current segment index in the path.\n * @param params - Accumulated dynamic parameters so far.\n * @returns The resolved match, or null if no match found.\n */\n function search(\n node: Node<T>,\n index: number,\n params: Record<string, string>\n ): Resolved<T> | null {\n if (index === segments.length) {\n return node.handler ? { handler: node.handler, params } : null\n }\n\n const segment = segments[index]\n\n const child = node.children.get(segment)\n\n if (child) {\n const result = search(child, index + 1, params)\n\n if (result) {\n return result\n }\n }\n\n if (node.child && node.child.name) {\n const result = search(node.child, index + 1, {\n ...params,\n [node.child.name]: segment,\n })\n\n if (result) {\n return result\n }\n }\n\n if (node.wildcard && node.wildcard.name && node.wildcard.handler) {\n const rest = segments.slice(index).join('/')\n\n return {\n handler: node.wildcard.handler,\n params: { ...params, [node.wildcard.name]: rest },\n }\n }\n\n return null\n }\n\n return search(root, 0, {})\n }\n\n return { register, match }\n}\n"],"mappings":"AAwIA,SAAgB,EAAiB,EAAkC,CACjE,IAAM,EAAgB,GAAS,MAAQ,CAAE,SAAU,IAAI,IAAO,CAW9D,SAAS,EAAS,EAAiB,EAAY,CAC7C,IAAM,EAAW,EAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ,CAC/C,EAAO,EAEX,IAAK,IAAM,KAAW,EAAU,CAC9B,GAAI,EAAQ,WAAW,IAAI,CAAE,CAC3B,IAAM,EAAO,EAAQ,OAAS,EAAI,EAAQ,MAAM,EAAE,CAAG,IAErD,AACE,EAAK,WAAW,CAAE,SAAU,IAAI,IAAO,OAAM,CAG/C,EAAO,EAAK,SACZ,SAGF,GAAI,EAAQ,WAAW,IAAI,CAAE,CAC3B,IAAM,EAAO,EAAQ,MAAM,EAAE,CAE7B,AACE,EAAK,QAAQ,CAAE,SAAU,IAAI,IAAO,OAAM,CAG5C,EAAO,EAAK,MACZ,SAGF,IAAI,EAAO,EAAK,SAAS,IAAI,EAAQ,CAEhC,IACH,EAAO,CAAE,SAAU,IAAI,IAAO,CAC9B,EAAK,SAAS,IAAI,EAAS,EAAK,EAGlC,EAAO,EAGT,EAAK,QAAU,EAYjB,SAAS,EAAM,EAAkC,CAC/C,IAAM,EAAW,EAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAchD,SAAS,EACP,EACA,EACA,EACoB,CACpB,GAAI,IAAU,EAAS,OACrB,OAAO,EAAK,QAAU,CAAE,QAAS,EAAK,QAAS,SAAQ,CAAG,KAG5D,IAAM,EAAU,EAAS,GAEnB,EAAQ,EAAK,SAAS,IAAI,EAAQ,CAExC,GAAI,EAAO,CACT,IAAM,EAAS,EAAO,EAAO,EAAQ,EAAG,EAAO,CAE/C,GAAI,EACF,OAAO,EAIX,GAAI,EAAK,OAAS,EAAK,MAAM,KAAM,CACjC,IAAM,EAAS,EAAO,EAAK,MAAO,EAAQ,EAAG,CAC3C,GAAG,GACF,EAAK,MAAM,MAAO,EACpB,CAAC,CAEF,GAAI,EACF,OAAO,EAIX,GAAI,EAAK,UAAY,EAAK,SAAS,MAAQ,EAAK,SAAS,QAAS,CAChE,IAAM,EAAO,EAAS,MAAM,EAAM,CAAC,KAAK,IAAI,CAE5C,MAAO,CACL,QAAS,EAAK,SAAS,QACvB,OAAQ,CAAE,GAAG,GAAS,EAAK,SAAS,MAAO,EAAM,CAClD,CAGH,OAAO,KAGT,OAAO,EAAO,EAAM,EAAG,EAAE,CAAC,CAG5B,MAAO,CAAE,WAAU,QAAO"}
@@ -0,0 +1,69 @@
1
+ //#region src/router/matcher.ts
2
+ function e(e) {
3
+ let t = e?.root ?? { children: /* @__PURE__ */ new Map() };
4
+ function n(e, n) {
5
+ let r = e.split("/").filter(Boolean), i = t;
6
+ for (let e of r) {
7
+ if (e.startsWith("*")) {
8
+ let t = e.length > 1 ? e.slice(1) : "*";
9
+ i.wildcard ||= {
10
+ children: /* @__PURE__ */ new Map(),
11
+ name: t
12
+ }, i = i.wildcard;
13
+ continue;
14
+ }
15
+ if (e.startsWith(":")) {
16
+ let t = e.slice(1);
17
+ i.child ||= {
18
+ children: /* @__PURE__ */ new Map(),
19
+ name: t
20
+ }, i = i.child;
21
+ continue;
22
+ }
23
+ let t = i.children.get(e);
24
+ t || (t = { children: /* @__PURE__ */ new Map() }, i.children.set(e, t)), i = t;
25
+ }
26
+ i.handler = n;
27
+ }
28
+ function r(e) {
29
+ let n = e.split("/").filter(Boolean);
30
+ function r(e, t, i) {
31
+ if (t === n.length) return e.handler ? {
32
+ handler: e.handler,
33
+ params: i
34
+ } : null;
35
+ let a = n[t], o = e.children.get(a);
36
+ if (o) {
37
+ let e = r(o, t + 1, i);
38
+ if (e) return e;
39
+ }
40
+ if (e.child && e.child.name) {
41
+ let n = r(e.child, t + 1, {
42
+ ...i,
43
+ [e.child.name]: a
44
+ });
45
+ if (n) return n;
46
+ }
47
+ if (e.wildcard && e.wildcard.name && e.wildcard.handler) {
48
+ let r = n.slice(t).join("/");
49
+ return {
50
+ handler: e.wildcard.handler,
51
+ params: {
52
+ ...i,
53
+ [e.wildcard.name]: r
54
+ }
55
+ };
56
+ }
57
+ return null;
58
+ }
59
+ return r(t, 0, {});
60
+ }
61
+ return {
62
+ register: n,
63
+ match: r
64
+ };
65
+ }
66
+ //#endregion
67
+ export { e as t };
68
+
69
+ //# sourceMappingURL=matcher-XNPYU-tD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matcher-XNPYU-tD.js","names":[],"sources":["../src/router/matcher.ts"],"sourcesContent":["/**\n * Describes a route matcher that maps URL path patterns to\n * handlers. Supports static segments, dynamic `:param`\n * segments, and wildcard `*param` segments with a trie-based\n * lookup.\n *\n * @typeParam T - The handler type associated with each route.\n */\nexport interface Matcher<T> {\n /**\n * Registers a route pattern with a corresponding handler.\n * Patterns use `/`-separated segments where `:name` denotes\n * a dynamic parameter (e.g. `/user/:id/posts`) and `*name`\n * denotes a wildcard that captures the rest of the path\n * (e.g. `/files/*path`). A bare `*` captures into a param\n * named `'*'`.\n *\n * @param pattern - The URL path pattern to register.\n * @param handler - The handler to associate with this pattern.\n */\n readonly register: (pattern: string, handler: T) => void\n\n /**\n * Attempts to match a URL path against registered routes.\n * Static segments take priority over dynamic ones, which\n * take priority over wildcard segments. Returns the matched\n * handler and extracted parameters, or `null` if no route\n * matches.\n *\n * @param path - The URL path to match (e.g. `/user/42`).\n * @returns The resolved match with handler and params, or null.\n */\n readonly match: (path: string) => Resolved<T> | null\n}\n\n/**\n * The result of a successful route match. Contains the handler\n * registered for the matched pattern and a record of extracted\n * dynamic parameters.\n *\n * @typeParam T - The handler type associated with the route.\n */\nexport interface Resolved<T> {\n /**\n * The handler that was registered for the matched route pattern.\n */\n readonly handler: T\n\n /**\n * Dynamic path parameters extracted from the URL. Keys are the\n * parameter names from the pattern (without the `:` prefix),\n * values are the corresponding URL segments.\n *\n * @example\n * Pattern `/user/:id` matched against `/user/42`\n * produces `{ id: \"42\" }`.\n */\n readonly params: Record<string, string>\n}\n\n/**\n * Configuration options for creating a new matcher instance.\n *\n * @typeParam T - The handler type associated with each route.\n */\nexport interface Options<T> {\n /**\n * An existing trie root node to use instead of creating\n * an empty one. Useful for pre-built or shared route trees.\n */\n readonly root?: Node<T>\n}\n\n/**\n * A node in the route-matching trie. Each node represents a\n * single URL path segment and may hold a handler (indicating\n * a complete route), static children (keyed by segment string),\n * a single dynamic child (for `:param` segments), and/or a\n * wildcard child (for `*param` segments that capture the rest\n * of the path).\n *\n * @typeParam T - The handler type associated with each route.\n */\nexport interface Node<T> {\n /**\n * Map of static child segments. Each key is a literal path\n * segment string (e.g. `\"user\"`, `\"posts\"`).\n */\n readonly children: Map<string, Node<T>>\n\n /**\n * The handler registered at this node, or `undefined` if\n * this node is only an intermediate segment in a longer\n * pattern.\n */\n handler?: T\n\n /**\n * The single dynamic child node for `:param` segments.\n * Only one dynamic segment is allowed per trie level.\n */\n child?: Node<T>\n\n /**\n * The parameter name for this dynamic segment (without the\n * `:` prefix). Only set on nodes created from `:param`\n * patterns.\n */\n readonly name?: string\n\n /**\n * The wildcard child node for `*param` segments. Captures\n * all remaining path segments into a single parameter.\n * Only one wildcard is allowed per trie level and it must\n * be the last segment in the pattern.\n */\n wildcard?: Node<T>\n}\n\n/**\n * Creates a new trie-based route matcher. Routes are registered\n * with patterns containing static segments, dynamic (`:param`)\n * segments, and wildcard (`*param`) segments. Matching\n * prioritises static segments over dynamic ones, and dynamic\n * over wildcards, performing a depth-first search through the\n * trie.\n *\n * Wildcard segments capture all remaining path segments into a\n * single parameter joined by `/`. A bare `*` captures into\n * a param named `'*'`. Wildcards must be the last segment\n * in a pattern.\n *\n * @typeParam T - The handler type associated with each route.\n * @param options - Optional configuration with a pre-built root node.\n * @returns A matcher instance with `register` and `match` methods.\n */\nexport function createMatcher<T>(options?: Options<T>): Matcher<T> {\n const root: Node<T> = options?.root ?? { children: new Map() }\n\n /**\n * Registers a route pattern by walking/creating trie nodes\n * for each segment and attaching the handler at the leaf.\n * Wildcard segments (`*param`) create a terminal wildcard\n * node — no further segments are allowed after a wildcard.\n *\n * @param pattern - The URL path pattern to register.\n * @param handler - The handler to store at the leaf node.\n */\n function register(pattern: string, handler: T) {\n const segments = pattern.split('/').filter(Boolean)\n let node = root\n\n for (const segment of segments) {\n if (segment.startsWith('*')) {\n const name = segment.length > 1 ? segment.slice(1) : '*'\n\n if (!node.wildcard) {\n node.wildcard = { children: new Map(), name }\n }\n\n node = node.wildcard\n continue\n }\n\n if (segment.startsWith(':')) {\n const name = segment.slice(1)\n\n if (!node.child) {\n node.child = { children: new Map(), name }\n }\n\n node = node.child\n continue\n }\n\n let next = node.children.get(segment)\n\n if (!next) {\n next = { children: new Map() }\n node.children.set(segment, next)\n }\n\n node = next\n }\n\n node.handler = handler\n }\n\n /**\n * Matches a URL path against the trie by splitting it into\n * segments and performing a depth-first search. Static\n * children are tried before the dynamic child, and dynamic\n * before the wildcard, at each level.\n *\n * @param path - The URL path to match.\n * @returns The resolved handler and params, or null.\n */\n function match(path: string): Resolved<T> | null {\n const segments = path.split('/').filter(Boolean)\n\n /**\n * Recursively searches the trie for a matching route.\n * Tries the static child first (exact segment match),\n * then falls back to the dynamic child, and finally\n * to the wildcard child which captures all remaining\n * segments.\n *\n * @param node - The current trie node being examined.\n * @param index - The current segment index in the path.\n * @param params - Accumulated dynamic parameters so far.\n * @returns The resolved match, or null if no match found.\n */\n function search(\n node: Node<T>,\n index: number,\n params: Record<string, string>\n ): Resolved<T> | null {\n if (index === segments.length) {\n return node.handler ? { handler: node.handler, params } : null\n }\n\n const segment = segments[index]\n\n const child = node.children.get(segment)\n\n if (child) {\n const result = search(child, index + 1, params)\n\n if (result) {\n return result\n }\n }\n\n if (node.child && node.child.name) {\n const result = search(node.child, index + 1, {\n ...params,\n [node.child.name]: segment,\n })\n\n if (result) {\n return result\n }\n }\n\n if (node.wildcard && node.wildcard.name && node.wildcard.handler) {\n const rest = segments.slice(index).join('/')\n\n return {\n handler: node.wildcard.handler,\n params: { ...params, [node.wildcard.name]: rest },\n }\n }\n\n return null\n }\n\n return search(root, 0, {})\n }\n\n return { register, match }\n}\n"],"mappings":";AAwIA,SAAgB,EAAiB,GAAkC;CACjE,IAAM,IAAgB,GAAS,QAAQ,EAAE,0BAAU,IAAI,KAAK,EAAE;CAW9D,SAAS,EAAS,GAAiB,GAAY;EAC7C,IAAM,IAAW,EAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ,EAC/C,IAAO;AAEX,OAAK,IAAM,KAAW,GAAU;AAC9B,OAAI,EAAQ,WAAW,IAAI,EAAE;IAC3B,IAAM,IAAO,EAAQ,SAAS,IAAI,EAAQ,MAAM,EAAE,GAAG;AAMrD,IAJA,AACE,EAAK,aAAW;KAAE,0BAAU,IAAI,KAAK;KAAE;KAAM,EAG/C,IAAO,EAAK;AACZ;;AAGF,OAAI,EAAQ,WAAW,IAAI,EAAE;IAC3B,IAAM,IAAO,EAAQ,MAAM,EAAE;AAM7B,IAJA,AACE,EAAK,UAAQ;KAAE,0BAAU,IAAI,KAAK;KAAE;KAAM,EAG5C,IAAO,EAAK;AACZ;;GAGF,IAAI,IAAO,EAAK,SAAS,IAAI,EAAQ;AAOrC,GALK,MACH,IAAO,EAAE,0BAAU,IAAI,KAAK,EAAE,EAC9B,EAAK,SAAS,IAAI,GAAS,EAAK,GAGlC,IAAO;;AAGT,IAAK,UAAU;;CAYjB,SAAS,EAAM,GAAkC;EAC/C,IAAM,IAAW,EAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;EAchD,SAAS,EACP,GACA,GACA,GACoB;AACpB,OAAI,MAAU,EAAS,OACrB,QAAO,EAAK,UAAU;IAAE,SAAS,EAAK;IAAS;IAAQ,GAAG;GAG5D,IAAM,IAAU,EAAS,IAEnB,IAAQ,EAAK,SAAS,IAAI,EAAQ;AAExC,OAAI,GAAO;IACT,IAAM,IAAS,EAAO,GAAO,IAAQ,GAAG,EAAO;AAE/C,QAAI,EACF,QAAO;;AAIX,OAAI,EAAK,SAAS,EAAK,MAAM,MAAM;IACjC,IAAM,IAAS,EAAO,EAAK,OAAO,IAAQ,GAAG;KAC3C,GAAG;MACF,EAAK,MAAM,OAAO;KACpB,CAAC;AAEF,QAAI,EACF,QAAO;;AAIX,OAAI,EAAK,YAAY,EAAK,SAAS,QAAQ,EAAK,SAAS,SAAS;IAChE,IAAM,IAAO,EAAS,MAAM,EAAM,CAAC,KAAK,IAAI;AAE5C,WAAO;KACL,SAAS,EAAK,SAAS;KACvB,QAAQ;MAAE,GAAG;OAAS,EAAK,SAAS,OAAO;MAAM;KAClD;;AAGH,UAAO;;AAGT,SAAO,EAAO,GAAM,GAAG,EAAE,CAAC;;AAG5B,QAAO;EAAE;EAAU;EAAO"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./matcher-CSJ3hjzA.cjs`);exports.createMatcher=e.t;
package/dist/router.js ADDED
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./matcher-XNPYU-tD.js";
2
+ export { e as createMatcher };
@@ -0,0 +1,6 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);const t=require(`./matcher-CSJ3hjzA.cjs`);let n=require(`react/jsx-runtime`),r=require(`react`);function i({value:e,children:t}){return e?.reduceRight((e,t,r)=>(0,n.jsx)(t,{children:e},r),t)??t}var a=e((e=>{var t=require(`react`).__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;e.c=function(e){return t.H.useMemoCache(e)}})),o=e((e=>{process.env.NODE_ENV!==`production`&&(function(){var t=require(`react`).__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;e.c=function(e){var n=t.H;return n===null&&console.error(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
2
+ 1. You might have mismatching versions of React and the renderer (such as React DOM)
3
+ 2. You might be breaking the Rules of Hooks
4
+ 3. You might have more than one copy of React in the same app
5
+ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.`),n.useMemoCache(e)}})()})),s=e(((e,t)=>{process.env.NODE_ENV===`production`?t.exports=a():t.exports=o()}))(),c=(0,r.createContext)({}),l=(0,r.createContext)(null),u=(0,r.createContext)(null),d=(0,r.createContext)(null);function f(){let e=(0,s.c)(1),t;return e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,n.jsx)(`div`,{children:`Not Found`}),e[0]=t):t=e[0],t}var p=(0,r.createContext)(null);function m(e){let t=e??(0,r.use)(p);if(t===null)throw Error(`useNavigationHandlers requires a <Router> or <TransitionContext> provider`);let[,n]=t;function i(e){if(e.prefetch===void 0)return;let t=e.prefetch;return async function(n){await t({params:e.params,url:e.url,controller:n})}}function a(e){return function(){return new Promise(function(t,r){n(async function(){try{await e(),t()}catch(e){r(e)}})})}}return{createPrecommitHandler:i,createHandler:a}}var h=(0,r.createContext)(t.t());function g(e){let t=e?.matcher??(0,r.use)(h);return function(e,n){let r={handler:{component:n},params:{}};return e?t.match(new URL(e).pathname)??r:r}}function _(e,t){let n=(0,r.useEffectEvent)(function(e){t.onNavigate?.(e)}),i=(0,r.useEffectEvent)(function(){t.onNavigateSuccess?.()}),a=(0,r.useEffectEvent)(function(e){t.onNavigateError?.(e.error)});(0,r.useEffect)(function(){return e.addEventListener(`navigate`,n),e.addEventListener(`navigatesuccess`,i),e.addEventListener(`navigateerror`,a),function(){e.removeEventListener(`navigate`,n),e.removeEventListener(`navigatesuccess`,i),e.removeEventListener(`navigateerror`,a)}},[e])}var v=(0,r.createContext)(`/`);function y(e){return e?new URL(e,`http://localhost`).pathname:`/`}function b(e){let t=(0,s.c)(44),a=(0,r.use)(l),o=e.navigation??a??window.navigation,b=e.matcher??(0,r.use)(h),x=(0,r.useTransition)(),S=e.transition??x,C;t[0]===b?C=t[1]:(C={matcher:b},t[0]=b,t[1]=C);let w=g(C),T=e.notFound??f,E;t[2]!==o.currentEntry?.url||t[3]!==w||t[4]!==T?(E=function(){let e=o.currentEntry?.url??null;return{match:w(e,T),signal:null,navigationType:null,pathname:y(e)}},t[2]=o.currentEntry?.url,t[3]=w,t[4]=T,t[5]=E):E=t[5];let[D,O]=(0,r.useState)(E),{createPrecommitHandler:k,createHandler:A}=m(S),j;t[6]!==A||t[7]!==k||t[8]!==w||t[9]!==T?(j=function(e){if(!e.canIntercept||e.hashChange||e.downloadRequest!==null)return;let t=w(e.destination.url,T);if(e.formData!==null&&t.handler.formHandler!==void 0){e.intercept({scroll:t.handler.scroll,focusReset:t.handler.focusReset,async handler(){await t.handler.formHandler(e.formData,e)}});return}let n=k({prefetch:t.handler.prefetch,params:t.params,url:new URL(e.destination.url)}),r=A(function(){O({match:t,signal:e.signal,navigationType:e.navigationType,pathname:y(e.destination.url)})});e.intercept({handler:r,precommitHandler:n,scroll:t.handler.scroll,focusReset:t.handler.focusReset})},t[6]=A,t[7]=k,t[8]=w,t[9]=T,t[10]=j):j=t[10];let M=(0,r.useEffectEvent)(j),N;t[11]!==M||t[12]!==e.onNavigateError||t[13]!==e.onNavigateSuccess?(N={onNavigate:M,onNavigateSuccess:e.onNavigateSuccess,onNavigateError:e.onNavigateError},t[11]=M,t[12]=e.onNavigateError,t[13]=e.onNavigateSuccess,t[14]=N):N=t[14],_(o,N);let P=D.match.handler.component,F=D.match.handler.middlewares,I;t[15]===P?I=t[16]:(I=(0,n.jsx)(P,{}),t[15]=P,t[16]=I);let L;t[17]!==F||t[18]!==I?(L=(0,n.jsx)(i,{value:F,children:I}),t[17]=F,t[18]=I,t[19]=L):L=t[19];let R;t[20]!==e.fallback||t[21]!==L?(R=(0,n.jsx)(r.Suspense,{fallback:e.fallback,children:L}),t[20]=e.fallback,t[21]=L,t[22]=R):R=t[22];let z;t[23]!==D.match.params||t[24]!==R?(z=(0,n.jsx)(c,{value:D.match.params,children:R}),t[23]=D.match.params,t[24]=R,t[25]=z):z=t[25];let B;t[26]!==D.pathname||t[27]!==z?(B=(0,n.jsx)(v,{value:D.pathname,children:z}),t[26]=D.pathname,t[27]=z,t[28]=B):B=t[28];let V;t[29]!==D.signal||t[30]!==B?(V=(0,n.jsx)(u,{value:D.signal,children:B}),t[29]=D.signal,t[30]=B,t[31]=V):V=t[31];let H;t[32]!==D.navigationType||t[33]!==V?(H=(0,n.jsx)(d,{value:D.navigationType,children:V}),t[32]=D.navigationType,t[33]=V,t[34]=H):H=t[34];let U;t[35]!==b||t[36]!==H?(U=(0,n.jsx)(h,{value:b,children:H}),t[35]=b,t[36]=H,t[37]=U):U=t[37];let W;t[38]!==o||t[39]!==U?(W=(0,n.jsx)(l,{value:o,children:U}),t[38]=o,t[39]=U,t[40]=W):W=t[40];let G;return t[41]!==W||t[42]!==S?(G=(0,n.jsx)(p,{value:S,children:W}),t[41]=W,t[42]=S,t[43]=G):G=t[43],G}function x(e,t){let n=S(e,(0,r.use)(v),t?.exact??!0);return{isActive:n,props:{"data-active":n||void 0,"aria-current":n?`page`:void 0}}}function S(e,t,n){if(e===void 0)return!1;let r=y(e);return n?r===t:t===r||t.startsWith(r+`/`)}function C(e){let t=e?.matcher??(0,r.use)(h);return function(e){let n=new URL(e,`http://localhost`),r=t.match(n.pathname);if(r?.handler.prefetch===void 0)return;let i={params:r.params,url:n,controller:{redirect(){},addHandler(){}}};return r.handler.prefetch(i)}}function w(e,t){let{href:n,on:i,once:a=!0,matcher:o}=t,s=C({matcher:o}),c=(0,r.useEffectEvent)(function(e,t){for(let t of e)t.isIntersecting&&n!==void 0&&s(n);a&&t.disconnect()}),l=(0,r.useEffectEvent)(function(){n!==void 0&&s(n)});(0,r.useEffect)(function(){if(i===void 0)return;let t=e.current;if(t!==null)switch(i){case`hover`:return t.addEventListener(`mouseenter`,l,{once:a}),function(){t.removeEventListener(`mouseenter`,l)};case`viewport`:{let e=new IntersectionObserver(c);return e.observe(t),function(){e.disconnect()}}}},[i,a,n,e])}function T(e){let t=(0,s.c)(23),i,a,o,c,l,u,d;t[0]===e?(i=t[1],a=t[2],o=t[3],c=t[4],l=t[5],u=t[6],d=t[7]):({prefetch:c,once:u,href:a,matcher:o,className:i,activeExact:d,...l}=e,t[0]=e,t[1]=i,t[2]=a,t[3]=o,t[4]=c,t[5]=l,t[6]=u,t[7]=d);let f=u===void 0?!0:u,p=d===void 0?!0:d,m=(0,r.useRef)(null),h;t[8]===p?h=t[9]:(h={exact:p},t[8]=p,t[9]=h);let{isActive:g,props:_}=x(a,h),v;t[10]!==a||t[11]!==o||t[12]!==f||t[13]!==c?(v={href:a,on:c,once:f,matcher:o},t[10]=a,t[11]=o,t[12]=f,t[13]=c,t[14]=v):v=t[14],w(m,v);let y;t[15]!==i||t[16]!==g?(y=typeof i==`function`?i({isActive:g}):i,t[15]=i,t[16]=g,t[17]=y):y=t[17];let b=y,S;return t[18]!==_||t[19]!==a||t[20]!==l||t[21]!==b?(S=(0,n.jsx)(`a`,{ref:m,href:a,className:b,..._,...l}),t[18]=_,t[19]=a,t[20]=l,t[21]=b,t[22]=S):S=t[22],S}function E(){let e=(0,r.use)(l);if(e===null)throw Error(`useNavigation requires a <Router> or <NavigationContext> provider`);return e}function D(){let e=E();return function(t,n){return e.navigate(t,n)}}function O(){return(0,r.use)(u)}function k(){return(0,r.use)(d)}function A(){return(0,r.use)(c)}function j(){let e=(0,r.use)(p);if(e===null)throw Error(`useIsPending requires a <Router> or <TransitionContext> provider`);return e[0]}function M(){return(0,r.use)(v)}function N(){let e=E(),t=e.currentEntry?.url,n=t?new URL(t).searchParams:new URLSearchParams;function r(t,n){let r=e.currentEntry,i=new URL(r?.url??`/`,`http://localhost`),a=typeof t==`function`?t(i.searchParams):t,o=(a instanceof URLSearchParams?a:new URLSearchParams(a)).toString(),s=i.pathname+(o?`?`+o:``);return e.navigate(s,{history:n?.history??`replace`})}return[n,r]}function P(){let e=E();function t(t){return e.back(t)}return{back:t,canGoBack:e.canGoBack}}function F(){let e=E();function t(t){return e.forward(t)}return{forward:t,canGoForward:e.canGoForward}}function I(e){let t={url:e.url};function n(){}function r(){}function i(){return{committed:Promise.resolve(t),finished:Promise.resolve(t)}}function a(){return[t]}return{currentEntry:t,canGoBack:!1,canGoForward:!1,transition:null,addEventListener:n,removeEventListener:r,navigate:i,entries:a}}function L(e,t){return e===``&&t===``?``:e===``?t:t===``||t===`/`?e:(e.endsWith(`/`)?e.slice(0,-1):e)+(t.startsWith(`/`)?t:`/`+t)}function R(e){if(e.length!==0)return e.length===1?e[0]:async function(t){for(let n of e)await n(t)}}function z(){return null}function B(e,t){return function(n){let r={path:n,middlewares:[],prefetches:[],scroll:void 0,focusReset:void 0,formHandler:void 0};function i(){let e=L(t.prefix,r.path??``);if(e===``)throw Error(`cannot register a route without a path or group prefix`);return e}function a(){let e=[...t.middlewares,...r.middlewares];return e.length>0?e:void 0}function o(){return R([...t.prefetches,...r.prefetches])}let s={middleware(e){return r.middlewares.push(...e),s},prefetch(e){return r.prefetches.push(e),s},scroll(e){return r.scroll=e,s},focusReset(e){return r.focusReset=e,s},formHandler(e){return r.formHandler=e,s},render(t){let n=i(),s={component:t,middlewares:a(),prefetch:o(),scroll:r.scroll,focusReset:r.focusReset,formHandler:r.formHandler};e.register(n,s)},redirect(t){let n=i(),o={component:z,middlewares:a(),prefetch:function(e){let n=typeof t==`function`?t(e):t;e.controller.redirect(n)},scroll:r.scroll,focusReset:r.focusReset};e.register(n,o)},group(){return B(e,{prefix:L(t.prefix,r.path??``),middlewares:[...t.middlewares,...r.middlewares],prefetches:[...t.prefetches,...r.prefetches]})}};return s}}function V(e){let n=t.t();return e(B(n,{prefix:``,middlewares:[],prefetches:[]})),n}exports.Link=T,exports.MatcherContext=h,exports.Middlewares=i,exports.NavigationContext=l,exports.NavigationSignalContext=u,exports.NavigationTypeContext=d,exports.NotFound=f,exports.ParamsContext=c,exports.PathnameContext=v,exports.Router=b,exports.TransitionContext=p,exports.createMemoryNavigation=I,exports.createRouter=V,exports.extractPathname=y,exports.useActiveLinkProps=x,exports.useBack=P,exports.useForward=F,exports.useIsPending=j,exports.useNavigate=D,exports.useNavigation=E,exports.useNavigationEvents=_,exports.useNavigationHandlers=m,exports.useNavigationSignal=O,exports.useNavigationType=k,exports.useNextMatch=g,exports.useParams=A,exports.usePathname=M,exports.usePrefetch=C,exports.usePrefetchEffect=w,exports.useSearchParams=N;
6
+ //# sourceMappingURL=router_react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router_react.cjs","names":["ReactNode","Handler","MiddlewaresProps","value","children","Middlewares","reduceRight","inner","Middleware","index","NotFound","$","_c","t0","Symbol","for","ComponentType","ReactNode","Suspense","use","useEffectEvent","useState","useTransition","Handler","Matcher","ParamsContext","NavigationContext","NavigationSignalContext","NavigationTypeContext","Resolved","Middlewares","NotFound","useNavigationHandlers","useNextMatch","useNavigationEvents","MatcherContext","TransitionContext","PathnameContext","extractPathname","CurrentState","match","signal","AbortSignal","navigationType","NavigationType","pathname","RouterProps","matcher","notFound","fallback","navigation","Navigation","transition","ReturnType","onNavigateSuccess","onNavigateError","error","Router","options","$","_c","contextNavigation","window","internalTransition","t0","next","t1","currentEntry","url","current","setCurrent","createPrecommitHandler","createHandler","t2","event","canIntercept","hashChange","downloadRequest","destination","formData","handler","formHandler","undefined","intercept","scroll","focusReset","precommitHandler","prefetch","params","URL","onNavigate","t3","CurrentComponent","component","middlewares","t4","t5","t6","t7","t8","t9","t10","t11","t12","t13","AnchorHTMLAttributes","useRef","useActiveLinkProps","PrefetchStrategy","usePrefetchEffect","Handler","Matcher","LinkRenderProps","isActive","LinkProps","Omit","HTMLAnchorElement","prefetch","once","matcher","className","props","activeExact","Link","t0","$","_c","href","t1","t2","undefined","ref","t3","exact","activeProps","t4","on","t5","resolvedClassName","t6"],"sources":["../src/react/components/Middlewares.tsx","../node_modules/react/cjs/react-compiler-runtime.production.js","../node_modules/react/cjs/react-compiler-runtime.development.js","../node_modules/react/compiler-runtime.js","../src/react/context/PropsContext.ts","../src/react/context/NavigationContext.ts","../src/react/context/NavigationSignalContext.ts","../src/react/context/NavigationTypeContext.ts","../src/react/components/NotFound.tsx","../src/react/context/TransitionContext.ts","../src/react/hooks/useNavigationHandlers.ts","../src/react/context/MatcherContext.ts","../src/react/hooks/useNextMatch.ts","../src/react/hooks/useNavigationEvents.ts","../src/react/context/PathnameContext.ts","../src/react/extractPathname.ts","../src/react/components/Router.tsx","../src/react/hooks/useActiveLinkProps.ts","../src/react/hooks/usePrefetch.ts","../src/react/hooks/usePrefetchEffect.ts","../src/react/components/Link.tsx","../src/react/hooks/useNavigation.ts","../src/react/hooks/useNavigate.ts","../src/react/hooks/useNavigationSignal.ts","../src/react/hooks/useNavigationType.ts","../src/react/hooks/useParams.ts","../src/react/hooks/useIsPending.ts","../src/react/hooks/usePathname.ts","../src/react/hooks/useSearchParams.ts","../src/react/hooks/useBack.ts","../src/react/hooks/useForward.ts","../src/react/navigation/createMemoryNavigation.ts","../src/react/createRouter.ts"],"sourcesContent":["import { type ReactNode } from 'react'\nimport { type Handler } from 'router/react:router'\n\n/**\n * Props for the Middlewares wrapper component.\n */\nexport interface MiddlewaresProps {\n /**\n * The array of middleware components to wrap around children.\n * May be `undefined` when the matched route has no middlewares.\n */\n value: Handler['middlewares']\n\n /**\n * The content to wrap inside the middleware chain. Typically\n * the matched route component rendered by the Router.\n */\n children?: ReactNode\n}\n\n/**\n * Wraps children in the given middleware components using\n * `reduceRight` so the first middleware in the array is the\n * outermost wrapper. When no middlewares are provided, renders\n * children directly.\n *\n * Each middleware component receives `children` as its only\n * prop and is responsible for rendering them (or not, in the\n * case of auth guards).\n */\nexport function Middlewares({ value, children }: MiddlewaresProps) {\n return (\n value?.reduceRight(\n (inner, Middleware, index) => <Middleware key={index}>{inner}</Middleware>,\n children\n ) ?? children\n )\n}\n","/**\n * @license React\n * react-compiler-runtime.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar ReactSharedInternals =\n require(\"react\").__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;\nexports.c = function (size) {\n return ReactSharedInternals.H.useMemoCache(size);\n};\n","/**\n * @license React\n * react-compiler-runtime.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n var ReactSharedInternals =\n require(\"react\").__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;\n exports.c = function (size) {\n var dispatcher = ReactSharedInternals.H;\n null === dispatcher &&\n console.error(\n \"Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\\n1. You might have mismatching versions of React and the renderer (such as React DOM)\\n2. You might be breaking the Rules of Hooks\\n3. You might have more than one copy of React in the same app\\nSee https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.\"\n );\n return dispatcher.useMemoCache(size);\n };\n })();\n","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-compiler-runtime.production.js');\n} else {\n module.exports = require('./cjs/react-compiler-runtime.development.js');\n}\n","import { createContext } from 'react'\n\n/**\n * Provides the route parameters extracted from the matched URL\n * pattern as a string-keyed record. Defaults to an empty object\n * when no route has been matched yet.\n *\n * Consumed via the `useParams` hook. The Router component\n * updates this context on every successful navigation with\n * the newly extracted parameters.\n */\nexport const ParamsContext = createContext<Record<string, string>>({})\n","import { createContext } from 'react'\n\n/**\n * Provides the native browser Navigation object through React context.\n *\n * Defaults to `null` — the Router component provides the real value.\n * This avoids accessing `window.navigation` at module scope, which\n * would crash in SSR, testing, or non-browser environments.\n *\n * The `useNavigation` hook throws a descriptive error when consumed\n * without a provider.\n */\nexport const NavigationContext = createContext<Navigation>(null as unknown as Navigation)\n","import { createContext } from 'react'\n\n/**\n * Provides the AbortSignal from the current NavigateEvent.\n * Consumers can use this to cancel in-flight async operations\n * (fetches, transitions, etc.) when a navigation is superseded\n * by another one.\n */\nexport const NavigationSignalContext = createContext<AbortSignal | null>(null)\n","import { createContext } from 'react'\n\n/**\n * Provides the navigation type of the most recent NavigateEvent\n * (`push`, `replace`, `reload`, or `traverse`). Allows route\n * components to vary behavior based on how they were reached.\n */\nexport const NavigationTypeContext = createContext<NavigationType | null>(null)\n","/**\n * Default fallback component rendered when no registered\n * route matches the current URL. Can be overridden via the\n * `notFound` prop on the Router component.\n */\nexport function NotFound() {\n return <div>Not Found</div>\n}\n","import { type TransitionFunction, createContext, useTransition } from 'react'\n\n/**\n * Provides the `[isPending, startTransition]` tuple from\n * `useTransition()` to descendant components. The Router and\n * navigation handlers use this to wrap state updates in\n * concurrent transitions.\n *\n * Defaults to `null` — a parent component must provide a real\n * `useTransition()` tuple via `<TransitionContext value={...}>`.\n * Using the standalone `startTransition` from React as a default\n * would silently break `isPending` tracking, so we require an\n * explicit provider instead.\n */\nexport const TransitionContext = createContext<ReturnType<typeof useTransition> | null>(null)\n\n/**\n * Type alias for the startTransition function extracted from\n * the useTransition tuple.\n */\nexport type StartTransitionFn = (callback: TransitionFunction) => void\n","import { type TransitionFunction, use, useTransition } from 'react'\nimport { TransitionContext } from 'router/react:context/TransitionContext'\nimport { type PrefetchFunc, type PrefetchContext } from 'router/react:router'\n\n/**\n * Options for creating a precommit handler that forwards\n * route context to the prefetch function.\n */\nexport interface PrecommitHandlerOptions {\n /**\n * The prefetch function from the matched route handler.\n * When undefined, no precommit handler is created.\n */\n readonly prefetch?: PrefetchFunc\n\n /**\n * Dynamic route parameters extracted from the matched\n * URL pattern.\n */\n readonly params: Record<string, string>\n\n /**\n * The destination URL being navigated to.\n */\n readonly url: URL\n}\n\n/**\n * Creates handler functions for the Navigation API's\n * `event.intercept()` method. The precommit handler runs\n * prefetch logic before the URL commits; the handler runs\n * the React state transition after the URL commits.\n *\n * Accepts an optional `transition` tuple to use directly.\n * When omitted, reads from TransitionContext instead. The\n * Router component passes its own transition tuple here to\n * avoid a circular dependency — the Router provides the\n * TransitionContext in its JSX return, but needs the\n * handlers during render before that provider exists in\n * the tree.\n *\n * @param transition - Optional `useTransition()` tuple to\n * use instead of reading from TransitionContext. Pass\n * this when calling from within the component that\n * provides TransitionContext.\n * @throws When no transition tuple is provided and the\n * hook is used outside a TransitionContext provider.\n */\nexport function useNavigationHandlers(transition?: ReturnType<typeof useTransition>) {\n const contextTransition = transition ?? use(TransitionContext)\n\n if (contextTransition === null) {\n throw new Error('useNavigationHandlers requires a <Router> or <TransitionContext> provider')\n }\n\n const [, startTransition] = contextTransition\n\n /**\n * Creates a precommit handler that constructs a\n * `PrefetchContext` from the matched route information\n * and forwards it to the route's prefetch function.\n * Runs before the URL commits, so no React state\n * transitions are needed here.\n */\n function createPrecommitHandler(options: PrecommitHandlerOptions) {\n if (options.prefetch === undefined) {\n return undefined\n }\n\n const prefetch = options.prefetch\n\n return async function (controller: NavigationPrecommitController) {\n const context: PrefetchContext = {\n params: options.params,\n url: options.url,\n controller,\n }\n\n await prefetch(context)\n }\n }\n\n /**\n * Creates a post-commit handler that wraps the state\n * update in a React async transition for concurrent\n * rendering. The promise resolves only after the async\n * transition callback completes, ensuring the Navigation\n * API waits for React to finish rendering before firing\n * `navigatesuccess` and performing scroll restoration.\n *\n * @param callback - The transition function containing\n * the state update to perform after the URL commits.\n */\n function createHandler(callback: TransitionFunction) {\n return function handler() {\n return new Promise<void>(function (resolve, reject) {\n startTransition(async function () {\n try {\n await callback()\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n })\n }\n }\n\n return { createPrecommitHandler, createHandler }\n}\n","import { createContext } from 'react'\nimport { type Handler } from 'router/react:router'\nimport { createMatcher, type Matcher } from 'router:matcher'\n\n/**\n * Provides the route Matcher instance through React context.\n * Defaults to an empty matcher with no registered routes.\n *\n * The Router component and hooks like `useNextMatch` and\n * `usePrefetch` consume this context to resolve URLs against\n * registered route patterns. Override by passing a `matcher`\n * prop to Router or wrapping with `<MatcherContext value={...}>`.\n */\nexport const MatcherContext = createContext<Matcher<Handler>>(createMatcher())\n","import { type ComponentType, use } from 'react'\nimport { MatcherContext } from 'router/react:context/MatcherContext'\nimport { type Handler } from 'router/react:router'\nimport { type Matcher, type Resolved } from 'router:matcher'\n\n/**\n * Options for the `useNextMatch` hook.\n */\nexport interface NextMatchOptions {\n /**\n * Optional matcher override. When omitted the hook reads\n * from `MatcherContext`.\n */\n matcher?: Matcher<Handler>\n}\n\n/**\n * Returns a function that resolves a destination URL into a\n * route match. When no route matches, a fallback `Resolved`\n * is returned using the provided `notFound` component.\n *\n * Used internally by the Router to determine which component\n * to render for an incoming navigation event.\n *\n * @param options - Optional matcher override.\n * @returns A resolver function that takes a destination URL\n * and a not-found component, returning the resolved match.\n */\nexport function useNextMatch(options?: NextMatchOptions) {\n const matcher = options?.matcher ?? use(MatcherContext)\n\n /**\n * Resolves a destination URL string into a route match.\n * Falls back to a synthetic match wrapping the `notFound`\n * component when the URL doesn't match any registered route.\n *\n * @param destination - The full destination URL string, or\n * `null` when no URL is available (e.g. initial load\n * without a current entry).\n * @param notFound - The component to render when no route\n * matches the destination.\n * @returns The resolved route match with handler and params.\n */\n return function (destination: string | null, notFound: ComponentType): Resolved<Handler> {\n const handler: Handler = { component: notFound }\n const fallbackResolved: Resolved<Handler> = { handler, params: {} }\n\n if (!destination) {\n return fallbackResolved\n }\n\n return matcher.match(new URL(destination).pathname) ?? fallbackResolved\n }\n}\n","import { useEffect, useEffectEvent } from 'react'\n\n/**\n * Callbacks for navigation lifecycle events. All callbacks\n * are optional — only provided callbacks are subscribed.\n */\nexport interface NavigationEventHandlers {\n /**\n * Called when a same-document navigation is initiated.\n * The Router uses this to intercept the event, match\n * the destination URL, and trigger a React transition.\n */\n readonly onNavigate?: (event: NavigateEvent) => void\n\n /**\n * Called after a navigation completes successfully.\n * Fires in sync with the Navigation API's\n * `navigatesuccess` event.\n */\n readonly onNavigateSuccess?: () => void\n\n /**\n * Called when a navigation fails. Receives the error\n * extracted from the Navigation API's `navigateerror`\n * ErrorEvent.\n *\n * @param error - The error that caused the navigation\n * to fail.\n */\n readonly onNavigateError?: (error: unknown) => void\n}\n\n/**\n * Subscribes to the Navigation API's `navigate`,\n * `navigatesuccess`, and `navigateerror` events on the\n * given navigation object. All callbacks are wrapped in\n * `useEffectEvent` so the effects only depend on the\n * navigation instance itself — inline arrow functions\n * from the caller don't cause unnecessary re-subscriptions.\n *\n * Cleans up all listeners on unmount or when the navigation\n * instance changes.\n *\n * @param navigation - The Navigation object to subscribe to.\n * @param handlers - Callbacks for each navigation lifecycle\n * event. All are optional.\n */\nexport function useNavigationEvents(navigation: Navigation, handlers: NavigationEventHandlers) {\n /**\n * Stable wrapper for the navigate event callback. Reads\n * the latest `onNavigate` handler on each invocation\n * without causing the subscription effect to re-run.\n */\n const onNavigate = useEffectEvent(function (event: NavigateEvent) {\n handlers.onNavigate?.(event)\n })\n\n /**\n * Stable wrapper for the navigatesuccess callback.\n */\n const onSuccess = useEffectEvent(function () {\n handlers.onNavigateSuccess?.()\n })\n\n /**\n * Stable wrapper for the navigateerror callback.\n * Extracts the error from the ErrorEvent before\n * forwarding to the handler.\n */\n const onError = useEffectEvent(function (event: Event) {\n handlers.onNavigateError?.((event as ErrorEvent).error)\n })\n\n /**\n * Subscribes to all three navigation lifecycle events.\n * A single effect handles all subscriptions since they\n * share the same dependency (the navigation object) and\n * the same lifecycle (subscribe on mount, clean up on\n * unmount or navigation change).\n */\n useEffect(\n function () {\n navigation.addEventListener('navigate', onNavigate)\n navigation.addEventListener('navigatesuccess', onSuccess)\n navigation.addEventListener('navigateerror', onError)\n\n return function () {\n navigation.removeEventListener('navigate', onNavigate)\n navigation.removeEventListener('navigatesuccess', onSuccess)\n navigation.removeEventListener('navigateerror', onError)\n }\n },\n [navigation]\n )\n}\n","import { createContext } from 'react'\n\n/**\n * Provides the current URL pathname to descendant components.\n * Updated by the Router on every navigation with the pathname\n * extracted from the destination URL.\n *\n * Consumed by the `usePathname` hook and the `Link` component\n * for active link detection. Defaults to `'/'` when no Router\n * is present in the tree.\n */\nexport const PathnameContext = createContext<string>('/')\n","/**\n * Extracts the pathname portion from a URL string. Uses a\n * dummy base URL to handle both absolute and relative paths\n * correctly. Returns `'/'` when the input is null, undefined,\n * or an empty string.\n *\n * Used by the Router (to extract pathname from navigation\n * destination URLs), Link (for active link comparison), and\n * usePrefetch (to match URLs against registered routes).\n *\n * @param url - The URL string to extract a pathname from.\n * May be absolute (`https://example.com/foo`), relative\n * (`/foo/bar`), or nullish.\n * @returns The pathname string, or `'/'` when no URL is\n * provided.\n */\nexport function extractPathname(url: string | null | undefined): string {\n if (!url) {\n return '/'\n }\n\n return new URL(url, 'http://localhost').pathname\n}\n","import {\n type ComponentType,\n type ReactNode,\n Suspense,\n use,\n useEffectEvent,\n useState,\n useTransition,\n} from 'react'\nimport { type Handler } from 'router/react:router'\nimport { type Matcher } from 'router:matcher'\nimport { ParamsContext } from 'router/react:context/PropsContext'\nimport { NavigationContext } from 'router/react:context/NavigationContext'\nimport { NavigationSignalContext } from 'router/react:context/NavigationSignalContext'\nimport { NavigationTypeContext } from 'router/react:context/NavigationTypeContext'\nimport { type Resolved } from 'router:matcher'\nimport { Middlewares } from 'router/react:components/Middlewares'\nimport { NotFound } from 'router/react:components/NotFound'\nimport { useNavigationHandlers } from 'router/react:hooks/useNavigationHandlers'\nimport { useNextMatch } from 'router/react:hooks/useNextMatch'\nimport { useNavigationEvents } from 'router/react:hooks/useNavigationEvents'\nimport { MatcherContext } from 'router/react:context/MatcherContext'\nimport { TransitionContext } from 'router/react:context/TransitionContext'\nimport { PathnameContext } from 'router/react:context/PathnameContext'\nimport { extractPathname } from 'router/react:extractPathname'\n\n/**\n * Internal state tracked alongside the resolved route match.\n * Includes the AbortSignal and navigation type from the\n * NavigateEvent that produced this match.\n */\ninterface CurrentState {\n /**\n * The resolved route match containing the handler\n * configuration and extracted URL parameters.\n */\n match: Resolved<Handler>\n\n /**\n * The AbortSignal from the NavigateEvent that produced\n * this match. Aborts when the navigation is cancelled\n * by a newer navigation or the user pressing Stop.\n * Null for the initial render before any navigation event.\n */\n signal: AbortSignal | null\n\n /**\n * The type of navigation that produced this match\n * (`push`, `replace`, `reload`, or `traverse`).\n * Null for the initial render before any navigation event.\n */\n navigationType: NavigationType | null\n\n /**\n * The pathname extracted from the destination URL for this\n * navigation. Used by descendant components to determine\n * active links and read the current location.\n */\n pathname: string\n}\n\n/**\n * Props accepted by the Router component.\n */\nexport interface RouterProps {\n /**\n * Route matcher instance with registered routes. When\n * omitted, falls back to the value from MatcherContext.\n */\n matcher?: Matcher<Handler>\n\n /**\n * Component to render when no route matches the current\n * URL. Defaults to the built-in NotFound component.\n */\n notFound?: ComponentType\n\n /**\n * Suspense fallback shown while lazy route components\n * or suspended middleware are loading.\n */\n fallback?: ReactNode\n\n /**\n * Native Navigation object override. Defaults to the value\n * from NavigationContext, which itself falls back to\n * `window.navigation`. Useful for testing or providing\n * a custom navigation instance.\n */\n navigation?: Navigation\n\n /**\n * Optional `useTransition()` tuple override. When omitted\n * the Router calls `useTransition()` internally. Provide\n * this when you need to read `isPending` above the Router\n * in the component tree, or to share a single transition\n * across multiple Routers.\n */\n transition?: ReturnType<typeof useTransition>\n\n /**\n * Callback invoked after a navigation completes successfully.\n * Fires in sync with the Navigation API's `navigatesuccess`\n * event. Wrapped in `useEffectEvent` internally so inline\n * arrow functions don't cause effect churn.\n */\n onNavigateSuccess?: () => void\n\n /**\n * Callback invoked when a navigation fails. Receives the\n * error from the Navigation API's `navigateerror` event.\n * Wrapped in `useEffectEvent` internally so inline arrow\n * functions don't cause effect churn.\n *\n * @param error - The error that caused the navigation\n * to fail.\n */\n onNavigateError?: (error: unknown) => void\n}\n\n/**\n * Top-level router component that listens to the Navigation API's\n * `navigate` event, matches the destination URL against registered\n * routes, and renders the matched component inside Suspense with\n * middleware support.\n *\n * Calls `useTransition()` internally to wrap navigation state\n * updates in concurrent transitions. An optional `transition` prop\n * allows overriding this when the consuming code needs to read\n * `isPending` above the Router in the tree.\n *\n * Accepts optional `navigation` and `matcher` overrides; falls back\n * to context values when not provided. The navigation object\n * ultimately falls back to `window.navigation` when neither a prop\n * nor a context value is available.\n *\n * Provides several contexts to descendant components:\n * - `TransitionContext` — the `[isPending, startTransition]` tuple\n * - `NavigationContext` — the Navigation object\n * - `MatcherContext` — the route matcher\n * - `NavigationTypeContext` — the current navigation type\n * - `NavigationSignalContext` — the current AbortSignal\n * - `PathnameContext` — the current URL pathname\n * - `ParamsContext` — the extracted route parameters\n */\nexport function Router(options: RouterProps) {\n const contextNavigation = use(NavigationContext)\n const navigation: Navigation = options.navigation ?? contextNavigation ?? window.navigation\n const matcher: Matcher<Handler> = options.matcher ?? use(MatcherContext)\n const internalTransition = useTransition()\n const transition = options.transition ?? internalTransition\n const next = useNextMatch({ matcher })\n const notFound = options.notFound ?? NotFound\n\n const [current, setCurrent] = useState<CurrentState>(function () {\n const url = navigation.currentEntry?.url ?? null\n\n return {\n match: next(url, notFound),\n signal: null,\n navigationType: null,\n pathname: extractPathname(url),\n }\n })\n\n /**\n * Extracts navigation handler factories using the resolved\n * transition tuple directly, bypassing TransitionContext.\n * This is necessary because Router provides TransitionContext\n * in its JSX return, which hasn't rendered at this point.\n */\n const { createPrecommitHandler, createHandler } = useNavigationHandlers(transition)\n\n /**\n * Central navigate event handler. Intercepts all same-document\n * navigations including link clicks, form submissions,\n * back/forward buttons, and programmatic navigation.\n *\n * Skips non-interceptable navigations, hash-only changes,\n * and download requests. For form submissions with a dedicated\n * `formHandler`, delegates to that handler instead of the\n * normal component render flow.\n */\n const onNavigate = useEffectEvent(function (event: NavigateEvent) {\n if (!event.canIntercept || event.hashChange || event.downloadRequest !== null) {\n return\n }\n\n const match = next(event.destination.url, notFound)\n\n if (event.formData !== null && match.handler.formHandler !== undefined) {\n event.intercept({\n scroll: match.handler.scroll,\n focusReset: match.handler.focusReset,\n async handler() {\n await match.handler.formHandler!(event.formData!, event)\n },\n })\n\n return\n }\n\n const precommitHandler = createPrecommitHandler({\n prefetch: match.handler.prefetch,\n params: match.params,\n url: new URL(event.destination.url),\n })\n\n const handler = createHandler(function () {\n setCurrent({\n match,\n signal: event.signal,\n navigationType: event.navigationType,\n pathname: extractPathname(event.destination.url),\n })\n })\n\n event.intercept({\n handler,\n precommitHandler,\n scroll: match.handler.scroll,\n focusReset: match.handler.focusReset,\n })\n })\n\n useNavigationEvents(navigation, {\n onNavigate,\n onNavigateSuccess: options.onNavigateSuccess,\n onNavigateError: options.onNavigateError,\n })\n\n const CurrentComponent = current.match.handler.component\n const middlewares = current.match.handler.middlewares\n\n return (\n <TransitionContext value={transition}>\n <NavigationContext value={navigation}>\n <MatcherContext value={matcher}>\n <NavigationTypeContext value={current.navigationType}>\n <NavigationSignalContext value={current.signal}>\n <PathnameContext value={current.pathname}>\n <ParamsContext value={current.match.params}>\n <Suspense fallback={options.fallback}>\n <Middlewares value={middlewares}>\n <CurrentComponent />\n </Middlewares>\n </Suspense>\n </ParamsContext>\n </PathnameContext>\n </NavigationSignalContext>\n </NavigationTypeContext>\n </MatcherContext>\n </NavigationContext>\n </TransitionContext>\n )\n}\n","import { use } from 'react'\nimport { PathnameContext } from 'router/react:context/PathnameContext'\nimport { extractPathname } from 'router/react:extractPathname'\n\n/**\n * Options for the `useActiveLinkProps` hook.\n */\nexport interface ActiveLinkOptions {\n /**\n * When true, the link is only considered active when\n * the current pathname exactly matches the href\n * pathname. When false, the link is active when the\n * current pathname starts with the href pathname,\n * which is useful for parent navigation items that\n * should highlight when any child route is active.\n *\n * Defaults to `true`.\n */\n exact?: boolean\n}\n\n/**\n * Props returned by the hook to spread onto an anchor\n * element for active link styling and accessibility.\n */\nexport interface ActiveLinkProps {\n /**\n * Present (set to `true`) when the link is active.\n * Absent (`undefined`) when inactive. Use the\n * `a[data-active]` CSS selector for styling.\n */\n 'data-active': true | undefined\n\n /**\n * Set to `'page'` when the link is active to indicate\n * to assistive technologies that this link represents\n * the current page. Absent when inactive.\n */\n 'aria-current': 'page' | undefined\n}\n\n/**\n * Computes active link attributes for an anchor element\n * by comparing its href against the current pathname from\n * the Router's PathnameContext.\n *\n * Returns a props object containing `data-active` and\n * `aria-current` attributes ready to spread onto an `<a>`\n * element or any element that should reflect active state.\n *\n * Also returns an `isActive` boolean for conditional logic\n * like dynamic class names.\n *\n * Must be used inside a `<Router>` component tree where\n * `PathnameContext` is provided.\n *\n * @param href - The href to compare against the current\n * pathname. When undefined, the link is never active.\n * @param options - Optional configuration for exact vs\n * prefix matching.\n * @returns An object with `isActive` boolean and `props`\n * to spread onto the element.\n *\n * @example\n * ```tsx\n * function NavItem({ href, children }: NavItemProps) {\n * const { isActive, props } = useActiveLinkProps(href)\n *\n * return (\n * <a href={href} className={isActive ? 'active' : ''} {...props}>\n * {children}\n * </a>\n * )\n * }\n * ```\n */\nexport function useActiveLinkProps(\n href: string | undefined,\n options?: ActiveLinkOptions\n): { isActive: boolean; props: ActiveLinkProps } {\n const currentPathname = use(PathnameContext)\n const isExact = options?.exact ?? true\n\n const isActive = isActiveHref(href, currentPathname, isExact)\n\n return {\n isActive,\n props: {\n 'data-active': isActive || undefined,\n 'aria-current': isActive ? 'page' : undefined,\n },\n }\n}\n\n/**\n * Determines whether an href should be considered active\n * by comparing its pathname against the current router\n * pathname. Handles undefined hrefs, exact matching, and\n * prefix matching for parent-level navigation items.\n *\n * @param href - The href string to test. Returns false\n * when undefined.\n * @param currentPathname - The current pathname from the\n * router's PathnameContext.\n * @param isExact - Whether to require an exact match or\n * allow prefix matching.\n * @returns True when the href should be marked as active.\n */\nfunction isActiveHref(\n href: string | undefined,\n currentPathname: string,\n isExact: boolean\n): boolean {\n if (href === undefined) {\n return false\n }\n\n const linkPathname = extractPathname(href)\n\n if (isExact) {\n return linkPathname === currentPathname\n }\n\n return currentPathname === linkPathname || currentPathname.startsWith(linkPathname + '/')\n}\n","import { use } from 'react'\nimport { MatcherContext } from 'router/react:context/MatcherContext'\nimport { type Handler, type PrefetchContext } from 'router/react:router'\nimport { type Matcher } from 'router:matcher'\n\n/**\n * Options for the `usePrefetch` hook.\n */\nexport interface PrefetchOptions {\n /**\n * Optional matcher override. When omitted the hook reads\n * from `MatcherContext`.\n */\n matcher?: Matcher<Handler>\n}\n\n/**\n * Returns a function that triggers the prefetch logic for a\n * given URL by resolving it against the matcher and calling\n * the route's prefetch function. Used by the Link component\n * for hover and viewport prefetch strategies.\n *\n * Since prefetch triggered from Link happens outside of a\n * navigation event, a stub NavigationPrecommitController is\n * passed (the redirect capability is not meaningful here).\n *\n * @param options - Optional matcher override.\n * @returns A function that accepts a URL string and invokes\n * the matched route's prefetch handler, if any.\n */\nexport function usePrefetch(options?: PrefetchOptions) {\n const matcher = options?.matcher ?? use(MatcherContext)\n\n /**\n * Triggers prefetch for the given URL by matching it against\n * registered routes and calling the route's prefetch function\n * with a context containing the matched params, the parsed\n * URL, and a stub controller. Extracts the pathname from the\n * URL before matching to handle both absolute and relative URLs.\n *\n * @param url - The URL or path to prefetch data for.\n * @returns The prefetch promise, or undefined if no prefetch\n * handler is registered for the matched route.\n */\n return function (url: string) {\n const parsed = new URL(url, 'http://localhost')\n const match = matcher.match(parsed.pathname)\n\n if (match?.handler.prefetch === undefined) {\n return\n }\n\n /**\n * Stub controller for prefetch outside of navigation events.\n * Redirect and addHandler are no-ops in this context since\n * there is no actual navigation to modify.\n */\n const stubController: NavigationPrecommitController = {\n redirect() {},\n addHandler() {},\n }\n\n const context: PrefetchContext = {\n params: match.params,\n url: parsed,\n controller: stubController,\n }\n\n return match.handler.prefetch(context)\n }\n}\n","import { type RefObject, useEffect, useEffectEvent } from 'react'\nimport { usePrefetch } from 'router/react:hooks/usePrefetch'\nimport { type Handler } from 'router/react:router'\nimport { type Matcher } from 'router:matcher'\n\n/**\n * Prefetch trigger strategy. Determines which DOM event\n * activates the prefetch for the target element.\n *\n * - `viewport` — prefetch fires when the element enters\n * the viewport via an IntersectionObserver.\n * - `hover` — prefetch fires on `mouseenter`.\n */\nexport type PrefetchStrategy = 'viewport' | 'hover'\n\n/**\n * Options for the `usePrefetchEffect` hook.\n */\nexport interface PrefetchEffectOptions {\n /**\n * The URL to prefetch. When undefined, the effect is\n * a no-op (no observer or listener is attached).\n */\n href: string | undefined\n\n /**\n * Prefetch trigger strategy. When undefined, the effect\n * is a no-op — no proactive prefetch is set up.\n */\n on: PrefetchStrategy | undefined\n\n /**\n * Whether to only prefetch once. When true, hover\n * listeners use the `{ once }` option and viewport\n * observers disconnect after the first intersection.\n * Defaults to `true`.\n */\n once?: boolean\n\n /**\n * Optional matcher override. When omitted, reads from\n * `MatcherContext` via `usePrefetch`.\n */\n matcher?: Matcher<Handler>\n}\n\n/**\n * Attaches prefetch behavior to a DOM element via a ref.\n * Sets up an IntersectionObserver (for `viewport` strategy)\n * or a mouseenter listener (for `hover` strategy) that\n * triggers route prefetching when activated.\n *\n * When `on` is undefined or `href` is undefined, no\n * observer or listener is attached — the hook is a no-op.\n *\n * This hook is used internally by the Link component and\n * can also be used standalone to add prefetch behavior to\n * any DOM element.\n *\n * @param ref - A ref to the DOM element to observe. The\n * element must be mounted before the effect runs.\n * @param options - Configuration for the prefetch behavior\n * including the URL, trigger strategy, and matcher.\n *\n * @example\n * ```tsx\n * function Card({ href }: { href: string }) {\n * const ref = useRef<HTMLDivElement>(null)\n *\n * usePrefetchEffect(ref, { href, on: 'viewport' })\n *\n * return <div ref={ref}>...</div>\n * }\n * ```\n */\nexport function usePrefetchEffect(ref: RefObject<Element | null>, options: PrefetchEffectOptions) {\n const { href, on, once = true, matcher } = options\n const prefetchRoute = usePrefetch({ matcher })\n\n /**\n * IntersectionObserver callback that triggers prefetch\n * when the element enters the viewport. Disconnects\n * the observer after the first intersection when `once`\n * is true.\n */\n const onViewportIntersection = useEffectEvent<IntersectionObserverCallback>(\n function (entries, observer) {\n for (const entry of entries) {\n if (entry.isIntersecting && href !== undefined) {\n void prefetchRoute(href)\n }\n }\n\n if (once) {\n observer.disconnect()\n }\n }\n )\n\n /**\n * Mouse enter callback that triggers prefetch when the\n * user hovers over the element.\n */\n const onHover = useEffectEvent<EventListener>(function () {\n if (href !== undefined) {\n void prefetchRoute(href)\n }\n })\n\n /**\n * Sets up the prefetch observer or listener based on the\n * chosen strategy. When `on` is undefined, no setup is\n * performed. Cleans up on unmount or when the strategy,\n * once flag, or href changes.\n */\n useEffect(\n function () {\n if (on === undefined) {\n return\n }\n\n const current = ref.current\n\n if (current === null) {\n return\n }\n\n switch (on) {\n case 'hover': {\n current.addEventListener('mouseenter', onHover, { once })\n\n return function () {\n current.removeEventListener('mouseenter', onHover)\n }\n }\n case 'viewport': {\n const observer = new IntersectionObserver(onViewportIntersection)\n\n observer.observe(current)\n\n return function () {\n observer.disconnect()\n }\n }\n }\n },\n [on, once, href, ref]\n )\n}\n","import { type AnchorHTMLAttributes, useRef } from 'react'\nimport { useActiveLinkProps } from 'router/react:hooks/useActiveLinkProps'\nimport { type PrefetchStrategy, usePrefetchEffect } from 'router/react:hooks/usePrefetchEffect'\nimport { type Handler } from 'router/react:router'\nimport { type Matcher } from 'router:matcher'\n\n/**\n * State passed to the className function variant, allowing\n * consumers to dynamically compute class names based on the\n * link's active state.\n */\nexport interface LinkRenderProps {\n /**\n * Whether this link's href matches the current pathname.\n * True for both exact and prefix matches depending on\n * the `activeExact` prop.\n */\n readonly isActive: boolean\n}\n\n/**\n * Props for the Link component, extending standard anchor\n * element attributes with router-specific prefetch behavior\n * and active link detection.\n */\nexport interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className'> {\n /**\n * Prefetch trigger strategy. When set to `'hover'`,\n * prefetch fires on mouseenter. When set to `'viewport'`,\n * prefetch fires when the link enters the viewport via\n * IntersectionObserver. When omitted, no proactive\n * prefetch is performed — the Navigation API handles\n * it during the click navigation.\n */\n prefetch?: PrefetchStrategy\n\n /**\n * Whether to only prefetch once. When true, hover\n * listeners use the `{ once }` option and viewport\n * observers disconnect after the first intersection.\n * Defaults to `true`.\n */\n once?: boolean\n\n /**\n * Optional matcher override. When omitted, reads from\n * `MatcherContext`. Useful when you need to prefetch\n * against a specific set of routes.\n */\n matcher?: Matcher<Handler>\n\n /**\n * CSS class name(s) for the anchor element. Accepts either\n * a static string or a function that receives the link's\n * active state and returns a class name string. The function\n * form is useful for conditional styling based on whether\n * the link is currently active.\n *\n * @example\n * ```tsx\n * <Link\n * href=\"/about\"\n * className={({ isActive }) => isActive ? 'nav-active' : 'nav-link'}\n * />\n * ```\n */\n className?: string | ((props: LinkRenderProps) => string)\n\n /**\n * When true, the link is only considered active when the\n * current pathname exactly matches the href pathname.\n * When false, the link is active when the current\n * pathname starts with the href pathname, which is useful\n * for parent navigation items that should highlight when\n * any child route is active.\n *\n * Defaults to `true`.\n */\n activeExact?: boolean\n}\n\n/**\n * Renders an anchor element that integrates with the router's\n * prefetch system and active link detection. The Navigation\n * API intercepts the click natively, so no `onClick` or\n * `preventDefault` is needed.\n *\n * Supports two proactive prefetch strategies: `hover`\n * (prefetch on mouseenter) and `viewport` (prefetch when\n * the link scrolls into view via IntersectionObserver).\n * When `prefetch` is omitted, no proactive prefetch is\n * performed.\n *\n * When the link's href matches the current pathname, the\n * component adds `data-active` and `aria-current=\"page\"`\n * attributes. The `className` prop can be a function that\n * receives `{ isActive }` for dynamic class computation.\n */\nexport function Link({\n prefetch,\n once = true,\n href,\n matcher,\n className,\n activeExact = true,\n ...props\n}: LinkProps) {\n const ref = useRef<HTMLAnchorElement>(null)\n const { isActive, props: activeProps } = useActiveLinkProps(href, { exact: activeExact })\n\n usePrefetchEffect(ref, { href, on: prefetch, once, matcher })\n\n const resolvedClassName = typeof className === 'function' ? className({ isActive }) : className\n\n return <a ref={ref} href={href} className={resolvedClassName} {...activeProps} {...props} />\n}\n","import { use } from 'react'\nimport { NavigationContext } from 'router/react:context/NavigationContext'\n\n/**\n * Returns the native browser Navigation object from context.\n * Gives full access to the Navigation API: `entries()`,\n * `traverseTo()`, `updateCurrentEntry()`, `canGoBack`,\n * `canGoForward`, `transition`, `currentEntry`, etc.\n *\n * Must be used inside a `<Router>` or a component tree\n * that provides a `<NavigationContext>` value.\n *\n * @returns The Navigation object from the nearest provider.\n * @throws When used outside a NavigationContext provider.\n */\nexport function useNavigation(): Navigation {\n const navigation = use(NavigationContext)\n\n if (navigation === null) {\n throw new Error('useNavigation requires a <Router> or <NavigationContext> provider')\n }\n\n return navigation\n}\n","import { useNavigation } from 'router/react:hooks/useNavigation'\n\n/**\n * Returns a function to programmatically navigate to a URL\n * with full Navigation API options support (`state`, `info`,\n * `history`). This is a thin convenience wrapper around\n * `navigation.navigate()`.\n *\n * @returns A navigate function that accepts a URL string and\n * optional `NavigationNavigateOptions`.\n */\nexport function useNavigate() {\n const navigation = useNavigation()\n\n /**\n * Programmatically navigates to the given URL. Delegates\n * to the native `navigation.navigate()` method, which\n * fires the `navigate` event intercepted by the Router.\n *\n * @param url - The destination URL to navigate to.\n * @param options - Optional Navigation API options including\n * `state`, `info`, and `history` behavior.\n * @returns The NavigationResult from the Navigation API.\n */\n return function (url: string, options?: NavigationNavigateOptions) {\n return navigation.navigate(url, options)\n }\n}\n","import { use } from 'react'\nimport { NavigationSignalContext } from 'router/react:context/NavigationSignalContext'\n\n/**\n * Returns the AbortSignal from the current navigation event.\n * The signal aborts when the navigation is cancelled (e.g.,\n * by the user pressing Stop or a new navigation superseding\n * this one). Pass this to fetch calls or other cancellable\n * async operations to avoid stale work.\n *\n * Returns `null` before any navigation event has occurred\n * (i.e. on the initial render).\n *\n * @returns The current AbortSignal or null.\n */\nexport function useNavigationSignal(): AbortSignal | null {\n return use(NavigationSignalContext)\n}\n","import { use } from 'react'\nimport { NavigationTypeContext } from 'router/react:context/NavigationTypeContext'\n\n/**\n * Returns the navigation type of the most recent navigation\n * (`push`, `replace`, `reload`, or `traverse`). Useful for\n * varying animations, skipping prefetch on reload, or\n * applying different behavior for back/forward traversals.\n *\n * Returns `null` before any navigation event has occurred\n * (i.e. on the initial render).\n *\n * @returns The current NavigationType or null.\n */\nexport function useNavigationType(): NavigationType | null {\n return use(NavigationTypeContext)\n}\n","import { use } from 'react'\nimport { ParamsContext } from 'router/react:context/PropsContext'\n\n/**\n * Returns the dynamic route parameters extracted from the\n * currently matched URL pattern. The keys correspond to the\n * `:param` names defined in the route pattern, and the values\n * are the matching URL segments.\n *\n * Must be used inside a `<Router>` component tree where\n * `ParamsContext` is provided.\n *\n * @returns A record of parameter names to their string values.\n *\n * @example\n * ```tsx\n * // Route pattern: \"/user/:id\"\n * // URL: \"/user/42\"\n * const { id } = useParams() // id === \"42\"\n * ```\n */\nexport function useParams() {\n return use(ParamsContext)\n}\n","import { use } from 'react'\nimport { TransitionContext } from 'router/react:context/TransitionContext'\n\n/**\n * Returns whether a navigation transition is currently pending.\n * This reflects the `isPending` value from the `useTransition`\n * tuple managed by the Router component.\n *\n * Useful for displaying loading indicators, progress bars, or\n * adjusting UI opacity while a route transition is in progress.\n *\n * Must be used inside a `<Router>` component tree or a\n * `<TransitionContext>` provider.\n *\n * @returns `true` while a navigation transition is pending,\n * `false` otherwise.\n * @throws When used outside a TransitionContext provider.\n *\n * @example\n * ```tsx\n * function NavBar() {\n * const isPending = useIsPending()\n *\n * return (\n * <nav style={{ opacity: isPending ? 0.7 : 1 }}>\n * ...\n * </nav>\n * )\n * }\n * ```\n */\nexport function useIsPending(): boolean {\n const transition = use(TransitionContext)\n\n if (transition === null) {\n throw new Error('useIsPending requires a <Router> or <TransitionContext> provider')\n }\n\n return transition[0]\n}\n","import { use } from 'react'\nimport { PathnameContext } from 'router/react:context/PathnameContext'\n\n/**\n * Returns the current URL pathname from the Router's state.\n * The value updates on every navigation and reflects the\n * pathname of the committed destination URL.\n *\n * Useful for active link detection, conditional rendering\n * based on the current route, or building breadcrumbs.\n *\n * Must be used inside a `<Router>` component tree where\n * `PathnameContext` is provided.\n *\n * @returns The current pathname string (e.g. `\"/user/42\"`).\n *\n * @example\n * ```tsx\n * function Breadcrumb() {\n * const pathname = usePathname()\n *\n * return <span>{pathname}</span>\n * }\n * ```\n */\nexport function usePathname(): string {\n return use(PathnameContext)\n}\n","import { useNavigation } from 'router/react:hooks/useNavigation'\n\n/**\n * Updater function signature for setting search params.\n * Accepts either a new URLSearchParams instance, a plain\n * record of string key-value pairs, or a function that\n * receives the current params and returns updated params.\n */\nexport type SearchParamsUpdater =\n | URLSearchParams\n | Record<string, string>\n | ((current: URLSearchParams) => URLSearchParams | Record<string, string>)\n\n/**\n * Options for the search params navigation performed by\n * the setter function returned from `useSearchParams`.\n */\nexport interface SetSearchParamsOptions {\n /**\n * History behavior for the navigation. Defaults to\n * `'replace'` since search param changes typically\n * should not create new history entries.\n */\n history?: NavigationHistoryBehavior\n}\n\n/**\n * Returns the current URL's search parameters as a\n * `URLSearchParams` instance and a setter function to\n * update them via navigation.\n *\n * The getter reads from `navigation.currentEntry.url`\n * on each render, so it always reflects the committed\n * URL. The setter performs a navigation with the updated\n * search string, defaulting to `history: 'replace'` to\n * avoid polluting the history stack with parameter changes.\n *\n * The React Compiler handles memoization of the setter,\n * so no manual `useCallback` is needed.\n *\n * Must be used inside a `<Router>` component tree.\n *\n * @returns A tuple of `[searchParams, setSearchParams]`.\n *\n * @example\n * ```tsx\n * function SearchPage() {\n * const [searchParams, setSearchParams] = useSearchParams()\n * const query = searchParams.get('q') ?? ''\n *\n * return (\n * <input\n * value={query}\n * onChange={function (event) {\n * setSearchParams({ q: event.target.value })\n * }}\n * />\n * )\n * }\n * ```\n */\nexport function useSearchParams(): [\n URLSearchParams,\n (updater: SearchParamsUpdater, options?: SetSearchParamsOptions) => NavigationResult,\n] {\n const navigation = useNavigation()\n\n const currentUrl = navigation.currentEntry?.url\n\n const searchParams = currentUrl ? new URL(currentUrl).searchParams : new URLSearchParams()\n\n /**\n * Navigates to the current pathname with updated search\n * parameters. Accepts a URLSearchParams instance, a plain\n * record, or a function that receives the current params\n * and returns new ones.\n */\n function setSearchParams(updater: SearchParamsUpdater, options?: SetSearchParamsOptions) {\n const currentEntry = navigation.currentEntry\n const url = new URL(currentEntry?.url ?? '/', 'http://localhost')\n\n const next = typeof updater === 'function' ? updater(url.searchParams) : updater\n\n const nextParams = next instanceof URLSearchParams ? next : new URLSearchParams(next)\n\n const search = nextParams.toString()\n const destination = url.pathname + (search ? '?' + search : '')\n\n return navigation.navigate(destination, {\n history: options?.history ?? 'replace',\n })\n }\n\n return [searchParams, setSearchParams]\n}\n","import { useNavigation } from 'router/react:hooks/useNavigation'\n\n/**\n * Return value from the `useBack` hook, providing both\n * a traversal function and a boolean indicating whether\n * backward navigation is possible.\n */\nexport interface UseBackResult {\n /**\n * Navigates backward in the session history. Delegates\n * to `navigation.back()` from the Navigation API.\n *\n * @param options - Optional navigation options such as\n * `info` to pass data to the navigate event handler.\n * @returns The NavigationResult with `committed` and\n * `finished` promises.\n */\n readonly back: (options?: NavigationOptions) => NavigationResult\n\n /**\n * Whether backward navigation is possible. Mirrors\n * `navigation.canGoBack` from the Navigation API.\n * When false, calling `back()` will throw.\n */\n readonly canGoBack: boolean\n}\n\n/**\n * Provides backward navigation capabilities using the\n * Navigation API. Returns a `back` function and a\n * `canGoBack` boolean that reflects whether the history\n * stack has a previous entry to traverse to.\n *\n * Must be used inside a `<Router>` component tree.\n *\n * @returns An object with `back` and `canGoBack`.\n *\n * @example\n * ```tsx\n * function BackButton() {\n * const { back, canGoBack } = useBack()\n *\n * return (\n * <button onClick={back} disabled={!canGoBack}>\n * Go Back\n * </button>\n * )\n * }\n * ```\n */\nexport function useBack(): UseBackResult {\n const navigation = useNavigation()\n\n /**\n * Traverses backward in the session history by\n * delegating to `navigation.back()`.\n */\n function back(options?: NavigationOptions) {\n return navigation.back(options)\n }\n\n return {\n back,\n canGoBack: navigation.canGoBack,\n }\n}\n","import { useNavigation } from 'router/react:hooks/useNavigation'\n\n/**\n * Return value from the `useForward` hook, providing both\n * a traversal function and a boolean indicating whether\n * forward navigation is possible.\n */\nexport interface UseForwardResult {\n /**\n * Navigates forward in the session history. Delegates\n * to `navigation.forward()` from the Navigation API.\n *\n * @param options - Optional navigation options such as\n * `info` to pass data to the navigate event handler.\n * @returns The NavigationResult with `committed` and\n * `finished` promises.\n */\n readonly forward: (options?: NavigationOptions) => NavigationResult\n\n /**\n * Whether forward navigation is possible. Mirrors\n * `navigation.canGoForward` from the Navigation API.\n * When false, calling `forward()` will throw.\n */\n readonly canGoForward: boolean\n}\n\n/**\n * Provides forward navigation capabilities using the\n * Navigation API. Returns a `forward` function and a\n * `canGoForward` boolean that reflects whether the history\n * stack has a next entry to traverse to.\n *\n * Must be used inside a `<Router>` component tree.\n *\n * @returns An object with `forward` and `canGoForward`.\n *\n * @example\n * ```tsx\n * function ForwardButton() {\n * const { forward, canGoForward } = useForward()\n *\n * return (\n * <button onClick={forward} disabled={!canGoForward}>\n * Go Forward\n * </button>\n * )\n * }\n * ```\n */\nexport function useForward(): UseForwardResult {\n const navigation = useNavigation()\n\n /**\n * Traverses forward in the session history by\n * delegating to `navigation.forward()`.\n */\n function forward(options?: NavigationOptions) {\n return navigation.forward(options)\n }\n\n return {\n forward,\n canGoForward: navigation.canGoForward,\n }\n}\n","/**\n * Minimal subset of the NavigationHistoryEntry interface\n * needed by the Router component. Only the `url` property\n * is read during rendering. The full NavigationHistoryEntry\n * interface is far larger, but the Router never accesses\n * properties like `key`, `id`, `sameDocument`, `getState`,\n * or the event handlers.\n */\ninterface MemoryNavigationEntry {\n /**\n * The full URL string for this history entry.\n */\n readonly url: string\n}\n\n/**\n * Options for creating a memory navigation instance.\n */\nexport interface MemoryNavigationOptions {\n /**\n * The initial URL for the memory navigation. This is the\n * URL that `currentEntry.url` will return. Typically the\n * request URL from the server for SSR, or a test URL.\n *\n * @example `'https://example.com/user/42?tab=posts'`\n */\n readonly url: string\n}\n\n/**\n * Creates a minimal in-memory Navigation object suitable for\n * server-side rendering and testing environments where the\n * browser Navigation API is unavailable.\n *\n * The returned object satisfies the subset of the `Navigation`\n * interface consumed by the Router component:\n *\n * - `currentEntry.url` — returns the initial URL\n * - `addEventListener` / `removeEventListener` — no-ops\n * (no events fire in a memory environment)\n * - `navigate()` — no-op that returns a NavigationResult\n * with immediately-resolved promises\n * - `canGoBack` / `canGoForward` — always false\n * - `entries()` — returns a single-entry array\n *\n * The object is cast to `Navigation` for compatibility with\n * the Router's `navigation` prop and `NavigationContext`.\n * Properties not listed above are not implemented and will\n * throw if accessed by consumer code outside the Router.\n *\n * @param options - Configuration including the initial URL.\n * @returns A Navigation-compatible object for SSR or testing.\n *\n * @example\n * ```tsx\n * // Server-side rendering\n * const navigation = createMemoryNavigation({\n * url: request.url,\n * })\n *\n * const html = renderToString(\n * <Router navigation={navigation} matcher={matcher}>\n * <App />\n * </Router>\n * )\n * ```\n */\nexport function createMemoryNavigation(options: MemoryNavigationOptions): Navigation {\n const entry: MemoryNavigationEntry = {\n url: options.url,\n }\n\n /**\n * No-op event listener registration. In SSR and testing\n * environments, no navigation events are dispatched, so\n * the Router's effect subscriptions are harmless no-ops.\n */\n function addEventListener() {}\n\n /**\n * No-op event listener removal. Mirrors addEventListener\n * as a symmetric no-op.\n */\n function removeEventListener() {}\n\n /**\n * No-op navigate that returns a NavigationResult with\n * pre-resolved committed and finished promises. In SSR\n * the result is never awaited, but returning valid\n * promises avoids runtime errors if consumer code chains\n * on the result.\n */\n function navigate(): NavigationResult {\n return {\n committed: Promise.resolve(entry as unknown as NavigationHistoryEntry),\n finished: Promise.resolve(entry as unknown as NavigationHistoryEntry),\n }\n }\n\n /**\n * Returns the single-entry history list. The memory\n * adapter only ever has one entry — the initial URL.\n */\n function entries(): NavigationHistoryEntry[] {\n return [entry as unknown as NavigationHistoryEntry]\n }\n\n return {\n currentEntry: entry,\n canGoBack: false,\n canGoForward: false,\n transition: null,\n addEventListener,\n removeEventListener,\n navigate,\n entries,\n } as unknown as Navigation\n}\n","import { type ComponentType } from 'react'\nimport { createMatcher, type Matcher } from 'router:matcher'\nimport {\n type FormHandler,\n type Handler,\n type MiddlewareProps,\n type PrefetchContext,\n type PrefetchFunc,\n type RedirectTarget,\n} from 'router/react:router'\n\n/**\n * Accumulated configuration inherited from parent groups.\n * Passed down through nested `.group()` calls so that child\n * routes merge their own configuration with the parent's.\n */\ninterface InheritedConfig {\n /**\n * Path prefix accumulated from parent groups. Each group\n * that specifies a path appends it to this prefix. Child\n * route paths are concatenated after this prefix when\n * registering on the matcher.\n */\n readonly prefix: string\n\n /**\n * Middleware components inherited from parent groups.\n * Child routes prepend these before their own middlewares\n * so that outermost group middlewares wrap outermost.\n */\n readonly middlewares: ComponentType<MiddlewareProps>[]\n\n /**\n * Prefetch functions inherited from parent groups. When\n * a child route also defines a prefetch, the parent\n * functions run first (in order) followed by the child's.\n */\n readonly prefetches: PrefetchFunc[]\n}\n\n/**\n * Mutable state accumulated on a single route builder\n * instance via its chainable methods. Merged with the\n * inherited config when a terminal method is called.\n */\ninterface BuilderState {\n /**\n * The path segment for this route, or undefined when the\n * builder is used purely for group-level configuration.\n */\n path: string | undefined\n\n /**\n * Middleware components added via `.middleware()` on this\n * builder. Appended after inherited middlewares.\n */\n middlewares: ComponentType<MiddlewareProps>[]\n\n /**\n * Prefetch functions added via `.prefetch()` on this\n * builder. Appended after inherited prefetches.\n */\n prefetches: PrefetchFunc[]\n\n /**\n * Scroll restoration behavior for this route. Set via\n * `.scroll()`. Undefined means the browser default.\n */\n scroll: NavigationScrollBehavior | undefined\n\n /**\n * Focus reset behavior for this route. Set via\n * `.focusReset()`. Undefined means the browser default.\n */\n focusReset: NavigationFocusReset | undefined\n\n /**\n * Form submission handler for this route. Set via\n * `.formHandler()`.\n */\n formHandler: FormHandler | undefined\n}\n\n/**\n * Chainable route builder returned by the `route()` factory.\n * Accumulates handler configuration through method calls and\n * terminates with `.render()`, `.redirect()`, or `.group()`.\n *\n * Chainable methods (return the builder for further chaining):\n * - `.middleware()` — appends middleware components\n * - `.prefetch()` — adds a prefetch function to the chain\n * - `.scroll()` — sets scroll restoration behavior\n * - `.focusReset()` — sets focus reset behavior\n * - `.formHandler()` — sets the form submission handler\n *\n * Terminal methods:\n * - `.render()` — registers a route with a component\n * - `.redirect()` — registers a precommit redirect\n * - `.group()` — returns a scoped `RouteFactory` that\n * inherits this builder's config\n */\nexport interface RouteBuilder {\n /**\n * Appends middleware components to this route or group.\n * Middlewares are applied outermost-first: inherited group\n * middlewares wrap before this route's middlewares, and\n * within the array the first element wraps outermost.\n *\n * @param list - Middleware components to append.\n * @returns The builder for further chaining.\n */\n middleware(list: ComponentType<MiddlewareProps>[]): RouteBuilder\n\n /**\n * Adds a prefetch function to the chain for this route\n * or group. When multiple prefetch functions are chained\n * (from parent groups and the route itself), they execute\n * sequentially: parent prefetches run first, then this\n * route's, in the order they were added.\n *\n * @param fn - The prefetch function to add.\n * @returns The builder for further chaining.\n */\n prefetch(fn: PrefetchFunc): RouteBuilder\n\n /**\n * Sets the scroll restoration behavior for this route.\n * - `'after-transition'` — browser handles scroll after\n * the handler promise resolves (default).\n * - `'manual'` — disables automatic scrolling so the\n * route component can call `event.scroll()` manually.\n *\n * @param behavior - The scroll behavior to use.\n * @returns The builder for further chaining.\n */\n scroll(behavior: NavigationScrollBehavior): RouteBuilder\n\n /**\n * Sets the focus reset behavior for this route.\n * - `'after-transition'` — focuses the first autofocus\n * element after the handler resolves (default).\n * - `'manual'` — disables automatic focus reset.\n *\n * @param behavior - The focus reset behavior to use.\n * @returns The builder for further chaining.\n */\n focusReset(behavior: NavigationFocusReset): RouteBuilder\n\n /**\n * Sets the form submission handler for this route. When\n * a navigation includes FormData and matches this route,\n * the form handler is called instead of rendering the\n * component.\n *\n * @param fn - The form handler function.\n * @returns The builder for further chaining.\n */\n formHandler(fn: FormHandler): RouteBuilder\n\n /**\n * Terminal method that registers this route on the matcher\n * with the given component. Merges inherited and local\n * configuration into a `Handler` and registers it at the\n * full path (group prefix + route path).\n *\n * @param component - The React component to render.\n * @throws When no path was provided to the `route()` call\n * and no group prefix exists.\n */\n render(component: ComponentType): void\n\n /**\n * Terminal method that registers a precommit redirect.\n * When the Navigation API matches this route, the\n * precommit handler calls `controller.redirect(target)`\n * before the URL commits, avoiding any component render\n * or visual flash.\n *\n * The target can be a static absolute path string, or a\n * callback that receives the prefetch context and returns\n * the path. The callback form enables dynamic redirects\n * that carry route parameters to the new location.\n *\n * The resolved target path is absolute and is NOT prefixed\n * by parent groups.\n *\n * @param target - The redirect target: a static path or a\n * callback receiving `PrefetchContext` and returning one.\n * @throws When no path was provided to the `route()` call\n * and no group prefix exists.\n *\n * @example\n * ```ts\n * // Static redirect\n * route('/old').redirect('/new')\n *\n * // Dynamic redirect using route params\n * route('/old-user/:id').redirect(({ params }) => `/user/${params.id}`)\n * ```\n */\n redirect(target: RedirectTarget): void\n\n /**\n * Terminal method that creates a nested route scope.\n * Returns a `RouteFactory` whose routes inherit this\n * builder's middleware and prefetch configuration. When\n * a path was provided, it is prepended to all child\n * route paths as a prefix.\n *\n * @returns A scoped `RouteFactory` for defining child\n * routes that inherit this builder's config.\n *\n * @example\n * ```ts\n * const admin = route('/admin').middleware([Auth]).group()\n * admin('/dashboard').render(Dashboard)\n * admin('/settings').render(Settings)\n * ```\n */\n group(): RouteFactory\n}\n\n/**\n * Factory function that creates a route builder for a given\n * path. When path is omitted, the builder is used purely for\n * group-level configuration (middleware, prefetch) without\n * contributing a path segment.\n *\n * @param path - Optional path pattern for this route. May\n * contain dynamic (`:param`) and wildcard (`*param`)\n * segments.\n * @returns A chainable route builder.\n */\nexport type RouteFactory = (path?: string) => RouteBuilder\n\n/**\n * Joins a group prefix and a route path into a single\n * pattern string. Handles the edge cases of empty prefix,\n * empty path, double slashes, and root-only paths.\n *\n * @param prefix - The accumulated group prefix (e.g.\n * `'/dashboard'`).\n * @param path - The route path (e.g. `'/settings'`).\n * @returns The joined path pattern.\n */\nfunction joinPaths(prefix: string, path: string): string {\n if (prefix === '' && path === '') {\n return ''\n }\n\n if (prefix === '') {\n return path\n }\n\n if (path === '' || path === '/') {\n return prefix\n }\n\n const normalizedPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix\n\n const normalizedPath = path.startsWith('/') ? path : '/' + path\n\n return normalizedPrefix + normalizedPath\n}\n\n/**\n * Combines an array of prefetch functions into a single\n * `PrefetchFunc` that calls each one sequentially. Returns\n * `undefined` when the array is empty.\n *\n * @param prefetches - The prefetch functions to chain.\n * @returns A single combined prefetch function, or undefined.\n */\nfunction chainPrefetches(prefetches: PrefetchFunc[]): PrefetchFunc | undefined {\n if (prefetches.length === 0) {\n return undefined\n }\n\n if (prefetches.length === 1) {\n return prefetches[0]\n }\n\n return async function (context: PrefetchContext) {\n for (const fn of prefetches) {\n await fn(context)\n }\n }\n}\n\n/**\n * A no-op React component used as the `component` field for\n * redirect routes. Never actually renders because the\n * precommit redirect fires before the URL commits, but the\n * `Handler` interface requires a component.\n */\nfunction RedirectFallback() {\n return null\n}\n\n/**\n * Creates a route builder bound to a specific matcher and\n * inherited configuration. Each call to the returned factory\n * produces a fresh builder that inherits the given config.\n *\n * @param matcher - The matcher to register routes on.\n * @param inherited - Configuration from parent groups.\n * @returns A `RouteFactory` function.\n */\nfunction createRouteFactory(matcher: Matcher<Handler>, inherited: InheritedConfig): RouteFactory {\n return function route(path?: string): RouteBuilder {\n const state: BuilderState = {\n path,\n middlewares: [],\n prefetches: [],\n scroll: undefined,\n focusReset: undefined,\n formHandler: undefined,\n }\n\n /**\n * Computes the full registration path by joining the\n * inherited prefix with this builder's path. Throws\n * when neither a prefix nor a path exists, since a\n * route must have a resolvable path to register.\n *\n * @returns The full path pattern.\n * @throws When both the group prefix and route path\n * are empty or undefined.\n */\n function resolveFullPath(): string {\n const fullPath = joinPaths(inherited.prefix, state.path ?? '')\n\n if (fullPath === '') {\n throw new Error('cannot register a route without a path or group prefix')\n }\n\n return fullPath\n }\n\n /**\n * Merges inherited and local middlewares into a single\n * array. Returns `undefined` when no middlewares exist\n * (to match the optional `Handler.middlewares` field).\n *\n * @returns The merged middleware array, or undefined.\n */\n function resolveMiddlewares(): ComponentType<MiddlewareProps>[] | undefined {\n const merged = [...inherited.middlewares, ...state.middlewares]\n\n return merged.length > 0 ? merged : undefined\n }\n\n /**\n * Merges inherited and local prefetches into a single\n * chained function. Returns `undefined` when no\n * prefetches exist.\n *\n * @returns The chained prefetch function, or undefined.\n */\n function resolvePrefetches(): PrefetchFunc | undefined {\n return chainPrefetches([...inherited.prefetches, ...state.prefetches])\n }\n\n const builder: RouteBuilder = {\n middleware(list) {\n state.middlewares.push(...list)\n\n return builder\n },\n\n prefetch(fn) {\n state.prefetches.push(fn)\n\n return builder\n },\n\n scroll(behavior) {\n state.scroll = behavior\n\n return builder\n },\n\n focusReset(behavior) {\n state.focusReset = behavior\n\n return builder\n },\n\n formHandler(fn) {\n state.formHandler = fn\n\n return builder\n },\n\n render(component) {\n const fullPath = resolveFullPath()\n\n const handler: Handler = {\n component,\n middlewares: resolveMiddlewares(),\n prefetch: resolvePrefetches(),\n scroll: state.scroll,\n focusReset: state.focusReset,\n formHandler: state.formHandler,\n }\n\n matcher.register(fullPath, handler)\n },\n\n redirect(target) {\n const fullPath = resolveFullPath()\n\n const handler: Handler = {\n component: RedirectFallback,\n middlewares: resolveMiddlewares(),\n prefetch: function (context) {\n const resolved = typeof target === 'function' ? target(context) : target\n\n context.controller.redirect(resolved)\n },\n scroll: state.scroll,\n focusReset: state.focusReset,\n }\n\n matcher.register(fullPath, handler)\n },\n\n group() {\n const childPrefix = joinPaths(inherited.prefix, state.path ?? '')\n\n const childInherited: InheritedConfig = {\n prefix: childPrefix,\n middlewares: [...inherited.middlewares, ...state.middlewares],\n prefetches: [...inherited.prefetches, ...state.prefetches],\n }\n\n return createRouteFactory(matcher, childInherited)\n },\n }\n\n return builder\n }\n}\n\n/**\n * Creates a route matcher using a declarative builder API.\n * Routes are defined inside a callback that receives a\n * `route` factory function for chainable route configuration.\n *\n * The builder supports middleware inheritance, prefetch\n * chaining, nested groups with path prefixing, redirects,\n * and all handler options (scroll, focusReset, formHandler).\n *\n * Returns a `Matcher<Handler>` that plugs directly into the\n * `<Router matcher={...}>` component.\n *\n * @param callback - A function that defines routes using the\n * provided `route` factory.\n * @returns A populated matcher ready for the Router.\n *\n * @example\n * ```tsx\n * const router = createRouter(function (route) {\n * route('/').render(Home)\n * route('/old').redirect('/new')\n *\n * route('/other')\n * .prefetch(prefetchOther)\n * .scroll('after-transition')\n * .render(Other)\n *\n * const authed = route().middleware([Auth]).group()\n * authed('/dashboard').render(Dashboard)\n * authed('/user/:id').render(User)\n *\n * const admin = authed('/admin')\n * .middleware([AdminOnly])\n * .group()\n * admin('/settings').render(Settings)\n * })\n *\n * <Router matcher={router} />\n * ```\n */\nexport function createRouter(callback: (route: RouteFactory) => void): Matcher<Handler> {\n const matcher = createMatcher<Handler>()\n\n const rootInherited: InheritedConfig = {\n prefix: '',\n middlewares: [],\n prefetches: [],\n }\n\n const route = createRouteFactory(matcher, rootInherited)\n\n callback(route)\n\n return matcher\n}\n"],"x_google_ignoreList":[1,2,3],"mappings":"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"}