@vertz/ui 0.2.0 → 0.2.1

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 (35) 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 +696 -167
  7. package/dist/index.js +461 -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 +62 -7
  13. package/dist/query/public.js +12 -4
  14. package/dist/router/public.d.ts +186 -26
  15. package/dist/router/public.js +22 -7
  16. package/dist/shared/{chunk-f1ynwam4.js → chunk-0p5f7gmg.js} +155 -32
  17. package/dist/shared/{chunk-j8vzvne3.js → chunk-9e92w0wt.js} +4 -1
  18. package/dist/shared/{chunk-xd9d7q5p.js → chunk-cq7xg4xe.js} +59 -10
  19. package/dist/shared/chunk-g4rch80a.js +33 -0
  20. package/dist/shared/{chunk-pgymxpn1.js → chunk-hrd0mft1.js} +136 -34
  21. package/dist/shared/chunk-nmjyj8p9.js +290 -0
  22. package/dist/shared/chunk-pp3a6xbn.js +483 -0
  23. package/dist/shared/chunk-prj7nm08.js +67 -0
  24. package/dist/shared/chunk-q6cpe5k7.js +230 -0
  25. package/dist/shared/chunk-ryb49346.js +374 -0
  26. package/dist/shared/chunk-v3yyf79g.js +48 -0
  27. package/dist/shared/chunk-vx0kzack.js +103 -0
  28. package/dist/shared/chunk-wv6kkj1w.js +464 -0
  29. package/dist/test/index.d.ts +67 -6
  30. package/dist/test/index.js +4 -3
  31. package/package.json +13 -8
  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-zbbvx05f.js +0 -202
@@ -1,3 +1,44 @@
1
+ import {
2
+ __append,
3
+ __element,
4
+ __enterChildren,
5
+ __exitChildren
6
+ } from "./chunk-ryb49346.js";
7
+
8
+ // src/component/children.ts
9
+ var MAX_RESOLVE_DEPTH = 100;
10
+ function resolveChildren(value, _depth = 0) {
11
+ if (value == null) {
12
+ return [];
13
+ }
14
+ if (typeof value === "function") {
15
+ if (_depth >= MAX_RESOLVE_DEPTH) {
16
+ throw new Error("resolveChildren: max recursion depth exceeded — possible circular thunk");
17
+ }
18
+ return resolveChildren(value(), _depth + 1);
19
+ }
20
+ if (typeof value === "string") {
21
+ return [document.createTextNode(value)];
22
+ }
23
+ if (typeof value === "number") {
24
+ return [document.createTextNode(String(value))];
25
+ }
26
+ if (Array.isArray(value)) {
27
+ const result = [];
28
+ for (const child of value) {
29
+ const resolved = resolveChildren(child, _depth);
30
+ for (const node of resolved) {
31
+ result.push(node);
32
+ }
33
+ }
34
+ return result;
35
+ }
36
+ return [value];
37
+ }
38
+ function children(accessor) {
39
+ return () => resolveChildren(accessor());
40
+ }
41
+
1
42
  // src/css/token-tables.ts
2
43
  var PROPERTY_MAP = {
3
44
  p: { properties: ["padding"], valueType: "spacing" },
@@ -37,6 +78,7 @@ var PROPERTY_MAP = {
37
78
  weight: { properties: ["font-weight"], valueType: "font-weight" },
38
79
  leading: { properties: ["line-height"], valueType: "line-height" },
39
80
  tracking: { properties: ["letter-spacing"], valueType: "raw" },
81
+ decoration: { properties: ["text-decoration"], valueType: "raw" },
40
82
  ring: { properties: ["outline"], valueType: "ring" },
41
83
  cursor: { properties: ["cursor"], valueType: "raw" },
42
84
  transition: { properties: ["transition"], valueType: "raw" },
@@ -65,7 +107,12 @@ var KEYWORD_MAP = {
65
107
  uppercase: [{ property: "text-transform", value: "uppercase" }],
66
108
  lowercase: [{ property: "text-transform", value: "lowercase" }],
67
109
  capitalize: [{ property: "text-transform", value: "capitalize" }],
68
- "outline-none": [{ property: "outline", value: "none" }]
110
+ "outline-none": [{ property: "outline", value: "none" }],
111
+ "overflow-hidden": [{ property: "overflow", value: "hidden" }],
112
+ "select-none": [{ property: "user-select", value: "none" }],
113
+ "pointer-events-none": [{ property: "pointer-events", value: "none" }],
114
+ "whitespace-nowrap": [{ property: "white-space", value: "nowrap" }],
115
+ "shrink-0": [{ property: "flex-shrink", value: "0" }]
69
116
  };
70
117
  var DISPLAY_MAP = {
71
118
  flex: "flex",
@@ -114,7 +161,8 @@ var SPACING_SCALE = {
114
161
  };
115
162
  var RADIUS_SCALE = {
116
163
  none: "0",
117
- sm: "0.125rem",
164
+ xs: "0.125rem",
165
+ sm: "0.25rem",
118
166
  md: "0.375rem",
119
167
  lg: "0.5rem",
120
168
  xl: "0.75rem",
@@ -123,6 +171,7 @@ var RADIUS_SCALE = {
123
171
  full: "9999px"
124
172
  };
125
173
  var SHADOW_SCALE = {
174
+ xs: "0 1px 1px 0 rgb(0 0 0 / 0.03)",
126
175
  sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
127
176
  md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
128
177
  lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
@@ -209,7 +258,14 @@ var COLOR_NAMESPACES = new Set([
209
258
  "input",
210
259
  "card",
211
260
  "popover",
212
- "gray"
261
+ "gray",
262
+ "primary-foreground",
263
+ "secondary-foreground",
264
+ "accent-foreground",
265
+ "destructive-foreground",
266
+ "muted-foreground",
267
+ "card-foreground",
268
+ "popover-foreground"
213
269
  ]);
214
270
  var CSS_COLOR_KEYWORDS = new Set([
215
271
  "transparent",
@@ -244,8 +300,8 @@ var PSEUDO_MAP = {
244
300
  };
245
301
 
246
302
  // src/css/class-generator.ts
247
- function generateClassName(filePath, blockName) {
248
- const input = `${filePath}::${blockName}`;
303
+ function generateClassName(filePath, blockName, styleFingerprint = "") {
304
+ const input = styleFingerprint ? `${filePath}::${blockName}::${styleFingerprint}` : `${filePath}::${blockName}`;
249
305
  const hash = djb2Hash(input);
250
306
  return `_${hash}`;
251
307
  }
@@ -558,20 +614,47 @@ function formatShorthand(parsed) {
558
614
  // src/css/css.ts
559
615
  var DEFAULT_FILE_PATH = "__runtime__";
560
616
  var injectedCSS = new Set;
617
+ var vertzSheets = new Set;
561
618
  function injectCSS(cssText) {
562
- if (!cssText || typeof document === "undefined" || injectedCSS.has(cssText))
619
+ if (!cssText)
620
+ return;
621
+ const isSSR = typeof globalThis.__SSR_URL__ === "string";
622
+ if (!isSSR && injectedCSS.has(cssText))
563
623
  return;
564
624
  injectedCSS.add(cssText);
625
+ if (typeof document === "undefined")
626
+ return;
627
+ if (typeof CSSStyleSheet !== "undefined" && document.adoptedStyleSheets !== undefined) {
628
+ const sheet = new CSSStyleSheet;
629
+ sheet.replaceSync(cssText);
630
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
631
+ vertzSheets.add(sheet);
632
+ return;
633
+ }
565
634
  const style = document.createElement("style");
566
635
  style.setAttribute("data-vertz-css", "");
567
636
  style.textContent = cssText;
568
637
  document.head.appendChild(style);
569
638
  }
639
+ function resetInjectedStyles() {
640
+ injectedCSS.clear();
641
+ if (typeof document !== "undefined" && document.adoptedStyleSheets !== undefined) {
642
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s) => !vertzSheets.has(s));
643
+ }
644
+ vertzSheets.clear();
645
+ }
646
+ function getInjectedCSS() {
647
+ return Array.from(injectedCSS);
648
+ }
570
649
  function css(input, filePath = DEFAULT_FILE_PATH) {
650
+ if ("css" in input) {
651
+ throw new Error("css(): block name 'css' is reserved. Rename the block.");
652
+ }
571
653
  const classNames = {};
572
654
  const cssRules = [];
573
655
  for (const [blockName, entries] of Object.entries(input)) {
574
- const className = generateClassName(filePath, blockName);
656
+ const styleFingerprint = serializeEntries(entries);
657
+ const className = generateClassName(filePath, blockName, styleFingerprint);
575
658
  classNames[blockName] = className;
576
659
  const baseDeclarations = [];
577
660
  const pseudoDeclarations = new Map;
@@ -591,12 +674,20 @@ function css(input, filePath = DEFAULT_FILE_PATH) {
591
674
  for (const [selector, nestedEntries] of Object.entries(entry)) {
592
675
  const nestedDecls = [];
593
676
  for (const nestedEntry of nestedEntries) {
594
- const parsed = parseShorthand(nestedEntry);
595
- const resolved = resolveToken(parsed);
596
- nestedDecls.push(...resolved.declarations);
677
+ if (typeof nestedEntry === "string") {
678
+ const parsed = parseShorthand(nestedEntry);
679
+ const resolved = resolveToken(parsed);
680
+ nestedDecls.push(...resolved.declarations);
681
+ } else if ("property" in nestedEntry && "value" in nestedEntry) {
682
+ nestedDecls.push({ property: nestedEntry.property, value: nestedEntry.value });
683
+ }
684
+ }
685
+ if (selector.startsWith("@")) {
686
+ nestedRules.push(formatAtRule(selector, `.${className}`, nestedDecls));
687
+ } else {
688
+ const resolvedSelector = selector.replaceAll("&", `.${className}`);
689
+ nestedRules.push(formatRule(resolvedSelector, nestedDecls));
597
690
  }
598
- const resolvedSelector = selector.replace("&", `.${className}`);
599
- nestedRules.push(formatRule(resolvedSelector, nestedDecls));
600
691
  }
601
692
  }
602
693
  }
@@ -611,10 +702,21 @@ function css(input, filePath = DEFAULT_FILE_PATH) {
611
702
  const cssText = cssRules.join(`
612
703
  `);
613
704
  injectCSS(cssText);
614
- return {
615
- classNames,
616
- css: cssText
617
- };
705
+ const result = { ...classNames };
706
+ Object.defineProperty(result, "css", {
707
+ value: cssText,
708
+ enumerable: false,
709
+ configurable: false,
710
+ writable: false
711
+ });
712
+ return result;
713
+ }
714
+ function serializeEntries(entries) {
715
+ return entries.map((entry) => {
716
+ if (typeof entry === "string")
717
+ return entry;
718
+ return Object.entries(entry).map(([sel, vals]) => `${sel}:{${vals.map((v) => typeof v === "string" ? v : `${v.property}=${v.value}`).join(",")}}`).join(";");
719
+ }).join("|");
618
720
  }
619
721
  function formatRule(selector, declarations) {
620
722
  const props = declarations.map((d) => ` ${d.property}: ${d.value};`).join(`
@@ -623,6 +725,15 @@ function formatRule(selector, declarations) {
623
725
  ${props}
624
726
  }`;
625
727
  }
728
+ function formatAtRule(atRule, classSelector, declarations) {
729
+ const props = declarations.map((d) => ` ${d.property}: ${d.value};`).join(`
730
+ `);
731
+ return `${atRule} {
732
+ ${classSelector} {
733
+ ${props}
734
+ }
735
+ }`;
736
+ }
626
737
 
627
738
  // src/css/global-css.ts
628
739
  function globalCss(input) {
@@ -687,6 +798,21 @@ function compileTheme(theme) {
687
798
  const rootVars = [];
688
799
  const darkVars = [];
689
800
  const tokenPaths = [];
801
+ for (const name of Object.keys(theme.colors)) {
802
+ if (/[A-Z]/.test(name)) {
803
+ throw new Error(`Color token '${name}' uses camelCase. Use kebab-case to match CSS custom property naming.`);
804
+ }
805
+ }
806
+ for (const [name, values] of Object.entries(theme.colors)) {
807
+ for (const key of Object.keys(values)) {
808
+ if (key === "DEFAULT" || key.startsWith("_"))
809
+ continue;
810
+ const compoundName = `${name}-${key}`;
811
+ if (COLOR_NAMESPACES.has(compoundName)) {
812
+ throw new Error(`Token collision: '${name}.${key}' produces CSS variable '--color-${name}-${key}' ` + `which conflicts with semantic token '${compoundName}'.`);
813
+ }
814
+ }
815
+ }
690
816
  for (const [name, values] of Object.entries(theme.colors)) {
691
817
  for (const [key, value] of Object.entries(values)) {
692
818
  if (key === "DEFAULT") {
@@ -734,17 +860,14 @@ ${darkVars.join(`
734
860
  }
735
861
 
736
862
  // src/css/theme-provider.ts
737
- function ThemeProvider(props) {
738
- const { theme = "light", children } = props;
739
- const el = document.createElement("div");
740
- el.setAttribute("data-theme", theme);
741
- for (const child of children) {
742
- if (typeof child === "string") {
743
- el.appendChild(document.createTextNode(child));
744
- } else {
745
- el.appendChild(child);
746
- }
747
- }
863
+ function ThemeProvider({ theme = "light", children: children2 }) {
864
+ const el = __element("div", { "data-theme": theme });
865
+ __enterChildren(el);
866
+ const nodes = resolveChildren(children2);
867
+ for (const node of nodes) {
868
+ __append(el, node);
869
+ }
870
+ __exitChildren();
748
871
  return el;
749
872
  }
750
873
 
@@ -772,7 +895,7 @@ function deriveConfigKey(config) {
772
895
  function variants(config) {
773
896
  const { base, variants: variantDefs, defaultVariants, compoundVariants } = config;
774
897
  const filePath = deriveConfigKey(config);
775
- const baseResult = base.length > 0 ? css({ base }, filePath) : { classNames: {}, css: "" };
898
+ const baseResult = css({ base }, filePath);
776
899
  const variantResults = {};
777
900
  for (const [variantName, options] of Object.entries(variantDefs)) {
778
901
  variantResults[variantName] = {};
@@ -780,7 +903,7 @@ function variants(config) {
780
903
  if (styles.length > 0) {
781
904
  const blockName = `${variantName}_${optionName}`;
782
905
  const result = css({ [blockName]: styles }, filePath);
783
- const className = result.classNames[blockName];
906
+ const className = result[blockName];
784
907
  if (className) {
785
908
  variantResults[variantName][optionName] = {
786
909
  className,
@@ -800,7 +923,7 @@ function variants(config) {
800
923
  if (styles.length > 0) {
801
924
  const blockName = `compound_${i}`;
802
925
  const result = css({ [blockName]: styles }, filePath);
803
- const className = result.classNames[blockName];
926
+ const className = result[blockName];
804
927
  if (className) {
805
928
  compoundResults.push({
806
929
  conditions,
@@ -826,7 +949,7 @@ function variants(config) {
826
949
  }
827
950
  const fn = (props) => {
828
951
  const classNames = [];
829
- const baseClassName = baseResult.classNames.base;
952
+ const baseClassName = baseResult.base;
830
953
  if (baseClassName) {
831
954
  classNames.push(baseClassName);
832
955
  }
@@ -869,4 +992,4 @@ function variants(config) {
869
992
  return fn;
870
993
  }
871
994
 
872
- export { PROPERTY_MAP, KEYWORD_MAP, DISPLAY_MAP, SPACING_SCALE, RADIUS_SCALE, SHADOW_SCALE, FONT_SIZE_SCALE, FONT_WEIGHT_SCALE, LINE_HEIGHT_SCALE, ALIGNMENT_MAP, SIZE_KEYWORDS, HEIGHT_AXIS_PROPERTIES, COLOR_NAMESPACES, CSS_COLOR_KEYWORDS, CONTENT_MAP, PSEUDO_PREFIXES, PSEUDO_MAP, css, globalCss, s, defineTheme, compileTheme, ThemeProvider, variants };
995
+ export { resolveChildren, children, PROPERTY_MAP, KEYWORD_MAP, DISPLAY_MAP, SPACING_SCALE, RADIUS_SCALE, SHADOW_SCALE, FONT_SIZE_SCALE, FONT_WEIGHT_SCALE, LINE_HEIGHT_SCALE, ALIGNMENT_MAP, SIZE_KEYWORDS, HEIGHT_AXIS_PROPERTIES, COLOR_NAMESPACES, CSS_COLOR_KEYWORDS, CONTENT_MAP, PSEUDO_PREFIXES, PSEUDO_MAP, injectCSS, resetInjectedStyles, getInjectedCSS, css, globalCss, s, defineTheme, compileTheme, ThemeProvider, variants };
@@ -67,7 +67,10 @@ function matchRoute(routes, url) {
67
67
  for (const [key, value] of searchParams.entries()) {
68
68
  raw[key] = value;
69
69
  }
70
- search = m.route.searchParams.parse(raw);
70
+ const parseResult = m.route.searchParams.parse(raw);
71
+ if (parseResult.ok) {
72
+ search = parseResult.data;
73
+ }
71
74
  break;
72
75
  }
73
76
  }
@@ -1,13 +1,17 @@
1
1
  import {
2
2
  executeLoaders,
3
3
  matchRoute
4
- } from "./chunk-j8vzvne3.js";
4
+ } from "./chunk-9e92w0wt.js";
5
+ import {
6
+ prefetchNavData
7
+ } from "./chunk-vx0kzack.js";
5
8
  import {
6
9
  signal
7
- } from "./chunk-pgymxpn1.js";
10
+ } from "./chunk-hrd0mft1.js";
8
11
 
9
12
  // src/router/navigate.ts
10
- function createRouter(routes, initialUrl) {
13
+ var DEFAULT_NAV_THRESHOLD_MS = 500;
14
+ function createRouter(routes, initialUrl, options) {
11
15
  const isSSR = typeof window === "undefined" || typeof globalThis.__SSR_URL__ !== "undefined";
12
16
  let url;
13
17
  if (initialUrl) {
@@ -24,6 +28,42 @@ function createRouter(routes, initialUrl) {
24
28
  const searchParams = signal(initialMatch?.search ?? {});
25
29
  let navigationGen = 0;
26
30
  let currentAbort = null;
31
+ const serverNavEnabled = !!options?.serverNav;
32
+ const serverNavTimeout = typeof options?.serverNav === "object" ? options.serverNav.timeout : undefined;
33
+ const prefetchFn = options?._prefetchNavData ?? (serverNavEnabled ? prefetchNavData : null);
34
+ let activePrefetch = null;
35
+ function startPrefetch(navUrl) {
36
+ if (!serverNavEnabled || !prefetchFn)
37
+ return null;
38
+ if (activePrefetch) {
39
+ activePrefetch.abort();
40
+ }
41
+ const prefetchOpts = {};
42
+ if (serverNavTimeout !== undefined) {
43
+ prefetchOpts.timeout = serverNavTimeout;
44
+ }
45
+ activePrefetch = prefetchFn(navUrl, prefetchOpts);
46
+ return activePrefetch;
47
+ }
48
+ async function awaitPrefetch(handle) {
49
+ if (!handle?.done)
50
+ return;
51
+ await Promise.race([
52
+ handle.done,
53
+ new Promise((r) => setTimeout(r, DEFAULT_NAV_THRESHOLD_MS))
54
+ ]);
55
+ }
56
+ if (isSSR) {
57
+ const g = globalThis;
58
+ const prev = g.__VERTZ_SSR_SYNC_ROUTER__;
59
+ g.__VERTZ_SSR_SYNC_ROUTER__ = (ssrUrl) => {
60
+ if (typeof prev === "function")
61
+ prev(ssrUrl);
62
+ const match = matchRoute(routes, ssrUrl);
63
+ current.value = match;
64
+ searchParams.value = match?.search ?? {};
65
+ };
66
+ }
27
67
  if (initialMatch) {
28
68
  const gen = ++navigationGen;
29
69
  const abort = new AbortController;
@@ -63,15 +103,19 @@ function createRouter(routes, initialUrl) {
63
103
  }
64
104
  }
65
105
  }
66
- async function navigate(url2, options) {
106
+ async function navigate(navUrl, navOptions) {
107
+ const handle = startPrefetch(navUrl);
67
108
  if (!isSSR) {
68
- if (options?.replace) {
69
- window.history.replaceState(null, "", url2);
109
+ if (navOptions?.replace) {
110
+ window.history.replaceState(null, "", navUrl);
70
111
  } else {
71
- window.history.pushState(null, "", url2);
112
+ window.history.pushState(null, "", navUrl);
72
113
  }
73
114
  }
74
- await applyNavigation(url2);
115
+ if (handle?.done) {
116
+ await awaitPrefetch(handle);
117
+ }
118
+ await applyNavigation(navUrl);
75
119
  }
76
120
  async function revalidate() {
77
121
  const match = current.value;
@@ -88,8 +132,9 @@ function createRouter(routes, initialUrl) {
88
132
  let onPopState = null;
89
133
  if (!isSSR) {
90
134
  onPopState = () => {
91
- const url2 = window.location.pathname + window.location.search;
92
- applyNavigation(url2).catch(() => {});
135
+ const popUrl = window.location.pathname + window.location.search;
136
+ startPrefetch(popUrl);
137
+ applyNavigation(popUrl).catch(() => {});
93
138
  };
94
139
  window.addEventListener("popstate", onPopState);
95
140
  }
@@ -100,6 +145,10 @@ function createRouter(routes, initialUrl) {
100
145
  if (currentAbort) {
101
146
  currentAbort.abort();
102
147
  }
148
+ if (activePrefetch) {
149
+ activePrefetch.abort();
150
+ activePrefetch = null;
151
+ }
103
152
  }
104
153
  return {
105
154
  current,
@@ -0,0 +1,33 @@
1
+ // src/dom/dom-adapter.ts
2
+ function createDOMAdapter() {
3
+ return {
4
+ createElement: (tag) => document.createElement(tag),
5
+ createElementNS: (ns, tag) => document.createElementNS(ns, tag),
6
+ createTextNode: (text) => document.createTextNode(text),
7
+ createComment: (text) => document.createComment(text),
8
+ createDocumentFragment: () => document.createDocumentFragment(),
9
+ isNode: (value) => typeof Node !== "undefined" && value instanceof Node
10
+ };
11
+ }
12
+
13
+ // src/dom/adapter.ts
14
+ var RENDER_NODE_BRAND = Symbol.for("vertz:render-node");
15
+ function isRenderNode(value) {
16
+ if (value == null || typeof value !== "object")
17
+ return false;
18
+ if (RENDER_NODE_BRAND in value)
19
+ return true;
20
+ return typeof Node !== "undefined" && value instanceof Node;
21
+ }
22
+ var currentAdapter = null;
23
+ function getAdapter() {
24
+ if (!currentAdapter) {
25
+ currentAdapter = createDOMAdapter();
26
+ }
27
+ return currentAdapter;
28
+ }
29
+ function setAdapter(adapter) {
30
+ currentAdapter = adapter;
31
+ }
32
+
33
+ export { createDOMAdapter, RENDER_NODE_BRAND, isRenderNode, getAdapter, setAdapter };