@usetheo/ui 0.1.0-next.1 → 0.4.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,65 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0-next.0] - 2026-05-22
11
+
12
+ Minor bump — public API gains 7 new theme exports. Zero visual break for
13
+ consumers in 0.3.x (default theme remains `violet-forge`).
14
+
15
+ ### Added
16
+
17
+ - **7 new built-in themes (2026-05-22, RFC 0007)** — `vercelMono`, `githubDark`, `dracula`, `oneDark`, `anthropicStyle`, `openaiStyle`, `linearGlass`. `builtinThemes` grows from 3 to 10 entries. Each ships light + dark mode. Derivative slugs from brand names use suffixes (`-mono`, `-style`, `-glass`) and descriptions include "Inspired by, not affiliated with [Company]" per D1.1 ADR (trademark protection / no false-affiliation). Canonical OSS themes (Dracula, One Dark, GitHub Dark) keep their reusable names. Bundle delta: ~60 KB CSS injection if consumer passes `builtinThemes` (alternative: `themes={[violetForge, dracula]}` for ~12 KB). (#TBD)
18
+ - **`validateThemeContrast` quality gate (2026-05-22)** — Pure-JS WCAG 2.1 contrast validator in `scripts/lib/wcag-contrast.ts` + gate in `validate-quality-gates.ts`. Iterates 10 themes × 2 modes × 4 high-stakes pairs, enforces 4.5:1 (body) and 3:1 (large/button) thresholds. Runs <50ms. Caught 14 pre-existing AA failures in `violet-forge`, `classic-paper`, `aurora-terminal` accent contrast; `classic-paper` accent darkened from `37 92% 50%` → `37 92% 40%` and `openai-style` dark primary darkened from `155 78% 43%` → `155 78% 30%` to satisfy the gate. (#TBD)
19
+ - **`scripts/lib/wcag-contrast.ts` + `.test.ts` (NEW)** — Pure functions `parseHsl`, `hslToLuminance`, `contrastRatio`. 9 tests cover edge cases (achromatic, hue overflow, percent stripping — EC-3). (#TBD)
20
+
21
+ ## [0.3.0-next.0] - 2026-05-22
22
+
23
+ Minor bump — visual defaults realigned to FAANG-modern density baseline
24
+ (shadcn / Linear / Vercel / Stripe). Public API unchanged; no type/prop
25
+ signatures touched. Every consumer in 0.2.x will see tighter form controls,
26
+ smaller body text, and a less-padded Card after upgrading.
27
+
28
+ ### Migration from 0.2.x
29
+
30
+ If you depended on the prior visual defaults (Button 40px, Card 24px
31
+ padding, body-md 15px), you have two options:
32
+
33
+ 1. **Per-component** — pass explicit `size="lg"` to Button/Input/Select/
34
+ Textarea/Card. These render the prior dimensions.
35
+ 2. **Global override** — set `<ThemeProvider defaultDensity="spacious">`
36
+ at the app root. All form controls bump to 44px globally.
37
+
38
+ No code change required if you accept the new defaults. Type-only
39
+ exports added: `Density`, `DensityContextValue`.
40
+
41
+ ### Added
42
+
43
+ - **`useDensity()` hook + `data-density` attribute (2026-05-22, RFC 0006)** — Global density override without rewriting `size` props per call site. Three tiers: `compact` (32px), `comfortable` (36px, default), `spacious` (44px). `<ThemeProvider defaultDensity="compact">` at the app root flips the entire surface. Persisted to localStorage. **EC-1 fix**: density implemented via CSS variables on `:root` (`--theo-control-h`, `--theo-control-px`) injected by ThemeProvider, not Tailwind class modifiers. Only the `md` cva variant reads the var; `sm` and `lg` stay hardcoded so explicit `size` prop always overrides density. (#TBD)
44
+ - **`docs/design-system.md > Density policy` section** — declares default heights per component + WCAG 2.5.8 AA tap-target policy + density override patterns. Closes the style-guide gap (previously implicit in source). (#TBD)
45
+ - **`playground/density-demo.tsx`** — live preview with 3-way density toggle. Mount via `?view=density` in the Vite playground. (#TBD)
46
+
47
+ ### Changed (BREAKING visual default, not API)
48
+
49
+ - **Form-control `md` defaults: 40px → 36px** (FAANG-tier modern density). Affects `Button`, `Input`, `Select.Trigger`, `Textarea`. `sm` stays 32px, `lg` recalibrated to 44px. (#TBD)
50
+ - **`body-md` typescale: 15px → 14px** (shadcn / Vercel Geist / Linear standard). `body-sm` recalibrated 14px → 13px to preserve a distinct tier. `validateDesignSystemFidelity` gate updated atomically with `tailwind-preset.ts`. (#TBD)
51
+ - **Card `md` padding: 24px → 20px** (`p-6` → `p-5`). `sm` unchanged (`p-3`); `lg` recalibrated 28px → 24px (`p-7` → `p-6`). (#TBD)
52
+ - **Bundle baseline rebased** for the new defaults (~+700 bytes total — CSS-var class strings + Density type union). Engines (whiteboard / slide / slide-deck) untouched. (#TBD)
53
+
54
+ ## [0.2.0-next.0] - 2026-05-20
55
+
56
+ Minor bump (not patch) because public API surface grew: new `defineTheme` /
57
+ `hex` / `rgb` exports plus `size` prop standardized across 9 primitives.
58
+ All additions are backwards-compatible — `defaultVariants.size = "md"`
59
+ preserves rendered markup for callers that don't pass `size`.
60
+
61
+ ### Added
62
+ - **`defineTheme(partial)` + `hex()` / `rgb()` helpers (2026-05-20, theming-and-sizes plan, Phase 2)** — Reduzem o atrito de criar tema customizado de "58 cor keys obrigatórias" para "só sobrescreva o que mudar". `defineTheme({ name, light: { primary: hex('#FF5722') } })` merja partial overrides em `violetForge` e retorna um `Theme` completo. `hex('#7C3AED')` e `rgb(124, 58, 237)` retornam HSL string-tuple (`"262 83% 58%"`) drop-in compatível com `ColorScale`. Suporta short hex (#abc), 8-char alpha (alpha descartado), case-insensitive. **EC-3** (last-writer-wins): passar `defineTheme({ name: 'violet-forge', ... })` sobrescreve o built-in, comportamento documentado em teste. **EC-4** (case-insensitive) e **EC-5** (4-char alpha) cobertos por testes. **EC-7** (override só light/dark): nota em JSDoc lembra o consumer que se omitir um modo, ele herda violetForge — pode gerar inconsistência visual intencional. Drop-in: `<ThemeProvider themes={[defineTheme({ name: 'corp' })]}>` funciona sem mudança no provider. (#TBD)
63
+ - **9 primitives expose `size` prop (2026-05-20, theming-and-sizes plan, Phase 1)** — `Input`, `Badge`, `Toast`, `Checkbox`, `Switch`, `Card`, `FormField`, `Textarea`, `Select.Trigger` agora aceitam `size?: 'sm' | 'md' | 'lg'` (default `md`, backwards-compat preservada). Compounds `Card` e `FormField` propagam size via React Context para os subparts. **EC-1**: `Input` usa `Omit<InputHTMLAttributes<HTMLInputElement>, 'size'>` no extends para evitar conflict com o HTML attribute nativo (`size: number` = text-input columns); type-test garantido via `@ts-expect-error`. **EC-2**: `Select.Trigger` confirmado Radix-button (sem `SelectHTMLAttributes` conflict). Subparts de Card/FormField não aceitam `size` próprio — use `className` para per-subpart tweaks (EC-8 documentado em JSDoc). (#TBD)
64
+ - **`cn()` ensina tailwind-merge sobre o Violet Forge typescale (2026-05-20)** — `src/lib/cn.ts` substitui `twMerge` direto por `extendTailwindMerge` declarando o `font-size` classGroup com as 16 typescale tokens (`display-2xl`/`display-xl`/`headline`/`title-lg`/`body-md`/`label-caps`/`code-md`/etc.). Sem essa extensão, classes como `text-label` (font-size) e `text-accent` (color) colapsavam ambas no mesmo `text-*` group, e o último vencia — quebrando size+color em CVA variants. (#TBD)
65
+ - **Registry descriptors for the engine surface (2026-05-19)** — Seven new shadcn-compatible registry items so `docs.usetheo.dev/theoui` and the `npx shadcn add` flow can deliver the engines as copy-paste components: `whiteboard` (14 files under `components/ui/whiteboard/`), `slide` (16 files under `components/ui/slide/`, including 3 CSS theme files), `slide-deck` (19 files under `components/blocks/slide-deck/`), and four Tier 2 plugins — `slide-plugin-shiki`, `slide-plugin-math`, `slide-plugin-mermaid`, `slide-plugin-emoji` — each shipping its own subpath under `components/ui/slide/plugins/<name>/`. Cross-item references resolved via `registryDependencies` (each plugin + slide-deck depend on `slide`). Honest install: dependencies arrays list every static or dynamic peer-dep a copy-paste consumer needs (`roughjs`, `perfect-freehand`, `zod` for whiteboard; the full markdown / mdast / hast stack for slide; `shiki` / `katex` / `mermaid` per plugin). Total: 121 registry items (was 114). (#TBD)
66
+ - **`scripts/build-registry.ts` strips source ESM extensions on external imports** — `rewriteRegistryImports` now drops `.js` / `.jsx` / `.ts` / `.tsx` from non-relative specifiers (e.g. `roughjs/bin/generator.js` → `roughjs/bin/generator`). Previously only relative imports were normalized; engines that import third-party submodules with the explicit ESM extension (whiteboard does this for `roughjs/bin/*`) would fail `validate-registry`'s `consumer-unsafe extension` gate. Limited to known source extensions so basenames that happen to end in `.js` inside URLs are untouched. (#TBD)
67
+ - **`scripts/validate-quality-gates.ts > validateRegistryStoriesAndTests` is entry-aware** — When a descriptor lists multiple files (engines like whiteboard / slide / slide-deck), the gate now only checks `<descriptor.name>.test.tsx` / `.stories.tsx` next to the entry file (`<name>.tsx` or `<name>.ts`), not every internal module. Internal helpers carry their own focused tests but don't need a story sibling. Single-file registry items are unaffected. (#TBD)
68
+
10
69
  ## [0.1.0-next.1] - 2026-05-19
11
70
 
12
71
  ### Added
package/dist/index.d.ts CHANGED
@@ -86,6 +86,17 @@ interface Theme {
86
86
  fontUrls?: string[];
87
87
  }
88
88
 
89
+ type Density = "compact" | "comfortable" | "spacious";
90
+ interface DensityContextValue {
91
+ density: Density;
92
+ setDensity: (next: Density) => void;
93
+ }
94
+ /**
95
+ * Read the current density from the active ThemeProvider context. Throws
96
+ * outside the provider so misuse fails loud — analogous to `useTheme`.
97
+ */
98
+ declare function useDensity(): DensityContextValue;
99
+
89
100
  interface ThemeContextValue {
90
101
  /** Active theme (full descriptor). */
91
102
  theme: Theme;
@@ -127,6 +138,13 @@ interface ThemeProviderProps {
127
138
  * Default: "theo-ui:theme".
128
139
  */
129
140
  storageKey?: string | null;
141
+ /**
142
+ * Initial density. Drives `data-density` on `<html>` and the `--theo-control-h`
143
+ * / `--theo-control-px` CSS vars consumed by form-control `md` variants.
144
+ * Defaults to `"comfortable"` (36px controls — FAANG-tier modern density).
145
+ * Plan: faang-density-tightening (D3).
146
+ */
147
+ defaultDensity?: Density;
130
148
  }
131
149
  /**
132
150
  * ThemeProvider — central registry + runtime switcher for Theo themes.
@@ -139,7 +157,7 @@ interface ThemeProviderProps {
139
157
  * 3. Lazy-loads theme font URLs by injecting `<link rel="stylesheet">`.
140
158
  * 4. Optionally persists choice in localStorage.
141
159
  */
142
- declare function ThemeProvider({ children, defaultTheme, defaultMode, themes: themesProp, storageKey, }: ThemeProviderProps): JSX.Element;
160
+ declare function ThemeProvider({ children, defaultTheme, defaultMode, themes: themesProp, storageKey, defaultDensity, }: ThemeProviderProps): JSX.Element;
143
161
  /**
144
162
  * useTheme — access theme state from any component inside <ThemeProvider>.
145
163
  * Throws if used outside the provider — fail-fast.
@@ -234,9 +252,202 @@ declare const classicPaper: Theme;
234
252
  */
235
253
  declare const auroraTerminal: Theme;
236
254
 
255
+ /**
256
+ * `defineTheme(input)` — build a `Theme` from a partial override.
257
+ *
258
+ * Reduces the boilerplate of authoring a custom theme from 58 colour
259
+ * keys (`light` × 29 + `dark` × 29) to "just what you want to change".
260
+ * The merge always uses `violetForge` as the base — this is a pure,
261
+ * deterministic helper that does not depend on whatever theme is active
262
+ * at the call site.
263
+ *
264
+ * The `Theme` object it returns is drop-in compatible with
265
+ * `<ThemeProvider themes={[...]}>` — same shape as `violetForge`,
266
+ * `classicPaper`, and `auroraTerminal`.
267
+ *
268
+ * Honest caveat: if you override `light.primary` but NOT `dark.primary`,
269
+ * the two modes will use different colours — your override in light,
270
+ * Violet Forge's default in dark. That's intentional. Pass both sides
271
+ * to keep them in sync.
272
+ *
273
+ * @example
274
+ * import { defineTheme, hex } from "@usetheo/ui";
275
+ * export const corp = defineTheme({
276
+ * name: "corp",
277
+ * light: { primary: hex("#0EA5E9") },
278
+ * dark: { primary: hex("#38BDF8") },
279
+ * });
280
+ *
281
+ * Plan: `.claude/knowledge-base/plans/theming-and-sizes-plan.md` T2.1.
282
+ */
283
+
284
+ interface DefineThemeInput {
285
+ /**
286
+ * Stable id used in `data-theme="<name>"` on the root element. Must
287
+ * match `/^[a-z][a-z0-9-]*$/i` (CSS-identifier-safe). Required.
288
+ */
289
+ name: string;
290
+ /**
291
+ * Human-readable label for theme switchers. Defaults to the
292
+ * capitalized version of `name` (e.g. "corp" → "Corp").
293
+ */
294
+ label?: string;
295
+ /** Optional one-line description shown in switchers. */
296
+ description?: string;
297
+ /**
298
+ * Override light-mode colours. Any key omitted is inherited from
299
+ * `violetForge.light`. See `ColorScale` for the full list.
300
+ */
301
+ light?: Partial<ColorScale>;
302
+ /**
303
+ * Override dark-mode colours. Any key omitted is inherited from
304
+ * `violetForge.dark`.
305
+ */
306
+ dark?: Partial<ColorScale>;
307
+ /**
308
+ * Override fonts (`display`, `body`, `mono`). Any key omitted is
309
+ * inherited from `violetForge.fonts`.
310
+ */
311
+ fonts?: Partial<ThemeFonts>;
312
+ /**
313
+ * Replace the default remote font URLs. Pass an empty array to skip
314
+ * font fetching entirely. Defaults to `violetForge.fontUrls` when
315
+ * omitted (so consumers that don't care still get Geist preloaded).
316
+ */
317
+ fontUrls?: string[];
318
+ }
319
+ declare function defineTheme(input: DefineThemeInput): Theme;
320
+
321
+ /**
322
+ * Color helpers that return values in the HSL string-tuple format the
323
+ * `ColorScale` shape expects (e.g. `"262 83% 58%"`).
324
+ *
325
+ * Why this format: matches the shadcn / Violet Forge convention where
326
+ * CSS variables hold the H S% L% components and consumers write
327
+ * `hsl(var(--primary))` (allowing alpha overlays via
328
+ * `hsl(var(--primary) / 0.5)`). Returning an object would force callers
329
+ * to write `${theme.light.primary.h} ${theme.light.primary.s}% …` —
330
+ * exactly the friction `hex()` is meant to remove.
331
+ *
332
+ * No external dependency: vanilla algorithm from CSS Color spec.
333
+ * Alpha channels are intentionally discarded — `ColorScale` is opaque;
334
+ * use `hsl(var(--primary) / 0.5)` in CSS for transparency.
335
+ *
336
+ * Plan: `.claude/knowledge-base/plans/theming-and-sizes-plan.md` T2.2.
337
+ */
338
+ /**
339
+ * Convert a hex color string to the HSL string-tuple format used by
340
+ * `ColorScale` ("`H S% L%`", e.g. `"262 83% 58%"`).
341
+ *
342
+ * Accepts `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`. Case-insensitive.
343
+ * Alpha bytes are silently dropped — use `hsl(var(--primary) / 0.5)`
344
+ * in CSS for transparency.
345
+ *
346
+ * @throws if the input is malformed.
347
+ *
348
+ * @example
349
+ * hex("#7C3AED") // "262 83% 58%"
350
+ * hex("#7c3aed") // "262 83% 58%" (same)
351
+ * hex("#abc") // expanded to "#aabbcc"
352
+ */
353
+ declare function hex(input: string): string;
354
+ /**
355
+ * Convert an RGB triplet (each in `[0, 255]`) to the HSL string-tuple
356
+ * format used by `ColorScale`.
357
+ *
358
+ * @throws if any channel is out of `[0, 255]`.
359
+ *
360
+ * @example
361
+ * rgb(124, 58, 237) // "262 83% 58%"
362
+ */
363
+ declare function rgb(r: number, g: number, b: number): string;
364
+
365
+ /**
366
+ * Vercel Mono — razor-sharp monochrome + signature blue.
367
+ *
368
+ * Inspired by, not affiliated with Vercel. Based on Geist Design tokens
369
+ * (https://github.com/vercel/geist). Light = pure white + black ink + blue
370
+ * accent (#0070F3); dark = near-black canvas + white text + same blue.
371
+ *
372
+ * Plan: .claude/knowledge-base/plans/seven-themes-plan.md T2.1
373
+ */
374
+ declare const vercelMono: Theme;
375
+
376
+ /**
377
+ * GitHub Dark — GitHub's default dark theme.
378
+ *
379
+ * Based on the canonical Primer Primitives tokens
380
+ * (https://github.com/primer/primitives, MIT). Light fallback uses GitHub's
381
+ * "light-default" Primer scale.
382
+ *
383
+ * Plan: .claude/knowledge-base/plans/seven-themes-plan.md T3.1
384
+ */
385
+ declare const githubDark: Theme;
386
+
387
+ /**
388
+ * Dracula — the cult OSS dark theme (https://draculatheme.com, MIT).
389
+ *
390
+ * Dark mode = canonical Dracula spec (background #282A36, signature pink
391
+ * #FF79C6, purple #BD93F9, etc.).
392
+ *
393
+ * Note: "light" mode is a Theo-original adaptation — Dracula upstream
394
+ * spec is dark-only. We darken the signature pink/purple to pass WCAG AA
395
+ * against light backgrounds, sacrificing palette purity for accessibility.
396
+ *
397
+ * Plan: .claude/knowledge-base/plans/seven-themes-plan.md T4.1
398
+ */
399
+ declare const dracula: Theme;
400
+
401
+ /**
402
+ * One Dark / One Light — Atom's iconic syntax theme.
403
+ *
404
+ * Sources:
405
+ * - atom/one-dark-syntax (MIT) — dark mode canonical
406
+ * - atom/one-light-syntax (MIT) — light mode canonical
407
+ *
408
+ * Plan: .claude/knowledge-base/plans/seven-themes-plan.md T5.1
409
+ */
410
+ declare const oneDark: Theme;
411
+
412
+ /**
413
+ * Anthropic-style — claude.ai-inspired editorial calm.
414
+ *
415
+ * Inspired by, not affiliated with Anthropic. Visually informed by claude.ai's
416
+ * warm cream canvas + burnt sienna primary + ink-on-paper feel. No proprietary
417
+ * assets reproduced (font is Geist, colors are independent measurements).
418
+ *
419
+ * Plan: .claude/knowledge-base/plans/seven-themes-plan.md T6.1
420
+ */
421
+ declare const anthropicStyle: Theme;
422
+
423
+ /**
424
+ * OpenAI-style — chatgpt.com-inspired minimal tech-utility.
425
+ *
426
+ * Inspired by, not affiliated with OpenAI. Pure white / charcoal canvas +
427
+ * signature ChatGPT green (#10A37F). Minimal saturation, high contrast.
428
+ *
429
+ * Plan: .claude/knowledge-base/plans/seven-themes-plan.md T7.1
430
+ */
431
+ declare const openaiStyle: Theme;
432
+
433
+ /**
434
+ * Linear Glass — linear.app-inspired glassy indigo.
435
+ *
436
+ * Inspired by, not affiliated with Linear. Refined indigo-violet primary
437
+ * (#5E6AD2) on near-black canvas in dark, pure white in light. Subtle
438
+ * glassmorphic surface temperature.
439
+ *
440
+ * Plan: .claude/knowledge-base/plans/seven-themes-plan.md T8.1
441
+ */
442
+ declare const linearGlass: Theme;
443
+
237
444
  /**
238
445
  * All themes bundled with Theo UI. Pass to `<ThemeProvider themes={builtinThemes}>`
239
- * if you want all of them available out of the box.
446
+ * if you want all 10 available out of the box.
447
+ *
448
+ * EC-4 note: passing the full 10-entry list triggers ~60 KB CSS injection in
449
+ * `<style id="theo-ui-theme-vars">`. For apps focused on 1-2 themes, prefer
450
+ * `themes={[violetForge, dracula]}` to keep the payload at ~12 KB.
240
451
  */
241
452
  declare const builtinThemes: Theme[];
242
453
 
@@ -257,6 +468,7 @@ declare const builtinThemes: Theme[];
257
468
  */
258
469
  declare const toastVariants: (props?: ({
259
470
  variant?: "success" | "warning" | "destructive" | "info" | "default" | null | undefined;
471
+ size?: "sm" | "md" | "lg" | null | undefined;
260
472
  } & class_variance_authority_types.ClassProp) | undefined) => string;
261
473
  type ToastVariant = NonNullable<VariantProps<typeof toastVariants>["variant"]>;
262
474
  interface ToastProps extends ComponentPropsWithoutRef<typeof ToastPrimitive.Root>, VariantProps<typeof toastVariants> {
@@ -428,7 +640,7 @@ interface TaskStep {
428
640
  * `asChild` swaps the root for the consumer's element (Radix Slot pattern).
429
641
  */
430
642
  declare const buttonVariants: (props?: ({
431
- variant?: "primary" | "secondary" | "accent" | "destructive" | "link" | "ghost" | null | undefined;
643
+ variant?: "accent" | "link" | "primary" | "secondary" | "destructive" | "ghost" | null | undefined;
432
644
  size?: "sm" | "md" | "lg" | "icon" | null | undefined;
433
645
  } & class_variance_authority_types.ClassProp) | undefined) => string;
434
646
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
@@ -452,7 +664,8 @@ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAtt
452
664
  * "Running", "Failed" rows in deployment lists.
453
665
  */
454
666
  declare const badgeVariants: (props?: ({
455
- variant?: "primary" | "accent" | "success" | "warning" | "destructive" | "default" | "outline" | null | undefined;
667
+ variant?: "accent" | "primary" | "success" | "warning" | "destructive" | "default" | "outline" | null | undefined;
668
+ size?: "sm" | "md" | "lg" | null | undefined;
456
669
  } & class_variance_authority_types.ClassProp) | undefined) => string;
457
670
  interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {
458
671
  }
@@ -466,6 +679,29 @@ declare const BadgeWithDot: typeof Badge & {
466
679
  Dot: typeof Dot;
467
680
  };
468
681
 
682
+ /**
683
+ * Card — surface container for grouping related content.
684
+ *
685
+ * Composition pattern (shadcn-style):
686
+ * <Card>
687
+ * <Card.Header>
688
+ * <Card.Title>…</Card.Title>
689
+ * <Card.Description>…</Card.Description>
690
+ * </Card.Header>
691
+ * <Card.Body>…</Card.Body>
692
+ * <Card.Footer>…</Card.Footer>
693
+ * </Card>
694
+ *
695
+ * The `size` prop on the root propagates to subparts via Context, so a
696
+ * single declaration controls padding + heading scale across the compound.
697
+ * Subparts used in isolation default to `md`. Subparts do NOT accept a `size`
698
+ * prop of their own — use `className` for granular per-subpart tweaks.
699
+ * (EC-8, edge-case review 2026-05-20.)
700
+ */
701
+ type CardSize = "sm" | "md" | "lg";
702
+ interface CardRootProps extends HTMLAttributes<HTMLDivElement> {
703
+ size?: CardSize;
704
+ }
469
705
  interface TitleProps extends HTMLAttributes<HTMLHeadingElement> {
470
706
  /**
471
707
  * When true, renders the child element with the Card.Title styles applied
@@ -474,7 +710,7 @@ interface TitleProps extends HTMLAttributes<HTMLHeadingElement> {
474
710
  */
475
711
  asChild?: boolean;
476
712
  }
477
- declare const Card: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>> & {
713
+ declare const Card: react.ForwardRefExoticComponent<CardRootProps & react.RefAttributes<HTMLDivElement>> & {
478
714
  Header: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
479
715
  Title: react.ForwardRefExoticComponent<TitleProps & react.RefAttributes<HTMLHeadingElement>>;
480
716
  Description: react.ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & react.RefAttributes<HTMLParagraphElement>>;
@@ -482,8 +718,9 @@ declare const Card: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElemen
482
718
  Footer: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
483
719
  };
484
720
 
485
- interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
486
- }
721
+ declare const inputVariants: (props?: ({
722
+ size?: "sm" | "md" | "lg" | null | undefined;
723
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
487
724
  /**
488
725
  * Input — text input primitive.
489
726
  *
@@ -492,7 +729,15 @@ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
492
729
  * - rounded-md (6px) — slightly less than buttons to differentiate.
493
730
  * - focus uses violet ring (--ring).
494
731
  * - placeholder uses --muted-foreground.
732
+ *
733
+ * The `size` prop accepts `"sm" | "md" | "lg"`. Default `md` preserves the
734
+ * 40px tall input from before this prop existed. EC-1 (edge-case review):
735
+ * this overrides the native HTML `size` attribute (text-input columns) —
736
+ * use `{...{ size: 20 } as any}` if you genuinely need the HTML attribute,
737
+ * which is exceedingly rare.
495
738
  */
739
+ interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size">, VariantProps<typeof inputVariants> {
740
+ }
496
741
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
497
742
 
498
743
  interface ContentProps$1 extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
@@ -628,7 +873,7 @@ declare const Skeleton: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivEl
628
873
  */
629
874
  declare const avatarVariants: (props?: ({
630
875
  size?: "sm" | "md" | "lg" | "xs" | "xl" | null | undefined;
631
- tone?: "primary" | "accent" | "muted" | null | undefined;
876
+ tone?: "accent" | "primary" | "muted" | null | undefined;
632
877
  } & class_variance_authority_types.ClassProp) | undefined) => string;
633
878
  interface AvatarProps extends ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>, VariantProps<typeof avatarVariants> {
634
879
  }
@@ -650,11 +895,37 @@ interface LabelProps extends ComponentPropsWithoutRef<typeof LabelPrimitive.Root
650
895
  }
651
896
  declare const Label: react.ForwardRefExoticComponent<LabelProps & react.RefAttributes<HTMLLabelElement>>;
652
897
 
898
+ /**
899
+ * FormField — composition wrapper for accessible form rows.
900
+ *
901
+ * Provides context with a generated `id`, so children (Label, Input, Hint,
902
+ * Error) wire themselves via `htmlFor` / `id` / `aria-describedby` without
903
+ * the consumer having to thread IDs manually.
904
+ *
905
+ * Composition:
906
+ * <FormField>
907
+ * <FormField.Label required>Email</FormField.Label>
908
+ * <FormField.Control>
909
+ * <Input type="email" placeholder="…" />
910
+ * </FormField.Control>
911
+ * <FormField.Hint>We never share your email.</FormField.Hint>
912
+ * <FormField.Error>{error}</FormField.Error>
913
+ * </FormField>
914
+ *
915
+ * Errors take precedence over hints (only one of them shows at once).
916
+ */
917
+ type FormFieldSize = "sm" | "md" | "lg";
653
918
  interface FormFieldProps extends HTMLAttributes<HTMLDivElement> {
654
919
  /** Optional explicit id override. */
655
920
  id?: string;
656
921
  /** Marks the field as invalid; switches Hint → Error and toggles aria. */
657
922
  invalid?: boolean;
923
+ /**
924
+ * Size scale propagated to Label / Hint / Error subparts via Context.
925
+ * Default `md` preserves prior behavior. Subparts do NOT accept a `size`
926
+ * prop of their own — use `className` for granular tweaks (EC-8).
927
+ */
928
+ size?: FormFieldSize;
658
929
  }
659
930
  interface FormFieldLabelProps extends ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {
660
931
  required?: boolean;
@@ -696,6 +967,17 @@ interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, "title">
696
967
  */
697
968
  declare const EmptyState: react.ForwardRefExoticComponent<EmptyStateProps & react.RefAttributes<HTMLDivElement>>;
698
969
 
970
+ /**
971
+ * Trigger size variant (theming-and-sizes plan T1.9).
972
+ * Items inside Select.Content stay md-equivalent regardless — the floating
973
+ * menu is isolated from the trigger context (documented decision).
974
+ *
975
+ * EC-2 guard: `<Select.Trigger>` is a Radix `<button>` — no SelectHTMLAttributes
976
+ * conflict to Omit. Verified before implementation.
977
+ */
978
+ declare const selectTriggerVariants: (props?: ({
979
+ size?: "sm" | "md" | "lg" | null | undefined;
980
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
699
981
  /**
700
982
  * Select — styled wrapper around Radix Select.
701
983
  *
@@ -715,7 +997,9 @@ declare const EmptyState: react.ForwardRefExoticComponent<EmptyStateProps & reac
715
997
  * Trigger matches Input height + violet focus ring. Content uses popover
716
998
  * surface with check on the selected item.
717
999
  */
718
- declare const SelectTrigger: react.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1000
+ interface SelectTriggerProps extends ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, VariantProps<typeof selectTriggerVariants> {
1001
+ }
1002
+ declare const SelectTrigger: react.ForwardRefExoticComponent<SelectTriggerProps & react.RefAttributes<HTMLButtonElement>>;
719
1003
  declare const SelectContent: react.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
720
1004
  declare const SelectLabel: react.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectLabelProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
721
1005
  declare const SelectItem: react.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
@@ -735,8 +1019,17 @@ declare const Select: typeof SelectPrimitive.Root & {
735
1019
  *
736
1020
  * Supports tri-state via `checked="indeterminate"`. Violet fill when on,
737
1021
  * border-only when off. Themed via tokens (--primary, --background).
1022
+ *
1023
+ * The `size` prop accepts `"sm" | "md" | "lg"`. Default `md` preserves the
1024
+ * 16px box from before this prop existed. The `sm` size keeps a >=24px
1025
+ * effective tap target via an invisible expanded hit area (WCAG 2.5.5).
738
1026
  */
739
- declare const Checkbox: react.ForwardRefExoticComponent<Omit<CheckboxPrimitive.CheckboxProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1027
+ declare const checkboxVariants: (props?: ({
1028
+ size?: "sm" | "md" | "lg" | null | undefined;
1029
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
1030
+ interface CheckboxProps extends ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, VariantProps<typeof checkboxVariants> {
1031
+ }
1032
+ declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLButtonElement>>;
740
1033
 
741
1034
  declare const RadioGroup: react.ForwardRefExoticComponent<Omit<RadioGroupPrimitive.RadioGroupProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>> & {
742
1035
  Item: react.ForwardRefExoticComponent<Omit<RadioGroupPrimitive.RadioGroupItemProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
@@ -748,17 +1041,33 @@ declare const RadioGroup: react.ForwardRefExoticComponent<Omit<RadioGroupPrimiti
748
1041
  *
749
1042
  * Off-state uses --muted, on-state uses --primary with a subtle glow shadow
750
1043
  * to mark "this is active" in the violet brand language.
1044
+ *
1045
+ * The `size` prop accepts `"sm" | "md" | "lg"`. Default `md` preserves the
1046
+ * 20×36 track from before this prop existed.
751
1047
  */
752
- declare const Switch: react.ForwardRefExoticComponent<Omit<SwitchPrimitive.SwitchProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
753
-
754
- interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
1048
+ declare const switchVariants: (props?: ({
1049
+ size?: "sm" | "md" | "lg" | null | undefined;
1050
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
1051
+ interface SwitchProps extends ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>, VariantProps<typeof switchVariants> {
755
1052
  }
1053
+ declare const Switch: react.ForwardRefExoticComponent<SwitchProps & react.RefAttributes<HTMLButtonElement>>;
1054
+
756
1055
  /**
757
1056
  * Textarea — multi-line input mirror of Input.
758
1057
  *
759
1058
  * Matches Input visuals (violet focus ring, --input border, --card bg).
760
- * Default minimum height of 96px; consumer can override via className.
1059
+ * The `size` prop accepts `"sm" | "md" | "lg"`. Default `md` preserves the
1060
+ * 80px (5rem) min-height + body-md text from before this prop existed.
1061
+ *
1062
+ * Note: `TextareaHTMLAttributes<HTMLTextAreaElement>` does NOT declare a
1063
+ * native `size` attribute (textareas use `rows` / `cols`), so no Omit is
1064
+ * needed — contrast with `<Input>` which had EC-1 collision.
761
1065
  */
1066
+ declare const textareaVariants: (props?: ({
1067
+ size?: "sm" | "md" | "lg" | null | undefined;
1068
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
1069
+ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, VariantProps<typeof textareaVariants> {
1070
+ }
762
1071
  declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
763
1072
 
764
1073
  interface ContextWindowBarProps extends HTMLAttributes<HTMLDivElement> {
@@ -1635,7 +1944,7 @@ declare const TopNav: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement
1635
1944
  */
1636
1945
  declare const Overlay: react.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogOverlayProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1637
1946
  declare const sheetVariants: (props?: ({
1638
- side?: "right" | "left" | "top" | "bottom" | null | undefined;
1947
+ side?: "bottom" | "left" | "right" | "top" | null | undefined;
1639
1948
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1640
1949
  interface ContentProps extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content>, VariantProps<typeof sheetVariants> {
1641
1950
  hideCloseButton?: boolean;
@@ -3060,4 +3369,4 @@ interface CommandPaletteProps {
3060
3369
  */
3061
3370
  declare function CommandPalette({ open, onOpenChange, items, onSelect, placeholder, emptyMessage, filter, }: CommandPaletteProps): react_jsx_runtime.JSX.Element;
3062
3371
 
3063
- export { ALL_MODES, AgentComposer, type AgentDraft, AgentEditor, AgentErrorCard, type AgentErrorKind, AgentEvent, type AgentEvent$1 as AgentEventModel, type AgentEventStatus, type AgentEventType, AgentHandoff, AgentProfile, type AgentProfileDescriptor, AgentStartingState, AgentStream, type AgentStreamItem, AgentStreaming, AgentTimeline, ApprovalCard, type ApprovalSeverity, ArtifactPreview, type Attachment, AttachmentChip, type AuditActorKind, type AuditEntry, AuditLogEntry, type AuditSeverity, AutoCompactNotice, Avatar, BadgeWithDot as Badge, type BadgeProps, BrowserControls, BuildLogStream, Button, type ButtonProps, type Capability, CapabilityIndicator, type CapabilityState, Card, ChatComposer, ChatMessage, ChatThread, Checkbox, type ColorScale, type CommandItem, CommandPalette, type ComposerMode, ContextCard, ContextWindowBar, CostMeter, type CreatedFile, CreatedFilesCard, type CronJob, CronJobCard, type CronJobStatus, CronJobsList, type Deployment, DeploymentRow, type DeploymentStatus, Dialog, type DiffHunk, type DiffLine, type DiffLineKind, DiffViewer, type Domain, DomainConfig, type DomainStatus, EmptyState, type EnvScope, type EnvVar, EnvVarEditor, FolderContextCard, type FolderEntry, FolderSelector, FormField, HOOK_EVENTS, type HandoffParty, HookConfig, type HookEntry, type HookEvent, type HookEventEntry, HookEventLog, type HookEventResult, Input, type InputProps, type IntentOption, IntentSelector, Label, type Lane, LaneBoard, type LaneCard, type LaneState, type LogLevel, type LogLine, LoginSplit, type MCPServer, MCPServerCard, MCPServerList, type MCPServerStatus, MODE_LABEL, MemoryEditor, type MemoryLayer, type MemoryScope, type MentionItem, MentionMenu, type MentionTrigger, type Message, type MessageRole, type Metric, MetricsPanel, type Mode, type ModelCapabilityFlag, ModelCard, type ModelInfo, type ModelOption, ModelSelector, type PermissionDecision, type PermissionDecisionKind, PermissionMatrix, PermissionModal, type PermissionOperation, type PermissionRequest, type PermissionRule, type PlanNode, type PlanNodeStatus, type PreviewEnv, PreviewEnvCard, PreviewPanel, type PreviewService, ProgressChecklist, type Project, ProjectCard, type ProjectStatus, ProjectSwitcher, type QuickAction, QuickActionChips, RadioGroup, type RailStep, type RecentFolder, RecentFoldersList, type RollbackTarget, RollbackUI, type Rule, RuleCard, RuleEditor, type RuleScope, type RuleState, RunStats, type RunningTaskItem, type RunningTaskStatus, RunningTasksPanel, ScrollArea, Select, SessionListItem, type SessionMode, type SessionRunStatus, type SessionStatus, type SessionSummary, SessionTimeline, Sheet, Sidebar, Skeleton, type Skill, SkillCard, SkillEditor, type SkillSource, type SkillState, SkillsList, SocialAuthRow, type SocialProvider, StepsRail, SubAgentDispatch, type SubAgentRun, type SubAgentState, Switch, SystemPromptEditor, Tabs, TaskHeader, TaskNode, TaskPlan, type TaskSource, type TaskStatus, type TaskStep, type TaskStepStatus, type TerminalLine, TerminalPanel, Textarea, type TextareaProps, type Theme, type ThemeFonts, type ThemeMode, ThemeProvider, ThemeScript, ThemeSwitcher, TheoUIProvider, type TheoUIProviderProps, Toast, type ToastVariant, Toaster, TokenUsageChart, type TokenUsagePoint, ToolCall, ToolCallCard, type ToolCallStatus, type ToolEnablement, type ToolEntry, ToolResult, ToolsList, TooltipWithStatics as Tooltip, TopNav, auroraTerminal, avatarVariants, badgeVariants, builtinThemes, buttonVariants, capabilityPresets, classicPaper, cn, modelCapabilityPresets, sheetVariants, useTheme, useToast, violetForge };
3372
+ export { ALL_MODES, AgentComposer, type AgentDraft, AgentEditor, AgentErrorCard, type AgentErrorKind, AgentEvent, type AgentEvent$1 as AgentEventModel, type AgentEventStatus, type AgentEventType, AgentHandoff, AgentProfile, type AgentProfileDescriptor, AgentStartingState, AgentStream, type AgentStreamItem, AgentStreaming, AgentTimeline, ApprovalCard, type ApprovalSeverity, ArtifactPreview, type Attachment, AttachmentChip, type AuditActorKind, type AuditEntry, AuditLogEntry, type AuditSeverity, AutoCompactNotice, Avatar, BadgeWithDot as Badge, type BadgeProps, BrowserControls, BuildLogStream, Button, type ButtonProps, type Capability, CapabilityIndicator, type CapabilityState, Card, ChatComposer, ChatMessage, ChatThread, Checkbox, type ColorScale, type CommandItem, CommandPalette, type ComposerMode, ContextCard, ContextWindowBar, CostMeter, type CreatedFile, CreatedFilesCard, type CronJob, CronJobCard, type CronJobStatus, CronJobsList, type DefineThemeInput, type Density, type DensityContextValue, type Deployment, DeploymentRow, type DeploymentStatus, Dialog, type DiffHunk, type DiffLine, type DiffLineKind, DiffViewer, type Domain, DomainConfig, type DomainStatus, EmptyState, type EnvScope, type EnvVar, EnvVarEditor, FolderContextCard, type FolderEntry, FolderSelector, FormField, HOOK_EVENTS, type HandoffParty, HookConfig, type HookEntry, type HookEvent, type HookEventEntry, HookEventLog, type HookEventResult, Input, type InputProps, type IntentOption, IntentSelector, Label, type Lane, LaneBoard, type LaneCard, type LaneState, type LogLevel, type LogLine, LoginSplit, type MCPServer, MCPServerCard, MCPServerList, type MCPServerStatus, MODE_LABEL, MemoryEditor, type MemoryLayer, type MemoryScope, type MentionItem, MentionMenu, type MentionTrigger, type Message, type MessageRole, type Metric, MetricsPanel, type Mode, type ModelCapabilityFlag, ModelCard, type ModelInfo, type ModelOption, ModelSelector, type PermissionDecision, type PermissionDecisionKind, PermissionMatrix, PermissionModal, type PermissionOperation, type PermissionRequest, type PermissionRule, type PlanNode, type PlanNodeStatus, type PreviewEnv, PreviewEnvCard, PreviewPanel, type PreviewService, ProgressChecklist, type Project, ProjectCard, type ProjectStatus, ProjectSwitcher, type QuickAction, QuickActionChips, RadioGroup, type RailStep, type RecentFolder, RecentFoldersList, type RollbackTarget, RollbackUI, type Rule, RuleCard, RuleEditor, type RuleScope, type RuleState, RunStats, type RunningTaskItem, type RunningTaskStatus, RunningTasksPanel, ScrollArea, Select, SessionListItem, type SessionMode, type SessionRunStatus, type SessionStatus, type SessionSummary, SessionTimeline, Sheet, Sidebar, Skeleton, type Skill, SkillCard, SkillEditor, type SkillSource, type SkillState, SkillsList, SocialAuthRow, type SocialProvider, StepsRail, SubAgentDispatch, type SubAgentRun, type SubAgentState, Switch, SystemPromptEditor, Tabs, TaskHeader, TaskNode, TaskPlan, type TaskSource, type TaskStatus, type TaskStep, type TaskStepStatus, type TerminalLine, TerminalPanel, Textarea, type TextareaProps, type Theme, type ThemeFonts, type ThemeMode, ThemeProvider, ThemeScript, ThemeSwitcher, TheoUIProvider, type TheoUIProviderProps, Toast, type ToastVariant, Toaster, TokenUsageChart, type TokenUsagePoint, ToolCall, ToolCallCard, type ToolCallStatus, type ToolEnablement, type ToolEntry, ToolResult, ToolsList, TooltipWithStatics as Tooltip, TopNav, anthropicStyle, auroraTerminal, avatarVariants, badgeVariants, builtinThemes, buttonVariants, capabilityPresets, classicPaper, cn, defineTheme, dracula, githubDark, hex, linearGlass, modelCapabilityPresets, oneDark, openaiStyle, rgb, sheetVariants, useDensity, useTheme, useToast, vercelMono, violetForge };