@usetheo/ui 0.1.0-next.0 → 0.3.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +116 -9
  3. package/dist/index.d.ts +242 -16
  4. package/dist/index.js +436 -131
  5. package/dist/index.js.map +1 -1
  6. package/dist/plugin-Atb0VKtr.d.ts +172 -0
  7. package/dist/slide/index.d.ts +212 -0
  8. package/dist/slide/index.js +714 -0
  9. package/dist/slide/index.js.map +1 -0
  10. package/dist/slide/plugins/emoji/index.d.ts +29 -0
  11. package/dist/slide/plugins/emoji/index.js +157 -0
  12. package/dist/slide/plugins/emoji/index.js.map +1 -0
  13. package/dist/slide/plugins/math/index.d.ts +13 -0
  14. package/dist/slide/plugins/math/index.js +145 -0
  15. package/dist/slide/plugins/math/index.js.map +1 -0
  16. package/dist/slide/plugins/mermaid/index.d.ts +55 -0
  17. package/dist/slide/plugins/mermaid/index.js +218 -0
  18. package/dist/slide/plugins/mermaid/index.js.map +1 -0
  19. package/dist/slide/plugins/shiki/index.d.ts +18 -0
  20. package/dist/slide/plugins/shiki/index.js +87 -0
  21. package/dist/slide/plugins/shiki/index.js.map +1 -0
  22. package/dist/slide/themes/default.css +256 -0
  23. package/dist/slide/themes/layouts.css +143 -0
  24. package/dist/slide/themes/violet-forge.css +256 -0
  25. package/dist/slide-deck/index.css +52 -0
  26. package/dist/slide-deck/index.css.map +1 -0
  27. package/dist/slide-deck/index.d.ts +377 -0
  28. package/dist/slide-deck/index.js +1797 -0
  29. package/dist/slide-deck/index.js.map +1 -0
  30. package/dist/whiteboard/index.d.ts +258 -0
  31. package/dist/whiteboard/index.js +738 -0
  32. package/dist/whiteboard/index.js.map +1 -0
  33. package/package.json +126 -6
  34. package/registry/index.json +42 -0
  35. package/registry/r/agent-composer.json +4 -4
  36. package/registry/r/agent-editor.json +9 -9
  37. package/registry/r/agent-error-card.json +2 -2
  38. package/registry/r/agent-event.json +4 -4
  39. package/registry/r/agent-handoff.json +2 -2
  40. package/registry/r/agent-profile.json +2 -2
  41. package/registry/r/agent-starting-state.json +2 -2
  42. package/registry/r/agent-stream.json +9 -9
  43. package/registry/r/agent-streaming.json +2 -2
  44. package/registry/r/agent-timeline.json +4 -4
  45. package/registry/r/approval-card.json +4 -4
  46. package/registry/r/artifact-preview.json +2 -2
  47. package/registry/r/attachment-chip.json +4 -4
  48. package/registry/r/audit-log-entry.json +3 -3
  49. package/registry/r/auto-compact-notice.json +2 -2
  50. package/registry/r/avatar.json +2 -2
  51. package/registry/r/badge.json +3 -3
  52. package/registry/r/browser-controls.json +2 -2
  53. package/registry/r/build-log-stream.json +2 -2
  54. package/registry/r/button.json +3 -3
  55. package/registry/r/capability-indicator.json +3 -3
  56. package/registry/r/card.json +3 -3
  57. package/registry/r/chat-composer.json +3 -3
  58. package/registry/r/chat-message.json +3 -3
  59. package/registry/r/chat-thread.json +2 -2
  60. package/registry/r/checkbox.json +4 -3
  61. package/registry/r/cn.json +1 -1
  62. package/registry/r/command-palette.json +4 -4
  63. package/registry/r/context-card.json +3 -3
  64. package/registry/r/context-window-bar.json +2 -2
  65. package/registry/r/cost-meter.json +2 -2
  66. package/registry/r/created-files-card.json +3 -3
  67. package/registry/r/cron-job-card.json +2 -2
  68. package/registry/r/cron-jobs-list.json +3 -3
  69. package/registry/r/deployment-row.json +3 -3
  70. package/registry/r/dialog.json +2 -2
  71. package/registry/r/diff-viewer.json +2 -2
  72. package/registry/r/domain-config.json +6 -6
  73. package/registry/r/empty-state.json +3 -3
  74. package/registry/r/env-var-editor.json +5 -5
  75. package/registry/r/folder-context-card.json +3 -3
  76. package/registry/r/folder-selector.json +2 -2
  77. package/registry/r/form-field.json +3 -3
  78. package/registry/r/hook-config.json +2 -2
  79. package/registry/r/hook-event-log.json +2 -2
  80. package/registry/r/input.json +6 -3
  81. package/registry/r/intent-selector.json +3 -3
  82. package/registry/r/label.json +2 -2
  83. package/registry/r/lane-board.json +2 -2
  84. package/registry/r/login-split.json +2 -2
  85. package/registry/r/mcp-server-card.json +2 -2
  86. package/registry/r/mcp-server-list.json +3 -3
  87. package/registry/r/memory-editor.json +3 -3
  88. package/registry/r/mention-menu.json +3 -3
  89. package/registry/r/metrics-panel.json +2 -2
  90. package/registry/r/model-card.json +3 -3
  91. package/registry/r/model-selector.json +2 -2
  92. package/registry/r/permission-matrix.json +2 -2
  93. package/registry/r/permission-modal.json +4 -4
  94. package/registry/r/preview-env-card.json +5 -5
  95. package/registry/r/preview-panel.json +3 -3
  96. package/registry/r/progress-checklist.json +3 -3
  97. package/registry/r/project-card.json +5 -5
  98. package/registry/r/project-switcher.json +2 -2
  99. package/registry/r/quick-action-chips.json +3 -3
  100. package/registry/r/radio-group.json +2 -2
  101. package/registry/r/recent-folders-list.json +2 -2
  102. package/registry/r/rollback-ui.json +4 -4
  103. package/registry/r/rule-card.json +3 -3
  104. package/registry/r/rule-editor.json +10 -10
  105. package/registry/r/rule-types.json +1 -1
  106. package/registry/r/run-stats.json +2 -2
  107. package/registry/r/running-tasks-panel.json +2 -2
  108. package/registry/r/scroll-area.json +2 -2
  109. package/registry/r/select.json +4 -3
  110. package/registry/r/session-list-item.json +2 -2
  111. package/registry/r/session-timeline.json +2 -2
  112. package/registry/r/sheet.json +2 -2
  113. package/registry/r/sidebar.json +2 -2
  114. package/registry/r/skeleton.json +2 -2
  115. package/registry/r/skill-card.json +4 -4
  116. package/registry/r/skill-editor.json +10 -10
  117. package/registry/r/skills-list.json +3 -3
  118. package/registry/r/slide-deck.json +130 -0
  119. package/registry/r/slide-plugin-emoji.json +28 -0
  120. package/registry/r/slide-plugin-math.json +24 -0
  121. package/registry/r/slide-plugin-mermaid.json +23 -0
  122. package/registry/r/slide-plugin-shiki.json +23 -0
  123. package/registry/r/slide.json +123 -0
  124. package/registry/r/social-auth-row.json +3 -3
  125. package/registry/r/steps-rail.json +2 -2
  126. package/registry/r/sub-agent-dispatch.json +2 -2
  127. package/registry/r/switch.json +5 -4
  128. package/registry/r/system-prompt-editor.json +2 -2
  129. package/registry/r/tabs.json +2 -2
  130. package/registry/r/tailwind-preset.json +1 -1
  131. package/registry/r/task-header.json +4 -4
  132. package/registry/r/task-plan.json +2 -2
  133. package/registry/r/terminal-panel.json +2 -2
  134. package/registry/r/textarea.json +6 -3
  135. package/registry/r/theme-provider.json +4 -4
  136. package/registry/r/theme-script.json +1 -1
  137. package/registry/r/theo-ui-provider.json +2 -2
  138. package/registry/r/toast.json +3 -3
  139. package/registry/r/token-usage-chart.json +2 -2
  140. package/registry/r/tool-call-card.json +3 -3
  141. package/registry/r/tool-call.json +2 -2
  142. package/registry/r/tool-result.json +2 -2
  143. package/registry/r/tools-list.json +3 -3
  144. package/registry/r/tooltip.json +2 -2
  145. package/registry/r/topnav.json +2 -2
  146. package/registry/r/whiteboard.json +101 -0
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
2
+ import { extendTailwindMerge } from 'tailwind-merge';
3
3
  import { createContext, forwardRef, useId, Children, isValidElement, cloneElement, useState, useMemo, Fragment as Fragment$1, useRef, useEffect, useContext, useCallback } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import * as DropdownMenu2 from '@radix-ui/react-dropdown-menu';
@@ -20,6 +20,19 @@ import * as SwitchPrimitive from '@radix-ui/react-switch';
20
20
  import { Command } from 'cmdk';
21
21
 
22
22
  // src/lib/cn.ts
23
+ var twMerge = extendTailwindMerge({
24
+ extend: {
25
+ classGroups: {
26
+ "font-size": [
27
+ { text: ["display-2xl", "display-xl", "display-lg", "display-md"] },
28
+ { text: ["headline", "title-lg", "title-md"] },
29
+ { text: ["body-lg", "body-md", "body-sm"] },
30
+ { text: ["label", "label-caps"] },
31
+ { text: ["code-md", "code-sm"] }
32
+ ]
33
+ }
34
+ }
35
+ });
23
36
  function cn(...inputs) {
24
37
  return twMerge(clsx(inputs));
25
38
  }
@@ -39,8 +52,30 @@ function safeHref(url) {
39
52
  }
40
53
  return url;
41
54
  }
55
+ var DensityContext = createContext(void 0);
56
+ var STYLE_ELEMENT_ID = "theo-ui-density-vars";
57
+ var DENSITY_CSS = `[data-density="compact"] { --theo-control-h: 2rem; --theo-control-px: 0.75rem; }
58
+ [data-density="comfortable"] { --theo-control-h: 2.25rem; --theo-control-px: 0.875rem; }
59
+ [data-density="spacious"] { --theo-control-h: 2.75rem; --theo-control-px: 1rem; }
60
+ `;
61
+ function injectDensityCss() {
62
+ if (typeof document === "undefined") return false;
63
+ if (document.getElementById(STYLE_ELEMENT_ID)) return false;
64
+ const style = document.createElement("style");
65
+ style.id = STYLE_ELEMENT_ID;
66
+ style.textContent = DENSITY_CSS;
67
+ document.head.appendChild(style);
68
+ return true;
69
+ }
70
+ function useDensity() {
71
+ const ctx = useContext(DensityContext);
72
+ if (!ctx) {
73
+ throw new Error("useDensity must be used inside <ThemeProvider>.");
74
+ }
75
+ return ctx;
76
+ }
42
77
  var ThemeContext = createContext(void 0);
43
- var STYLE_ELEMENT_ID = "theo-ui-theme-vars";
78
+ var STYLE_ELEMENT_ID2 = "theo-ui-theme-vars";
44
79
  var COLOR_VALUE_PATTERN = /^(#[0-9a-fA-F]{3,8}|(?:oklch|oklab|rgb|rgba|hsl|hsla|lab|lch|color)\(\s*[\d.\s%,/+\-]+\s*\)|-?\d+(?:\.\d+)?%?(?:\s+-?\d+(?:\.\d+)?%?){1,3}|var\(--[a-zA-Z0-9-]+(?:\s*,\s*[^();{}]+)?\)|transparent|currentColor|inherit|initial|unset)$/;
45
80
  var FONT_FAMILY_PATTERN = /^[\w\s,"'\-.]+$/;
46
81
  var THEME_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
@@ -86,10 +121,10 @@ function fontsToCss(name, fonts) {
86
121
  }
87
122
  function injectThemeCss(themes) {
88
123
  if (typeof document === "undefined") return;
89
- let style = document.getElementById(STYLE_ELEMENT_ID);
124
+ let style = document.getElementById(STYLE_ELEMENT_ID2);
90
125
  if (!style) {
91
126
  style = document.createElement("style");
92
- style.id = STYLE_ELEMENT_ID;
127
+ style.id = STYLE_ELEMENT_ID2;
93
128
  document.head.appendChild(style);
94
129
  }
95
130
  const blocks = [];
@@ -124,7 +159,8 @@ function ThemeProvider({
124
159
  defaultTheme = "violet-forge",
125
160
  defaultMode = "dark",
126
161
  themes: themesProp,
127
- storageKey = "theo-ui:theme"
162
+ storageKey = "theo-ui:theme",
163
+ defaultDensity = "comfortable"
128
164
  }) {
129
165
  if (!themesProp || themesProp.length === 0) {
130
166
  throw new Error(
@@ -171,6 +207,16 @@ function ThemeProvider({
171
207
  return defaultMode;
172
208
  }
173
209
  });
210
+ const [density, setDensityState] = useState(() => {
211
+ if (typeof window === "undefined" || !storageKey) return defaultDensity;
212
+ try {
213
+ const stored = window.localStorage.getItem(`${storageKey}:density`);
214
+ return stored === "compact" || stored === "comfortable" || stored === "spacious" ? stored : defaultDensity;
215
+ } catch (err) {
216
+ warnStorageFailure("read density", err);
217
+ return defaultDensity;
218
+ }
219
+ });
174
220
  useEffect(() => {
175
221
  injectThemeCss(themes);
176
222
  }, [themes]);
@@ -180,24 +226,28 @@ function ThemeProvider({
180
226
  if (!active2) return;
181
227
  document.documentElement.setAttribute("data-theme", active2.name);
182
228
  document.documentElement.setAttribute("data-mode", mode);
229
+ document.documentElement.setAttribute("data-density", density);
183
230
  document.documentElement.classList.toggle("dark", mode === "dark");
184
231
  loadThemeFonts(active2);
185
- }, [themeName, mode, themes]);
232
+ injectDensityCss();
233
+ }, [themeName, mode, density, themes]);
186
234
  useEffect(() => {
187
235
  if (typeof window === "undefined" || !storageKey) return;
188
236
  try {
189
237
  window.localStorage.setItem(`${storageKey}:name`, themeName);
190
238
  window.localStorage.setItem(`${storageKey}:mode`, mode);
239
+ window.localStorage.setItem(`${storageKey}:density`, density);
191
240
  } catch (err) {
192
- warnStorageFailure("persist theme + mode", err);
241
+ warnStorageFailure("persist theme + mode + density", err);
193
242
  }
194
- }, [themeName, mode, storageKey]);
243
+ }, [themeName, mode, density, storageKey]);
195
244
  const setTheme = useCallback((name) => setThemeName(name), []);
196
245
  const setMode = useCallback((next) => setModeState(next), []);
197
246
  const toggleMode = useCallback(
198
247
  () => setModeState((cur) => cur === "light" ? "dark" : "light"),
199
248
  []
200
249
  );
250
+ const setDensity = useCallback((next) => setDensityState(next), []);
201
251
  const registerTheme = useCallback((theme) => {
202
252
  setThemes((cur) => {
203
253
  const idx = cur.findIndex((t) => t.name === theme.name);
@@ -222,7 +272,8 @@ function ThemeProvider({
222
272
  }),
223
273
  [active, mode, themes, setTheme, setMode, toggleMode, registerTheme]
224
274
  );
225
- return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
275
+ const densityValue = useMemo(() => ({ density, setDensity }), [density, setDensity]);
276
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children: /* @__PURE__ */ jsx(DensityContext.Provider, { value: densityValue, children }) });
226
277
  }
227
278
  function useTheme() {
228
279
  const ctx = useContext(ThemeContext);
@@ -550,11 +601,119 @@ var auroraTerminal = {
550
601
  }
551
602
  };
552
603
 
604
+ // src/themes/define.ts
605
+ var NAME_PATTERN = /^[a-z][a-z0-9-]*$/i;
606
+ function defaultLabel(name) {
607
+ if (name.length === 0) return name;
608
+ return name.charAt(0).toUpperCase() + name.slice(1);
609
+ }
610
+ function defineTheme(input) {
611
+ if (typeof input?.name !== "string" || input.name.length === 0) {
612
+ throw new Error("defineTheme: `name` is required and cannot be empty.");
613
+ }
614
+ if (!NAME_PATTERN.test(input.name)) {
615
+ throw new Error(
616
+ `defineTheme: invalid name "${input.name}". Must match /^[a-z][a-z0-9-]*$/i \u2014 letters, digits, and hyphens only, starting with a letter.`
617
+ );
618
+ }
619
+ const lightOverride = input.light ?? {};
620
+ const darkOverride = input.dark ?? {};
621
+ const fontsOverride = input.fonts ?? {};
622
+ const theme = {
623
+ name: input.name,
624
+ label: input.label ?? defaultLabel(input.name),
625
+ description: input.description,
626
+ fonts: { ...violetForge.fonts, ...fontsOverride },
627
+ light: { ...violetForge.light, ...lightOverride },
628
+ dark: { ...violetForge.dark, ...darkOverride },
629
+ fontUrls: input.fontUrls ?? violetForge.fontUrls
630
+ };
631
+ return theme;
632
+ }
633
+
634
+ // src/themes/color.ts
635
+ function hexCharToNibble(ch) {
636
+ if (ch >= "0" && ch <= "9") return ch.charCodeAt(0) - 48;
637
+ if (ch >= "a" && ch <= "f") return ch.charCodeAt(0) - 87;
638
+ if (ch >= "A" && ch <= "F") return ch.charCodeAt(0) - 55;
639
+ throw new Error(`hex(): invalid hex character "${ch}"`);
640
+ }
641
+ function parseHex(input) {
642
+ if (!input.startsWith("#")) {
643
+ throw new Error(`hex(): expected '#'-prefixed input, got "${input}"`);
644
+ }
645
+ const body = input.slice(1);
646
+ let r;
647
+ let g;
648
+ let b;
649
+ if (body.length === 3 || body.length === 4) {
650
+ const nr = hexCharToNibble(body.charAt(0));
651
+ const ng = hexCharToNibble(body.charAt(1));
652
+ const nb = hexCharToNibble(body.charAt(2));
653
+ r = nr << 4 | nr;
654
+ g = ng << 4 | ng;
655
+ b = nb << 4 | nb;
656
+ } else if (body.length === 6 || body.length === 8) {
657
+ r = hexCharToNibble(body.charAt(0)) << 4 | hexCharToNibble(body.charAt(1));
658
+ g = hexCharToNibble(body.charAt(2)) << 4 | hexCharToNibble(body.charAt(3));
659
+ b = hexCharToNibble(body.charAt(4)) << 4 | hexCharToNibble(body.charAt(5));
660
+ } else {
661
+ throw new Error(
662
+ `hex(): invalid length ${body.length} for hex input "${input}" \u2014 expected 3, 4, 6, or 8 hex chars after the '#'.`
663
+ );
664
+ }
665
+ return { r, g, b };
666
+ }
667
+ function rgbToHsl(r, g, b) {
668
+ const rn = r / 255;
669
+ const gn = g / 255;
670
+ const bn = b / 255;
671
+ const max = Math.max(rn, gn, bn);
672
+ const min = Math.min(rn, gn, bn);
673
+ const l = (max + min) / 2;
674
+ let h = 0;
675
+ let s = 0;
676
+ if (max !== min) {
677
+ const d = max - min;
678
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
679
+ switch (max) {
680
+ case rn:
681
+ h = (gn - bn) / d + (gn < bn ? 6 : 0);
682
+ break;
683
+ case gn:
684
+ h = (bn - rn) / d + 2;
685
+ break;
686
+ default:
687
+ h = (rn - gn) / d + 4;
688
+ break;
689
+ }
690
+ h *= 60;
691
+ }
692
+ const hh = Math.round(h);
693
+ const ss = Math.round(s * 100);
694
+ const ll = Math.round(l * 100);
695
+ return `${hh} ${ss}% ${ll}%`;
696
+ }
697
+ function hex(input) {
698
+ const { r, g, b } = parseHex(input);
699
+ return rgbToHsl(r, g, b);
700
+ }
701
+ function rgb(r, g, b) {
702
+ for (const value of [r, g, b]) {
703
+ if (!Number.isFinite(value) || value < 0 || value > 255) {
704
+ throw new Error(
705
+ `rgb(): channel out of range \u2014 expected 0..255, got ${value}. Did you mix percentage values?`
706
+ );
707
+ }
708
+ }
709
+ return rgbToHsl(Math.round(r), Math.round(g), Math.round(b));
710
+ }
711
+
553
712
  // src/themes/index.ts
554
713
  var builtinThemes = [violetForge, classicPaper, auroraTerminal];
555
714
  var toastVariants = cva(
556
715
  [
557
- "group pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-lg border p-4 pr-10 shadow-md",
716
+ "group pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-lg border pr-10 shadow-md",
558
717
  "data-[state=open]:slide-in-from-top-full data-[state=open]:fade-in-0 data-[state=open]:animate-in",
559
718
  "data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=closed]:animate-out",
560
719
  "data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]",
@@ -568,9 +727,14 @@ var toastVariants = cva(
568
727
  success: "border-success/40 bg-popover text-popover-foreground",
569
728
  warning: "border-warning/40 bg-popover text-popover-foreground",
570
729
  destructive: "border-destructive/50 bg-popover text-popover-foreground"
730
+ },
731
+ size: {
732
+ sm: "p-3 text-body-sm",
733
+ md: "p-4 text-body-md",
734
+ lg: "p-5 text-body-lg"
571
735
  }
572
736
  },
573
- defaultVariants: { variant: "default" }
737
+ defaultVariants: { variant: "default", size: "md" }
574
738
  }
575
739
  );
576
740
  var iconForVariant = {
@@ -581,10 +745,18 @@ var iconForVariant = {
581
745
  destructive: /* @__PURE__ */ jsx(AlertCircle, { className: "size-4 shrink-0 text-destructive", "aria-hidden": "true" })
582
746
  };
583
747
  var ToastRoot = forwardRef(
584
- ({ className, variant = "default", children, ...props }, ref) => /* @__PURE__ */ jsxs(ToastPrimitive.Root, { ref, className: cn(toastVariants({ variant }), className), ...props, children: [
585
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: iconForVariant[variant] }),
586
- /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children })
587
- ] })
748
+ ({ className, variant = "default", size, children, ...props }, ref) => /* @__PURE__ */ jsxs(
749
+ ToastPrimitive.Root,
750
+ {
751
+ ref,
752
+ className: cn(toastVariants({ variant, size }), className),
753
+ ...props,
754
+ children: [
755
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: iconForVariant[variant] }),
756
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children })
757
+ ]
758
+ }
759
+ )
588
760
  );
589
761
  ToastRoot.displayName = "Toast";
590
762
  var ToastTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
@@ -747,9 +919,12 @@ var buttonVariants = cva(
747
919
  },
748
920
  size: {
749
921
  sm: "h-8 px-3 text-body-sm",
750
- md: "h-10 px-4 text-body-md",
751
- lg: "h-12 px-6 text-body-lg",
752
- icon: "h-10 w-10 p-0"
922
+ // md: tier ajustável via density (CSS var on :root). See D3 ADR of
923
+ // faang-density-tightening plan. Default `comfortable` density makes
924
+ // this 36px (--theo-control-h: 2.25rem). sm and lg stay hardcoded.
925
+ md: "h-[var(--theo-control-h,2.25rem)] px-[var(--theo-control-px,0.875rem)] text-body-sm",
926
+ lg: "h-11 px-4 text-body-md",
927
+ icon: "h-[var(--theo-control-h,2.25rem)] w-[var(--theo-control-h,2.25rem)] p-0"
753
928
  }
754
929
  },
755
930
  defaultVariants: {
@@ -775,8 +950,8 @@ var Button = forwardRef(
775
950
  Button.displayName = "Button";
776
951
  var badgeVariants = cva(
777
952
  [
778
- "inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5",
779
- "font-sans text-label uppercase tracking-wider",
953
+ "inline-flex items-center gap-1.5 rounded-full border",
954
+ "font-sans uppercase tracking-wider",
780
955
  "transition-colors"
781
956
  ],
782
957
  {
@@ -789,12 +964,19 @@ var badgeVariants = cva(
789
964
  warning: "border-warning/40 bg-warning/15 text-warning",
790
965
  destructive: "border-destructive/40 bg-destructive/15 text-destructive",
791
966
  outline: "border-border bg-transparent text-foreground"
967
+ },
968
+ size: {
969
+ sm: "px-2 py-0.5 text-label-caps",
970
+ md: "px-2.5 py-0.5 text-label",
971
+ lg: "px-3 py-1 text-body-md"
792
972
  }
793
973
  },
794
- defaultVariants: { variant: "default" }
974
+ defaultVariants: { variant: "default", size: "md" }
795
975
  }
796
976
  );
797
- var Badge = forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx("span", { ref, className: cn(badgeVariants({ variant }), className), ...props }));
977
+ var Badge = forwardRef(
978
+ ({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
979
+ );
798
980
  Badge.displayName = "Badge";
799
981
  var toneClass = {
800
982
  primary: "bg-primary",
@@ -823,8 +1005,10 @@ var Dot = forwardRef(
823
1005
  Dot.displayName = "Badge.Dot";
824
1006
  var BadgeWithDot = Badge;
825
1007
  BadgeWithDot.Dot = Dot;
1008
+ var CardContext = createContext({ size: "md" });
1009
+ var useCardSize = () => useContext(CardContext).size;
826
1010
  var Root3 = forwardRef(
827
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1011
+ ({ className, size = "md", ...props }, ref) => /* @__PURE__ */ jsx(CardContext.Provider, { value: { size }, children: /* @__PURE__ */ jsx(
828
1012
  "div",
829
1013
  {
830
1014
  ref,
@@ -835,21 +1019,39 @@ var Root3 = forwardRef(
835
1019
  ),
836
1020
  ...props
837
1021
  }
838
- )
1022
+ ) })
839
1023
  );
840
1024
  Root3.displayName = "Card";
1025
+ var headerPadBySize = {
1026
+ sm: "gap-1 p-3 pb-1.5",
1027
+ md: "gap-1.5 p-5 pb-2.5",
1028
+ lg: "gap-2 p-6 pb-3"
1029
+ };
841
1030
  var Header = forwardRef(
842
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col gap-1.5 p-6 pb-3", className), ...props })
1031
+ ({ className, ...props }, ref) => {
1032
+ const size = useCardSize();
1033
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col", headerPadBySize[size], className), ...props });
1034
+ }
843
1035
  );
844
1036
  Header.displayName = "Card.Header";
1037
+ var titleFontBySize = {
1038
+ sm: "text-title-md",
1039
+ md: "text-title-lg",
1040
+ lg: "text-headline"
1041
+ };
845
1042
  var Title2 = forwardRef(
846
1043
  ({ className, asChild = false, ...props }, ref) => {
847
1044
  const Comp = asChild ? Slot : "h3";
1045
+ const size = useCardSize();
848
1046
  return /* @__PURE__ */ jsx(
849
1047
  Comp,
850
1048
  {
851
1049
  ref,
852
- className: cn("font-display text-foreground text-title-lg tracking-tight", className),
1050
+ className: cn(
1051
+ "font-display text-foreground tracking-tight",
1052
+ titleFontBySize[size],
1053
+ className
1054
+ ),
853
1055
  ...props
854
1056
  }
855
1057
  );
@@ -860,19 +1062,39 @@ var Description2 = forwardRef(
860
1062
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-body-sm text-muted-foreground", className), ...props })
861
1063
  );
862
1064
  Description2.displayName = "Card.Description";
1065
+ var bodyPadBySize = {
1066
+ sm: "p-3 pt-1.5",
1067
+ md: "p-5 pt-2.5",
1068
+ lg: "p-6 pt-3"
1069
+ };
863
1070
  var Body = forwardRef(
864
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-3", className), ...props })
1071
+ ({ className, ...props }, ref) => {
1072
+ const size = useCardSize();
1073
+ return /* @__PURE__ */ jsx("div", { ref, className: cn(bodyPadBySize[size], className), ...props });
1074
+ }
865
1075
  );
866
1076
  Body.displayName = "Card.Body";
1077
+ var footerPadBySize = {
1078
+ sm: "gap-2 p-3 pt-2",
1079
+ md: "gap-3 p-5 pt-3",
1080
+ lg: "gap-4 p-6 pt-4"
1081
+ };
867
1082
  var Footer = forwardRef(
868
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
869
- "div",
870
- {
871
- ref,
872
- className: cn("flex items-center gap-3 border-border/40 border-t p-6 pt-4", className),
873
- ...props
874
- }
875
- )
1083
+ ({ className, ...props }, ref) => {
1084
+ const size = useCardSize();
1085
+ return /* @__PURE__ */ jsx(
1086
+ "div",
1087
+ {
1088
+ ref,
1089
+ className: cn(
1090
+ "flex items-center border-border/40 border-t",
1091
+ footerPadBySize[size],
1092
+ className
1093
+ ),
1094
+ ...props
1095
+ }
1096
+ );
1097
+ }
876
1098
  );
877
1099
  Footer.displayName = "Card.Footer";
878
1100
  var Card = /* @__PURE__ */ Object.assign(Root3, {
@@ -882,25 +1104,30 @@ var Card = /* @__PURE__ */ Object.assign(Root3, {
882
1104
  Body,
883
1105
  Footer
884
1106
  });
1107
+ var inputVariants = cva(
1108
+ [
1109
+ "flex w-full rounded-md border border-input bg-card",
1110
+ "text-foreground placeholder:text-muted-foreground",
1111
+ "transition-[box-shadow,border-color] duration-base ease-out-soft",
1112
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1113
+ "focus-visible:border-primary",
1114
+ "disabled:cursor-not-allowed disabled:opacity-50",
1115
+ "file:border-0 file:bg-transparent file:font-medium file:text-body-sm"
1116
+ ],
1117
+ {
1118
+ variants: {
1119
+ size: {
1120
+ sm: "h-8 px-2.5 py-1 text-body-sm",
1121
+ // md: density-tunable via CSS var. Comfortable (default) = 36px.
1122
+ md: "h-[var(--theo-control-h,2.25rem)] px-[var(--theo-control-px,0.875rem)] py-1.5 text-body-sm",
1123
+ lg: "h-11 px-4 py-2.5 text-body-md"
1124
+ }
1125
+ },
1126
+ defaultVariants: { size: "md" }
1127
+ }
1128
+ );
885
1129
  var Input = forwardRef(
886
- ({ className, type = "text", ...props }, ref) => /* @__PURE__ */ jsx(
887
- "input",
888
- {
889
- ref,
890
- type,
891
- className: cn(
892
- "flex h-10 w-full rounded-md border border-input bg-card px-3 py-2",
893
- "text-body-md text-foreground placeholder:text-muted-foreground",
894
- "transition-[box-shadow,border-color] duration-base ease-out-soft",
895
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
896
- "focus-visible:border-primary",
897
- "disabled:cursor-not-allowed disabled:opacity-50",
898
- "file:border-0 file:bg-transparent file:font-medium file:text-body-sm",
899
- className
900
- ),
901
- ...props
902
- }
903
- )
1130
+ ({ className, type = "text", size, ...props }, ref) => /* @__PURE__ */ jsx("input", { ref, type, className: cn(inputVariants({ size }), className), ...props })
904
1131
  );
905
1132
  Input.displayName = "Input";
906
1133
  var Overlay2 = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
@@ -1251,30 +1478,47 @@ function useFormField() {
1251
1478
  if (!ctx) throw new Error("FormField subcomponents must be inside <FormField>.");
1252
1479
  return ctx;
1253
1480
  }
1481
+ var rootGapBySize = {
1482
+ sm: "gap-1",
1483
+ md: "gap-1.5",
1484
+ lg: "gap-2"
1485
+ };
1254
1486
  var FormFieldRoot = forwardRef(
1255
- ({ className, id: idProp, invalid, ...props }, ref) => {
1487
+ ({ className, id: idProp, invalid, size = "md", ...props }, ref) => {
1256
1488
  const auto = useId();
1257
1489
  const fieldId = idProp ?? `field-${auto}`;
1258
1490
  const ctx = {
1259
1491
  fieldId,
1260
1492
  hintId: `${fieldId}-hint`,
1261
1493
  errorId: `${fieldId}-error`,
1262
- hasError: !!invalid
1494
+ hasError: !!invalid,
1495
+ size
1263
1496
  };
1264
- return /* @__PURE__ */ jsx(FormFieldContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx("div", { ref, className: cn("grid gap-1.5", className), ...props }) });
1497
+ return /* @__PURE__ */ jsx(FormFieldContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx("div", { ref, className: cn("grid", rootGapBySize[size], className), ...props }) });
1265
1498
  }
1266
1499
  );
1267
1500
  FormFieldRoot.displayName = "FormField";
1501
+ var labelFontBySize = {
1502
+ sm: "text-label-caps",
1503
+ md: "text-body-sm",
1504
+ lg: "text-body-md"
1505
+ };
1506
+ var hintFontBySize = {
1507
+ sm: "text-label-caps",
1508
+ md: "text-body-sm",
1509
+ lg: "text-body-md"
1510
+ };
1268
1511
  var FormFieldLabel = forwardRef(
1269
1512
  ({ className, required, children, ...props }, ref) => {
1270
- const { fieldId } = useFormField();
1513
+ const { fieldId, size } = useFormField();
1271
1514
  return /* @__PURE__ */ jsxs(
1272
1515
  LabelPrimitive.Root,
1273
1516
  {
1274
1517
  ref,
1275
1518
  htmlFor: fieldId,
1276
1519
  className: cn(
1277
- "inline-flex items-center gap-1 font-medium font-sans text-body-sm text-foreground",
1520
+ "inline-flex items-center gap-1 font-medium font-sans text-foreground",
1521
+ labelFontBySize[size],
1278
1522
  "peer-disabled:cursor-not-allowed peer-disabled:opacity-60",
1279
1523
  className
1280
1524
  ),
@@ -1304,14 +1548,14 @@ var FormFieldControl = forwardRef(
1304
1548
  FormFieldControl.displayName = "FormField.Control";
1305
1549
  var FormFieldHint = forwardRef(
1306
1550
  ({ className, children, ...props }, ref) => {
1307
- const { hintId, hasError } = useFormField();
1551
+ const { hintId, hasError, size } = useFormField();
1308
1552
  if (hasError) return null;
1309
1553
  return /* @__PURE__ */ jsx(
1310
1554
  "p",
1311
1555
  {
1312
1556
  ref,
1313
1557
  id: hintId,
1314
- className: cn("text-body-sm text-muted-foreground", className),
1558
+ className: cn("text-muted-foreground", hintFontBySize[size], className),
1315
1559
  ...props,
1316
1560
  children
1317
1561
  }
@@ -1321,7 +1565,7 @@ var FormFieldHint = forwardRef(
1321
1565
  FormFieldHint.displayName = "FormField.Hint";
1322
1566
  var FormFieldError = forwardRef(
1323
1567
  ({ className, children, ...props }, ref) => {
1324
- const { errorId, hasError } = useFormField();
1568
+ const { errorId, hasError, size } = useFormField();
1325
1569
  if (!hasError) return null;
1326
1570
  return /* @__PURE__ */ jsxs(
1327
1571
  "p",
@@ -1329,7 +1573,7 @@ var FormFieldError = forwardRef(
1329
1573
  ref,
1330
1574
  id: errorId,
1331
1575
  role: "alert",
1332
- className: cn("flex items-center gap-1 text-body-sm text-destructive", className),
1576
+ className: cn("flex items-center gap-1 text-destructive", hintFontBySize[size], className),
1333
1577
  ...props,
1334
1578
  children: [
1335
1579
  /* @__PURE__ */ jsx(AlertCircle, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
@@ -1368,28 +1612,42 @@ var EmptyState = forwardRef(
1368
1612
  )
1369
1613
  );
1370
1614
  EmptyState.displayName = "EmptyState";
1371
- var SelectTrigger = forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1372
- SelectPrimitive.Trigger,
1615
+ var selectTriggerVariants = cva(
1616
+ [
1617
+ "flex w-full items-center justify-between gap-2 rounded-md border border-input bg-card",
1618
+ "text-foreground placeholder:text-muted-foreground",
1619
+ "transition-[border-color,box-shadow] duration-base ease-out-soft",
1620
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1621
+ "focus-visible:border-primary",
1622
+ "data-[placeholder]:text-muted-foreground",
1623
+ "disabled:cursor-not-allowed disabled:opacity-50",
1624
+ "[&>span]:line-clamp-1"
1625
+ ],
1373
1626
  {
1374
- ref,
1375
- className: cn(
1376
- "flex h-10 w-full items-center justify-between gap-2 rounded-md border border-input bg-card px-3 py-2",
1377
- "text-body-md text-foreground placeholder:text-muted-foreground",
1378
- "transition-[border-color,box-shadow] duration-base ease-out-soft",
1379
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1380
- "focus-visible:border-primary",
1381
- "data-[placeholder]:text-muted-foreground",
1382
- "disabled:cursor-not-allowed disabled:opacity-50",
1383
- "[&>span]:line-clamp-1",
1384
- className
1385
- ),
1386
- ...props,
1387
- children: [
1388
- children,
1389
- /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }) })
1390
- ]
1627
+ variants: {
1628
+ size: {
1629
+ sm: "h-8 px-2.5 py-1 text-body-sm",
1630
+ md: "h-[var(--theo-control-h,2.25rem)] px-[var(--theo-control-px,0.875rem)] py-1.5 text-body-sm",
1631
+ lg: "h-11 px-4 py-2.5 text-body-md"
1632
+ }
1633
+ },
1634
+ defaultVariants: { size: "md" }
1391
1635
  }
1392
- ));
1636
+ );
1637
+ var SelectTrigger = forwardRef(
1638
+ ({ className, children, size, ...props }, ref) => /* @__PURE__ */ jsxs(
1639
+ SelectPrimitive.Trigger,
1640
+ {
1641
+ ref,
1642
+ className: cn(selectTriggerVariants({ size }), className),
1643
+ ...props,
1644
+ children: [
1645
+ children,
1646
+ /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }) })
1647
+ ]
1648
+ }
1649
+ )
1650
+ );
1393
1651
  SelectTrigger.displayName = "Select.Trigger";
1394
1652
  var SelectScrollUpButton = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1395
1653
  SelectPrimitive.ScrollUpButton,
@@ -1489,23 +1747,45 @@ Select.Group = SelectPrimitive.Group;
1489
1747
  Select.Label = SelectLabel;
1490
1748
  Select.Item = SelectItem;
1491
1749
  Select.Separator = SelectSeparator;
1492
- var Checkbox = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1493
- CheckboxPrimitive.Root,
1750
+ var checkboxVariants = cva(
1751
+ [
1752
+ "peer relative shrink-0 rounded-sm border border-border bg-card",
1753
+ "transition-[background-color,border-color,box-shadow] duration-base ease-out-soft",
1754
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1755
+ "data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
1756
+ "data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
1757
+ "disabled:cursor-not-allowed disabled:opacity-50"
1758
+ ],
1494
1759
  {
1495
- ref,
1496
- className: cn(
1497
- "peer size-4 shrink-0 rounded-sm border border-border bg-card",
1498
- "transition-[background-color,border-color,box-shadow] duration-base ease-out-soft",
1499
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1500
- "data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
1501
- "data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
1502
- "disabled:cursor-not-allowed disabled:opacity-50",
1503
- className
1504
- ),
1505
- ...props,
1506
- children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx(Minus, { className: "size-3.5", "aria-hidden": "true", strokeWidth: 3 }) : /* @__PURE__ */ jsx(Check, { className: "size-3.5", "aria-hidden": "true", strokeWidth: 3 }) })
1760
+ variants: {
1761
+ size: {
1762
+ sm: "size-3.5 before:absolute before:inset-[-5px] before:content-['']",
1763
+ md: "size-4",
1764
+ lg: "size-5"
1765
+ }
1766
+ },
1767
+ defaultVariants: { size: "md" }
1507
1768
  }
1508
- ));
1769
+ );
1770
+ var iconClassBySize = {
1771
+ sm: "size-2.5",
1772
+ md: "size-3.5",
1773
+ lg: "size-3.5"
1774
+ };
1775
+ var Checkbox = forwardRef(
1776
+ ({ className, size, ...props }, ref) => {
1777
+ const iconClass = iconClassBySize[size ?? "md"];
1778
+ return /* @__PURE__ */ jsx(
1779
+ CheckboxPrimitive.Root,
1780
+ {
1781
+ ref,
1782
+ className: cn(checkboxVariants({ size }), className),
1783
+ ...props,
1784
+ children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx(Minus, { className: iconClass, "aria-hidden": "true", strokeWidth: 3 }) : /* @__PURE__ */ jsx(Check, { className: iconClass, "aria-hidden": "true", strokeWidth: 3 }) })
1785
+ }
1786
+ );
1787
+ }
1788
+ );
1509
1789
  Checkbox.displayName = "Checkbox";
1510
1790
  var RadioGroupRoot = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { ref, className: cn("grid gap-3", className), ...props }));
1511
1791
  RadioGroupRoot.displayName = "RadioGroup";
@@ -1529,48 +1809,73 @@ RadioGroupItem.displayName = "RadioGroup.Item";
1529
1809
  var RadioGroup = /* @__PURE__ */ Object.assign(RadioGroupRoot, {
1530
1810
  Item: RadioGroupItem
1531
1811
  });
1532
- var Switch = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1533
- SwitchPrimitive.Root,
1812
+ var switchVariants = cva(
1813
+ [
1814
+ "peer inline-flex shrink-0 cursor-pointer items-center rounded-full border border-transparent",
1815
+ "transition-[background-color,box-shadow] duration-base ease-out-soft",
1816
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1817
+ "data-[state=checked]:bg-primary data-[state=checked]:shadow-[0_0_8px_hsl(var(--primary)/0.35)]",
1818
+ "data-[state=unchecked]:bg-muted",
1819
+ "disabled:cursor-not-allowed disabled:opacity-50"
1820
+ ],
1534
1821
  {
1535
- ref,
1536
- className: cn(
1537
- "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border border-transparent",
1538
- "transition-[background-color,box-shadow] duration-base ease-out-soft",
1539
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1540
- "data-[state=checked]:bg-primary data-[state=checked]:shadow-[0_0_8px_hsl(var(--primary)/0.35)]",
1541
- "data-[state=unchecked]:bg-muted",
1542
- "disabled:cursor-not-allowed disabled:opacity-50",
1543
- className
1544
- ),
1545
- ...props,
1546
- children: /* @__PURE__ */ jsx(
1547
- SwitchPrimitive.Thumb,
1548
- {
1549
- className: cn(
1550
- "pointer-events-none block size-4 rounded-full bg-card shadow-sm",
1551
- "transition-transform duration-base ease-out-soft",
1552
- "data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0.5"
1553
- )
1822
+ variants: {
1823
+ size: {
1824
+ sm: "h-4 w-7",
1825
+ md: "h-5 w-9",
1826
+ lg: "h-6 w-11"
1554
1827
  }
1555
- )
1828
+ },
1829
+ defaultVariants: { size: "md" }
1556
1830
  }
1557
- ));
1831
+ );
1832
+ var thumbClassBySize = {
1833
+ sm: "size-3 data-[state=checked]:translate-x-3 data-[state=unchecked]:translate-x-0.5",
1834
+ md: "size-4 data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0.5",
1835
+ lg: "size-5 data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0.5"
1836
+ };
1837
+ var Switch = forwardRef(
1838
+ ({ className, size, ...props }, ref) => /* @__PURE__ */ jsx(SwitchPrimitive.Root, { ref, className: cn(switchVariants({ size }), className), ...props, children: /* @__PURE__ */ jsx(
1839
+ SwitchPrimitive.Thumb,
1840
+ {
1841
+ className: cn(
1842
+ "pointer-events-none block rounded-full bg-card shadow-sm",
1843
+ "transition-transform duration-base ease-out-soft",
1844
+ thumbClassBySize[size ?? "md"]
1845
+ )
1846
+ }
1847
+ ) })
1848
+ );
1558
1849
  Switch.displayName = "Switch";
1850
+ var textareaVariants = cva(
1851
+ [
1852
+ "flex w-full resize-y rounded-md border border-input bg-card",
1853
+ "text-foreground placeholder:text-muted-foreground",
1854
+ "transition-[box-shadow,border-color] duration-base ease-out-soft",
1855
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1856
+ "focus-visible:border-primary",
1857
+ "disabled:cursor-not-allowed disabled:opacity-50"
1858
+ ],
1859
+ {
1860
+ variants: {
1861
+ size: {
1862
+ sm: "min-h-[64px] px-2.5 py-1.5 text-body-sm",
1863
+ // md: text scale + padding tighten to body-sm per FAANG density.
1864
+ // min-h stays 96px because multiline has its own height rationale.
1865
+ md: "min-h-[6rem] px-[var(--theo-control-px,0.875rem)] py-1.5 text-body-sm",
1866
+ lg: "min-h-[128px] px-4 py-2.5 text-body-md"
1867
+ }
1868
+ },
1869
+ defaultVariants: { size: "md" }
1870
+ }
1871
+ );
1559
1872
  var Textarea = forwardRef(
1560
- ({ className, rows = 3, ...props }, ref) => /* @__PURE__ */ jsx(
1873
+ ({ className, rows = 3, size, ...props }, ref) => /* @__PURE__ */ jsx(
1561
1874
  "textarea",
1562
1875
  {
1563
1876
  ref,
1564
1877
  rows,
1565
- className: cn(
1566
- "flex min-h-[6rem] w-full resize-y rounded-md border border-input bg-card px-3 py-2",
1567
- "text-body-md text-foreground placeholder:text-muted-foreground",
1568
- "transition-[box-shadow,border-color] duration-base ease-out-soft",
1569
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1570
- "focus-visible:border-primary",
1571
- "disabled:cursor-not-allowed disabled:opacity-50",
1572
- className
1573
- ),
1878
+ className: cn(textareaVariants({ size }), className),
1574
1879
  ...props
1575
1880
  }
1576
1881
  )
@@ -7741,6 +8046,6 @@ function CommandPalette({
7741
8046
  ] }) });
7742
8047
  }
7743
8048
 
7744
- export { ALL_MODES, AgentComposer, AgentEditor, AgentErrorCard, AgentEvent, AgentHandoff, AgentProfile, AgentStartingState, AgentStream, AgentStreaming, AgentTimeline, ApprovalCard, ArtifactPreview, AttachmentChip, AuditLogEntry, AutoCompactNotice, Avatar, BadgeWithDot as Badge, BrowserControls, BuildLogStream, Button, CapabilityIndicator, Card, ChatComposer, ChatMessage, ChatThread, Checkbox, CommandPalette, ContextCard, ContextWindowBar, CostMeter, CreatedFilesCard, CronJobCard, CronJobsList, DeploymentRow, Dialog, DiffViewer, DomainConfig, EmptyState, EnvVarEditor, FolderContextCard, FolderSelector, FormField, HOOK_EVENTS, HookConfig, HookEventLog, Input, IntentSelector, Label, LaneBoard, LoginSplit, MCPServerCard, MCPServerList, MODE_LABEL, MemoryEditor, MentionMenu, MetricsPanel, ModelCard, ModelSelector, PermissionMatrix, PermissionModal, PreviewEnvCard, PreviewPanel, ProgressChecklist, ProjectCard, ProjectSwitcher, QuickActionChips, RadioGroup, RecentFoldersList, RollbackUI, RuleCard, RuleEditor, RunStats, RunningTasksPanel, ScrollArea, Select, SessionListItem, SessionTimeline, Sheet, Sidebar, Skeleton, SkillCard, SkillEditor, SkillsList, SocialAuthRow, StepsRail, SubAgentDispatch, Switch, SystemPromptEditor, Tabs, TaskHeader, TaskNode, TaskPlan, TerminalPanel, Textarea, ThemeProvider, ThemeScript, ThemeSwitcher, TheoUIProvider, Toast, Toaster, TokenUsageChart, ToolCall, ToolCallCard, ToolResult, ToolsList, TooltipWithStatics as Tooltip, TopNav, auroraTerminal, avatarVariants, badgeVariants, builtinThemes, buttonVariants, capabilityPresets, classicPaper, cn, modelCapabilityPresets, sheetVariants, useTheme, useToast, violetForge };
8049
+ export { ALL_MODES, AgentComposer, AgentEditor, AgentErrorCard, AgentEvent, AgentHandoff, AgentProfile, AgentStartingState, AgentStream, AgentStreaming, AgentTimeline, ApprovalCard, ArtifactPreview, AttachmentChip, AuditLogEntry, AutoCompactNotice, Avatar, BadgeWithDot as Badge, BrowserControls, BuildLogStream, Button, CapabilityIndicator, Card, ChatComposer, ChatMessage, ChatThread, Checkbox, CommandPalette, ContextCard, ContextWindowBar, CostMeter, CreatedFilesCard, CronJobCard, CronJobsList, DeploymentRow, Dialog, DiffViewer, DomainConfig, EmptyState, EnvVarEditor, FolderContextCard, FolderSelector, FormField, HOOK_EVENTS, HookConfig, HookEventLog, Input, IntentSelector, Label, LaneBoard, LoginSplit, MCPServerCard, MCPServerList, MODE_LABEL, MemoryEditor, MentionMenu, MetricsPanel, ModelCard, ModelSelector, PermissionMatrix, PermissionModal, PreviewEnvCard, PreviewPanel, ProgressChecklist, ProjectCard, ProjectSwitcher, QuickActionChips, RadioGroup, RecentFoldersList, RollbackUI, RuleCard, RuleEditor, RunStats, RunningTasksPanel, ScrollArea, Select, SessionListItem, SessionTimeline, Sheet, Sidebar, Skeleton, SkillCard, SkillEditor, SkillsList, SocialAuthRow, StepsRail, SubAgentDispatch, Switch, SystemPromptEditor, Tabs, TaskHeader, TaskNode, TaskPlan, TerminalPanel, Textarea, ThemeProvider, ThemeScript, ThemeSwitcher, TheoUIProvider, Toast, Toaster, TokenUsageChart, ToolCall, ToolCallCard, ToolResult, ToolsList, TooltipWithStatics as Tooltip, TopNav, auroraTerminal, avatarVariants, badgeVariants, builtinThemes, buttonVariants, capabilityPresets, classicPaper, cn, defineTheme, hex, modelCapabilityPresets, rgb, sheetVariants, useDensity, useTheme, useToast, violetForge };
7745
8050
  //# sourceMappingURL=index.js.map
7746
8051
  //# sourceMappingURL=index.js.map