@urbicon-ui/blocks 6.40.4 → 6.43.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 (72) hide show
  1. package/dist/components/Chat/A2UIView/A2UINode.svelte +20 -39
  2. package/dist/components/Chat/A2UIView/A2UIView.svelte +47 -50
  3. package/dist/components/Chat/A2UIView/a2ui-basic-catalog.d.ts +17 -0
  4. package/dist/components/Chat/A2UIView/a2ui-basic-catalog.js +69 -0
  5. package/dist/components/Chat/A2UIView/a2ui-catalog.d.ts +95 -0
  6. package/dist/components/Chat/A2UIView/a2ui-catalog.js +87 -0
  7. package/dist/components/Chat/A2UIView/a2ui-node-common.d.ts +40 -0
  8. package/dist/components/Chat/A2UIView/a2ui-node-common.js +72 -0
  9. package/dist/components/Chat/A2UIView/a2ui-prompt.d.ts +21 -10
  10. package/dist/components/Chat/A2UIView/a2ui-prompt.js +170 -24
  11. package/dist/components/Chat/A2UIView/a2ui-registry.d.ts +1 -1
  12. package/dist/components/Chat/A2UIView/a2ui-registry.js +2 -1
  13. package/dist/components/Chat/A2UIView/a2ui-render.d.ts +30 -0
  14. package/dist/components/Chat/A2UIView/a2ui-render.js +61 -23
  15. package/dist/components/Chat/A2UIView/a2ui-router.d.ts +136 -0
  16. package/dist/components/Chat/A2UIView/a2ui-router.js +264 -0
  17. package/dist/components/Chat/A2UIView/a2ui-schema.d.ts +45 -0
  18. package/dist/components/Chat/A2UIView/a2ui-schema.js +133 -0
  19. package/dist/components/Chat/A2UIView/a2ui-stream.d.ts +120 -0
  20. package/dist/components/Chat/A2UIView/a2ui-stream.js +406 -0
  21. package/dist/components/Chat/A2UIView/a2ui-transcript.d.ts +65 -0
  22. package/dist/components/Chat/A2UIView/a2ui-transcript.js +101 -0
  23. package/dist/components/Chat/A2UIView/a2ui-validate.d.ts +33 -1
  24. package/dist/components/Chat/A2UIView/a2ui-validate.js +167 -63
  25. package/dist/components/Chat/A2UIView/a2ui.types.d.ts +50 -0
  26. package/dist/components/Chat/A2UIView/a2ui.types.js +38 -1
  27. package/dist/components/Chat/A2UIView/index.d.ts +35 -2
  28. package/dist/components/Chat/A2UIView/index.js +13 -0
  29. package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte +831 -0
  30. package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte.d.ts +4 -0
  31. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.d.ts +14 -0
  32. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.js +87 -0
  33. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.d.ts +78 -0
  34. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.js +783 -0
  35. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.d.ts +43 -0
  36. package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.js +33 -0
  37. package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.d.ts +7 -0
  38. package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.js +86 -0
  39. package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +19 -19
  40. package/dist/components/FileUpload/fileUpload.variants.js +15 -4
  41. package/dist/components/PinInput/PinInput.svelte +1 -0
  42. package/dist/components/PinInput/pin-input.variants.js +14 -1
  43. package/dist/components/TimeInput/time-input.variants.js +16 -1
  44. package/dist/internal/field-chrome.d.ts +18 -1
  45. package/dist/internal/field-chrome.js +18 -1
  46. package/dist/primitives/Avatar/avatar.variants.js +4 -1
  47. package/dist/primitives/Badge/badge.variants.js +11 -2
  48. package/dist/primitives/Button/button.variants.js +4 -1
  49. package/dist/primitives/Card/card.variants.js +4 -1
  50. package/dist/primitives/Checkbox/checkbox.variants.js +7 -1
  51. package/dist/primitives/Combobox/Combobox.svelte +9 -1
  52. package/dist/primitives/Combobox/combobox.variants.d.ts +25 -0
  53. package/dist/primitives/Combobox/combobox.variants.js +32 -3
  54. package/dist/primitives/Combobox/index.d.ts +8 -2
  55. package/dist/primitives/Dialog/dialog.variants.js +4 -1
  56. package/dist/primitives/Drawer/drawer.variants.js +4 -1
  57. package/dist/primitives/Input/input.variants.js +17 -1
  58. package/dist/primitives/Menu/menu.variants.js +5 -1
  59. package/dist/primitives/Progress/progress.variants.js +5 -2
  60. package/dist/primitives/RadioGroup/radioGroup.variants.js +68 -9
  61. package/dist/primitives/Select/select.variants.js +13 -4
  62. package/dist/primitives/Slider/Slider.svelte +4 -1
  63. package/dist/primitives/Slider/slider.variants.js +9 -2
  64. package/dist/primitives/Textarea/textarea.variants.js +15 -1
  65. package/dist/primitives/Toast/toast.variants.js +5 -1
  66. package/dist/primitives/Toggle/toggle.variants.js +92 -18
  67. package/dist/primitives/Tooltip/tooltip.variants.d.ts +3 -3
  68. package/dist/primitives/Tooltip/tooltip.variants.js +5 -1
  69. package/dist/utils/persistent-state.svelte.d.ts +25 -1
  70. package/dist/utils/persistent-state.svelte.js +98 -10
  71. package/docs/MIGRATION-v5.md +29 -0
  72. package/package.json +3 -3
@@ -4,7 +4,10 @@ export const buttonVariants = tv({
4
4
  base: [
5
5
  'relative inline-flex items-center justify-center gap-2',
6
6
  'font-medium text-center whitespace-nowrap border cursor-pointer select-none',
7
- 'transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-[var(--blocks-duration-fast)] ease-out overflow-hidden',
7
+ // `scale`, NOT `transform`: Tailwind 4 emits `scale-*` as the discrete
8
+ // CSS `scale:` property, so a list naming only `transform` never animates
9
+ // the press cue (`active:scale-[0.98]` / `pressed`) — it would jump.
10
+ 'transition-[color,background-color,border-color,box-shadow,opacity,scale] duration-[var(--blocks-duration-fast)] ease-out overflow-hidden',
8
11
  // Radius is driven by the `tier` variant axis below — see `tier`.
9
12
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',
10
13
  'disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none'
@@ -2,7 +2,10 @@ import { tv } from '../../utils/variants.js';
2
2
  export const cardVariants = tv({
3
3
  slots: {
4
4
  base: [
5
- 'relative block w-full transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-[var(--blocks-duration-fast)] ease-out box-border',
5
+ // `translate`, NOT `transform`: Tailwind 4 emits `-translate-y-*` as the
6
+ // discrete CSS `translate:` property, so a list naming only `transform`
7
+ // never animates the `interactive` hover lift — it would jump.
8
+ 'relative block w-full transition-[color,background-color,border-color,box-shadow,opacity,translate] duration-[var(--blocks-duration-fast)] ease-out box-border',
6
9
  // Structure radius — cards are architectural surfaces, not human/CTA.
7
10
  'rounded-contain'
8
11
  ],
@@ -207,11 +207,17 @@ export const checkboxVariants = tv({
207
207
  }
208
208
  },
209
209
  // ── Error overrides unchecked border ──
210
+ // `group-hover:border-danger` is not redundant: modifier prefixes are part of
211
+ // the conflict bucket, so the plain `border-danger` never folds the unchecked
212
+ // variants' `group-hover:border-border-emphasis` above — without the pin, an
213
+ // errored checkbox loses its danger boundary the moment it is hovered.
210
214
  {
211
215
  error: true,
212
216
  checked: false,
213
217
  indeterminate: false,
214
- class: { box: 'border-danger peer-focus-visible:ring-danger/40' }
218
+ class: {
219
+ box: 'border-danger group-hover:border-danger peer-focus-visible:ring-danger/40'
220
+ }
215
221
  }
216
222
  ],
217
223
  defaultVariants: {
@@ -307,12 +307,20 @@
307
307
  };
308
308
  });
309
309
 
310
+ // `error` is the same signal that drives `aria-invalid` (`ff.invalid`), so
311
+ // the visible frame and the announced state can never disagree. It also
312
+ // reaches `resolveSlotClasses`, so a consumer `overrides` entry can target
313
+ // the invalid state.
310
314
  const variantProps: ComboboxVariants = $derived({
311
315
  variant,
312
316
  tier: effectiveTier,
313
317
  size,
314
318
  open,
315
- disabled
319
+ disabled,
320
+ // `|| undefined` rather than a plain `false`, matching Input: these props
321
+ // are also matched against `BlocksProvider` `overrides`, where an entry
322
+ // keyed `{ error: false }` must not fire on a valid field.
323
+ error: ff.invalid || undefined
316
324
  });
317
325
  const styles = $derived(comboboxVariants(variantProps));
318
326
 
@@ -5,6 +5,7 @@ export declare const comboboxVariants: ((props?: {
5
5
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
6
6
  open?: boolean | undefined;
7
7
  disabled?: boolean | undefined;
8
+ error?: boolean | undefined;
8
9
  } | undefined) => {
9
10
  base: (props?: ({
10
11
  tier?: "commit" | "modify" | undefined;
@@ -12,6 +13,7 @@ export declare const comboboxVariants: ((props?: {
12
13
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
13
14
  open?: boolean | undefined;
14
15
  disabled?: boolean | undefined;
16
+ error?: boolean | undefined;
15
17
  } & {
16
18
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
17
19
  }) | undefined) => string;
@@ -21,6 +23,7 @@ export declare const comboboxVariants: ((props?: {
21
23
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
22
24
  open?: boolean | undefined;
23
25
  disabled?: boolean | undefined;
26
+ error?: boolean | undefined;
24
27
  } & {
25
28
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
26
29
  }) | undefined) => string;
@@ -30,6 +33,7 @@ export declare const comboboxVariants: ((props?: {
30
33
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
31
34
  open?: boolean | undefined;
32
35
  disabled?: boolean | undefined;
36
+ error?: boolean | undefined;
33
37
  } & {
34
38
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
35
39
  }) | undefined) => string;
@@ -39,6 +43,7 @@ export declare const comboboxVariants: ((props?: {
39
43
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
40
44
  open?: boolean | undefined;
41
45
  disabled?: boolean | undefined;
46
+ error?: boolean | undefined;
42
47
  } & {
43
48
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
44
49
  }) | undefined) => string;
@@ -48,6 +53,7 @@ export declare const comboboxVariants: ((props?: {
48
53
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
49
54
  open?: boolean | undefined;
50
55
  disabled?: boolean | undefined;
56
+ error?: boolean | undefined;
51
57
  } & {
52
58
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
53
59
  }) | undefined) => string;
@@ -57,6 +63,7 @@ export declare const comboboxVariants: ((props?: {
57
63
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
58
64
  open?: boolean | undefined;
59
65
  disabled?: boolean | undefined;
66
+ error?: boolean | undefined;
60
67
  } & {
61
68
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
62
69
  }) | undefined) => string;
@@ -66,6 +73,7 @@ export declare const comboboxVariants: ((props?: {
66
73
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
67
74
  open?: boolean | undefined;
68
75
  disabled?: boolean | undefined;
76
+ error?: boolean | undefined;
69
77
  } & {
70
78
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
71
79
  }) | undefined) => string;
@@ -75,6 +83,7 @@ export declare const comboboxVariants: ((props?: {
75
83
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
76
84
  open?: boolean | undefined;
77
85
  disabled?: boolean | undefined;
86
+ error?: boolean | undefined;
78
87
  } & {
79
88
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
80
89
  }) | undefined) => string;
@@ -84,6 +93,7 @@ export declare const comboboxVariants: ((props?: {
84
93
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
85
94
  open?: boolean | undefined;
86
95
  disabled?: boolean | undefined;
96
+ error?: boolean | undefined;
87
97
  } & {
88
98
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
89
99
  }) | undefined) => string;
@@ -93,6 +103,7 @@ export declare const comboboxVariants: ((props?: {
93
103
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
94
104
  open?: boolean | undefined;
95
105
  disabled?: boolean | undefined;
106
+ error?: boolean | undefined;
96
107
  } & {
97
108
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
98
109
  }) | undefined) => string;
@@ -102,6 +113,7 @@ export declare const comboboxVariants: ((props?: {
102
113
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
103
114
  open?: boolean | undefined;
104
115
  disabled?: boolean | undefined;
116
+ error?: boolean | undefined;
105
117
  } & {
106
118
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
107
119
  }) | undefined) => string;
@@ -111,6 +123,7 @@ export declare const comboboxVariants: ((props?: {
111
123
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
112
124
  open?: boolean | undefined;
113
125
  disabled?: boolean | undefined;
126
+ error?: boolean | undefined;
114
127
  } & {
115
128
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
116
129
  }) | undefined) => string;
@@ -120,6 +133,7 @@ export declare const comboboxVariants: ((props?: {
120
133
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
121
134
  open?: boolean | undefined;
122
135
  disabled?: boolean | undefined;
136
+ error?: boolean | undefined;
123
137
  } & {
124
138
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
125
139
  }) | undefined) => string;
@@ -129,6 +143,7 @@ export declare const comboboxVariants: ((props?: {
129
143
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
130
144
  open?: boolean | undefined;
131
145
  disabled?: boolean | undefined;
146
+ error?: boolean | undefined;
132
147
  } & {
133
148
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
134
149
  }) | undefined) => string;
@@ -138,6 +153,7 @@ export declare const comboboxVariants: ((props?: {
138
153
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
139
154
  open?: boolean | undefined;
140
155
  disabled?: boolean | undefined;
156
+ error?: boolean | undefined;
141
157
  } & {
142
158
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
143
159
  }) | undefined) => string;
@@ -147,6 +163,7 @@ export declare const comboboxVariants: ((props?: {
147
163
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
148
164
  open?: boolean | undefined;
149
165
  disabled?: boolean | undefined;
166
+ error?: boolean | undefined;
150
167
  } & {
151
168
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
152
169
  }) | undefined) => string;
@@ -156,6 +173,7 @@ export declare const comboboxVariants: ((props?: {
156
173
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
157
174
  open?: boolean | undefined;
158
175
  disabled?: boolean | undefined;
176
+ error?: boolean | undefined;
159
177
  } & {
160
178
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
161
179
  }) | undefined) => string;
@@ -165,6 +183,7 @@ export declare const comboboxVariants: ((props?: {
165
183
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
166
184
  open?: boolean | undefined;
167
185
  disabled?: boolean | undefined;
186
+ error?: boolean | undefined;
168
187
  } & {
169
188
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
170
189
  }) | undefined) => string;
@@ -174,6 +193,7 @@ export declare const comboboxVariants: ((props?: {
174
193
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
175
194
  open?: boolean | undefined;
176
195
  disabled?: boolean | undefined;
196
+ error?: boolean | undefined;
177
197
  } & {
178
198
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
179
199
  }) | undefined) => string;
@@ -183,6 +203,7 @@ export declare const comboboxVariants: ((props?: {
183
203
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
184
204
  open?: boolean | undefined;
185
205
  disabled?: boolean | undefined;
206
+ error?: boolean | undefined;
186
207
  } & {
187
208
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
188
209
  }) | undefined) => string;
@@ -192,6 +213,7 @@ export declare const comboboxVariants: ((props?: {
192
213
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
193
214
  open?: boolean | undefined;
194
215
  disabled?: boolean | undefined;
216
+ error?: boolean | undefined;
195
217
  } & {
196
218
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
197
219
  }) | undefined) => string;
@@ -201,6 +223,7 @@ export declare const comboboxVariants: ((props?: {
201
223
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
202
224
  open?: boolean | undefined;
203
225
  disabled?: boolean | undefined;
226
+ error?: boolean | undefined;
204
227
  } & {
205
228
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
206
229
  }) | undefined) => string;
@@ -210,6 +233,7 @@ export declare const comboboxVariants: ((props?: {
210
233
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
211
234
  open?: boolean | undefined;
212
235
  disabled?: boolean | undefined;
236
+ error?: boolean | undefined;
213
237
  } & {
214
238
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
215
239
  }) | undefined) => string;
@@ -219,6 +243,7 @@ export declare const comboboxVariants: ((props?: {
219
243
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
220
244
  open?: boolean | undefined;
221
245
  disabled?: boolean | undefined;
246
+ error?: boolean | undefined;
222
247
  } & {
223
248
  class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
224
249
  }) | undefined) => string;
@@ -1,3 +1,4 @@
1
+ import { FIELD_MESSAGE_TONES, fieldErrorFrame } from '../../internal/field-chrome.js';
1
2
  import { tv } from '../../utils/variants.js';
2
3
  export const comboboxVariants = tv({
3
4
  slots: {
@@ -14,8 +15,15 @@ export const comboboxVariants = tv({
14
15
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:border-primary',
15
16
  'disabled:opacity-50 disabled:cursor-not-allowed'
16
17
  ],
17
- message: 'text-xs text-danger',
18
- helper: 'text-xs text-text-tertiary',
18
+ // Message tone follows the ROLE of the text, not the field state: the
19
+ // `message` slot only ever renders the `error` string (the markup picks it
20
+ // over `helper`, they are mutually exclusive), so the two slots carry the
21
+ // two shared field-message tones — a helper never reads red. Sibling
22
+ // fields express the same thing through a `messageType` axis because they
23
+ // render both roles through ONE `message` slot; here the slot split
24
+ // already encodes it.
25
+ message: ['text-xs', FIELD_MESSAGE_TONES.error],
26
+ helper: ['text-xs', FIELD_MESSAGE_TONES.helper],
19
27
  // `position`, `width`, `overflow-y` are set inline in Combobox.svelte
20
28
  // so the native `popover="manual"` top-layer rendering works
21
29
  // correctly and the UA's `overflow: auto` doesn't render a duplicate
@@ -204,6 +212,26 @@ export const comboboxVariants = tv({
204
212
  },
205
213
  disabled: {
206
214
  true: { base: 'opacity-50 pointer-events-none' }
215
+ },
216
+ // Validation frame, at parity with every other field — the SHARED fragment
217
+ // (`fieldErrorFrame`), not a hand-copied one, so the next token fix cannot
218
+ // miss Combobox the way it missed it before this axis existed (until then
219
+ // an invalid Combobox only announced itself via `aria-invalid`, with no
220
+ // visible frame at all).
221
+ //
222
+ // Both frames are painted because the visible frame moves between modes:
223
+ // single mode wears it on the `input`, multi mode on the tokenizer
224
+ // `control` — which lights via `focus-within`, since focus lives on the
225
+ // borderless search input inside it. Declared LAST so it wins the
226
+ // border/ring buckets against `variant`; Combobox has no `intent` axis (a
227
+ // deliberate non-goal for now), so nothing else competes. If one is ever
228
+ // added, move this frame to the compound stage — see the precedence note
229
+ // in input.variants.ts.
230
+ error: {
231
+ true: {
232
+ input: fieldErrorFrame('focus-visible'),
233
+ control: fieldErrorFrame('focus-within')
234
+ }
207
235
  }
208
236
  },
209
237
  defaultVariants: {
@@ -211,6 +239,7 @@ export const comboboxVariants = tv({
211
239
  variant: 'outlined',
212
240
  size: 'md',
213
241
  open: false,
214
- disabled: false
242
+ disabled: false,
243
+ error: false
215
244
  }
216
245
  });
@@ -20,7 +20,7 @@ export interface ComboboxGroup<T extends SelectValue = string> {
20
20
  * live on {@link ComboboxSingleProps} / {@link ComboboxMultipleProps} and narrow
21
21
  * against `multiple`.
22
22
  */
23
- interface ComboboxBaseProps<T extends SelectValue = string> extends ComboboxVariants, Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
23
+ interface ComboboxBaseProps<T extends SelectValue = string> extends Omit<ComboboxVariants, 'error'>, Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
24
24
  /** Array of selectable options. Each needs a unique `value`. */
25
25
  options?: ComboboxOption<T>[];
26
26
  /**
@@ -38,7 +38,13 @@ interface ComboboxBaseProps<T extends SelectValue = string> extends ComboboxVari
38
38
  label?: string;
39
39
  /** Helper text shown below the field. Hidden when an error is set. */
40
40
  helper?: string;
41
- /** Error message — replaces helper text and flags the field as invalid. */
41
+ /**
42
+ * Error message — replaces helper text, flags the field as invalid
43
+ * (`aria-invalid`) and paints the shared danger frame on the input (single
44
+ * mode) or the tokenizer control (multi). The string prop shadows the boolean
45
+ * `error` variant axis, which the component derives from it (mirrors Input /
46
+ * Select) — that is what the `Omit` above is for.
47
+ */
42
48
  error?: string;
43
49
  /**
44
50
  * Marks the field as required. Adds the asterisk on the label. @default false
@@ -37,7 +37,10 @@ export const dialogVariants = tv({
37
37
  // internal/core/.
38
38
  closeButton: [
39
39
  'relative font-medium text-center whitespace-nowrap border overflow-hidden',
40
- 'transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-[var(--blocks-duration-fast)] ease-out',
40
+ // `scale`, NOT `transform` mirrors buttonVariants.base: Tailwind 4 emits
41
+ // `scale-*` as the discrete `scale:` property, so `active:scale-[0.98]`
42
+ // below only animates if the list names `scale`.
43
+ 'transition-[color,background-color,border-color,box-shadow,opacity,scale] duration-[var(--blocks-duration-fast)] ease-out',
41
44
  'rounded-commit bg-transparent border-transparent shadow-none',
42
45
  'hover:shadow-[var(--blocks-shadow-md)] active:scale-[0.98] active:shadow-[var(--blocks-shadow-sm)]',
43
46
  'h-8 px-3 text-sm gap-1.5 text-neutral-emphasis hover:bg-neutral-subtle',
@@ -29,7 +29,10 @@ export const drawerVariants = tv({
29
29
  // See internal/core/.
30
30
  closeButton: [
31
31
  'relative font-medium text-center whitespace-nowrap border overflow-hidden',
32
- 'transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-[var(--blocks-duration-fast)] ease-out',
32
+ // `scale`, NOT `transform` mirrors buttonVariants.base: Tailwind 4 emits
33
+ // `scale-*` as the discrete `scale:` property, so `active:scale-[0.98]`
34
+ // below only animates if the list names `scale`.
35
+ 'transition-[color,background-color,border-color,box-shadow,opacity,scale] duration-[var(--blocks-duration-fast)] ease-out',
33
36
  'rounded-commit bg-transparent border-transparent shadow-none',
34
37
  'hover:shadow-[var(--blocks-shadow-md)] active:scale-[0.98] active:shadow-[var(--blocks-shadow-sm)]',
35
38
  'h-8 px-3 text-sm gap-1.5 text-neutral-emphasis hover:bg-neutral-subtle',
@@ -125,9 +125,11 @@ export const inputVariants = tv({
125
125
  error: { message: FIELD_MESSAGE_TONES.error },
126
126
  helper: { message: FIELD_MESSAGE_TONES.helper }
127
127
  },
128
+ // The error FRAME is not declared here — it lives in the compound stage
129
+ // below, where it beats `intent` by construction. See the precedence note
130
+ // on the first compound entry.
128
131
  error: {
129
132
  true: {
130
- base: fieldErrorFrame(focus),
131
133
  message: FIELD_MESSAGE_TONES.error
132
134
  }
133
135
  },
@@ -144,6 +146,20 @@ export const inputVariants = tv({
144
146
  }
145
147
  },
146
148
  compoundVariants: [
149
+ // ── Validation precedence: `error` beats `intent`, explicitly ────────────
150
+ // Both axes paint the SAME three buckets (border-color plus the focused
151
+ // border/ring tint), so exactly one of them can win. Emitting the error
152
+ // frame here rather than on the `error` axis makes that rule structural:
153
+ // compounds always fold after every axis, so `error: true` overrides
154
+ // whatever `intent` painted regardless of how the axes are ordered above.
155
+ // Previously the winner was decided purely by `error` happening to be
156
+ // DECLARED after `intent` — reordering the axes (or slipping a new one
157
+ // between them) would have silently turned validation feedback back into a
158
+ // green/amber frame. `intent` keeps its tonal job for the non-error states.
159
+ {
160
+ error: true,
161
+ class: { base: fieldErrorFrame(focus) }
162
+ },
147
163
  // Ghost keeps a transparent border in its resting state — even when an
148
164
  // intent would otherwise colour it. The error state intentionally drops
149
165
  // this override so validation feedback (`border-danger`) stays visible.
@@ -5,7 +5,11 @@ export const menuVariants = tv({
5
5
  trigger: ['w-full justify-between gap-3 min-w-36'],
6
6
  triggerText: ['flex flex-1 items-center text-left truncate'],
7
7
  chevron: [
8
- 'w-4 h-4 shrink-0 opacity-70 transition-[opacity,transform] duration-[var(--blocks-duration-fast)] ease-out'
8
+ // `rotate,translate`, NOT `transform`: Tailwind 4 emits `rotate-*` /
9
+ // `translate-*` as the discrete `rotate:` / `translate:` properties. The
10
+ // `chevronAnimation` axis drives exactly those two (rotate-0 ↔ rotate-180,
11
+ // translate-y-0 ↔ translate-y-1), so a `transform` entry animated neither.
12
+ 'w-4 h-4 shrink-0 opacity-70 transition-[opacity,rotate,translate] duration-[var(--blocks-duration-fast)] ease-out'
9
13
  ],
10
14
  // Floating panel surface. Position is owned by the wrapping Popover
11
15
  // (Floating UI sets `top` / `left` on its container); this slot just
@@ -6,8 +6,11 @@ export const progressVariants = tv({
6
6
  label: ['text-sm font-medium text-text-secondary'],
7
7
  valueText: ['text-sm tabular-nums text-text-tertiary'],
8
8
  // tier: commit — progress bar reads as a continuous status pill.
9
+ // Track fill is `surface-interactive` for the same reason as Slider's:
10
+ // `surface-subtle` equals `surface-elevated` in both modes, which made the
11
+ // track disappear on elevated surfaces (cards, popovers, dialogs).
9
12
  track: [
10
- 'relative w-full overflow-hidden rounded-commit bg-surface-subtle',
13
+ 'relative w-full overflow-hidden rounded-commit bg-surface-interactive',
11
14
  'transition-[background-color] duration-[var(--blocks-duration-fast)] ease-out'
12
15
  ],
13
16
  fill: [
@@ -16,7 +19,7 @@ export const progressVariants = tv({
16
19
  'transition-[width,background-color] duration-[var(--blocks-duration-normal)] ease-out'
17
20
  ],
18
21
  circularWrapper: ['relative inline-flex items-center justify-center'],
19
- circularTrack: ['stroke-current text-surface-subtle'],
22
+ circularTrack: ['stroke-current text-surface-interactive'],
20
23
  circularFill: [
21
24
  'stroke-current transition-[stroke-dashoffset] duration-[var(--blocks-duration-normal)] ease-out'
22
25
  ],
@@ -39,13 +39,32 @@ export const radioItemVariants = tv({
39
39
  // a radio indicator declares status, conventionally circular.
40
40
  indicator: [
41
41
  'relative flex items-center justify-center shrink-0 border',
42
- 'transition-[color,background-color,border-color,box-shadow] duration-[var(--blocks-duration-fast)] ease-out',
42
+ 'transition-[color,background-color,border-color,box-shadow,scale] duration-[var(--blocks-duration-fast)] ease-out',
43
+ // Press feedback on the control surface — the same small-element press
44
+ // cue Checkbox took from Badge/Avatar (`scale-95`); `group-active` so
45
+ // pressing the label squeezes the indicator too. It sits on the
46
+ // indicator rather than the dot: the dot already owns the `scale`
47
+ // bucket for its own check-in animation (`scale-0` → `scale-100`), and
48
+ // scaling the parent carries the dot along multiplicatively instead of
49
+ // fighting that bucket — the whole control squeezes as one, exactly as
50
+ // Checkbox's box does with its check glyph. `scale` is in the
51
+ // transition list above, and reduced motion collapses
52
+ // `--blocks-duration-fast` to 1ms.
53
+ 'group-active:scale-95',
43
54
  'peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50',
44
55
  'peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-surface-base'
45
56
  ],
46
57
  dot: [
47
58
  'opacity-0 scale-0',
48
- 'transition-[opacity,transform] duration-[var(--blocks-duration-fast)] ease-out'
59
+ // `scale`, not `transform`: Tailwind 4 compiles `scale-*` to the
60
+ // discrete `scale` property (`scale: var(--tw-scale-x) …`), which a
61
+ // `transition-property: transform` does NOT cover — so the check-in
62
+ // used to pop to full size instantly while only the opacity faded.
63
+ // (The shorthand `transition-transform` would work, since v4 expands it
64
+ // to `transform, translate, scale, rotate`; the explicit list has to
65
+ // name the property it actually animates.) Both durations are tokens,
66
+ // so reduced motion collapses the whole check-in to 1ms.
67
+ 'transition-[opacity,scale] duration-[var(--blocks-duration-fast)] ease-out'
49
68
  ],
50
69
  label: ['text-text-primary select-none leading-snug'],
51
70
  description: ['text-text-tertiary leading-snug']
@@ -139,41 +158,81 @@ export const radioItemVariants = tv({
139
158
  class: { indicator: 'bg-transparent border-transparent group-hover:bg-surface-subtle' }
140
159
  },
141
160
  // Checked intent colors
161
+ // Hover/active darken through the intent interaction-layer tokens — the
162
+ // same `bg-<intent>-hover` / `bg-<intent>-active` ladder Button and
163
+ // Checkbox use — via `group-*` so hovering/pressing the label counts too.
164
+ // The border stays on the base intent stop (as in Checkbox).
165
+ //
166
+ // The dot keeps ONE colour across all three stops: it is the intent's
167
+ // paired on-colour, and `style/contrast.test.ts` measures exactly that
168
+ // pairing (`--color-<intent>` / `-hover` / `-active` against
169
+ // `--color-text-on-primary` / `-on-warning`) across every theme × mode ×
170
+ // state — 126 combinations, all ≥ AA 4.5:1, and all ≥ the 3:1
171
+ // UI-component floor that actually binds a non-text mark. That includes
172
+ // the one adverse direction, `warning/light/active`, where the fill
173
+ // darkens *toward* the dark `text-on-warning`; warning-700 is pinned as
174
+ // the lowest press stop that still clears AA. So a state-dependent dot
175
+ // colour would buy nothing the token graph does not already guarantee.
142
176
  {
143
177
  checked: true,
144
178
  intent: 'primary',
145
- class: { indicator: 'bg-primary border-primary', dot: 'bg-text-on-primary' }
179
+ class: {
180
+ indicator: 'bg-primary border-primary group-hover:bg-primary-hover group-active:bg-primary-active',
181
+ dot: 'bg-text-on-primary'
182
+ }
146
183
  },
147
184
  {
148
185
  checked: true,
149
186
  intent: 'secondary',
150
- class: { indicator: 'bg-secondary border-secondary', dot: 'bg-text-on-primary' }
187
+ class: {
188
+ indicator: 'bg-secondary border-secondary group-hover:bg-secondary-hover group-active:bg-secondary-active',
189
+ dot: 'bg-text-on-primary'
190
+ }
151
191
  },
152
192
  {
153
193
  checked: true,
154
194
  intent: 'success',
155
- class: { indicator: 'bg-success border-success', dot: 'bg-text-on-primary' }
195
+ class: {
196
+ indicator: 'bg-success border-success group-hover:bg-success-hover group-active:bg-success-active',
197
+ dot: 'bg-text-on-primary'
198
+ }
156
199
  },
157
200
  {
158
201
  checked: true,
159
202
  intent: 'warning',
160
- class: { indicator: 'bg-warning border-warning', dot: 'bg-text-on-warning' }
203
+ class: {
204
+ indicator: 'bg-warning border-warning group-hover:bg-warning-hover group-active:bg-warning-active',
205
+ dot: 'bg-text-on-warning'
206
+ }
161
207
  },
162
208
  {
163
209
  checked: true,
164
210
  intent: 'danger',
165
- class: { indicator: 'bg-danger border-danger', dot: 'bg-text-on-primary' }
211
+ class: {
212
+ indicator: 'bg-danger border-danger group-hover:bg-danger-hover group-active:bg-danger-active',
213
+ dot: 'bg-text-on-primary'
214
+ }
166
215
  },
167
216
  {
168
217
  checked: true,
169
218
  intent: 'neutral',
170
- class: { indicator: 'bg-neutral border-neutral', dot: 'bg-text-on-primary' }
219
+ class: {
220
+ indicator: 'bg-neutral border-neutral group-hover:bg-neutral-hover group-active:bg-neutral-active',
221
+ dot: 'bg-text-on-primary'
222
+ }
171
223
  },
172
224
  // Error overrides unchecked border
225
+ // `group-hover:border-danger` pins the hover bucket too: the unchecked
226
+ // compounds above carry a `group-hover:border-*` step, and a plain
227
+ // `border-danger` does not fold it (modifier prefixes are part of the
228
+ // conflict bucket), so without this the error boundary went neutral the
229
+ // moment the pointer arrived — exactly when the mark matters.
173
230
  {
174
231
  error: true,
175
232
  checked: false,
176
- class: { indicator: 'border-danger peer-focus-visible:ring-danger/40' }
233
+ class: {
234
+ indicator: 'border-danger group-hover:border-danger peer-focus-visible:ring-danger/40'
235
+ }
177
236
  }
178
237
  ],
179
238
  defaultVariants: {