@vertz/ui 0.2.13 → 0.2.15

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.
@@ -82,6 +82,7 @@ var PROPERTY_MAP = {
82
82
  leading: { properties: ["line-height"], valueType: "line-height" },
83
83
  tracking: { properties: ["letter-spacing"], valueType: "raw" },
84
84
  decoration: { properties: ["text-decoration"], valueType: "raw" },
85
+ list: { properties: ["list-style"], valueType: "raw" },
85
86
  ring: { properties: ["outline"], valueType: "ring" },
86
87
  cursor: { properties: ["cursor"], valueType: "raw" },
87
88
  transition: { properties: ["transition"], valueType: "raw" },
@@ -115,7 +116,9 @@ var KEYWORD_MAP = {
115
116
  "select-none": [{ property: "user-select", value: "none" }],
116
117
  "pointer-events-none": [{ property: "pointer-events", value: "none" }],
117
118
  "whitespace-nowrap": [{ property: "white-space", value: "nowrap" }],
118
- "shrink-0": [{ property: "flex-shrink", value: "0" }]
119
+ "shrink-0": [{ property: "flex-shrink", value: "0" }],
120
+ italic: [{ property: "font-style", value: "italic" }],
121
+ "not-italic": [{ property: "font-style", value: "normal" }]
119
122
  };
120
123
  var DISPLAY_MAP = {
121
124
  flex: "flex",
@@ -399,6 +402,9 @@ function resolveToken(parsed) {
399
402
  if (property === "ring") {
400
403
  return { declarations: resolveRingMulti(value), pseudo };
401
404
  }
405
+ if (property === "list") {
406
+ return { declarations: resolveList(value), pseudo };
407
+ }
402
408
  const resolvedValue = resolveValue(value, mapping.valueType, property);
403
409
  const declarations = mapping.properties.map((prop) => ({
404
410
  property: prop,
@@ -551,6 +557,17 @@ function resolveRingMulti(value) {
551
557
  }
552
558
  return [{ property: "outline-color", value: resolveColor(value, "ring") }];
553
559
  }
560
+ var LIST_STYLE_KEYWORDS = new Set(["none", "disc", "decimal"]);
561
+ var LIST_POSITION_KEYWORDS = new Set(["inside", "outside"]);
562
+ function resolveList(value) {
563
+ if (LIST_STYLE_KEYWORDS.has(value)) {
564
+ return [{ property: "list-style", value }];
565
+ }
566
+ if (LIST_POSITION_KEYWORDS.has(value)) {
567
+ return [{ property: "list-style-position", value }];
568
+ }
569
+ throw new TokenResolveError(`Invalid list value '${value}'. Use: none, disc, decimal, inside, outside.`, `list:${value}`);
570
+ }
554
571
  function resolveRaw(value, property) {
555
572
  if (property === "border-r" || property === "border-l" || property === "border-t" || property === "border-b") {
556
573
  const num = Number(value);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  injectCSS
3
- } from "./chunk-c9xxsrat.js";
3
+ } from "./chunk-1wby7nex.js";
4
4
 
5
5
  // src/dom/animation.ts
6
6
  function onAnimationsComplete(el, callback) {
@@ -206,6 +206,13 @@ function form(sdkMethod, options) {
206
206
  submitting,
207
207
  dirty,
208
208
  valid,
209
+ fields: new Proxy(Object.create(null), {
210
+ get(_target, prop) {
211
+ if (typeof prop === "string")
212
+ return prop;
213
+ return;
214
+ }
215
+ }),
209
216
  __bindElement: (el) => {
210
217
  boundElement = el;
211
218
  el.addEventListener("input", handleInputOrChange);
@@ -12,6 +12,53 @@ import {
12
12
 
13
13
  // src/router/navigate.ts
14
14
  var DEFAULT_NAV_THRESHOLD_MS = 500;
15
+ function interpolatePath(path, params) {
16
+ const segments = path.split("/");
17
+ return segments.map((segment) => {
18
+ if (segment.startsWith(":")) {
19
+ const paramName = segment.slice(1);
20
+ const value = params?.[paramName];
21
+ if (value === undefined) {
22
+ throw new TypeError(`Missing route param "${paramName}" for path "${path}"`);
23
+ }
24
+ return encodeURIComponent(value);
25
+ }
26
+ if (segment === "*") {
27
+ const value = params?.["*"];
28
+ if (value === undefined) {
29
+ throw new TypeError(`Missing wildcard param "*" for path "${path}"`);
30
+ }
31
+ return value.replace(/^\/+|\/+$/g, "").split("/").map((part) => encodeURIComponent(part)).join("/");
32
+ }
33
+ return segment;
34
+ }).join("/");
35
+ }
36
+ function buildSearch(search) {
37
+ if (!search)
38
+ return "";
39
+ if (typeof search === "string") {
40
+ if (search === "")
41
+ return "";
42
+ return search.startsWith("?") ? search : `?${search}`;
43
+ }
44
+ const params = search instanceof URLSearchParams ? new URLSearchParams(search) : new URLSearchParams;
45
+ if (!(search instanceof URLSearchParams)) {
46
+ const entries = Object.entries(search).sort(([left], [right]) => left.localeCompare(right));
47
+ for (const [key, rawValue] of entries) {
48
+ const values = Array.isArray(rawValue) ? rawValue : [rawValue];
49
+ for (const value of values) {
50
+ if (value === undefined || value === null)
51
+ continue;
52
+ params.append(key, String(value));
53
+ }
54
+ }
55
+ }
56
+ const query = params.toString();
57
+ return query ? `?${query}` : "";
58
+ }
59
+ function buildNavigationUrl(to, options) {
60
+ return `${interpolatePath(to, options?.params)}${buildSearch(options?.search)}`;
61
+ }
15
62
  function createRouter(routes, initialUrl, options) {
16
63
  const ssrCtx = getSSRContext();
17
64
  const isSSR = ssrCtx !== undefined;
@@ -195,10 +242,11 @@ function createRouter(routes, initialUrl, options) {
195
242
  }
196
243
  }
197
244
  }
198
- async function navigate(navUrl, navOptions) {
245
+ async function navigate(input) {
246
+ const navUrl = buildNavigationUrl(input.to, input);
199
247
  const gen = ++navigateGen;
200
248
  const handle = startPrefetch(navUrl);
201
- if (navOptions?.replace) {
249
+ if (input.replace) {
202
250
  window.history.replaceState(null, "", navUrl);
203
251
  } else {
204
252
  window.history.pushState(null, "", navUrl);
@@ -150,6 +150,19 @@ type ClientAccessEvent = {
150
150
  type: "access:role_changed";
151
151
  } | {
152
152
  type: "access:plan_changed";
153
+ } | {
154
+ type: "access:plan_assigned";
155
+ planId: string;
156
+ } | {
157
+ type: "access:addon_attached";
158
+ addonId: string;
159
+ } | {
160
+ type: "access:addon_detached";
161
+ addonId: string;
162
+ } | {
163
+ type: "access:limit_reset";
164
+ entitlement: string;
165
+ max: number;
153
166
  };
154
167
  interface AccessEventClientOptions {
155
168
  /** WebSocket URL. Defaults to deriving from window.location. */
@@ -171,8 +171,16 @@ function handleAccessEvent(accessSet, event, flagEntitlementMap) {
171
171
  case "access:limit_updated":
172
172
  handleLimitUpdate(accessSet, current, event.entitlement, event.consumed, event.remaining, event.max);
173
173
  break;
174
+ case "access:plan_assigned":
175
+ handlePlanAssigned(accessSet, current, event.planId);
176
+ break;
177
+ case "access:limit_reset":
178
+ handleLimitReset(accessSet, current, event.entitlement, event.max);
179
+ break;
174
180
  case "access:role_changed":
175
181
  case "access:plan_changed":
182
+ case "access:addon_attached":
183
+ case "access:addon_detached":
176
184
  break;
177
185
  }
178
186
  }
@@ -200,6 +208,26 @@ function handleFlagToggle(accessSet, current, flag, enabled, flagEntitlementMap)
200
208
  }
201
209
  accessSet.value = { ...current, flags: newFlags, entitlements: newEntitlements };
202
210
  }
211
+ function handlePlanAssigned(accessSet, current, planId) {
212
+ accessSet.value = { ...current, plan: planId };
213
+ }
214
+ function handleLimitReset(accessSet, current, entitlement, max) {
215
+ const existingEntry = current.entitlements[entitlement];
216
+ if (!existingEntry)
217
+ return;
218
+ const newLimit = { max, consumed: 0, remaining: max };
219
+ const newEntitlements = { ...current.entitlements };
220
+ const reasons = existingEntry.reasons.filter((r) => r !== "limit_reached");
221
+ const wasOnlyLimitBlocked = existingEntry.reasons.length > 0 && existingEntry.reasons.every((r) => r === "limit_reached");
222
+ newEntitlements[entitlement] = {
223
+ ...existingEntry,
224
+ allowed: wasOnlyLimitBlocked ? true : existingEntry.allowed || reasons.length === 0,
225
+ reasons,
226
+ reason: reasons[0],
227
+ meta: { ...existingEntry.meta, limit: newLimit }
228
+ };
229
+ accessSet.value = { ...current, entitlements: newEntitlements };
230
+ }
203
231
  function handleLimitUpdate(accessSet, current, entitlement, consumed, remaining, max) {
204
232
  const existingEntry = current.entitlements[entitlement];
205
233
  if (!existingEntry)
@@ -6,7 +6,7 @@ import {
6
6
  globalCss,
7
7
  s,
8
8
  variants
9
- } from "../../shared/chunk-c9xxsrat.js";
9
+ } from "../../shared/chunk-1wby7nex.js";
10
10
  import"../../shared/chunk-j6qyxfdc.js";
11
11
  import"../../shared/chunk-prj7nm08.js";
12
12
  import"../../shared/chunk-h89w580h.js";
@@ -89,9 +89,11 @@ interface SdkMethodWithMeta<
89
89
  };
90
90
  }
91
91
  /** Reserved property names that cannot be used as field names on FormInstance. */
92
- type ReservedFormNames = "submitting" | "dirty" | "valid" | "action" | "method" | "onSubmit" | "reset" | "setFieldError" | "submit" | "__bindElement";
92
+ type ReservedFormNames = "submitting" | "dirty" | "valid" | "action" | "method" | "onSubmit" | "reset" | "setFieldError" | "submit" | "fields" | "__bindElement";
93
93
  /** Mapped type providing FieldState for each field in TBody. */
94
94
  type FieldAccessors<TBody> = { [K in keyof TBody] : FieldState<TBody[K]> };
95
+ /** Mapped type providing typed field name strings for compile-time input validation. */
96
+ type FieldNames<TBody> = { readonly [K in keyof TBody & string] : K };
95
97
  /** Base properties available on every form instance. */
96
98
  interface FormBaseProperties<TBody> {
97
99
  action: string;
@@ -103,6 +105,7 @@ interface FormBaseProperties<TBody> {
103
105
  submitting: Signal<boolean>;
104
106
  dirty: ReadonlySignal<boolean>;
105
107
  valid: ReadonlySignal<boolean>;
108
+ fields: FieldNames<TBody>;
106
109
  __bindElement: (el: HTMLFormElement) => void;
107
110
  }
108
111
  /**
@@ -164,4 +167,4 @@ interface FormDataOptions {
164
167
  * "true"/"false" become booleans.
165
168
  */
166
169
  declare function formDataToObject(formData: FormData, options?: FormDataOptions): Record<string, unknown>;
167
- export { validate, formDataToObject, form, createFieldState, ValidationResult, SdkMethodWithMeta, SdkMethod, FormSchema, FormOptions, FormInstance, FormDataOptions, FieldState };
170
+ export { validate, formDataToObject, form, createFieldState, ValidationResult, SdkMethodWithMeta, SdkMethod, FormSchema, FormOptions, FormInstance, FormDataOptions, FieldState, FieldNames };
@@ -3,7 +3,7 @@ import {
3
3
  form,
4
4
  formDataToObject,
5
5
  validate
6
- } from "../../shared/chunk-c30eg6wn.js";
6
+ } from "../../shared/chunk-5dbq8jp9.js";
7
7
  import"../../shared/chunk-8hsz5y4a.js";
8
8
  export {
9
9
  validate,
@@ -620,9 +620,11 @@ interface SdkMethodWithMeta<
620
620
  };
621
621
  }
622
622
  /** Reserved property names that cannot be used as field names on FormInstance. */
623
- type ReservedFormNames = "submitting" | "dirty" | "valid" | "action" | "method" | "onSubmit" | "reset" | "setFieldError" | "submit" | "__bindElement";
623
+ type ReservedFormNames = "submitting" | "dirty" | "valid" | "action" | "method" | "onSubmit" | "reset" | "setFieldError" | "submit" | "fields" | "__bindElement";
624
624
  /** Mapped type providing FieldState for each field in TBody. */
625
625
  type FieldAccessors<TBody> = { [K in keyof TBody] : FieldState<TBody[K]> };
626
+ /** Mapped type providing typed field name strings for compile-time input validation. */
627
+ type FieldNames<TBody> = { readonly [K in keyof TBody & string] : K };
626
628
  /** Base properties available on every form instance. */
627
629
  interface FormBaseProperties<TBody> {
628
630
  action: string;
@@ -634,6 +636,7 @@ interface FormBaseProperties<TBody> {
634
636
  submitting: Signal<boolean>;
635
637
  dirty: ReadonlySignal<boolean>;
636
638
  valid: ReadonlySignal<boolean>;
639
+ fields: FieldNames<TBody>;
637
640
  __bindElement: (el: HTMLFormElement) => void;
638
641
  }
639
642
  /**
@@ -915,6 +918,8 @@ type ExtractParams<T extends string> = [ExtractParamsFromSegments<WithoutWildcar
915
918
  * - Fallback: `string` → `string` (backward compat)
916
919
  */
917
920
  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;
921
+ /** Union of route pattern keys from a route map. */
922
+ type RoutePattern<TRouteMap extends Record<string, unknown>> = keyof TRouteMap & string;
918
923
  /**
919
924
  * Union of all valid URL shapes for a route map.
920
925
  * Maps each route pattern key through `PathWithParams` to produce the accepted URL shapes.
@@ -924,7 +929,7 @@ type PathWithParams<T extends string> = T extends `${infer Before}*` ? `${PathWi
924
929
  * RoutePaths<{ '/': ..., '/tasks/:id': ... }> = '/' | `/tasks/${string}`
925
930
  * ```
926
931
  */
927
- type RoutePaths<TRouteMap extends Record<string, unknown>> = { [K in keyof TRouteMap & string] : PathWithParams<K> }[keyof TRouteMap & string];
932
+ type RoutePaths<TRouteMap extends Record<string, unknown>> = { [K in RoutePattern<TRouteMap>] : PathWithParams<K> }[RoutePattern<TRouteMap>];
928
933
  /** Schema interface for parsing and validating values (search params, path params). */
929
934
  interface SearchParamSchema<T> {
930
935
  parse(data: unknown): {
@@ -1089,11 +1094,25 @@ interface LinkFactoryOptions {
1089
1094
  * @returns A Link component function
1090
1095
  */
1091
1096
  declare function createLink(currentPath: ReadonlySignal<string>, navigate: (url: string) => void, factoryOptions?: LinkFactoryOptions): (props: LinkProps) => HTMLAnchorElement;
1097
+ type NavigateSearchValue = string | number | boolean | null | undefined;
1098
+ type NavigateSearch = string | URLSearchParams | Record<string, NavigateSearchValue | readonly NavigateSearchValue[]>;
1092
1099
  /** Options for router.navigate(). */
1093
1100
  interface NavigateOptions {
1094
1101
  /** Use history.replaceState instead of pushState. */
1095
1102
  replace?: boolean;
1096
- }
1103
+ /** Route params used to interpolate dynamic segments in the route pattern. */
1104
+ params?: Record<string, string>;
1105
+ /** Search params appended to the final URL. */
1106
+ search?: NavigateSearch;
1107
+ }
1108
+ type NavigateOptionsFor<TPath extends string> = string extends TPath ? NavigateOptions : TPath extends `${string}:${string}` | `${string}*` ? Omit<NavigateOptions, "params"> & {
1109
+ params: ExtractParams<TPath>;
1110
+ } : Omit<NavigateOptions, "params"> & {
1111
+ params?: never;
1112
+ };
1113
+ type NavigateInput<TPath extends string = string> = {
1114
+ to: TPath;
1115
+ } & NavigateOptionsFor<TPath>;
1097
1116
  /** Handle returned by prefetchNavData for cancellation. */
1098
1117
  interface PrefetchHandle {
1099
1118
  abort: () => void;
@@ -1118,13 +1137,14 @@ interface RouterOptions {
1118
1137
  *
1119
1138
  * Generic over the route map `T`. Defaults to `RouteDefinitionMap` (string
1120
1139
  * index signature) for backward compatibility — unparameterized `Router`
1121
- * accepts any string in `navigate()`.
1140
+ * accepts any string in `navigate().to`.
1122
1141
  *
1123
1142
  * Method syntax on `navigate`, `revalidate`, and `dispose` enables bivariant
1124
1143
  * parameter checking under `strictFunctionTypes`. This means `Router<T>` is
1125
1144
  * assignable to `Router` (the unparameterized default), which is required for
1126
1145
  * storing typed routers in the `RouterContext` without contravariance errors.
1127
- * At call sites, TypeScript still enforces the `RoutePaths<T>` constraint.
1146
+ * At call sites, TypeScript still enforces the `RoutePattern<T>` constraint and
1147
+ * the params required for each route pattern.
1128
1148
  */
1129
1149
  interface Router<T extends Record<string, RouteConfigLike> = RouteDefinitionMap> {
1130
1150
  /** Current matched route (reactive signal). */
@@ -1135,8 +1155,8 @@ interface Router<T extends Record<string, RouteConfigLike> = RouteDefinitionMap>
1135
1155
  loaderError: Signal<Error | null>;
1136
1156
  /** Parsed search params from the current route (reactive signal). */
1137
1157
  searchParams: Signal<Record<string, unknown>>;
1138
- /** Navigate to a new URL path. */
1139
- navigate(url: RoutePaths<T>, options?: NavigateOptions): Promise<void>;
1158
+ /** Navigate to a route pattern, interpolating params and search into the final URL. */
1159
+ navigate<TPath extends RoutePattern<T>>(input: NavigateInput<TPath>): Promise<void>;
1140
1160
  /** Re-run all loaders for the current route. */
1141
1161
  revalidate(): Promise<void>;
1142
1162
  /** Remove popstate listener and clean up the router. */
@@ -1503,4 +1523,4 @@ declare function resetRelationSchemas_TEST_ONLY(): void;
1503
1523
  * ```
1504
1524
  */
1505
1525
  declare function createTestStore(data: Record<string, Record<string, unknown>>): EntityStore;
1506
- export { zoomOut, zoomIn, variants, validate, useSearchParams, useRouter, useParams, useDialogStack, useContext, untrack, slideOutToTop, slideOutToRight, slideOutToLeft, slideOutToBottom, slideInFromTop, slideInFromRight, slideInFromLeft, slideInFromBottom, signal, setAdapter, s, resolveChildren, resetRelationSchemas_TEST_ONLY, resetInjectedStyles, registerRelationSchema, ref, queryMatch, query, parseSearchParams, palettes, onMount2 as onMount, mount, keyframes, isRenderNode, isQueryDescriptor, invalidate, injectCSS, hydrate, globalCss, getRelationSchema, getQueryEnvelopeStore, getInjectedCSS, getEntityStore, getAdapter, formDataToObject, form, fadeOut, fadeIn, defineTheme, defineRoutes, css, createTestStore, createRouter, createOptimisticHandler, createLink, createFieldState, createDialogStack, createDOMAdapter, createContext, computed, compileTheme, children, batch, accordionUp, accordionDown, __staticText, __exitChildren, __enterChildren, __element, __append, VariantsConfig, VariantProps, VariantFunction, ValidationResult, UnwrapSignals, TypedRoutes, TypedRouter, ThemeProviderProps, ThemeProvider, ThemeInput, Theme, SuspenseProps, Suspense, StyleValue, StyleEntry, Signal, SerializedStore, SearchParamSchema, SdkMethodWithMeta, SdkMethod, RouterViewProps, RouterView, RouterOptions, RouterContext, Router, RoutePaths, RouteMatch, RouteDefinitionMap, RouteConfig, RenderText, RenderNode, RenderElement, RenderAdapter, RelationSchema, RelationFieldDef, Ref, ReadonlySignal, RawDeclaration, RENDER_NODE_BRAND, QueryResult, QueryOptions, QueryMatchHandlers, QueryEnvelopeStore, QueryEnvelope, QueryDescriptor3 as QueryDescriptor, PresenceProps, Presence, PathWithParams, ParamSchema, OutletContextValue, OutletContext, Outlet, NavigateOptions, MountOptions, MountHandle, MatchedRoute, LoaderData, ListTransitionProps, ListTransition, LinkProps, LinkFactoryOptions, InferRouteMap, GlobalCSSOutput, GlobalCSSInput, FormSchema, FormOptions, FormInstance, FormDataOptions, FieldState, ExtractParams, ErrorBoundaryProps, ErrorBoundary, EntityStoreOptions, EntityStore, DisposeFn, DisposalScopeError, DialogStackContext, DialogStack, DialogHandle, DialogDismissedError, DialogComponent, Context, Computed, ComponentRegistry, ComponentLoader, ComponentFunction, CompiledTheme, CompiledRoute, ColorPalette, ChildrenAccessor, ChildValue, CacheStore, CSSOutput, CSSInput, ANIMATION_EASING, ANIMATION_DURATION };
1526
+ export { zoomOut, zoomIn, variants, validate, useSearchParams, useRouter, useParams, useDialogStack, useContext, untrack, slideOutToTop, slideOutToRight, slideOutToLeft, slideOutToBottom, slideInFromTop, slideInFromRight, slideInFromLeft, slideInFromBottom, signal, setAdapter, s, resolveChildren, resetRelationSchemas_TEST_ONLY, resetInjectedStyles, registerRelationSchema, ref, queryMatch, query, parseSearchParams, palettes, onMount2 as onMount, mount, keyframes, isRenderNode, isQueryDescriptor, invalidate, injectCSS, hydrate, globalCss, getRelationSchema, getQueryEnvelopeStore, getInjectedCSS, getEntityStore, getAdapter, formDataToObject, form, fadeOut, fadeIn, defineTheme, defineRoutes, css, createTestStore, createRouter, createOptimisticHandler, createLink, createFieldState, createDialogStack, createDOMAdapter, createContext, computed, compileTheme, children, batch, accordionUp, accordionDown, __staticText, __exitChildren, __enterChildren, __element, __append, VariantsConfig, VariantProps, VariantFunction, ValidationResult, UnwrapSignals, TypedRoutes, TypedRouter, ThemeProviderProps, ThemeProvider, ThemeInput, Theme, SuspenseProps, Suspense, StyleValue, StyleEntry, Signal, SerializedStore, SearchParamSchema, SdkMethodWithMeta, SdkMethod, RouterViewProps, RouterView, RouterOptions, RouterContext, Router, RoutePattern, RoutePaths, RouteMatch, RouteDefinitionMap, RouteConfig, RenderText, RenderNode, RenderElement, RenderAdapter, RelationSchema, RelationFieldDef, Ref, ReadonlySignal, RawDeclaration, RENDER_NODE_BRAND, QueryResult, QueryOptions, QueryMatchHandlers, QueryEnvelopeStore, QueryEnvelope, QueryDescriptor3 as QueryDescriptor, PresenceProps, Presence, PathWithParams, ParamSchema, OutletContextValue, OutletContext, Outlet, NavigateOptions, NavigateInput, MountOptions, MountHandle, MatchedRoute, LoaderData, ListTransitionProps, ListTransition, LinkProps, LinkFactoryOptions, InferRouteMap, GlobalCSSOutput, GlobalCSSInput, FormSchema, FormOptions, FormInstance, FormDataOptions, FieldState, ExtractParams, ErrorBoundaryProps, ErrorBoundary, EntityStoreOptions, EntityStore, DisposeFn, DisposalScopeError, DialogStackContext, DialogStack, DialogHandle, DialogDismissedError, DialogComponent, Context, Computed, ComponentRegistry, ComponentLoader, ComponentFunction, CompiledTheme, CompiledRoute, ColorPalette, ChildrenAccessor, ChildValue, CacheStore, CSSOutput, CSSInput, ANIMATION_EASING, ANIMATION_DURATION };
package/dist/src/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  slideOutToTop,
21
21
  zoomIn,
22
22
  zoomOut
23
- } from "../shared/chunk-2sth83bd.js";
23
+ } from "../shared/chunk-4txc67nd.js";
24
24
  import {
25
25
  Outlet,
26
26
  OutletContext,
@@ -35,7 +35,7 @@ import {
35
35
  import"../shared/chunk-dksg08fq.js";
36
36
  import {
37
37
  createRouter
38
- } from "../shared/chunk-mj7b4t40.js";
38
+ } from "../shared/chunk-wymw818z.js";
39
39
  import {
40
40
  defineRoutes
41
41
  } from "../shared/chunk-83g4h38e.js";
@@ -44,7 +44,7 @@ import {
44
44
  form,
45
45
  formDataToObject,
46
46
  validate
47
- } from "../shared/chunk-c30eg6wn.js";
47
+ } from "../shared/chunk-5dbq8jp9.js";
48
48
  import {
49
49
  EntityStore,
50
50
  QueryEnvelopeStore,
@@ -72,7 +72,7 @@ import {
72
72
  resolveChildren,
73
73
  s,
74
74
  variants
75
- } from "../shared/chunk-c9xxsrat.js";
75
+ } from "../shared/chunk-1wby7nex.js";
76
76
  import {
77
77
  __append,
78
78
  __element,
@@ -2,7 +2,7 @@ import {
2
2
  deserializeProps,
3
3
  onAnimationsComplete,
4
4
  resolveComponent
5
- } from "../shared/chunk-2sth83bd.js";
5
+ } from "../shared/chunk-4txc67nd.js";
6
6
  import {
7
7
  __attr,
8
8
  __classList,
@@ -40,7 +40,7 @@ import {
40
40
  SIZE_KEYWORDS,
41
41
  SPACING_SCALE,
42
42
  compileTheme
43
- } from "../shared/chunk-c9xxsrat.js";
43
+ } from "../shared/chunk-1wby7nex.js";
44
44
  import {
45
45
  __append,
46
46
  __child,
@@ -34,6 +34,8 @@ type ExtractParams<T extends string> = [ExtractParamsFromSegments<WithoutWildcar
34
34
  * - Fallback: `string` → `string` (backward compat)
35
35
  */
36
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
+ /** Union of route pattern keys from a route map. */
38
+ type RoutePattern<TRouteMap extends Record<string, unknown>> = keyof TRouteMap & string;
37
39
  /**
38
40
  * Union of all valid URL shapes for a route map.
39
41
  * Maps each route pattern key through `PathWithParams` to produce the accepted URL shapes.
@@ -43,7 +45,7 @@ type PathWithParams<T extends string> = T extends `${infer Before}*` ? `${PathWi
43
45
  * RoutePaths<{ '/': ..., '/tasks/:id': ... }> = '/' | `/tasks/${string}`
44
46
  * ```
45
47
  */
46
- type RoutePaths<TRouteMap extends Record<string, unknown>> = { [K in keyof TRouteMap & string] : PathWithParams<K> }[keyof TRouteMap & string];
48
+ type RoutePaths<TRouteMap extends Record<string, unknown>> = { [K in RoutePattern<TRouteMap>] : PathWithParams<K> }[RoutePattern<TRouteMap>];
47
49
  /** Schema interface for parsing and validating values (search params, path params). */
48
50
  interface SearchParamSchema<T> {
49
51
  parse(data: unknown): {
@@ -251,11 +253,25 @@ interface LinkFactoryOptions {
251
253
  * @returns A Link component function
252
254
  */
253
255
  declare function createLink(currentPath: ReadonlySignal<string>, navigate: (url: string) => void, factoryOptions?: LinkFactoryOptions): (props: LinkProps) => HTMLAnchorElement;
256
+ type NavigateSearchValue = string | number | boolean | null | undefined;
257
+ type NavigateSearch = string | URLSearchParams | Record<string, NavigateSearchValue | readonly NavigateSearchValue[]>;
254
258
  /** Options for router.navigate(). */
255
259
  interface NavigateOptions {
256
260
  /** Use history.replaceState instead of pushState. */
257
261
  replace?: boolean;
262
+ /** Route params used to interpolate dynamic segments in the route pattern. */
263
+ params?: Record<string, string>;
264
+ /** Search params appended to the final URL. */
265
+ search?: NavigateSearch;
258
266
  }
267
+ type NavigateOptionsFor<TPath extends string> = string extends TPath ? NavigateOptions : TPath extends `${string}:${string}` | `${string}*` ? Omit<NavigateOptions, "params"> & {
268
+ params: ExtractParams<TPath>;
269
+ } : Omit<NavigateOptions, "params"> & {
270
+ params?: never;
271
+ };
272
+ type NavigateInput<TPath extends string = string> = {
273
+ to: TPath;
274
+ } & NavigateOptionsFor<TPath>;
259
275
  /** Handle returned by prefetchNavData for cancellation. */
260
276
  interface PrefetchHandle {
261
277
  abort: () => void;
@@ -280,13 +296,14 @@ interface RouterOptions {
280
296
  *
281
297
  * Generic over the route map `T`. Defaults to `RouteDefinitionMap` (string
282
298
  * index signature) for backward compatibility — unparameterized `Router`
283
- * accepts any string in `navigate()`.
299
+ * accepts any string in `navigate().to`.
284
300
  *
285
301
  * Method syntax on `navigate`, `revalidate`, and `dispose` enables bivariant
286
302
  * parameter checking under `strictFunctionTypes`. This means `Router<T>` is
287
303
  * assignable to `Router` (the unparameterized default), which is required for
288
304
  * storing typed routers in the `RouterContext` without contravariance errors.
289
- * At call sites, TypeScript still enforces the `RoutePaths<T>` constraint.
305
+ * At call sites, TypeScript still enforces the `RoutePattern<T>` constraint and
306
+ * the params required for each route pattern.
290
307
  */
291
308
  interface Router<T extends Record<string, RouteConfigLike> = RouteDefinitionMap> {
292
309
  /** Current matched route (reactive signal). */
@@ -297,8 +314,8 @@ interface Router<T extends Record<string, RouteConfigLike> = RouteDefinitionMap>
297
314
  loaderError: Signal<Error | null>;
298
315
  /** Parsed search params from the current route (reactive signal). */
299
316
  searchParams: Signal<Record<string, unknown>>;
300
- /** Navigate to a new URL path. */
301
- navigate(url: RoutePaths<T>, options?: NavigateOptions): Promise<void>;
317
+ /** Navigate to a route pattern, interpolating params and search into the final URL. */
318
+ navigate<TPath extends RoutePattern<T>>(input: NavigateInput<TPath>): Promise<void>;
302
319
  /** Re-run all loaders for the current route. */
303
320
  revalidate(): Promise<void>;
304
321
  /** Remove popstate listener and clean up the router. */
@@ -405,4 +422,4 @@ declare function parseSearchParams<T = Record<string, string>>(urlParams: URLSea
405
422
  * @returns The current search params value
406
423
  */
407
424
  declare function useSearchParams<T>(searchSignal: ReadonlySignal<T>): T;
408
- export { useSearchParams, useRouter, useParams, parseSearchParams, defineRoutes, createRouter, createLink, TypedRoutes, TypedRouter, SearchParamSchema, RouterViewProps, RouterView, RouterContext, Router, RoutePaths, RouteMatch, RouteDefinitionMap, RouteConfig, PathWithParams, ParamSchema, OutletContextValue, OutletContext, Outlet, NavigateOptions, MatchedRoute, LoaderData, LinkProps, InferRouteMap, ExtractParams, CompiledRoute };
425
+ export { useSearchParams, useRouter, useParams, parseSearchParams, defineRoutes, createRouter, createLink, TypedRoutes, TypedRouter, SearchParamSchema, RouterViewProps, RouterView, RouterContext, Router, RoutePattern, RoutePaths, RouteMatch, RouteDefinitionMap, RouteConfig, PathWithParams, ParamSchema, OutletContextValue, OutletContext, Outlet, NavigateOptions, NavigateInput, MatchedRoute, LoaderData, LinkProps, InferRouteMap, ExtractParams, CompiledRoute };
@@ -12,7 +12,7 @@ import {
12
12
  import"../../shared/chunk-dksg08fq.js";
13
13
  import {
14
14
  createRouter
15
- } from "../../shared/chunk-mj7b4t40.js";
15
+ } from "../../shared/chunk-wymw818z.js";
16
16
  import {
17
17
  defineRoutes
18
18
  } from "../../shared/chunk-83g4h38e.js";
@@ -138,25 +138,8 @@ type ExtractParams<T extends string> = [ExtractParamsFromSegments<WithoutWildcar
138
138
  } : Record<string, never> : HasWildcard<T> extends true ? { [K in ExtractParamsFromSegments<WithoutWildcard<T>>] : string } & {
139
139
  "*": string;
140
140
  } : { [K in ExtractParamsFromSegments<WithoutWildcard<T>>] : string };
141
- /**
142
- * Convert a route pattern to the union of URL shapes it accepts.
143
- * - Static: `'/'` → `'/'`
144
- * - Param: `'/tasks/:id'` → `` `/tasks/${string}` ``
145
- * - Wildcard: `'/files/*'` → `` `/files/${string}` ``
146
- * - Multi: `'/users/:id/posts/:postId'` → `` `/users/${string}/posts/${string}` ``
147
- * - Fallback: `string` → `string` (backward compat)
148
- */
149
- 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;
150
- /**
151
- * Union of all valid URL shapes for a route map.
152
- * Maps each route pattern key through `PathWithParams` to produce the accepted URL shapes.
153
- *
154
- * Example:
155
- * ```
156
- * RoutePaths<{ '/': ..., '/tasks/:id': ... }> = '/' | `/tasks/${string}`
157
- * ```
158
- */
159
- type RoutePaths<TRouteMap extends Record<string, unknown>> = { [K in keyof TRouteMap & string] : PathWithParams<K> }[keyof TRouteMap & string];
141
+ /** Union of route pattern keys from a route map. */
142
+ type RoutePattern<TRouteMap extends Record<string, unknown>> = keyof TRouteMap & string;
160
143
  /** Schema interface for parsing and validating values (search params, path params). */
161
144
  interface SearchParamSchema<T> {
162
145
  parse(data: unknown): {
@@ -273,23 +256,38 @@ interface Signal<T> {
273
256
  /** Manually notify all subscribers (useful after mutating the value in place). */
274
257
  notify(): void;
275
258
  }
259
+ type NavigateSearchValue = string | number | boolean | null | undefined;
260
+ type NavigateSearch = string | URLSearchParams | Record<string, NavigateSearchValue | readonly NavigateSearchValue[]>;
276
261
  /** Options for router.navigate(). */
277
262
  interface NavigateOptions {
278
263
  /** Use history.replaceState instead of pushState. */
279
264
  replace?: boolean;
265
+ /** Route params used to interpolate dynamic segments in the route pattern. */
266
+ params?: Record<string, string>;
267
+ /** Search params appended to the final URL. */
268
+ search?: NavigateSearch;
280
269
  }
270
+ type NavigateOptionsFor<TPath extends string> = string extends TPath ? NavigateOptions : TPath extends `${string}:${string}` | `${string}*` ? Omit<NavigateOptions, "params"> & {
271
+ params: ExtractParams<TPath>;
272
+ } : Omit<NavigateOptions, "params"> & {
273
+ params?: never;
274
+ };
275
+ type NavigateInput<TPath extends string = string> = {
276
+ to: TPath;
277
+ } & NavigateOptionsFor<TPath>;
281
278
  /**
282
279
  * The router instance returned by createRouter.
283
280
  *
284
281
  * Generic over the route map `T`. Defaults to `RouteDefinitionMap` (string
285
282
  * index signature) for backward compatibility — unparameterized `Router`
286
- * accepts any string in `navigate()`.
283
+ * accepts any string in `navigate().to`.
287
284
  *
288
285
  * Method syntax on `navigate`, `revalidate`, and `dispose` enables bivariant
289
286
  * parameter checking under `strictFunctionTypes`. This means `Router<T>` is
290
287
  * assignable to `Router` (the unparameterized default), which is required for
291
288
  * storing typed routers in the `RouterContext` without contravariance errors.
292
- * At call sites, TypeScript still enforces the `RoutePaths<T>` constraint.
289
+ * At call sites, TypeScript still enforces the `RoutePattern<T>` constraint and
290
+ * the params required for each route pattern.
293
291
  */
294
292
  interface Router<T extends Record<string, RouteConfigLike> = RouteDefinitionMap> {
295
293
  /** Current matched route (reactive signal). */
@@ -300,8 +298,8 @@ interface Router<T extends Record<string, RouteConfigLike> = RouteDefinitionMap>
300
298
  loaderError: Signal<Error | null>;
301
299
  /** Parsed search params from the current route (reactive signal). */
302
300
  searchParams: Signal<Record<string, unknown>>;
303
- /** Navigate to a new URL path. */
304
- navigate(url: RoutePaths<T>, options?: NavigateOptions): Promise<void>;
301
+ /** Navigate to a route pattern, interpolating params and search into the final URL. */
302
+ navigate<TPath extends RoutePattern<T>>(input: NavigateInput<TPath>): Promise<void>;
305
303
  /** Re-run all loaders for the current route. */
306
304
  revalidate(): Promise<void>;
307
305
  /** Remove popstate listener and clean up the router. */
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createRouter
3
- } from "../../shared/chunk-mj7b4t40.js";
3
+ } from "../../shared/chunk-wymw818z.js";
4
4
  import {
5
5
  defineRoutes
6
6
  } from "../../shared/chunk-83g4h38e.js";
@@ -199,7 +199,7 @@ async function createTestRouter(routes, opts) {
199
199
  container.setAttribute("data-testid", "test-router-container");
200
200
  await renderCurrentRoute(router, container);
201
201
  async function navigate(path) {
202
- await router.navigate(path);
202
+ await router.navigate({ to: path });
203
203
  await renderCurrentRoute(router, container);
204
204
  }
205
205
  return { component: container, navigate, router };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertz/ui",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Vertz UI framework — signals, components, JSX runtime",
@@ -69,11 +69,11 @@
69
69
  "typecheck": "tsc --noEmit"
70
70
  },
71
71
  "dependencies": {
72
- "@vertz/fetch": "^0.2.12"
72
+ "@vertz/fetch": "^0.2.14"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@happy-dom/global-registrator": "^20.7.0",
76
- "@vertz/schema": "^0.2.12",
76
+ "@vertz/schema": "^0.2.14",
77
77
  "bunup": "^0.16.31",
78
78
  "happy-dom": "^20.7.0",
79
79
  "typescript": "^5.7.0"