@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
@@ -0,0 +1,43 @@
1
+ import { type SlotNames, type VariantProps } from '../../../../utils/variants.js';
2
+ /**
3
+ * Extra slot styles the Urbicon A2UI dispatcher needs BEYOND the base
4
+ * `a2uiViewVariants` slots it inherits through the render context (column, row,
5
+ * list, icon, image, errorChip, pending, …). These are for the raw-HTML bits the
6
+ * Urbicon catalog renders itself — the `Section` archetype, plain body text, the
7
+ * field-error line — everything else renders through a real Urbicon component
8
+ * that carries its own tokens.
9
+ *
10
+ * Loaded LOCALLY by `UrbiconA2UINode.svelte` (never by the base `A2UIView` /
11
+ * `A2UINode`), so `urbicon/` value code stays out of the Basic bundle. Pure
12
+ * semantic tokens — no `dark:`, no hardcoded colours.
13
+ */
14
+ export declare const a2uiUrbiconVariants: ((props?: {} | undefined) => {
15
+ section: (props?: ({} & {
16
+ 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
+ }) | undefined) => string;
18
+ sectionHeader: (props?: ({} & {
19
+ 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;
20
+ }) | undefined) => string;
21
+ sectionTitle: (props?: ({} & {
22
+ 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;
23
+ }) | undefined) => string;
24
+ sectionDescription: (props?: ({} & {
25
+ 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
+ }) | undefined) => string;
27
+ body: (props?: ({} & {
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;
29
+ }) | undefined) => string;
30
+ fieldError: (props?: ({} & {
31
+ 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;
32
+ }) | undefined) => string;
33
+ field: (props?: ({} & {
34
+ 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
+ }) | undefined) => string;
36
+ emptyStateCta: (props?: ({} & {
37
+ 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;
38
+ }) | undefined) => string;
39
+ }) & {
40
+ readonly config: import("../../../../utils/variants.js").TVConfig;
41
+ };
42
+ export type A2UIViewUrbiconVariants = VariantProps<typeof a2uiUrbiconVariants>;
43
+ export type A2UIViewUrbiconSlots = SlotNames<typeof a2uiUrbiconVariants>;
@@ -0,0 +1,33 @@
1
+ import { tv } from '../../../../utils/variants.js';
2
+ /**
3
+ * Extra slot styles the Urbicon A2UI dispatcher needs BEYOND the base
4
+ * `a2uiViewVariants` slots it inherits through the render context (column, row,
5
+ * list, icon, image, errorChip, pending, …). These are for the raw-HTML bits the
6
+ * Urbicon catalog renders itself — the `Section` archetype, plain body text, the
7
+ * field-error line — everything else renders through a real Urbicon component
8
+ * that carries its own tokens.
9
+ *
10
+ * Loaded LOCALLY by `UrbiconA2UINode.svelte` (never by the base `A2UIView` /
11
+ * `A2UINode`), so `urbicon/` value code stays out of the Basic bundle. Pure
12
+ * semantic tokens — no `dark:`, no hardcoded colours.
13
+ */
14
+ export const a2uiUrbiconVariants = tv({
15
+ slots: {
16
+ /** Section wrapper (title/description block + body). */
17
+ section: 'flex min-w-0 flex-col gap-3',
18
+ /** Section header (title + optional description). */
19
+ sectionHeader: 'flex min-w-0 flex-col gap-1',
20
+ /** Section title heading. */
21
+ sectionTitle: 'min-w-0 text-lg font-semibold leading-tight text-text-primary',
22
+ /** Section description (secondary text under the title). */
23
+ sectionDescription: 'min-w-0 text-sm text-text-secondary',
24
+ /** Plain body text (Text variant=body — PLAIN, no Markdown). */
25
+ body: 'min-w-0 break-words text-sm text-text-primary',
26
+ /** A form field's error message line (shown under a field when `error` is non-empty). */
27
+ fieldError: 'mt-1 text-xs text-danger',
28
+ /** Wrapper around a form field + its error line. */
29
+ field: 'flex min-w-0 flex-col',
30
+ /** Wrapper for the EmptyState call-to-action. */
31
+ emptyStateCta: 'mt-2 flex justify-center'
32
+ }
33
+ });
@@ -0,0 +1,7 @@
1
+ /** One variant axis: its allowed values (sorted) and documented default. */
2
+ export interface UrbiconAxis {
3
+ readonly values: readonly string[];
4
+ readonly default?: string;
5
+ }
6
+ /** Urbicon component name → axis name → axis. The Urbicon A2UI registry references these. */
7
+ export declare const URBICON_AXES: Readonly<Record<string, Readonly<Record<string, UrbiconAxis>>>>;
@@ -0,0 +1,86 @@
1
+ // DO NOT EDIT — generated by scripts/a2ui-axes-gen.ts (`bun run a2ui:axes`).
2
+ // Source: packages/design-content/content/component-catalog.json (docs-gen artifact).
3
+ //
4
+ // The variant-axis truth of the Urbicon components the A2UI catalog maps. The
5
+ // hand-curated registry couples to this (values ⊆ axis; default ===; every
6
+ // `urbicon` reference exists) so the catalog can never advertise a value the real
7
+ // component does not support. Regenerate after docs:gen with `bun run a2ui:axes`.
8
+ /** Urbicon component name → axis name → axis. The Urbicon A2UI registry references these. */
9
+ export const URBICON_AXES = {
10
+ Accordion: {
11
+ size: { values: ["lg", "md", "sm"], default: "md" },
12
+ variant: { values: ["card", "default", "ghost"], default: "default" },
13
+ },
14
+ Alert: {
15
+ intent: { values: ["danger", "info", "neutral", "primary", "success", "warning"], default: "primary" },
16
+ size: { values: ["lg", "md", "sm"], default: "md" },
17
+ variant: { values: ["filled", "inline", "soft"], default: "soft" },
18
+ },
19
+ Avatar: {
20
+ intent: { values: ["danger", "neutral", "primary", "secondary", "success", "warning"], default: "neutral" },
21
+ size: { values: ["2xl", "lg", "md", "sm", "xl", "xs"], default: "md" },
22
+ variant: { values: ["circle", "rounded", "square"], default: "circle" },
23
+ },
24
+ Badge: {
25
+ intent: { values: ["danger", "neutral", "primary", "secondary", "success", "warning"], default: "primary" },
26
+ size: { values: ["lg", "md", "sm", "xs"], default: "md" },
27
+ variant: { values: ["dot", "filled", "outlined", "soft"], default: "filled" },
28
+ },
29
+ Button: {
30
+ intent: { values: ["danger", "neutral", "primary", "secondary", "success", "warning"], default: "neutral" },
31
+ size: { values: ["2xs", "lg", "md", "sm", "xl", "xs"], default: "md" },
32
+ variant: { values: ["filled", "ghost", "outlined", "text"], default: "filled" },
33
+ },
34
+ Card: {
35
+ variant: { values: ["elevated", "floating", "outlined", "quiet"], default: "quiet" },
36
+ },
37
+ Checkbox: {
38
+ intent: { values: ["danger", "neutral", "primary", "secondary", "success", "warning"], default: "primary" },
39
+ size: { values: ["lg", "md", "sm", "xs"], default: "md" },
40
+ variant: { values: ["filled", "ghost", "outlined"], default: "outlined" },
41
+ },
42
+ Input: {
43
+ intent: { values: ["danger", "default", "success", "warning"], default: "default" },
44
+ size: { values: ["lg", "md", "sm", "xl", "xs"], default: "md" },
45
+ variant: { values: ["filled", "ghost", "outlined", "underline"], default: "outlined" },
46
+ },
47
+ Progress: {
48
+ intent: { values: ["danger", "neutral", "primary", "secondary", "success", "warning"], default: "primary" },
49
+ size: { values: ["lg", "md", "sm", "xs"], default: "md" },
50
+ },
51
+ RadioGroup: {
52
+ orientation: { values: ["horizontal", "vertical"], default: "vertical" },
53
+ },
54
+ Select: {
55
+ size: { values: ["lg", "md", "sm", "xl", "xs"], default: "md" },
56
+ variant: { values: ["filled", "ghost", "outlined", "underline"], default: "outlined" },
57
+ },
58
+ Separator: {
59
+ orientation: { values: ["horizontal", "vertical"], default: "horizontal" },
60
+ size: { values: ["lg", "md", "sm"], default: "md" },
61
+ },
62
+ Slider: {
63
+ intent: { values: ["danger", "neutral", "primary", "secondary", "success", "warning"], default: "primary" },
64
+ size: { values: ["lg", "md", "sm"], default: "md" },
65
+ variant: { values: ["default", "rail"], default: "default" },
66
+ },
67
+ Stepper: {
68
+ orientation: { values: ["horizontal", "vertical"], default: "horizontal" },
69
+ size: { values: ["lg", "md", "sm"], default: "md" },
70
+ variant: { values: ["default", "minimal", "outlined"], default: "default" },
71
+ },
72
+ Textarea: {
73
+ intent: { values: ["danger", "default", "success", "warning"], default: "default" },
74
+ size: { values: ["lg", "md", "sm", "xl", "xs"], default: "md" },
75
+ },
76
+ TimeInput: {
77
+ intent: { values: ["danger", "default", "success", "warning"], default: "default" },
78
+ size: { values: ["lg", "md", "sm"], default: "md" },
79
+ variant: { values: ["filled", "ghost", "outlined"], default: "outlined" },
80
+ },
81
+ Toggle: {
82
+ intent: { values: ["danger", "neutral", "primary", "secondary", "success", "warning"], default: "primary" },
83
+ size: { values: ["lg", "md", "sm", "xs"], default: "md" },
84
+ variant: { values: ["default", "dot"], default: "default" },
85
+ },
86
+ };
@@ -2,131 +2,131 @@ import { type SlotNames, type VariantProps } from '../../../utils/variants.js';
2
2
  export declare const chatMessageVariants: ((props?: {
3
3
  layout?: "bubble" | "plain" | undefined;
4
4
  role?: "user" | "system" | "assistant" | undefined;
5
- density?: "comfortable" | "compact" | undefined;
5
+ density?: "compact" | "comfortable" | undefined;
6
6
  } | undefined) => {
7
7
  root: (props?: ({
8
8
  layout?: "bubble" | "plain" | undefined;
9
9
  role?: "user" | "system" | "assistant" | undefined;
10
- density?: "comfortable" | "compact" | undefined;
10
+ density?: "compact" | "comfortable" | undefined;
11
11
  } & {
12
12
  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;
13
13
  }) | undefined) => string;
14
14
  container: (props?: ({
15
15
  layout?: "bubble" | "plain" | undefined;
16
16
  role?: "user" | "system" | "assistant" | undefined;
17
- density?: "comfortable" | "compact" | undefined;
17
+ density?: "compact" | "comfortable" | undefined;
18
18
  } & {
19
19
  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;
20
20
  }) | undefined) => string;
21
21
  header: (props?: ({
22
22
  layout?: "bubble" | "plain" | undefined;
23
23
  role?: "user" | "system" | "assistant" | undefined;
24
- density?: "comfortable" | "compact" | undefined;
24
+ density?: "compact" | "comfortable" | undefined;
25
25
  } & {
26
26
  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;
27
27
  }) | undefined) => string;
28
28
  roleName: (props?: ({
29
29
  layout?: "bubble" | "plain" | undefined;
30
30
  role?: "user" | "system" | "assistant" | undefined;
31
- density?: "comfortable" | "compact" | undefined;
31
+ density?: "compact" | "comfortable" | undefined;
32
32
  } & {
33
33
  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;
34
34
  }) | undefined) => string;
35
35
  avatar: (props?: ({
36
36
  layout?: "bubble" | "plain" | undefined;
37
37
  role?: "user" | "system" | "assistant" | undefined;
38
- density?: "comfortable" | "compact" | undefined;
38
+ density?: "compact" | "comfortable" | undefined;
39
39
  } & {
40
40
  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;
41
41
  }) | undefined) => string;
42
42
  bubble: (props?: ({
43
43
  layout?: "bubble" | "plain" | undefined;
44
44
  role?: "user" | "system" | "assistant" | undefined;
45
- density?: "comfortable" | "compact" | undefined;
45
+ density?: "compact" | "comfortable" | undefined;
46
46
  } & {
47
47
  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;
48
48
  }) | undefined) => string;
49
49
  partsFlow: (props?: ({
50
50
  layout?: "bubble" | "plain" | undefined;
51
51
  role?: "user" | "system" | "assistant" | undefined;
52
- density?: "comfortable" | "compact" | undefined;
52
+ density?: "compact" | "comfortable" | undefined;
53
53
  } & {
54
54
  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;
55
55
  }) | undefined) => string;
56
56
  attachment: (props?: ({
57
57
  layout?: "bubble" | "plain" | undefined;
58
58
  role?: "user" | "system" | "assistant" | undefined;
59
- density?: "comfortable" | "compact" | undefined;
59
+ density?: "compact" | "comfortable" | undefined;
60
60
  } & {
61
61
  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
62
  }) | undefined) => string;
63
63
  attachmentIcon: (props?: ({
64
64
  layout?: "bubble" | "plain" | undefined;
65
65
  role?: "user" | "system" | "assistant" | undefined;
66
- density?: "comfortable" | "compact" | undefined;
66
+ density?: "compact" | "comfortable" | undefined;
67
67
  } & {
68
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;
69
69
  }) | undefined) => string;
70
70
  attachmentName: (props?: ({
71
71
  layout?: "bubble" | "plain" | undefined;
72
72
  role?: "user" | "system" | "assistant" | undefined;
73
- density?: "comfortable" | "compact" | undefined;
73
+ density?: "compact" | "comfortable" | undefined;
74
74
  } & {
75
75
  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;
76
76
  }) | undefined) => string;
77
77
  attachmentSize: (props?: ({
78
78
  layout?: "bubble" | "plain" | undefined;
79
79
  role?: "user" | "system" | "assistant" | undefined;
80
- density?: "comfortable" | "compact" | undefined;
80
+ density?: "compact" | "comfortable" | undefined;
81
81
  } & {
82
82
  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;
83
83
  }) | undefined) => string;
84
84
  sourcesFooter: (props?: ({
85
85
  layout?: "bubble" | "plain" | undefined;
86
86
  role?: "user" | "system" | "assistant" | undefined;
87
- density?: "comfortable" | "compact" | undefined;
87
+ density?: "compact" | "comfortable" | undefined;
88
88
  } & {
89
89
  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;
90
90
  }) | undefined) => string;
91
91
  placeholder: (props?: ({
92
92
  layout?: "bubble" | "plain" | undefined;
93
93
  role?: "user" | "system" | "assistant" | undefined;
94
- density?: "comfortable" | "compact" | undefined;
94
+ density?: "compact" | "comfortable" | undefined;
95
95
  } & {
96
96
  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;
97
97
  }) | undefined) => string;
98
98
  statusAlert: (props?: ({
99
99
  layout?: "bubble" | "plain" | undefined;
100
100
  role?: "user" | "system" | "assistant" | undefined;
101
- density?: "comfortable" | "compact" | undefined;
101
+ density?: "compact" | "comfortable" | undefined;
102
102
  } & {
103
103
  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;
104
104
  }) | undefined) => string;
105
105
  footer: (props?: ({
106
106
  layout?: "bubble" | "plain" | undefined;
107
107
  role?: "user" | "system" | "assistant" | undefined;
108
- density?: "comfortable" | "compact" | undefined;
108
+ density?: "compact" | "comfortable" | undefined;
109
109
  } & {
110
110
  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;
111
111
  }) | undefined) => string;
112
112
  actions: (props?: ({
113
113
  layout?: "bubble" | "plain" | undefined;
114
114
  role?: "user" | "system" | "assistant" | undefined;
115
- density?: "comfortable" | "compact" | undefined;
115
+ density?: "compact" | "comfortable" | undefined;
116
116
  } & {
117
117
  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;
118
118
  }) | undefined) => string;
119
119
  actionButton: (props?: ({
120
120
  layout?: "bubble" | "plain" | undefined;
121
121
  role?: "user" | "system" | "assistant" | undefined;
122
- density?: "comfortable" | "compact" | undefined;
122
+ density?: "compact" | "comfortable" | undefined;
123
123
  } & {
124
124
  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
125
  }) | undefined) => string;
126
126
  metadata: (props?: ({
127
127
  layout?: "bubble" | "plain" | undefined;
128
128
  role?: "user" | "system" | "assistant" | undefined;
129
- density?: "comfortable" | "compact" | undefined;
129
+ density?: "compact" | "comfortable" | undefined;
130
130
  } & {
131
131
  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;
132
132
  }) | undefined) => string;
@@ -8,14 +8,19 @@ export const fileUploadVariants = tv({
8
8
  'rounded-contain border-2 border-dashed',
9
9
  'border-border-default bg-surface-base',
10
10
  'cursor-pointer select-none',
11
- 'transition-[color,background-color,border-color,box-shadow,transform]',
11
+ // `scale`, NOT `transform`: Tailwind 4 emits `scale-*` as the discrete
12
+ // `scale:` property — the `dragging` compounds below lift the zone with
13
+ // `scale-[1.01]`, which a `transform` entry never animated.
14
+ 'transition-[color,background-color,border-color,box-shadow,scale]',
12
15
  'duration-[var(--blocks-duration-fast)]',
13
16
  'ease-[var(--blocks-ease-gentle)]',
14
17
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2'
15
18
  ],
16
19
  dropzoneIcon: [
17
20
  'text-text-quaternary',
18
- 'transition-[color,transform] duration-[var(--blocks-duration-fast)]'
21
+ // `scale`, NOT `transform` — the `dragging` compounds pop the icon with
22
+ // `scale-110` (discrete `scale:` property in Tailwind 4).
23
+ 'transition-[color,scale] duration-[var(--blocks-duration-fast)]'
19
24
  ],
20
25
  dropzoneTitle: ['font-medium text-text-primary'],
21
26
  dropzoneDescription: ['text-text-tertiary text-center max-w-xs'],
@@ -24,7 +29,10 @@ export const fileUploadVariants = tv({
24
29
  fileItem: [
25
30
  'group relative flex items-center gap-3',
26
31
  'rounded-contain border border-border-hairline bg-surface-quiet',
27
- 'transition-[background-color,border-color,box-shadow,opacity,transform]',
32
+ // No transform entry: nothing on this slot sets a scale/translate/rotate
33
+ // utility, and Tailwind 4 would emit those as discrete properties anyway —
34
+ // `transform` was dead weight.
35
+ 'transition-[background-color,border-color,box-shadow,opacity]',
28
36
  'duration-[var(--blocks-duration-fast)]',
29
37
  'hover:border-border-default hover:shadow-[var(--blocks-shadow-sm)]'
30
38
  ],
@@ -49,7 +57,10 @@ export const fileUploadVariants = tv({
49
57
  fileItemError: ['text-danger'],
50
58
  fileItemStatusIcon: [
51
59
  'flex-shrink-0',
52
- 'transition-[color,transform] duration-[var(--blocks-duration-fast)]'
60
+ // Colour only: the icon is swapped per status, never scaled/rotated, so a
61
+ // `transform` entry animated nothing (Tailwind 4 emits transforms as the
62
+ // discrete scale/translate/rotate properties).
63
+ 'transition-[color] duration-[var(--blocks-duration-fast)]'
53
64
  ]
54
65
  },
55
66
  variants: {
@@ -261,6 +261,7 @@
261
261
  role="group"
262
262
  aria-labelledby={label ? labelId : undefined}
263
263
  aria-label={label ? undefined : ariaLabel}
264
+ aria-disabled={disabled ? 'true' : undefined}
264
265
  class={unstyled ? (slotClasses?.group ?? '') : styles.group({ class: slotClasses?.group })}
265
266
  >
266
267
  {#each cellKeys as key, i (key)}
@@ -74,9 +74,11 @@ export const pinInputVariants = tv({
74
74
  error: { message: FIELD_MESSAGE_TONES.error },
75
75
  helper: { message: FIELD_MESSAGE_TONES.helper }
76
76
  },
77
+ // The error FRAME is not declared here — it lives in the compound stage
78
+ // below, where it beats `intent` by construction. See the precedence note
79
+ // on the first compound entry.
77
80
  error: {
78
81
  true: {
79
- cell: fieldErrorFrame(focus),
80
82
  message: FIELD_MESSAGE_TONES.error
81
83
  }
82
84
  },
@@ -85,6 +87,17 @@ export const pinInputVariants = tv({
85
87
  }
86
88
  },
87
89
  compoundVariants: [
90
+ // ── Validation precedence: `error` beats `intent`, explicitly ────────────
91
+ // Both axes paint the SAME three buckets (border-color plus the focused
92
+ // border/ring tint), so exactly one of them can win. Emitting the error
93
+ // frame here rather than on the `error` axis makes that rule structural:
94
+ // compounds always fold after every axis, so `error: true` overrides
95
+ // whatever `intent` painted regardless of how the axes are ordered above
96
+ // (it used to hinge purely on `error` being DECLARED after `intent`).
97
+ {
98
+ error: true,
99
+ class: { cell: fieldErrorFrame(focus) }
100
+ },
88
101
  // Ghost keeps a transparent border at rest — even under an intent. The error
89
102
  // state drops this so validation feedback (border-danger) stays visible.
90
103
  {
@@ -89,9 +89,11 @@ export const timeInputVariants = tv({
89
89
  error: { message: FIELD_MESSAGE_TONES.error },
90
90
  helper: { message: FIELD_MESSAGE_TONES.helper }
91
91
  },
92
+ // The error FRAME is not declared here — it lives in the compound stage
93
+ // below, where it beats `intent` by construction. See the precedence note
94
+ // on the first compound entry.
92
95
  error: {
93
96
  true: {
94
- field: fieldErrorFrame(focus),
95
97
  message: FIELD_MESSAGE_TONES.error
96
98
  }
97
99
  },
@@ -103,6 +105,19 @@ export const timeInputVariants = tv({
103
105
  }
104
106
  },
105
107
  compoundVariants: [
108
+ // ── Validation precedence: `error` beats `intent`, explicitly ────────────
109
+ // Both axes paint the SAME three buckets (border-color plus the focused
110
+ // border/ring tint), so exactly one of them can win. Emitting the error
111
+ // frame here rather than on the `error` axis makes that rule structural:
112
+ // compounds always fold after every axis, so `error: true` overrides
113
+ // whatever `intent` painted regardless of how the axes are ordered above
114
+ // (it used to hinge purely on `error` being DECLARED after `intent`).
115
+ // Folding after `fullWidth` too is harmless: that axis only paints layout
116
+ // buckets (`w`, `justify-content`), which never collide with the frame.
117
+ {
118
+ error: true,
119
+ class: { field: fieldErrorFrame(focus) }
120
+ },
106
121
  {
107
122
  variant: 'ghost',
108
123
  error: false,
@@ -21,6 +21,12 @@
21
21
  * whole field via `focus-within:`. That is why the ring / variant / intent /
22
22
  * error fragments are parameterised by {@link FieldFocus} rather than fixed.
23
23
  *
24
+ * Select and Combobox draw only on the validation subset ({@link fieldErrorFrame}
25
+ * and {@link FIELD_MESSAGE_TONES}) — their frames are otherwise their own (a
26
+ * trigger button, a tokenizer box). That subset is what kept drifting: Select
27
+ * hand-copied the error frame and Combobox had none at all, so an invalid
28
+ * Combobox announced itself through `aria-invalid` and looked untouched.
29
+ *
24
30
  * NOT covered here (deliberately component-local): the per-component frame
25
31
  * prefix (Input's `w-full`, PinInput's cell content styles, TimeInput's
26
32
  * `inline-flex` container), Input's `underline` variant and `placeholder`
@@ -70,7 +76,18 @@ export declare const fieldIntentFrames: (f: FieldFocus) => {
70
76
  warning: string;
71
77
  danger: string;
72
78
  };
73
- /** The error frame value (danger border + ring), parameterised by focus mode. */
79
+ /**
80
+ * The error frame value (danger border + ring), parameterised by focus mode.
81
+ *
82
+ * PRECEDENCE: this paints the same three buckets as {@link fieldIntentFrames}
83
+ * (border-color plus the focused border/ring tint), so in a config that has
84
+ * BOTH a tonal `intent` axis and a boolean `error` axis only one of them can
85
+ * win. Apply it from a `compoundVariants` entry (`{ error: true, … }`), never
86
+ * from the `error` axis: compounds fold after every axis, which makes "error
87
+ * beats intent" a rule instead of a side effect of the axis declaration order.
88
+ * Configs without an `intent` axis (Select, Combobox) can keep it on the axis —
89
+ * but must move it the day one is added. Reference: input.variants.ts.
90
+ */
74
91
  export declare const fieldErrorFrame: (f: FieldFocus) => string;
75
92
  /** Frame classes when the whole control is disabled (the `disabled` variant). */
76
93
  export declare const FIELD_DISABLED_FRAME = "opacity-50 cursor-not-allowed bg-surface-disabled pointer-events-none";
@@ -21,6 +21,12 @@
21
21
  * whole field via `focus-within:`. That is why the ring / variant / intent /
22
22
  * error fragments are parameterised by {@link FieldFocus} rather than fixed.
23
23
  *
24
+ * Select and Combobox draw only on the validation subset ({@link fieldErrorFrame}
25
+ * and {@link FIELD_MESSAGE_TONES}) — their frames are otherwise their own (a
26
+ * trigger button, a tokenizer box). That subset is what kept drifting: Select
27
+ * hand-copied the error frame and Combobox had none at all, so an invalid
28
+ * Combobox announced itself through `aria-invalid` and looked untouched.
29
+ *
24
30
  * NOT covered here (deliberately component-local): the per-component frame
25
31
  * prefix (Input's `w-full`, PinInput's cell content styles, TimeInput's
26
32
  * `inline-flex` container), Input's `underline` variant and `placeholder`
@@ -64,7 +70,18 @@ export const fieldIntentFrames = (f) => ({
64
70
  warning: `border-warning ${f}:border-warning ${f}:ring-warning/20`,
65
71
  danger: `border-danger ${f}:border-danger ${f}:ring-danger/20`
66
72
  });
67
- /** The error frame value (danger border + ring), parameterised by focus mode. */
73
+ /**
74
+ * The error frame value (danger border + ring), parameterised by focus mode.
75
+ *
76
+ * PRECEDENCE: this paints the same three buckets as {@link fieldIntentFrames}
77
+ * (border-color plus the focused border/ring tint), so in a config that has
78
+ * BOTH a tonal `intent` axis and a boolean `error` axis only one of them can
79
+ * win. Apply it from a `compoundVariants` entry (`{ error: true, … }`), never
80
+ * from the `error` axis: compounds fold after every axis, which makes "error
81
+ * beats intent" a rule instead of a side effect of the axis declaration order.
82
+ * Configs without an `intent` axis (Select, Combobox) can keep it on the axis —
83
+ * but must move it the day one is added. Reference: input.variants.ts.
84
+ */
68
85
  export const fieldErrorFrame = (f) => `border-danger ${f}:border-danger ${f}:ring-danger/20`;
69
86
  /** Frame classes when the whole control is disabled (the `disabled` variant). */
70
87
  export const FIELD_DISABLED_FRAME = 'opacity-50 cursor-not-allowed bg-surface-disabled pointer-events-none';
@@ -7,7 +7,10 @@ export const avatarVariants = tv({
7
7
  // the ring follows the avatar's shape.
8
8
  base: [
9
9
  'relative inline-flex shrink-0',
10
- 'transition-[color,background-color,border-color,box-shadow,opacity] duration-[var(--blocks-duration-fast)] ease-out'
10
+ // `scale` is listed because the `interactive` axis adds
11
+ // `hover:scale-105 active:scale-95` — Tailwind 4 emits those as the
12
+ // discrete `scale:` property, which nothing else in this list covers.
13
+ 'transition-[color,background-color,border-color,box-shadow,opacity,scale] duration-[var(--blocks-duration-fast)] ease-out'
11
14
  ],
12
15
  // The visible disc. This is the element that clips the image/initials to
13
16
  // the avatar shape; the status dot lives outside it so it stays whole.
@@ -15,7 +15,13 @@ export const badgeVariants = tv({
15
15
  base: [
16
16
  'relative inline-flex items-center justify-center',
17
17
  'font-medium text-center whitespace-nowrap border select-none',
18
- 'transition-[color,background-color,border-color,box-shadow,opacity] duration-[var(--blocks-duration-fast)] ease-out'
18
+ // `scale` is listed because the `interactive` axis adds
19
+ // `hover:scale-105 active:scale-95` — Tailwind 4 emits those as the
20
+ // discrete `scale:` property, which nothing else in this list covers.
21
+ // `translate` is deliberately NOT listed: the `placement` axis uses
22
+ // translate as layout, not motion (see the exemption in
23
+ // scripts/variants-lint.ts).
24
+ 'transition-[color,background-color,border-color,box-shadow,opacity,scale] duration-[var(--blocks-duration-fast)] ease-out'
19
25
  // Radius driven by `tier` axis below.
20
26
  ],
21
27
  // `[gap:inherit]` (arbitrary property), NOT `gap-inherit` — Tailwind v4 emits
@@ -40,7 +46,10 @@ export const badgeVariants = tv({
40
46
  'hover:shadow-[var(--blocks-shadow-md)] active:scale-[0.98] active:shadow-[var(--blocks-shadow-sm)]',
41
47
  'h-6 px-2 text-xs gap-1 focus-visible:ring-offset-2',
42
48
  // remove-control overrides (won the fold over the ghost base)
43
- 'ml-1 shrink-0 rounded-modify transition-colors text-current',
49
+ // `scale` is named because the interactive compound adds `active:scale-[0.98]`:
50
+ // Tailwind emits that as the discrete `scale` property, which `transition-colors`
51
+ // does not cover — the press cue would snap. Same fold as Dialog/Drawer's closeButton.
52
+ 'ml-1 shrink-0 rounded-modify transition-[color,background-color,scale] text-current',
44
53
  'hover:bg-neutral-950/10 focus-visible:ring-1 focus-visible:ring-current'
45
54
  ],
46
55
  removeIcon: ['w-3 h-3']