@vertz/ui 0.2.16 → 0.2.17

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.
@@ -39,4 +39,10 @@ function __classList(el, classMap) {
39
39
  };
40
40
  }
41
41
 
42
- export { __attr, __show, __classList };
42
+ // src/dom/events.ts
43
+ function __on(el, event, handler) {
44
+ el.addEventListener(event, handler);
45
+ return () => el.removeEventListener(event, handler);
46
+ }
47
+
48
+ export { __attr, __show, __classList, __on };
@@ -1,15 +1,7 @@
1
1
  import {
2
- __classList
3
- } from "./chunk-1rxa2fz4.js";
4
- import {
5
- RouterContext
6
- } from "./chunk-mtsvrj9e.js";
7
- import {
2
+ __classList,
8
3
  __on
9
- } from "./chunk-pnv25zep.js";
10
- import {
11
- isBrowser
12
- } from "./chunk-14eqne2a.js";
4
+ } from "./chunk-07bh4m1e.js";
13
5
  import {
14
6
  __append,
15
7
  __element,
@@ -18,6 +10,12 @@ import {
18
10
  __staticText,
19
11
  getIsHydrating
20
12
  } from "./chunk-vndfjfdy.js";
13
+ import {
14
+ RouterContext
15
+ } from "./chunk-mtsvrj9e.js";
16
+ import {
17
+ isBrowser
18
+ } from "./chunk-14eqne2a.js";
21
19
  import {
22
20
  _tryOnCleanup,
23
21
  createContext,
@@ -179,16 +179,6 @@ interface AccessEventClient {
179
179
  dispose(): void;
180
180
  }
181
181
  declare function createAccessEventClient(options: AccessEventClientOptions): AccessEventClient;
182
- interface AccessGateProps {
183
- fallback?: () => unknown;
184
- children: (() => unknown) | unknown;
185
- }
186
- /**
187
- * Gate component that blocks children while the access set is loading.
188
- * Use this to prevent flicker on initial render when access data
189
- * hasn't been hydrated yet.
190
- */
191
- declare function AccessGate({ fallback, children }: AccessGateProps): ReadonlySignal<unknown> | unknown;
192
182
  import { Result } from "@vertz/fetch";
193
183
  /**
194
184
  * Minimal schema interface compatible with @vertz/schema.
@@ -306,11 +296,6 @@ interface AuthProviderProps {
306
296
  children: (() => unknown) | unknown;
307
297
  }
308
298
  declare function AuthProvider({ basePath, accessControl, accessEvents, accessEventsUrl, flagEntitlementMap, children }: AuthProviderProps): HTMLElement;
309
- interface AuthGateProps {
310
- fallback?: () => unknown;
311
- children: (() => unknown) | unknown;
312
- }
313
- declare function AuthGate({ fallback, children }: AuthGateProps): ReadonlySignal<unknown> | unknown;
314
299
  /**
315
300
  * Create an AccessContextValue for use with AccessContext.Provider.
316
301
  * Hydrates from `window.__VERTZ_ACCESS_SET__` when available (SSR).
@@ -324,40 +309,24 @@ declare function AuthGate({ fallback, children }: AuthGateProps): ReadonlySignal
324
309
  * ```
325
310
  */
326
311
  declare function createAccessProvider(): AccessContextValue;
327
- interface OAuthButtonProps {
328
- /** Provider ID (e.g., 'github', 'google') */
329
- provider: string;
330
- /** Custom label text. Defaults to "Continue with {Name}". */
331
- label?: string;
332
- /** Render icon only, no text. */
333
- iconOnly?: boolean;
334
- /** @internal — injected providers array for testing. Uses useAuth() in production. */
335
- _providers?: OAuthProviderInfo[];
336
- }
337
- declare function OAuthButton({ provider, label, iconOnly, _providers }: OAuthButtonProps): Element;
338
- interface OAuthButtonsProps {
339
- /** @internal — injected providers array for testing. Uses useAuth() in production. */
340
- _providers?: OAuthProviderInfo[];
341
- }
342
- declare function OAuthButtons({ _providers }?: OAuthButtonsProps): HTMLDivElement;
343
- interface ProtectedRouteProps {
344
- /** Path to redirect to when unauthenticated. Default: '/login' */
345
- loginPath?: string;
346
- /** Rendered while auth is resolving (idle/loading). Default: null */
347
- fallback?: () => unknown;
348
- /** Rendered when authenticated */
349
- children: (() => unknown) | unknown;
350
- /** Optional: required entitlements (integrates with can()) */
351
- requires?: Entitlement[];
352
- /** Rendered when authenticated but lacking required entitlements. Default: null */
353
- forbidden?: () => unknown;
354
- /** Append ?returnTo=<currentPath> when redirecting. Default: true */
355
- returnTo?: boolean;
356
- }
357
- declare function ProtectedRoute({ loginPath, fallback, children, requires, forbidden, returnTo }: ProtectedRouteProps): ReadonlySignal<unknown> | unknown;
358
312
  /**
359
313
  * Get an SVG icon string for a provider.
360
314
  * Returns the built-in icon for known providers, or a generic fallback for unknown.
361
315
  */
362
316
  declare function getProviderIcon(providerId: string, size: number): string;
363
- export { useAuth, useAccessContext, getProviderIcon, createAccessProvider, createAccessEventClient, can, User, SignUpInput, SignOutOptions, SignInInput, ResetInput, ProtectedRouteProps, ProtectedRoute, OAuthProviderInfo, OAuthButtonsProps, OAuthButtons, OAuthButtonProps, OAuthButton, MfaInput, ForgotInput, EntitlementRegistry, Entitlement, DenialReason, DenialMeta, ClientAccessEvent, AuthStatus, AuthResponse, AuthProviderProps, AuthProvider, AuthGateProps, AuthGate, AuthErrorCode, AuthContextValue, AuthContext, AuthClientError, AccessSet, AccessGateProps, AccessGate, AccessEventClientOptions, AccessEventClient, AccessContextValue, AccessContext, AccessCheckData, AccessCheck };
317
+ /**
318
+ * Get a display name for a user with a fallback chain.
319
+ * Chain: user.name (if string & non-empty) → user.email → fallback (default: 'Unknown')
320
+ */
321
+ declare function getUserDisplayName(user: User | null | undefined, fallback?: string): string;
322
+ /**
323
+ * Get initials from a user's name or email (max 2 characters).
324
+ * Chain: first + last word initials from name → first char of email → '?'
325
+ */
326
+ declare function getUserInitials(user: User | null | undefined): string;
327
+ /**
328
+ * Default user silhouette icon for avatar fallbacks.
329
+ * Returns an inline SVG string — no external requests, works in SSR.
330
+ */
331
+ declare function getUserIcon(size: number): string;
332
+ export { useAuth, useAccessContext, getUserInitials, getUserIcon, getUserDisplayName, getProviderIcon, createAccessProvider, createAccessEventClient, can, User, SignUpInput, SignOutOptions, SignInInput, ResetInput, OAuthProviderInfo, MfaInput, ForgotInput, EntitlementRegistry, Entitlement, DenialReason, DenialMeta, ClientAccessEvent, AuthStatus, AuthResponse, AuthProviderProps, AuthProvider, AuthErrorCode, AuthContextValue, AuthContext, AuthClientError, AccessSet, AccessEventClientOptions, AccessEventClient, AccessContextValue, AccessContext, AccessCheckData, AccessCheck };
@@ -1,26 +1,14 @@
1
1
  import {
2
2
  RouterContext
3
3
  } from "../../shared/chunk-mtsvrj9e.js";
4
- import {
5
- __on
6
- } from "../../shared/chunk-pnv25zep.js";
7
4
  import {
8
5
  isBrowser
9
6
  } from "../../shared/chunk-14eqne2a.js";
10
- import {
11
- __append,
12
- __element,
13
- __enterChildren,
14
- __exitChildren,
15
- __staticText
16
- } from "../../shared/chunk-vndfjfdy.js";
17
- import"../../shared/chunk-prj7nm08.js";
18
- import"../../shared/chunk-afawz764.js";
19
7
  import {
20
8
  _tryOnCleanup,
21
9
  computed,
22
10
  createContext,
23
- domEffect,
11
+ getSSRContext,
24
12
  signal,
25
13
  useContext
26
14
  } from "../../shared/chunk-4fwcwxn6.js";
@@ -158,26 +146,6 @@ function createAccessEventClient(options) {
158
146
  }
159
147
  return { connect, disconnect, dispose };
160
148
  }
161
- // src/auth/access-gate.ts
162
- function AccessGate({
163
- fallback,
164
- children
165
- }) {
166
- const ctx = useContext(AccessContext);
167
- if (!ctx) {
168
- return typeof children === "function" ? children() : children;
169
- }
170
- const isLoaded = computed(() => {
171
- const set = ctx.accessSet;
172
- return set !== null;
173
- });
174
- return computed(() => {
175
- if (isLoaded.value) {
176
- return typeof children === "function" ? children() : children;
177
- }
178
- return fallback ? fallback() : null;
179
- });
180
- }
181
149
  // src/auth/access-event-handler.ts
182
150
  function handleAccessEvent(accessSet, event, flagEntitlementMap) {
183
151
  const current = accessSet.value;
@@ -791,6 +759,16 @@ function AuthProvider({
791
759
  refresh();
792
760
  }, 0);
793
761
  }
762
+ } else {
763
+ const ssrCtx = getSSRContext();
764
+ if (ssrCtx?.ssrAuth) {
765
+ if (ssrCtx.ssrAuth.status === "authenticated") {
766
+ userSignal.value = ssrCtx.ssrAuth.user;
767
+ statusSignal.value = "authenticated";
768
+ } else {
769
+ statusSignal.value = "unauthenticated";
770
+ }
771
+ }
794
772
  }
795
773
  if (accessControl && accessSetSignal && accessLoadingSignal) {
796
774
  if (isBrowser() && window.__VERTZ_ACCESS_SET__ && typeof window.__VERTZ_ACCESS_SET__.entitlements === "object" && window.__VERTZ_ACCESS_SET__.entitlements !== null) {
@@ -808,23 +786,6 @@ function AuthProvider({
808
786
  }
809
787
  return AuthContext.Provider({ value: contextValue, children });
810
788
  }
811
- // src/auth/auth-gate.ts
812
- function AuthGate({ fallback, children }) {
813
- const ctx = useContext(AuthContext);
814
- if (!ctx) {
815
- return typeof children === "function" ? children() : children;
816
- }
817
- const isResolved = computed(() => {
818
- const status = ctx.status;
819
- return status !== "idle" && status !== "loading";
820
- });
821
- return computed(() => {
822
- if (isResolved.value) {
823
- return typeof children === "function" ? children() : children;
824
- }
825
- return fallback ? fallback() : null;
826
- });
827
- }
828
789
  // src/auth/create-access-provider.ts
829
790
  function createAccessProvider() {
830
791
  const accessSet = signal(null);
@@ -851,127 +812,48 @@ function getProviderIcon(providerId, size) {
851
812
  const iconFn = icons[providerId];
852
813
  return iconFn ? iconFn(size) : fallbackIcon(size);
853
814
  }
854
-
855
- // src/auth/oauth-button.ts
856
- var DANGEROUS_SCHEMES = ["javascript:", "data:", "vbscript:"];
857
- function isSafeUrl(url) {
858
- const normalized = url.replace(/\s/g, "").toLowerCase();
859
- if (normalized.startsWith("//"))
860
- return false;
861
- for (const scheme of DANGEROUS_SCHEMES) {
862
- if (normalized.startsWith(scheme))
863
- return false;
864
- }
865
- return true;
815
+ // src/auth/user-display.ts
816
+ function getUserDisplayName(user, fallback = "Unknown") {
817
+ if (!user)
818
+ return fallback;
819
+ const name = user.name;
820
+ if (typeof name === "string" && name.trim().length > 0)
821
+ return name.trim();
822
+ if (user.email)
823
+ return user.email;
824
+ return fallback;
866
825
  }
867
- function OAuthButton({ provider, label, iconOnly, _providers }) {
868
- const providers = _providers ?? useAuth().providers;
869
- const providerInfo = providers.find((p) => p.id === provider);
870
- if (!providerInfo) {
871
- return __element("span");
872
- }
873
- const safeAuthUrl = isSafeUrl(providerInfo.authUrl) ? providerInfo.authUrl : "#";
874
- const props = { type: "button" };
875
- if (iconOnly) {
876
- props["aria-label"] = `Continue with ${providerInfo.name}`;
877
- }
878
- const el = __element("button", props);
879
- __on(el, "click", () => {
880
- window.location.href = safeAuthUrl;
881
- });
882
- __enterChildren(el);
883
- const iconSpan = __element("span");
884
- iconSpan.innerHTML = getProviderIcon(provider, 20);
885
- __append(el, iconSpan);
886
- if (!iconOnly) {
887
- const text = label ?? `Continue with ${providerInfo.name}`;
888
- const textSpan = __element("span");
889
- __enterChildren(textSpan);
890
- __append(textSpan, __staticText(text));
891
- __exitChildren();
892
- __append(el, textSpan);
893
- }
894
- __exitChildren();
895
- return el;
896
- }
897
- // src/auth/oauth-buttons.ts
898
- function OAuthButtons({ _providers } = {}) {
899
- const providers = _providers ?? useAuth().providers;
900
- const container = __element("div");
901
- __enterChildren(container);
902
- for (const provider of providers) {
903
- const button = OAuthButton({
904
- provider: provider.id,
905
- _providers: providers
906
- });
907
- __append(container, button);
908
- }
909
- __exitChildren();
910
- return container;
826
+ function getUserInitials(user) {
827
+ if (!user)
828
+ return "?";
829
+ const name = user.name;
830
+ if (typeof name === "string" && name.trim().length > 0) {
831
+ const words = name.trim().split(/\s+/);
832
+ const first = words[0] ?? "";
833
+ const last = words[words.length - 1] ?? "";
834
+ if (words.length === 1 || !last)
835
+ return first.charAt(0).toUpperCase() || "?";
836
+ return (first.charAt(0) + last.charAt(0)).toUpperCase();
837
+ }
838
+ if (user.email && user.email.length > 0)
839
+ return user.email.charAt(0).toUpperCase();
840
+ return "?";
911
841
  }
912
- // src/auth/protected-route.ts
913
- var __DEV__2 = typeof process !== "undefined" && true;
914
- function ProtectedRoute({
915
- loginPath = "/login",
916
- fallback,
917
- children,
918
- requires,
919
- forbidden,
920
- returnTo = true
921
- }) {
922
- const ctx = useContext(AuthContext);
923
- if (!ctx) {
924
- if (__DEV__2) {
925
- console.warn("ProtectedRoute used without AuthProvider — rendering children unprotected");
926
- }
927
- return typeof children === "function" ? children() : children;
928
- }
929
- const router = useContext(RouterContext);
930
- const checks = requires?.map((e) => can(e));
931
- const allAllowed = computed(() => !checks || checks.every((c) => c.allowed.value));
932
- const isResolved = computed(() => {
933
- const status = ctx.status;
934
- return status !== "idle" && status !== "loading";
935
- });
936
- const shouldRedirect = computed(() => {
937
- if (!isResolved.value)
938
- return false;
939
- return !ctx.isAuthenticated;
940
- });
941
- if (router) {
942
- domEffect(() => {
943
- if (shouldRedirect.value) {
944
- const search = returnTo && isBrowser() ? `?returnTo=${encodeURIComponent(window.location.pathname + window.location.search)}` : "";
945
- router.navigate({ to: `${loginPath}${search}`, replace: true });
946
- }
947
- });
948
- }
949
- return computed(() => {
950
- if (!isResolved.value) {
951
- return fallback ? fallback() : null;
952
- }
953
- if (shouldRedirect.value) {
954
- return fallback ? fallback() : null;
955
- }
956
- if (!allAllowed.value) {
957
- return forbidden ? forbidden() : null;
958
- }
959
- return typeof children === "function" ? children() : children;
960
- });
842
+ // src/auth/user-icon.ts
843
+ function getUserIcon(size) {
844
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>`;
961
845
  }
962
846
  export {
963
847
  useAuth,
964
848
  useAccessContext,
849
+ getUserInitials,
850
+ getUserIcon,
851
+ getUserDisplayName,
965
852
  getProviderIcon,
966
853
  createAccessProvider,
967
854
  createAccessEventClient,
968
855
  can,
969
- ProtectedRoute,
970
- OAuthButtons,
971
- OAuthButton,
972
856
  AuthProvider,
973
- AuthGate,
974
857
  AuthContext,
975
- AccessGate,
976
858
  AccessContext
977
859
  };
package/dist/src/index.js CHANGED
@@ -30,8 +30,8 @@ import {
30
30
  createLink,
31
31
  parseSearchParams,
32
32
  useSearchParams
33
- } from "../shared/chunk-b0qqqk03.js";
34
- import"../shared/chunk-1rxa2fz4.js";
33
+ } from "../shared/chunk-2wtb9x81.js";
34
+ import"../shared/chunk-07bh4m1e.js";
35
35
  import {
36
36
  createRouter
37
37
  } from "../shared/chunk-fkbgbf3n.js";
@@ -57,7 +57,7 @@ import {
57
57
  queryMatch,
58
58
  registerRelationSchema,
59
59
  resetRelationSchemas_TEST_ONLY
60
- } from "../shared/chunk-4mtn7af6.js";
60
+ } from "../shared/chunk-fs3eec4b.js";
61
61
  import"../shared/chunk-jrtrk5z4.js";
62
62
  import {
63
63
  ThemeProvider,
@@ -75,15 +75,6 @@ import {
75
75
  s,
76
76
  variants
77
77
  } from "../shared/chunk-dhehvmj0.js";
78
- import {
79
- RouterContext,
80
- useParams,
81
- useRouter
82
- } from "../shared/chunk-mtsvrj9e.js";
83
- import"../shared/chunk-pnv25zep.js";
84
- import {
85
- isBrowser
86
- } from "../shared/chunk-14eqne2a.js";
87
78
  import {
88
79
  __append,
89
80
  __element,
@@ -105,6 +96,14 @@ import {
105
96
  isRenderNode,
106
97
  setAdapter
107
98
  } from "../shared/chunk-afawz764.js";
99
+ import {
100
+ RouterContext,
101
+ useParams,
102
+ useRouter
103
+ } from "../shared/chunk-mtsvrj9e.js";
104
+ import {
105
+ isBrowser
106
+ } from "../shared/chunk-14eqne2a.js";
108
107
  import {
109
108
  DisposalScopeError,
110
109
  _tryOnCleanup,
@@ -969,7 +969,34 @@ interface SSRRenderContext {
969
969
  * Used by the build pipeline to discover which routes to pre-render.
970
970
  */
971
971
  discoveredRoutes?: string[];
972
+ /**
973
+ * Auth state resolved by the server (e.g. from session cookie).
974
+ * Set by ssrRenderToString() before Pass 1 so AuthProvider can
975
+ * hydrate status/user synchronously during SSR.
976
+ */
977
+ ssrAuth?: SSRAuth;
978
+ /**
979
+ * Written by ProtectedRoute during Pass 1 when the user is not
980
+ * authenticated. Signals ssrRenderToString() to skip Pass 2 and
981
+ * return a redirect response instead.
982
+ */
983
+ ssrRedirect?: {
984
+ to: string;
985
+ };
972
986
  }
987
+ /** Auth state injected into SSRRenderContext by the server. */
988
+ type SSRAuth = {
989
+ status: "authenticated";
990
+ user: {
991
+ id: string;
992
+ email: string;
993
+ role: string;
994
+ [key: string]: unknown;
995
+ };
996
+ expiresAt: number;
997
+ } | {
998
+ status: "unauthenticated";
999
+ };
973
1000
  type SSRContextResolver = () => SSRRenderContext | undefined;
974
1001
  declare function registerSSRResolver(resolver: SSRContextResolver | null): void;
975
1002
  declare function getSSRContext(): SSRRenderContext | undefined;
@@ -983,4 +1010,4 @@ declare function getSSRContext(): SSRRenderContext | undefined;
983
1010
  * clears during HMR module re-evaluation.
984
1011
  */
985
1012
  declare function hasSSRResolver(): boolean;
986
- export { stopSignalCollection, startSignalCollection, setContextScope, setAdapter, runCleanups, resolveComponent, removeNode, registerSSRResolver, pushScope, popScope, onCleanup, onAnimationsComplete, matchRoute, matchPath, lifecycleEffect, isRenderNode, isBrowser, insertBefore, hasSSRResolver, getSSRContext, getContextScope, getAdapter, executeLoaders, domEffect, deserializeProps, deriveKey, createDOMAdapter, compileTheme, clearChildren, _tryOnCleanup, __text, __staticText, __show, __on, __list, __insert, __exitChildren, __enterChildren, __element, __conditional, __classList, __child, __attr, __append, SSRRenderContext, SSRQueryEntry, SPACING_SCALE, SIZE_KEYWORDS, SHADOW_SCALE, RenderText, RenderNode, RenderElement, RenderAdapter, RENDER_NODE_BRAND, RADIUS_SCALE, QueryEnvelopeStore, PropertyMapping, PSEUDO_PREFIXES, PSEUDO_MAP, PROPERTY_MAP, MemoryCache, MatchResult, LINE_HEIGHT_SCALE, KEYWORD_MAP, HEIGHT_AXIS_PROPERTIES, FONT_WEIGHT_SCALE, FONT_SIZE_SCALE, EntityStore, DISPLAY_MAP, CSS_COLOR_KEYWORDS, CSSDeclarationEntry, CONTENT_MAP, COLOR_NAMESPACES, ALIGNMENT_MAP };
1013
+ export { stopSignalCollection, startSignalCollection, setContextScope, setAdapter, runCleanups, resolveComponent, removeNode, registerSSRResolver, pushScope, popScope, onCleanup, onAnimationsComplete, matchRoute, matchPath, lifecycleEffect, isRenderNode, isBrowser, insertBefore, hasSSRResolver, getSSRContext, getContextScope, getAdapter, executeLoaders, domEffect, deserializeProps, deriveKey, createDOMAdapter, compileTheme, clearChildren, _tryOnCleanup, __text, __staticText, __show, __on, __list, __insert, __exitChildren, __enterChildren, __element, __conditional, __classList, __child, __attr, __append, SSRRenderContext, SSRQueryEntry, SSRAuth, SPACING_SCALE, SIZE_KEYWORDS, SHADOW_SCALE, RenderText, RenderNode, RenderElement, RenderAdapter, RENDER_NODE_BRAND, RADIUS_SCALE, QueryEnvelopeStore, PropertyMapping, PSEUDO_PREFIXES, PSEUDO_MAP, PROPERTY_MAP, MemoryCache, MatchResult, LINE_HEIGHT_SCALE, KEYWORD_MAP, HEIGHT_AXIS_PROPERTIES, FONT_WEIGHT_SCALE, FONT_SIZE_SCALE, EntityStore, DISPLAY_MAP, CSS_COLOR_KEYWORDS, CSSDeclarationEntry, CONTENT_MAP, COLOR_NAMESPACES, ALIGNMENT_MAP };
@@ -6,8 +6,9 @@ import {
6
6
  import {
7
7
  __attr,
8
8
  __classList,
9
+ __on,
9
10
  __show
10
- } from "../shared/chunk-1rxa2fz4.js";
11
+ } from "../shared/chunk-07bh4m1e.js";
11
12
  import {
12
13
  executeLoaders,
13
14
  matchPath,
@@ -18,7 +19,7 @@ import {
18
19
  MemoryCache,
19
20
  QueryEnvelopeStore,
20
21
  deriveKey
21
- } from "../shared/chunk-4mtn7af6.js";
22
+ } from "../shared/chunk-fs3eec4b.js";
22
23
  import"../shared/chunk-jrtrk5z4.js";
23
24
  import {
24
25
  ALIGNMENT_MAP,
@@ -40,12 +41,6 @@ import {
40
41
  SPACING_SCALE,
41
42
  compileTheme
42
43
  } from "../shared/chunk-dhehvmj0.js";
43
- import {
44
- __on
45
- } from "../shared/chunk-pnv25zep.js";
46
- import {
47
- isBrowser
48
- } from "../shared/chunk-14eqne2a.js";
49
44
  import {
50
45
  __append,
51
46
  __child,
@@ -67,6 +62,9 @@ import {
67
62
  isRenderNode,
68
63
  setAdapter
69
64
  } from "../shared/chunk-afawz764.js";
65
+ import {
66
+ isBrowser
67
+ } from "../shared/chunk-14eqne2a.js";
70
68
  import {
71
69
  _tryOnCleanup,
72
70
  domEffect,
@@ -1,3 +1,7 @@
1
+ /** A ref container for DOM element access. */
2
+ interface Ref<T> {
3
+ current: T | undefined;
4
+ }
1
5
  /**
2
6
  * JSX namespace - required for TypeScript's react-jsx mode
3
7
  * to understand intrinsic element types and component types.
@@ -11,6 +15,7 @@ declare namespace JSX {
11
15
  }
12
16
  interface IntrinsicAttributes {
13
17
  key?: string | number;
18
+ ref?: Ref<unknown> | ((el: Element) => void);
14
19
  }
15
20
  interface IntrinsicElements {
16
21
  [key: string]: HTMLAttributes | undefined;
@@ -26,7 +26,7 @@ function jsxImpl(tag, props) {
26
26
  if (typeof tag === "function") {
27
27
  return tag(props || {});
28
28
  }
29
- const { children, ...attrs } = props || {};
29
+ const { children, ref: refProp, ...attrs } = props || {};
30
30
  const svg = isSVGTag(tag);
31
31
  const element = svg ? document.createElementNS(SVG_NS, tag) : document.createElement(tag);
32
32
  for (const [key, value] of Object.entries(attrs)) {
@@ -45,6 +45,13 @@ function jsxImpl(tag, props) {
45
45
  }
46
46
  }
47
47
  applyChildren(element, children);
48
+ if (refProp != null) {
49
+ if (typeof refProp === "function") {
50
+ refProp(element);
51
+ } else if (typeof refProp === "object" && "current" in refProp) {
52
+ refProp.current = element;
53
+ }
54
+ }
48
55
  return element;
49
56
  }
50
57
  function jsx(tag, props) {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  query,
3
3
  queryMatch
4
- } from "../../shared/chunk-4mtn7af6.js";
4
+ } from "../../shared/chunk-fs3eec4b.js";
5
5
  import"../../shared/chunk-jrtrk5z4.js";
6
- import"../../shared/chunk-14eqne2a.js";
7
6
  import"../../shared/chunk-afawz764.js";
7
+ import"../../shared/chunk-14eqne2a.js";
8
8
  import"../../shared/chunk-4fwcwxn6.js";
9
9
 
10
10
  // src/query/public.ts
@@ -6,8 +6,8 @@ import {
6
6
  createLink,
7
7
  parseSearchParams,
8
8
  useSearchParams
9
- } from "../../shared/chunk-b0qqqk03.js";
10
- import"../../shared/chunk-1rxa2fz4.js";
9
+ } from "../../shared/chunk-2wtb9x81.js";
10
+ import"../../shared/chunk-07bh4m1e.js";
11
11
  import {
12
12
  createRouter
13
13
  } from "../../shared/chunk-fkbgbf3n.js";
@@ -15,16 +15,15 @@ import {
15
15
  defineRoutes
16
16
  } from "../../shared/chunk-6wd36w21.js";
17
17
  import"../../shared/chunk-jrtrk5z4.js";
18
+ import"../../shared/chunk-vndfjfdy.js";
19
+ import"../../shared/chunk-prj7nm08.js";
20
+ import"../../shared/chunk-afawz764.js";
18
21
  import {
19
22
  RouterContext,
20
23
  useParams,
21
24
  useRouter
22
25
  } from "../../shared/chunk-mtsvrj9e.js";
23
- import"../../shared/chunk-pnv25zep.js";
24
26
  import"../../shared/chunk-14eqne2a.js";
25
- import"../../shared/chunk-vndfjfdy.js";
26
- import"../../shared/chunk-prj7nm08.js";
27
- import"../../shared/chunk-afawz764.js";
28
27
  import"../../shared/chunk-4fwcwxn6.js";
29
28
  export {
30
29
  useSearchParams,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertz/ui",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
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.15"
72
+ "@vertz/fetch": "^0.2.16"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@happy-dom/global-registrator": "^20.7.0",
76
- "@vertz/schema": "^0.2.15",
76
+ "@vertz/schema": "^0.2.16",
77
77
  "bunup": "^0.16.31",
78
78
  "happy-dom": "^20.7.0",
79
79
  "typescript": "^5.7.0"
@@ -1,7 +0,0 @@
1
- // src/dom/events.ts
2
- function __on(el, event, handler) {
3
- el.addEventListener(event, handler);
4
- return () => el.removeEventListener(event, handler);
5
- }
6
-
7
- export { __on };
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  isNavPrefetchActive
3
3
  } from "./chunk-jrtrk5z4.js";
4
- import {
5
- isBrowser
6
- } from "./chunk-14eqne2a.js";
7
4
  import {
8
5
  getAdapter,
9
6
  isRenderNode
10
7
  } from "./chunk-afawz764.js";
8
+ import {
9
+ isBrowser
10
+ } from "./chunk-14eqne2a.js";
11
11
  import {
12
12
  _tryOnCleanup,
13
13
  batch,