@vertz/ui 0.2.0 → 0.2.2

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 (36) hide show
  1. package/README.md +339 -857
  2. package/dist/css/public.d.ts +24 -27
  3. package/dist/css/public.js +5 -1
  4. package/dist/form/public.d.ts +94 -38
  5. package/dist/form/public.js +5 -3
  6. package/dist/index.d.ts +754 -167
  7. package/dist/index.js +606 -84
  8. package/dist/internals.d.ts +192 -23
  9. package/dist/internals.js +151 -102
  10. package/dist/jsx-runtime/index.d.ts +44 -17
  11. package/dist/jsx-runtime/index.js +26 -7
  12. package/dist/query/public.d.ts +73 -7
  13. package/dist/query/public.js +12 -4
  14. package/dist/router/public.d.ts +199 -26
  15. package/dist/router/public.js +22 -7
  16. package/dist/shared/chunk-0xcmwgdb.js +288 -0
  17. package/dist/shared/{chunk-j8vzvne3.js → chunk-9e92w0wt.js} +4 -1
  18. package/dist/shared/chunk-g4rch80a.js +33 -0
  19. package/dist/shared/chunk-hh0dhmb4.js +528 -0
  20. package/dist/shared/{chunk-pgymxpn1.js → chunk-hrd0mft1.js} +136 -34
  21. package/dist/shared/chunk-jrtrk5z4.js +125 -0
  22. package/dist/shared/chunk-ka5ked7n.js +188 -0
  23. package/dist/shared/chunk-n91rwj2r.js +483 -0
  24. package/dist/shared/chunk-prj7nm08.js +67 -0
  25. package/dist/shared/chunk-q6cpe5k7.js +230 -0
  26. package/dist/shared/{chunk-f1ynwam4.js → chunk-qacth5ah.js} +162 -36
  27. package/dist/shared/chunk-ryb49346.js +374 -0
  28. package/dist/shared/chunk-v3yyf79g.js +48 -0
  29. package/dist/test/index.d.ts +67 -6
  30. package/dist/test/index.js +4 -3
  31. package/package.json +14 -9
  32. package/dist/shared/chunk-bp3v6s9j.js +0 -62
  33. package/dist/shared/chunk-d8h2eh8d.js +0 -141
  34. package/dist/shared/chunk-tsdpgmks.js +0 -98
  35. package/dist/shared/chunk-xd9d7q5p.js +0 -115
  36. package/dist/shared/chunk-zbbvx05f.js +0 -202
@@ -1,31 +1,50 @@
1
1
  /**
2
- * JSX runtime for @vertz/ui used by Bun at test/dev time.
3
- *
4
- * At build time, the @vertz/ui-compiler transforms JSX into optimized
5
- * __element() / __on() / __text() / __attr() calls with compile-time
6
- * reactivity analysis. This runtime provides a simpler DOM-based
7
- * implementation for tests and development.
8
- *
9
- * Implements the "react-jsx" automatic runtime interface:
10
- * - jsx(type, props) — single child
11
- * - jsxs(type, props) — multiple children
12
- * - Fragment — document fragment
2
+ * JSX namespace - required for TypeScript's react-jsx mode
3
+ * to understand intrinsic element types and component types.
13
4
  */
14
- type JSXComponent = (props: Record<string, unknown>) => Node | Node[] | null;
15
- type Tag = string | JSXComponent;
5
+ declare namespace JSX {
6
+ type Element = HTMLElement | SVGElement;
7
+ type JSXComponent = (props: Record<string, unknown>) => Element;
8
+ interface HTMLAttributes {
9
+ [key: string]: unknown;
10
+ children?: unknown;
11
+ }
12
+ interface IntrinsicAttributes {
13
+ key?: string | number;
14
+ }
15
+ interface IntrinsicElements {
16
+ [key: string]: HTMLAttributes | undefined;
17
+ }
18
+ }
16
19
  /**
17
20
  * JSX factory function for client-side rendering.
18
21
  *
19
22
  * When tag is a function (component), calls it with props.
20
23
  * When tag is a string (HTML element), creates a DOM element.
21
24
  */
22
- declare function jsx(tag: Tag, props: Record<string, unknown>): Node | Node[] | null;
25
+ declare function jsx<K extends keyof HTMLElementTagNameMap>(tag: K, props: Record<string, unknown> | null | undefined): HTMLElementTagNameMap[K];
26
+ declare function jsx(tag: string, props: Record<string, unknown> | null | undefined): HTMLElement;
27
+ declare function jsx<
28
+ P extends Record<string, unknown>,
29
+ R extends JSX.Element
30
+ >(tag: (props: P) => R, props: P): R;
31
+ declare function jsx(tag: typeof Fragment, props: {
32
+ children?: unknown;
33
+ }): DocumentFragment;
23
34
  /**
24
35
  * JSX factory for elements with multiple children.
25
36
  * In the automatic runtime, this is used when there are multiple children.
26
37
  * For our implementation, it's the same as jsx().
27
38
  */
28
- declare const jsxs: typeof jsx;
39
+ declare function jsxs<K extends keyof HTMLElementTagNameMap>(tag: K, props: Record<string, unknown> | null | undefined): HTMLElementTagNameMap[K];
40
+ declare function jsxs(tag: string, props: Record<string, unknown> | null | undefined): HTMLElement;
41
+ declare function jsxs<
42
+ P extends Record<string, unknown>,
43
+ R extends JSX.Element
44
+ >(tag: (props: P) => R, props: P): R;
45
+ declare function jsxs(tag: typeof Fragment, props: {
46
+ children?: unknown;
47
+ }): DocumentFragment;
29
48
  /**
30
49
  * Fragment component — a DocumentFragment container for multiple children.
31
50
  */
@@ -36,5 +55,13 @@ declare function Fragment(props: {
36
55
  * JSX development mode factory (used with @jsxImportSource in tsconfig).
37
56
  * Same as jsx() for our implementation.
38
57
  */
39
- declare const jsxDEV: typeof jsx;
40
- export { jsxs, jsxDEV, jsx, Fragment };
58
+ declare function jsxDEV<K extends keyof HTMLElementTagNameMap>(tag: K, props: Record<string, unknown> | null | undefined): HTMLElementTagNameMap[K];
59
+ declare function jsxDEV(tag: string, props: Record<string, unknown> | null | undefined): HTMLElement;
60
+ declare function jsxDEV<
61
+ P extends Record<string, unknown>,
62
+ R extends JSX.Element
63
+ >(tag: (props: P) => R, props: P): R;
64
+ declare function jsxDEV(tag: typeof Fragment, props: {
65
+ children?: unknown;
66
+ }): DocumentFragment;
67
+ export { jsxs, jsxDEV, jsx, JSX, Fragment };
@@ -1,7 +1,17 @@
1
+ import {
2
+ SVG_NS,
3
+ isSVGTag,
4
+ normalizeSVGAttr
5
+ } from "../shared/chunk-prj7nm08.js";
6
+
1
7
  // src/jsx-runtime/index.ts
2
8
  function applyChildren(parent, children) {
3
9
  if (children == null || children === false || children === true)
4
10
  return;
11
+ if (typeof children === "function") {
12
+ applyChildren(parent, children());
13
+ return;
14
+ }
5
15
  if (Array.isArray(children)) {
6
16
  for (const child of children) {
7
17
  applyChildren(parent, child);
@@ -12,36 +22,45 @@ function applyChildren(parent, children) {
12
22
  parent.appendChild(document.createTextNode(String(children)));
13
23
  }
14
24
  }
15
- function jsx(tag, props) {
25
+ function jsxImpl(tag, props) {
16
26
  if (typeof tag === "function") {
17
- return tag(props);
27
+ return tag(props || {});
18
28
  }
19
29
  const { children, ...attrs } = props || {};
20
- const element = document.createElement(tag);
30
+ const svg = isSVGTag(tag);
31
+ const element = svg ? document.createElementNS(SVG_NS, tag) : document.createElement(tag);
21
32
  for (const [key, value] of Object.entries(attrs)) {
22
33
  if (key.startsWith("on") && typeof value === "function") {
23
34
  const eventName = key.slice(2).toLowerCase();
24
35
  element.addEventListener(eventName, value);
25
36
  } else if (key === "class" && value != null) {
26
- element.className = String(value);
37
+ element.setAttribute("class", String(value));
27
38
  } else if (key === "style" && value != null) {
28
39
  element.setAttribute("style", String(value));
29
40
  } else if (value === true) {
30
41
  element.setAttribute(key, "");
31
42
  } else if (value != null && value !== false) {
32
- element.setAttribute(key, String(value));
43
+ const attrName = svg ? normalizeSVGAttr(key) : key;
44
+ element.setAttribute(attrName, String(value));
33
45
  }
34
46
  }
35
47
  applyChildren(element, children);
36
48
  return element;
37
49
  }
38
- var jsxs = jsx;
50
+ function jsx(tag, props) {
51
+ return jsxImpl(tag, props);
52
+ }
53
+ function jsxs(tag, props) {
54
+ return jsxImpl(tag, props);
55
+ }
39
56
  function Fragment(props) {
40
57
  const frag = document.createDocumentFragment();
41
58
  applyChildren(frag, props?.children);
42
59
  return frag;
43
60
  }
44
- var jsxDEV = jsx;
61
+ function jsxDEV(tag, props) {
62
+ return jsxImpl(tag, props);
63
+ }
45
64
  export {
46
65
  jsxs,
47
66
  jsxDEV,
@@ -1,3 +1,5 @@
1
+ import { QueryDescriptor as QueryDescriptor2 } from "@vertz/fetch";
2
+ import { isQueryDescriptor } from "@vertz/fetch";
1
3
  /**
2
4
  * Interface for cache stores used by query().
3
5
  * Consumers can provide custom implementations (e.g. LRU, persistent storage).
@@ -6,7 +8,9 @@ interface CacheStore<T = unknown> {
6
8
  get(key: string): T | undefined;
7
9
  set(key: string, value: T): void;
8
10
  delete(key: string): void;
11
+ clear?(): void;
9
12
  }
13
+ import { QueryDescriptor } from "@vertz/fetch";
10
14
  /**
11
15
  * A read-only reactive value derived from other signals.
12
16
  */
@@ -16,6 +20,17 @@ interface ReadonlySignal<T> {
16
20
  /** Read the current value without subscribing. */
17
21
  peek(): T;
18
22
  }
23
+ /**
24
+ * Unwraps a ReadonlySignal to its value type.
25
+ * Used by signal APIs (like query()) to expose plain values in TypeScript
26
+ * while the compiler auto-unwraps them at runtime.
27
+ *
28
+ * @example
29
+ * type UnwrappedData = Unwrapped<ReadonlySignal<Task | undefined>>; // → Task | undefined
30
+ */
31
+ type Unwrapped<T> = T extends ReadonlySignal<infer U> ? U : T;
32
+ /** Dispose function returned by effect(). */
33
+ type DisposeFn = () => void;
19
34
  /** Options for query(). */
20
35
  interface QueryOptions<T> {
21
36
  /** Pre-populated data — skips the initial fetch when provided. */
@@ -28,15 +43,33 @@ interface QueryOptions<T> {
28
43
  key?: string;
29
44
  /** Custom cache store. Defaults to a shared in-memory Map. */
30
45
  cache?: CacheStore<T>;
46
+ /** Timeout in ms for SSR data loading. Default: 300. Set to 0 to disable. */
47
+ ssrTimeout?: number;
48
+ /**
49
+ * Polling interval in ms, or a function for dynamic intervals.
50
+ *
51
+ * - `number` — fixed interval in ms
52
+ * - `false` or `0` — disabled
53
+ * - `(data, iteration) => number | false` — called after each fetch to
54
+ * determine the next interval. Return `false` to stop polling.
55
+ * `iteration` counts polls since the last start/restart (resets to 0
56
+ * when the function returns `false`).
57
+ */
58
+ refetchInterval?: number | false | ((data: T | undefined, iteration: number) => number | false);
31
59
  }
32
60
  /** The reactive object returned by query(). */
33
- interface QueryResult<T> {
61
+ interface QueryResult<
62
+ T,
63
+ E = unknown
64
+ > {
34
65
  /** The fetched data, or undefined while loading. */
35
- readonly data: ReadonlySignal<T | undefined>;
36
- /** True while a fetch is in progress. */
37
- readonly loading: ReadonlySignal<boolean>;
66
+ readonly data: Unwrapped<ReadonlySignal<T | undefined>>;
67
+ /** True only on the initial load (no data yet). False during revalidation. */
68
+ readonly loading: Unwrapped<ReadonlySignal<boolean>>;
69
+ /** True when refetching while stale data is already available. */
70
+ readonly revalidating: Unwrapped<ReadonlySignal<boolean>>;
38
71
  /** The error from the latest failed fetch, or undefined. */
39
- readonly error: ReadonlySignal<unknown>;
72
+ readonly error: Unwrapped<ReadonlySignal<E | undefined>>;
40
73
  /** Manually trigger a refetch (clears cache for this key). */
41
74
  refetch: () => void;
42
75
  /** Alias for refetch — revalidate the cached data. */
@@ -50,9 +83,42 @@ interface QueryResult<T> {
50
83
  * The thunk is wrapped in an effect so that when reactive dependencies
51
84
  * used *before* the async call change, the query automatically re-fetches.
52
85
  *
53
- * @param thunk - An async function that returns the data.
86
+ * @param source - A QueryDescriptor or an async function that returns the data.
54
87
  * @param options - Optional configuration.
55
88
  * @returns A QueryResult with reactive signals for data, loading, and error.
56
89
  */
90
+ declare function query<
91
+ T,
92
+ E
93
+ >(descriptor: QueryDescriptor<T, E>, options?: Omit<QueryOptions<T>, "key">): QueryResult<T, E>;
57
94
  declare function query<T>(thunk: () => Promise<T>, options?: QueryOptions<T>): QueryResult<T>;
58
- export { query, QueryResult, QueryOptions, CacheStore };
95
+ interface QueryMatchHandlers<
96
+ T,
97
+ E
98
+ > {
99
+ loading: () => Node | null;
100
+ error: (error: E) => Node | null;
101
+ data: (data: T) => Node | null;
102
+ }
103
+ /**
104
+ * Pattern-match on a QueryResult's exclusive state.
105
+ *
106
+ * Returns a stable `<span style="display:contents">` wrapper that internally
107
+ * manages branch switching (loading/error/data) via a reactive effect.
108
+ * The same wrapper is returned for repeated calls with the same queryResult
109
+ * (cached via WeakMap), enabling __child's stable-node optimization.
110
+ *
111
+ * Priority: loading → error → data.
112
+ *
113
+ * `loading` only fires on the initial load (no data yet).
114
+ * When revalidating with existing data, the `data` handler receives the
115
+ * current data. Access `query.revalidating` from the component scope for
116
+ * revalidation state.
117
+ */
118
+ declare function queryMatch<
119
+ T,
120
+ E
121
+ >(queryResult: QueryResult<T, E>, handlers: QueryMatchHandlers<T, E>): HTMLElement & {
122
+ dispose: DisposeFn;
123
+ };
124
+ export { queryMatch, query, isQueryDescriptor, QueryResult, QueryOptions, QueryMatchHandlers, QueryDescriptor2 as QueryDescriptor, CacheStore };
@@ -1,7 +1,15 @@
1
1
  import {
2
- query
3
- } from "../shared/chunk-zbbvx05f.js";
4
- import"../shared/chunk-pgymxpn1.js";
2
+ query,
3
+ queryMatch
4
+ } from "../shared/chunk-hh0dhmb4.js";
5
+ import"../shared/chunk-jrtrk5z4.js";
6
+ import"../shared/chunk-g4rch80a.js";
7
+ import"../shared/chunk-hrd0mft1.js";
8
+
9
+ // src/query/public.ts
10
+ import { isQueryDescriptor } from "@vertz/fetch";
5
11
  export {
6
- query
12
+ queryMatch,
13
+ query,
14
+ isQueryDescriptor
7
15
  };
@@ -25,9 +25,34 @@ type ExtractParams<T extends string> = [ExtractParamsFromSegments<WithoutWildcar
25
25
  } : Record<string, never> : HasWildcard<T> extends true ? { [K in ExtractParamsFromSegments<WithoutWildcard<T>>] : string } & {
26
26
  "*": string;
27
27
  } : { [K in ExtractParamsFromSegments<WithoutWildcard<T>>] : string };
28
+ /**
29
+ * Convert a route pattern to the union of URL shapes it accepts.
30
+ * - Static: `'/'` → `'/'`
31
+ * - Param: `'/tasks/:id'` → `` `/tasks/${string}` ``
32
+ * - Wildcard: `'/files/*'` → `` `/files/${string}` ``
33
+ * - Multi: `'/users/:id/posts/:postId'` → `` `/users/${string}/posts/${string}` ``
34
+ * - Fallback: `string` → `string` (backward compat)
35
+ */
36
+ type PathWithParams<T extends string> = T extends `${infer Before}*` ? `${PathWithParams<Before>}${string}` : T extends `${infer Before}:${string}/${infer After}` ? `${Before}${string}/${PathWithParams<`${After}`>}` : T extends `${infer Before}:${string}` ? `${Before}${string}` : T;
37
+ /**
38
+ * Union of all valid URL shapes for a route map.
39
+ * Maps each route pattern key through `PathWithParams` to produce the accepted URL shapes.
40
+ *
41
+ * Example:
42
+ * ```
43
+ * RoutePaths<{ '/': ..., '/tasks/:id': ... }> = '/' | `/tasks/${string}`
44
+ * ```
45
+ */
46
+ type RoutePaths<TRouteMap extends Record<string, unknown>> = { [K in keyof TRouteMap & string] : PathWithParams<K> }[keyof TRouteMap & string];
28
47
  /** Simple schema interface for search param parsing. */
29
48
  interface SearchParamSchema<T> {
30
- parse(data: unknown): T;
49
+ parse(data: unknown): {
50
+ ok: true;
51
+ data: T;
52
+ } | {
53
+ ok: false;
54
+ error: unknown;
55
+ };
31
56
  }
32
57
  /** A route configuration for a single path. */
33
58
  interface RouteConfig<
@@ -55,6 +80,46 @@ interface RouteConfig<
55
80
  interface RouteDefinitionMap {
56
81
  [pattern: string]: RouteConfig;
57
82
  }
83
+ /**
84
+ * Loose route config used as the generic constraint for `defineRoutes`.
85
+ * Uses `Record<string, string>` for loader params so any concrete loader
86
+ * that accesses string params (e.g., `params.id`) satisfies the constraint.
87
+ */
88
+ interface RouteConfigLike {
89
+ component: () => Node | Promise<{
90
+ default: () => Node;
91
+ }>;
92
+ /**
93
+ * Method syntax (`loader?(ctx): R`) is intentional — it enables **bivariant**
94
+ * parameter checking under `strictFunctionTypes`. Property syntax
95
+ * (`loader?: (ctx) => R`) would be contravariant, causing `RouteConfig<string>`
96
+ * (whose loader has `params: Record<string, never>`) to fail assignability
97
+ * against this constraint's `params: Record<string, string>`.
98
+ */
99
+ loader?(ctx: {
100
+ params: Record<string, string>;
101
+ signal: AbortSignal;
102
+ }): unknown;
103
+ errorComponent?: (error: Error) => Node;
104
+ searchParams?: SearchParamSchema<unknown>;
105
+ children?: Record<string, RouteConfigLike>;
106
+ }
107
+ /**
108
+ * Phantom branded array that carries the route map type `T`.
109
+ * The `__routes` property never exists at runtime — it is a type-level
110
+ * marker used to thread the developer's literal route keys through
111
+ * `createRouter`, `useRouter`, etc.
112
+ */
113
+ type TypedRoutes<T extends Record<string, RouteConfigLike> = RouteDefinitionMap> = CompiledRoute[] & {
114
+ readonly __routes: T;
115
+ };
116
+ /**
117
+ * Extract the route map type from `TypedRoutes<T>`.
118
+ * If `T` is not a `TypedRoutes`, returns `T` as-is (passthrough).
119
+ *
120
+ * Usage: `useRouter<InferRouteMap<typeof routes>>()`
121
+ */
122
+ type InferRouteMap<T> = T extends TypedRoutes<infer R> ? R : T;
58
123
  /** Internal compiled route. */
59
124
  interface CompiledRoute {
60
125
  /** The original path pattern. */
@@ -100,7 +165,7 @@ type LoaderData<T> = T extends {
100
165
  * Define routes from a configuration map.
101
166
  * Returns an array of compiled routes preserving definition order.
102
167
  */
103
- declare function defineRoutes(map: RouteDefinitionMap): CompiledRoute[];
168
+ declare function defineRoutes<const T extends Record<string, RouteConfigLike>>(map: T): TypedRoutes<T>;
104
169
  /**
105
170
  * A reactive signal that holds a value and notifies subscribers on change.
106
171
  */
@@ -123,16 +188,50 @@ interface ReadonlySignal<T> {
123
188
  /** Read the current value without subscribing. */
124
189
  peek(): T;
125
190
  }
126
- /** Props for the Link component. */
127
- interface LinkProps {
191
+ /**
192
+ * Unwraps a ReadonlySignal to its value type.
193
+ * Used by signal APIs (like query()) to expose plain values in TypeScript
194
+ * while the compiler auto-unwraps them at runtime.
195
+ *
196
+ * @example
197
+ * type UnwrappedData = Unwrapped<ReadonlySignal<Task | undefined>>; // → Task | undefined
198
+ */
199
+ type Unwrapped<T> = T extends ReadonlySignal<infer U> ? U : T;
200
+ /**
201
+ * Unwraps all signal properties of an object type.
202
+ * Properties that are signals become their inner value type.
203
+ * Non-signal properties and primitive types pass through unchanged.
204
+ *
205
+ * Used by `useContext` to present context values without the Signal wrapper.
206
+ *
207
+ * @example
208
+ * type Settings = { theme: Signal<string>; setTheme: (t: string) => void };
209
+ * type Unwrapped = UnwrapSignals<Settings>; // { theme: string; setTheme: (t: string) => void }
210
+ */
211
+ type UnwrapSignals<T> = T extends object ? { [K in keyof T] : Unwrapped<T[K]> } : T;
212
+ /**
213
+ * Props for the Link component.
214
+ *
215
+ * Generic over the route map `T`. Defaults to `RouteDefinitionMap` (string
216
+ * index signature) for backward compatibility — unparameterized `LinkProps`
217
+ * accepts any string href.
218
+ */
219
+ interface LinkProps<T extends Record<string, RouteConfigLike> = RouteDefinitionMap> {
128
220
  /** The target URL path. */
129
- href: string;
130
- /** Text or content for the link. */
131
- children: string;
221
+ href: RoutePaths<T>;
222
+ /** Text or content for the link. Thunk may return string or Text node. */
223
+ children: string | (() => string | Node);
132
224
  /** Class applied when the link's href matches the current path. */
133
225
  activeClass?: string;
134
226
  /** Static class name for the anchor element. */
135
227
  className?: string;
228
+ /** Prefetch strategy. 'hover' triggers server pre-fetch on mouseenter/focus. */
229
+ prefetch?: "hover";
230
+ }
231
+ /** Options for createLink(). */
232
+ interface LinkFactoryOptions {
233
+ /** Callback fired when a link wants to prefetch its target URL. */
234
+ onPrefetch?: (url: string) => void;
136
235
  }
137
236
  /**
138
237
  * Create a Link component factory bound to the router's state.
@@ -141,14 +240,45 @@ interface LinkProps {
141
240
  * @param navigate - Navigation function from the router
142
241
  * @returns A Link component function
143
242
  */
144
- declare function createLink(currentPath: ReadonlySignal<string>, navigate: (url: string) => void): (props: LinkProps) => HTMLAnchorElement;
243
+ declare function createLink(currentPath: ReadonlySignal<string>, navigate: (url: string) => void, factoryOptions?: LinkFactoryOptions): (props: LinkProps) => HTMLAnchorElement;
145
244
  /** Options for router.navigate(). */
146
245
  interface NavigateOptions {
147
246
  /** Use history.replaceState instead of pushState. */
148
247
  replace?: boolean;
149
248
  }
150
- /** The router instance returned by createRouter. */
151
- interface Router {
249
+ /** Handle returned by prefetchNavData for cancellation. */
250
+ interface PrefetchHandle {
251
+ abort: () => void;
252
+ /** Resolves when SSE stream completes (data or done event). */
253
+ done?: Promise<void>;
254
+ /** Resolves when the first SSE event of any type arrives. */
255
+ firstEvent?: Promise<void>;
256
+ }
257
+ /** Options for createRouter(). */
258
+ interface RouterOptions {
259
+ /** Enable server-side navigation pre-fetch. When true, uses default timeout. */
260
+ serverNav?: boolean | {
261
+ timeout?: number;
262
+ };
263
+ /** @internal — injected for testing. Production uses the real module. */
264
+ _prefetchNavData?: (url: string, options?: {
265
+ timeout?: number;
266
+ }) => PrefetchHandle;
267
+ }
268
+ /**
269
+ * The router instance returned by createRouter.
270
+ *
271
+ * Generic over the route map `T`. Defaults to `RouteDefinitionMap` (string
272
+ * index signature) for backward compatibility — unparameterized `Router`
273
+ * accepts any string in `navigate()`.
274
+ *
275
+ * Method syntax on `navigate`, `revalidate`, and `dispose` enables bivariant
276
+ * parameter checking under `strictFunctionTypes`. This means `Router<T>` is
277
+ * assignable to `Router` (the unparameterized default), which is required for
278
+ * storing typed routers in the `RouterContext` without contravariance errors.
279
+ * At call sites, TypeScript still enforces the `RoutePaths<T>` constraint.
280
+ */
281
+ interface Router<T extends Record<string, RouteConfigLike> = RouteDefinitionMap> {
152
282
  /** Current matched route (reactive signal). */
153
283
  current: Signal<RouteMatch | null>;
154
284
  /** Loader data from the current route's loaders (reactive signal). */
@@ -158,43 +288,86 @@ interface Router {
158
288
  /** Parsed search params from the current route (reactive signal). */
159
289
  searchParams: Signal<Record<string, unknown>>;
160
290
  /** Navigate to a new URL path. */
161
- navigate: (url: string, options?: NavigateOptions) => Promise<void>;
291
+ navigate(url: RoutePaths<T>, options?: NavigateOptions): Promise<void>;
162
292
  /** Re-run all loaders for the current route. */
163
- revalidate: () => Promise<void>;
293
+ revalidate(): Promise<void>;
164
294
  /** Remove popstate listener and clean up the router. */
165
- dispose: () => void;
295
+ dispose(): void;
166
296
  }
167
297
  /**
298
+ * Convenience alias for a typed router.
299
+ * `TypedRouter<T>` is identical to `Router<T>` — it exists for readability
300
+ * when the generic parameter makes the intent clearer.
301
+ */
302
+ type TypedRouter<T extends Record<string, RouteConfigLike> = RouteDefinitionMap> = Router<T>;
303
+ /**
168
304
  * Create a router instance.
169
305
  *
170
306
  * @param routes - Compiled route list from defineRoutes()
171
307
  * @param initialUrl - The initial URL to match (optional; auto-detects from window.location or __SSR_URL__)
172
308
  * @returns Router instance with reactive state and navigation methods
173
309
  */
174
- declare function createRouter(routes: CompiledRoute[], initialUrl?: string): Router;
310
+ declare function createRouter<T extends Record<string, RouteConfigLike> = RouteDefinitionMap>(routes: TypedRoutes<T>, initialUrl?: string, options?: RouterOptions): Router<T>;
311
+ /**
312
+ * Props for the JSX pattern of Context.Provider.
313
+ *
314
+ * `children` accepts both raw values (what TypeScript sees in JSX) and
315
+ * thunks (what the compiler produces). At compile time the compiler wraps
316
+ * JSX children in `() => ...`, but TypeScript checks the pre-compilation
317
+ * source where children are plain elements.
318
+ */
319
+ interface ProviderJsxProps<T> {
320
+ value: T;
321
+ children: (() => unknown) | unknown;
322
+ }
175
323
  /** A context object created by `createContext`. */
176
324
  interface Context<T> {
177
- /** Provide a value to all `useContext` calls within the scope. */
178
- Provider: (value: T, fn: () => void) => void;
325
+ /** Provide a value via callback pattern. */
326
+ Provider(value: T, fn: () => void): void;
327
+ /** Provide a value via JSX pattern (single-arg object with children thunk). */
328
+ Provider(props: ProviderJsxProps<T>): HTMLElement;
179
329
  /** @internal — current value stack */
180
330
  _stack: T[];
181
331
  /** @internal — default value */
182
332
  _default: T | undefined;
183
333
  }
184
334
  /** Context value for the Outlet. */
185
- interface OutletContext {
186
- /** The child component factory to render, or undefined if no child. */
187
- childComponent: (() => Node) | undefined;
188
- /** The nesting depth (for debugging/tracking). */
189
- depth: number;
335
+ interface OutletContextValue {
336
+ /** Reactive child component factory (may return async module). */
337
+ childComponent: Signal<(() => Node | Promise<{
338
+ default: () => Node;
339
+ }>) | undefined>;
340
+ /** Router instance for restoring context in async resolution. */
341
+ router: Router;
342
+ }
343
+ /** Shared context used by RouterView and Outlet. */
344
+ declare const OutletContext: Context<OutletContextValue>;
345
+ /**
346
+ * Outlet component — renders the nested child route.
347
+ *
348
+ * Must be called inside a layout component rendered by RouterView.
349
+ * Reads from OutletContext to determine which child to render.
350
+ */
351
+ declare function Outlet(): Node;
352
+ declare const RouterContext: Context<Router>;
353
+ declare function useRouter<T extends Record<string, RouteConfigLike> = RouteDefinitionMap>(): UnwrapSignals<Router<T>>;
354
+ declare function useParams<TPath extends string = string>(): ExtractParams<TPath>;
355
+ interface RouterViewProps {
356
+ router: Router;
357
+ fallback?: () => Node;
190
358
  }
191
359
  /**
192
- * Create an Outlet component bound to a specific outlet context.
360
+ * Renders the matched route's component inside a container div.
361
+ *
362
+ * Handles sync and async (lazy-loaded) components, stale resolution guards,
363
+ * page cleanup on navigation, and RouterContext propagation.
193
364
  *
194
- * @param outletCtx - The context that holds the child component
195
- * @returns An Outlet component function
365
+ * Uses __element() so the container is claimed from SSR during hydration.
366
+ * On the first hydration render, children are already in the DOM — the
367
+ * domEffect runs the component factory (to attach reactivity/event handlers)
368
+ * but skips clearing the container.
196
369
  */
197
- declare function createOutlet(outletCtx: Context<OutletContext>): () => Node;
370
+ declare function RouterView({ router, fallback }: RouterViewProps): HTMLElement;
198
371
  /**
199
372
  * Parse URLSearchParams into a typed object, optionally through a schema.
200
373
  *
@@ -211,4 +384,4 @@ declare function parseSearchParams<T = Record<string, string>>(urlParams: URLSea
211
384
  * @returns The current search params value
212
385
  */
213
386
  declare function useSearchParams<T>(searchSignal: ReadonlySignal<T>): T;
214
- export { useSearchParams, parseSearchParams, defineRoutes, createRouter, createOutlet, createLink, SearchParamSchema, Router, RouteMatch, RouteDefinitionMap, RouteConfig, OutletContext, NavigateOptions, MatchedRoute, LoaderData, LinkProps, ExtractParams, CompiledRoute };
387
+ export { useSearchParams, useRouter, useParams, parseSearchParams, defineRoutes, createRouter, createLink, TypedRoutes, TypedRouter, SearchParamSchema, RouterViewProps, RouterView, RouterContext, Router, RoutePaths, RouteMatch, RouteDefinitionMap, RouteConfig, PathWithParams, OutletContextValue, OutletContext, Outlet, NavigateOptions, MatchedRoute, LoaderData, LinkProps, InferRouteMap, ExtractParams, CompiledRoute };
@@ -1,21 +1,36 @@
1
1
  import {
2
+ Outlet,
3
+ OutletContext,
4
+ RouterContext,
5
+ RouterView,
2
6
  createLink,
3
- createOutlet,
4
7
  parseSearchParams,
8
+ useParams,
9
+ useRouter,
5
10
  useSearchParams
6
- } from "../shared/chunk-bp3v6s9j.js";
11
+ } from "../shared/chunk-0xcmwgdb.js";
12
+ import"../shared/chunk-v3yyf79g.js";
7
13
  import {
8
14
  createRouter
9
- } from "../shared/chunk-xd9d7q5p.js";
15
+ } from "../shared/chunk-ka5ked7n.js";
10
16
  import {
11
17
  defineRoutes
12
- } from "../shared/chunk-j8vzvne3.js";
13
- import"../shared/chunk-pgymxpn1.js";
18
+ } from "../shared/chunk-9e92w0wt.js";
19
+ import"../shared/chunk-jrtrk5z4.js";
20
+ import"../shared/chunk-ryb49346.js";
21
+ import"../shared/chunk-g4rch80a.js";
22
+ import"../shared/chunk-hrd0mft1.js";
23
+ import"../shared/chunk-prj7nm08.js";
14
24
  export {
15
25
  useSearchParams,
26
+ useRouter,
27
+ useParams,
16
28
  parseSearchParams,
17
29
  defineRoutes,
18
30
  createRouter,
19
- createOutlet,
20
- createLink
31
+ createLink,
32
+ RouterView,
33
+ RouterContext,
34
+ OutletContext,
35
+ Outlet
21
36
  };