@adea-ai/ui 0.71.1 → 0.71.3

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 (99) hide show
  1. package/dist/components/composites/appearance-editor/appearance-editor.js +1 -1
  2. package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
  3. package/dist/components/composites/stat/stat.d.ts.map +1 -1
  4. package/dist/components/composites/stat/stat.js +8 -8
  5. package/dist/components/composites/stat/stat.js.map +1 -1
  6. package/dist/components/composites/update-dialog/update-dialog.d.ts +7 -0
  7. package/dist/components/composites/update-dialog/update-dialog.d.ts.map +1 -1
  8. package/dist/components/composites/update-dialog/update-dialog.js +71 -26
  9. package/dist/components/composites/update-dialog/update-dialog.js.map +1 -1
  10. package/dist/components/conversation/internal/chat-composer-shell.js +1 -1
  11. package/dist/components/conversation/internal/chat-composer-shell.js.map +1 -1
  12. package/dist/components/conversation/message-composer.d.ts.map +1 -1
  13. package/dist/components/conversation/message-composer.js +1 -1
  14. package/dist/components/conversation/message-composer.js.map +1 -1
  15. package/dist/components/ui/alert/alert.d.ts +3 -1
  16. package/dist/components/ui/alert/alert.d.ts.map +1 -1
  17. package/dist/components/ui/alert/alert.js +18 -8
  18. package/dist/components/ui/alert/alert.js.map +1 -1
  19. package/dist/components/ui/badge/badge.js +4 -4
  20. package/dist/components/ui/badge/badge.js.map +1 -1
  21. package/dist/components/ui/context-menu/context-menu.d.ts.map +1 -1
  22. package/dist/components/ui/context-menu/context-menu.js +2 -2
  23. package/dist/components/ui/context-menu/context-menu.js.map +1 -1
  24. package/dist/components/ui/dialog/dialog.d.ts +17 -1
  25. package/dist/components/ui/dialog/dialog.d.ts.map +1 -1
  26. package/dist/components/ui/dialog/dialog.js +120 -2
  27. package/dist/components/ui/dialog/dialog.js.map +1 -1
  28. package/dist/components/ui/diff-block/diff-block.js +2 -2
  29. package/dist/components/ui/diff-block/diff-block.js.map +1 -1
  30. package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +3 -2
  31. package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
  32. package/dist/components/ui/dropdown-menu/dropdown-menu.js +5 -4
  33. package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
  34. package/dist/components/ui/entity-icon/entity-icon.d.ts +3 -3
  35. package/dist/components/ui/entity-icon/entity-icon.js +7 -7
  36. package/dist/components/ui/entity-icon/entity-icon.js.map +1 -1
  37. package/dist/components/ui/field/field.js +1 -1
  38. package/dist/components/ui/field/field.js.map +1 -1
  39. package/dist/components/ui/menubar/menubar.d.ts.map +1 -1
  40. package/dist/components/ui/menubar/menubar.js +2 -2
  41. package/dist/components/ui/menubar/menubar.js.map +1 -1
  42. package/dist/components/ui/modal-dialog/modal-dialog.d.ts +12 -2
  43. package/dist/components/ui/modal-dialog/modal-dialog.d.ts.map +1 -1
  44. package/dist/components/ui/modal-dialog/modal-dialog.js +44 -27
  45. package/dist/components/ui/modal-dialog/modal-dialog.js.map +1 -1
  46. package/dist/components/ui/status-chip/status-chip.js +4 -4
  47. package/dist/components/ui/status-chip/status-chip.js.map +1 -1
  48. package/dist/lib/overlay.d.ts +2 -0
  49. package/dist/lib/overlay.d.ts.map +1 -1
  50. package/dist/lib/overlay.js +3 -1
  51. package/dist/lib/overlay.js.map +1 -1
  52. package/dist/lib/themes.d.ts +7 -0
  53. package/dist/lib/themes.d.ts.map +1 -1
  54. package/dist/lib/themes.js +22 -1
  55. package/dist/lib/themes.js.map +1 -1
  56. package/dist/lib/tokens.d.ts.map +1 -1
  57. package/dist/lib/tokens.js +4 -4
  58. package/dist/lib/tokens.js.map +1 -1
  59. package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +1 -1
  60. package/dist/r/src/components/composites/stat/stat.tsx +5 -8
  61. package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +98 -26
  62. package/dist/r/src/components/conversation/internal/chat-composer-shell.tsx +1 -1
  63. package/dist/r/src/components/conversation/message-composer.tsx +3 -1
  64. package/dist/r/src/components/ui/alert/alert.tsx +20 -7
  65. package/dist/r/src/components/ui/badge/badge.tsx +4 -4
  66. package/dist/r/src/components/ui/context-menu/context-menu.tsx +2 -2
  67. package/dist/r/src/components/ui/dialog/dialog.tsx +204 -2
  68. package/dist/r/src/components/ui/diff-block/diff-block.tsx +4 -4
  69. package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +5 -4
  70. package/dist/r/src/components/ui/entity-icon/entity-icon.tsx +7 -7
  71. package/dist/r/src/components/ui/field/field.tsx +1 -1
  72. package/dist/r/src/components/ui/menubar/menubar.tsx +2 -2
  73. package/dist/r/src/components/ui/modal-dialog/modal-dialog.tsx +24 -2
  74. package/dist/r/src/components/ui/status-chip/status-chip.tsx +4 -4
  75. package/dist/r/src/lib/overlay.ts +4 -0
  76. package/dist/r/src/lib/themes.ts +29 -0
  77. package/dist/r/src/lib/tokens.ts +19 -4
  78. package/dist/r/src/styles/theme.css +10 -10
  79. package/package.json +2 -2
  80. package/src/components/composites/appearance-editor/appearance-editor.tsx +1 -1
  81. package/src/components/composites/stat/stat.tsx +5 -8
  82. package/src/components/composites/update-dialog/update-dialog.tsx +98 -26
  83. package/src/components/conversation/internal/chat-composer-shell.tsx +1 -1
  84. package/src/components/conversation/message-composer.tsx +3 -1
  85. package/src/components/ui/alert/alert.tsx +20 -7
  86. package/src/components/ui/badge/badge.tsx +4 -4
  87. package/src/components/ui/context-menu/context-menu.tsx +2 -2
  88. package/src/components/ui/dialog/dialog.tsx +204 -2
  89. package/src/components/ui/diff-block/diff-block.tsx +4 -4
  90. package/src/components/ui/dropdown-menu/dropdown-menu.tsx +5 -4
  91. package/src/components/ui/entity-icon/entity-icon.tsx +7 -7
  92. package/src/components/ui/field/field.tsx +1 -1
  93. package/src/components/ui/menubar/menubar.tsx +2 -2
  94. package/src/components/ui/modal-dialog/modal-dialog.tsx +24 -2
  95. package/src/components/ui/status-chip/status-chip.tsx +4 -4
  96. package/src/lib/overlay.ts +4 -0
  97. package/src/lib/themes.ts +29 -0
  98. package/src/lib/tokens.ts +19 -4
  99. package/src/styles/theme.css +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,WAAW,GACX,aAAa,GACb,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,MAAM,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG;IAC5B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,SAAS,CAAA;IACf,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,eAAe,EAwSxC,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,eAAe,EAezC,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,eAAe,EAyE7C,CAAA;AAED;;+EAE+E;AAC/E,eAAO,MAAM,aAAa,EAAE,eAAe,EAmE1C,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,eAAe,EA2B5C,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,eAAe,EAkBzC,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,eAAe,EAyBzC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,YAAY,EAQ/C,CAAA;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,oFAAoF;IACpF,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,UAAU,EA+B3C,CAAA;AAEF,qCAAqC;AACrC,eAAO,MAAM,YAAY;;;;;;;;CAQf,CAAA;AAEV,yDAAyD;AACzD,eAAO,MAAM,SAAS,EAAE,eAAe,EAAuC,CAAA;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,EAAe,CAAA"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,WAAW,GACX,aAAa,GACb,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,MAAM,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG;IAC5B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,SAAS,CAAA;IACf,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,eAAe,EAuTxC,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,eAAe,EAezC,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,eAAe,EAyE7C,CAAA;AAED;;+EAE+E;AAC/E,eAAO,MAAM,aAAa,EAAE,eAAe,EAmE1C,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,eAAe,EA2B5C,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,eAAe,EAkBzC,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,eAAe,EAyBzC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,YAAY,EAQ/C,CAAA;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,oFAAoF;IACpF,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,UAAU,EA+B3C,CAAA;AAEF,qCAAqC;AACrC,eAAO,MAAM,YAAY;;;;;;;;CAQf,CAAA;AAEV,yDAAyD;AACzD,eAAO,MAAM,SAAS,EAAE,eAAe,EAAuC,CAAA;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,EAAe,CAAA"}
@@ -184,7 +184,7 @@ var colorTokens = [
184
184
  name: "destructive-subtle",
185
185
  kind: "color",
186
186
  themed: true,
187
- description: "Tinted destructive fill: alert banners, invalid fields."
187
+ description: "Opaque destructive tint against the canvas; subtle labels use foreground."
188
188
  },
189
189
  {
190
190
  name: "success",
@@ -202,7 +202,7 @@ var colorTokens = [
202
202
  name: "success-subtle",
203
203
  kind: "color",
204
204
  themed: true,
205
- description: "Tinted success fill."
205
+ description: "Opaque success tint against the canvas; subtle labels use foreground."
206
206
  },
207
207
  {
208
208
  name: "warning",
@@ -220,7 +220,7 @@ var colorTokens = [
220
220
  name: "warning-subtle",
221
221
  kind: "color",
222
222
  themed: true,
223
- description: "Tinted warning fill."
223
+ description: "Opaque warning tint against the canvas; subtle labels use foreground."
224
224
  },
225
225
  {
226
226
  name: "info",
@@ -238,7 +238,7 @@ var colorTokens = [
238
238
  name: "info-subtle",
239
239
  kind: "color",
240
240
  themed: true,
241
- description: "Tinted info fill."
241
+ description: "Opaque info tint against the canvas; subtle labels use foreground."
242
242
  },
243
243
  {
244
244
  name: "border",
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","names":[],"sources":["../../src/lib/tokens.ts"],"sourcesContent":["/**\n * The design system's token manifest.\n *\n * `theme.css` is the source of truth for token *values*. This file is the\n * source of truth for token *names and meaning* — what each one is for, and\n * which ones a theme may vary.\n *\n * It exists because a manifest that is only documentation rots. Two things read\n * it instead:\n *\n * - the token galleries in Storybook, so the review surface shows every token\n * rather than the ones an author remembered;\n * - `tests/tokens.test.ts`, which parses `theme.css` and fails when a token\n * is declared in one place and missing from the other.\n *\n * That pairing is what makes \"every token is documented and every documented\n * token exists\" a property the build enforces rather than a promise.\n */\n\nimport { ACCENTS } from '@adea-ai/themes'\n\nexport type TokenKind =\n | 'color'\n | 'dimension'\n | 'font-family'\n | 'number'\n | 'duration'\n | 'easing'\n | 'shadow'\n | 'text'\n\nexport type TokenDefinition = {\n /** The custom property name, without the leading `--`. */\n name: string\n kind: TokenKind\n /** One line: what this token is for. Shown in the gallery. */\n description: string\n /** True when the light and dark themes give it different values. */\n themed?: boolean\n}\n\n/**\n * Colour roles, in the order they appear in a page: surfaces first, then text,\n * then the lines between them, then the semantic fills. The order is the\n * documentation — reading the gallery top to bottom walks the surface ladder.\n */\nexport const colorTokens: TokenDefinition[] = [\n // Surfaces\n {\n name: 'background',\n kind: 'color',\n themed: true,\n description: 'The canvas every panel sits on.',\n },\n {\n name: 'foreground',\n kind: 'color',\n themed: true,\n description: 'Default body text on the canvas.',\n },\n {\n name: 'card',\n kind: 'color',\n themed: true,\n description: 'A panel or card raised one rung above the canvas.',\n },\n { name: 'card-foreground', kind: 'color', themed: true, description: 'Text on `card`.' },\n {\n name: 'popover',\n kind: 'color',\n themed: true,\n description: 'A floating surface: dialog, menu, popover, tooltip-free.',\n },\n { name: 'popover-foreground', kind: 'color', themed: true, description: 'Text on `popover`.' },\n {\n name: 'surface',\n kind: 'color',\n themed: true,\n description: 'Alias of `background`, for code that means \"a surface\" not \"the page\".',\n },\n {\n name: 'surface-sunken',\n kind: 'color',\n themed: true,\n description: 'A well: code blocks, inset lists, empty states.',\n },\n {\n name: 'surface-raised',\n kind: 'color',\n themed: true,\n description: 'Alias of `card`, for panels that sit on the canvas.',\n },\n {\n name: 'surface-overlay',\n kind: 'color',\n themed: true,\n description: 'Alias of `popover`, for floating layers.',\n },\n {\n name: 'surface-hover',\n kind: 'color',\n themed: true,\n description: 'The hover fill shared by rows, menu items and ghost controls.',\n },\n {\n name: 'surface-active',\n kind: 'color',\n themed: true,\n description: 'The pressed/selected fill, one rung past hover.',\n },\n {\n name: 'chrome',\n kind: 'color',\n themed: true,\n description: 'Window chrome: the top bar and its frosted fill.',\n },\n {\n name: 'chrome-alpha',\n kind: 'number',\n themed: true,\n description: 'Opacity of the chrome fill behind a blur.',\n },\n\n // The brand action\n {\n name: 'primary',\n kind: 'color',\n themed: true,\n description: 'The Adea emerald. The one primary action in a view.',\n },\n {\n name: 'primary-foreground',\n kind: 'color',\n themed: true,\n description: 'Label on `primary`. Black in dark, white in light — the accent flips polarity.',\n },\n {\n name: 'primary-hover',\n kind: 'color',\n themed: true,\n description: 'Hover rung for a primary action.',\n },\n {\n name: 'primary-subtle',\n kind: 'color',\n themed: true,\n description: 'Tinted primary fill: selected rows, focus rings, subtle buttons.',\n },\n\n {\n name: 'secondary',\n kind: 'color',\n themed: true,\n description: 'A quieter filled surface for a secondary action.',\n },\n {\n name: 'secondary-foreground',\n kind: 'color',\n themed: true,\n description: 'Label on `secondary`.',\n },\n {\n name: 'muted',\n kind: 'color',\n themed: true,\n description: 'A neutral fill: skeletons, inert chips, table footers.',\n },\n {\n name: 'muted-foreground',\n kind: 'color',\n themed: true,\n description: 'De-emphasised text. Measured to clear 4.5:1 on both `background` and `card`.',\n },\n {\n name: 'accent',\n kind: 'color',\n themed: true,\n description: \"shadcn's hover-surface accent. Not the brand colour — that is `primary`.\",\n },\n { name: 'accent-foreground', kind: 'color', themed: true, description: 'Text on `accent`.' },\n\n // Status\n {\n name: 'destructive',\n kind: 'color',\n themed: true,\n description: 'Irreversible or dangerous actions.',\n },\n {\n name: 'destructive-foreground',\n kind: 'color',\n themed: true,\n description: 'Label on `destructive`.',\n },\n {\n name: 'destructive-subtle',\n kind: 'color',\n themed: true,\n description: 'Tinted destructive fill: alert banners, invalid fields.',\n },\n { name: 'success', kind: 'color', themed: true, description: 'A completed or healthy state.' },\n { name: 'success-foreground', kind: 'color', themed: true, description: 'Label on `success`.' },\n { name: 'success-subtle', kind: 'color', themed: true, description: 'Tinted success fill.' },\n {\n name: 'warning',\n kind: 'color',\n themed: true,\n description: 'Something needs attention but is not broken.',\n },\n { name: 'warning-foreground', kind: 'color', themed: true, description: 'Label on `warning`.' },\n { name: 'warning-subtle', kind: 'color', themed: true, description: 'Tinted warning fill.' },\n { name: 'info', kind: 'color', themed: true, description: 'Neutral information.' },\n { name: 'info-foreground', kind: 'color', themed: true, description: 'Label on `info`.' },\n { name: 'info-subtle', kind: 'color', themed: true, description: 'Tinted info fill.' },\n\n // Lines\n {\n name: 'border',\n kind: 'color',\n themed: true,\n description: 'Every hairline: panel edges, dividers, card outlines.',\n },\n {\n name: 'input',\n kind: 'color',\n themed: true,\n description:\n 'The edge of an editable control. A rung stronger than `border` so a field is findable.',\n },\n {\n name: 'ring',\n kind: 'color',\n themed: true,\n description: 'The focus ring. Always paired with `primary-subtle` as its glow.',\n },\n\n // Theme-invariant glass\n {\n name: 'scrim',\n kind: 'color',\n description: 'Dark glass for overlays and on-screen controls. Same in both themes.',\n },\n { name: 'scrim-foreground', kind: 'color', description: 'Text drawn on `scrim`.' },\n { name: 'scrim-edge', kind: 'color', description: 'The hairline drawn on `scrim`.' },\n\n // Diff and code\n { name: 'diff-add', kind: 'color', themed: true, description: 'Background of an added line.' },\n {\n name: 'diff-add-foreground',\n kind: 'color',\n themed: true,\n description: 'Text of an added line.',\n },\n {\n name: 'diff-delete',\n kind: 'color',\n themed: true,\n description: 'Background of a removed line.',\n },\n {\n name: 'diff-delete-foreground',\n kind: 'color',\n themed: true,\n description: 'Text of a removed line.',\n },\n { name: 'diff-hunk', kind: 'color', themed: true, description: 'Background of a hunk header.' },\n {\n name: 'diff-hunk-foreground',\n kind: 'color',\n themed: true,\n description: 'Text of a hunk header.',\n },\n {\n name: 'diff-meta-foreground',\n kind: 'color',\n themed: true,\n description: 'File headers and line numbers in a diff.',\n },\n\n // Charts\n {\n name: 'chart-1',\n kind: 'color',\n themed: true,\n description: 'Categorical series 1. The set is closed at six.',\n },\n { name: 'chart-2', kind: 'color', themed: true, description: 'Categorical series 2.' },\n { name: 'chart-3', kind: 'color', themed: true, description: 'Categorical series 3.' },\n { name: 'chart-4', kind: 'color', themed: true, description: 'Categorical series 4.' },\n { name: 'chart-5', kind: 'color', themed: true, description: 'Categorical series 5.' },\n { name: 'chart-6', kind: 'color', themed: true, description: 'Categorical series 6.' },\n\n // Sidebar (the shadcn contract, kept whole)\n {\n name: 'sidebar',\n kind: 'color',\n themed: true,\n description: 'The rail and sidebar surface, tinted against the canvas.',\n },\n {\n name: 'sidebar-foreground',\n kind: 'color',\n themed: true,\n description: 'Default text in the rail and sidebar.',\n },\n {\n name: 'sidebar-primary',\n kind: 'color',\n themed: true,\n description: 'The active destination in the rail.',\n },\n {\n name: 'sidebar-primary-foreground',\n kind: 'color',\n themed: true,\n description: 'Text on the active rail destination.',\n },\n {\n name: 'sidebar-accent',\n kind: 'color',\n themed: true,\n description: 'Hover and selected fill for rail and sidebar rows.',\n },\n {\n name: 'sidebar-accent-foreground',\n kind: 'color',\n themed: true,\n description: 'Text on `sidebar-accent`.',\n },\n {\n name: 'sidebar-border',\n kind: 'color',\n themed: true,\n description: 'The rule between the rail and the canvas.',\n },\n { name: 'sidebar-ring', kind: 'color', themed: true, description: 'Focus ring inside the rail.' },\n {\n name: 'sidebar-muted-foreground',\n kind: 'color',\n themed: true,\n description: 'Rail labels that are not the current destination.',\n },\n]\n\nexport const radiusTokens: TokenDefinition[] = [\n {\n name: 'radius-lg',\n kind: 'dimension',\n description:\n '10px — cards and panels. Also the knob: move this one value to re-round the whole system.',\n },\n { name: 'radius-sm', kind: 'dimension', description: '6px — badges, keyboard keys, menu items.' },\n {\n name: 'radius-md',\n kind: 'dimension',\n description: '8px — every control: buttons, inputs, selects.',\n },\n { name: 'radius-xl', kind: 'dimension', description: '14px — dialogs, menus, sheets.' },\n { name: 'radius-2xl', kind: 'dimension', description: '18px — full-window surfaces and media.' },\n]\n\nexport const typographyTokens: TokenDefinition[] = [\n {\n name: 'font-sans',\n kind: 'font-family',\n description: 'The selected interface face. Space Grotesk unless the font axis says otherwise.',\n },\n {\n name: 'font-mono',\n kind: 'font-family',\n description: 'The selected monospace face. Code, terminals, ids, paths.',\n },\n {\n name: 'font-family-space-grotesk',\n kind: 'font-family',\n description: 'The interface default, and the face the visual language was drawn against.',\n },\n {\n name: 'font-family-jetbrains-mono',\n kind: 'font-family',\n description: 'The monospace default. Code, terminals, diffs.',\n },\n {\n name: 'font-family-geist',\n kind: 'font-family',\n description: 'An alternative interface face. cortana already ships it.',\n },\n {\n name: 'font-family-geist-mono',\n kind: 'font-family',\n description: 'The monospace counterpart to Geist.',\n },\n {\n name: 'font-family-system',\n kind: 'font-family',\n description: \"The platform's own interface face. First-class, not a fallback.\",\n },\n {\n name: 'font-family-system-mono',\n kind: 'font-family',\n description: \"The platform's own monospace face.\",\n },\n {\n name: 'ui-tracking',\n kind: 'text',\n description:\n 'Letter spacing for measured chrome. `normal` on a proportional face, tightened when the UI font is monospace — which is roughly 20% wider at the same size.',\n },\n {\n name: 'ui-word-spacing',\n kind: 'text',\n description:\n \"Word spacing for measured chrome. Mono's space is a full advance-width cell, so a two-word label reads as two floating words without this.\",\n },\n {\n name: 'text-2xs',\n kind: 'text',\n description: '11px — the smallest label the system permits: kbd keys, status bar.',\n },\n { name: 'text-xs', kind: 'text', description: '12px — metadata, badges, secondary rows.' },\n {\n name: 'text-sm',\n kind: 'text',\n description: '14px — the interface default. Body copy, labels, controls.',\n },\n { name: 'text-base', kind: 'text', description: '16px — card titles and dialog titles.' },\n { name: 'text-lg', kind: 'text', description: '18px — a section heading inside a page.' },\n { name: 'text-xl', kind: 'text', description: '20px — a page title.' },\n { name: 'text-2xl', kind: 'text', description: '24px — a display figure.' },\n {\n name: 'text-3xl',\n kind: 'text',\n description: '30px — the largest size in the system. Reserved for an empty-state headline.',\n },\n]\n\n/** Height tokens also size both axes of icon controls through Tailwind's --size\n * namespace. Padding has its own --spacing mapping. Nominal pixel descriptions\n * use a 16px rem; rendered dimensions follow the consumer's root font size. */\nexport const densityTokens: TokenDefinition[] = [\n { name: 'control-height-2xs', kind: 'dimension', description: '20px — an inline chip control.' },\n { name: 'control-height-xs', kind: 'dimension', description: '24px — a dense table row action.' },\n { name: 'control-height-sm', kind: 'dimension', description: '28px — the toolbar default.' },\n {\n name: 'control-height-md',\n kind: 'dimension',\n description: '32px — the form default. Button and Input are this size unless told otherwise.',\n },\n { name: 'control-height-lg', kind: 'dimension', description: '36px — a primary form action.' },\n {\n name: 'control-height-xl',\n kind: 'dimension',\n description: '40px — a hero control in an empty state.',\n },\n {\n name: 'control-padding-2xs',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 20px control.',\n },\n {\n name: 'control-padding-xs',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 24px control.',\n },\n {\n name: 'control-padding-sm',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 28px control.',\n },\n {\n name: 'control-padding-md',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 32px control.',\n },\n {\n name: 'control-padding-lg',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 36px control.',\n },\n {\n name: 'control-padding-xl',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 40px control.',\n },\n { name: 'row-height-sm', kind: 'dimension', description: '28px — a dense list row.' },\n { name: 'row-height-md', kind: 'dimension', description: '32px — the default list row.' },\n { name: 'row-height-lg', kind: 'dimension', description: '36px — a two-line list row.' },\n { name: 'rail-width', kind: 'dimension', description: '58px — the icon-only rail.' },\n { name: 'rail-width-expanded', kind: 'dimension', description: '236px — the labelled rail.' },\n {\n name: 'rail-item-height',\n kind: 'dimension',\n description: '36px — a rail or sidebar destination.',\n },\n {\n name: 'sidebar-width',\n kind: 'dimension',\n description: '256px — the secondary navigation column.',\n },\n {\n name: 'sidebar-width-compact',\n kind: 'dimension',\n description: '48px — the collapsed secondary column.',\n },\n { name: 'topbar-height', kind: 'dimension', description: '48px — the window title row.' },\n { name: 'statusbar-height', kind: 'dimension', description: '28px — the bottom readout strip.' },\n]\n\nexport const elevationTokens: TokenDefinition[] = [\n {\n name: 'shadow-2xs',\n kind: 'shadow',\n themed: true,\n description: 'Barely there: a chip resting on a card.',\n },\n {\n name: 'shadow-xs',\n kind: 'shadow',\n themed: true,\n description: 'A card or panel on the canvas.',\n },\n {\n name: 'shadow-sm',\n kind: 'shadow',\n themed: true,\n description: 'A control that lifts: a pressed toggle, a thumb.',\n },\n { name: 'shadow-md', kind: 'shadow', themed: true, description: 'A menu or popover.' },\n { name: 'shadow-lg', kind: 'shadow', themed: true, description: 'A dialog or sheet.' },\n {\n name: 'shadow-xl',\n kind: 'shadow',\n themed: true,\n description: 'The command palette, above everything.',\n },\n]\n\nexport const motionTokens: TokenDefinition[] = [\n {\n name: 'duration-fast',\n kind: 'duration',\n description: '120ms — a state change the user is already watching.',\n },\n { name: 'duration-normal', kind: 'duration', description: '200ms — an entrance.' },\n { name: 'duration-slow', kind: 'duration', description: '320ms — a layout settle.' },\n {\n name: 'ease-out',\n kind: 'easing',\n description: 'A fast start and a long settle. Reads as decisive rather than floaty.',\n },\n {\n name: 'ease-in-out',\n kind: 'easing',\n description: 'For a loop that has no start or end, such as a shimmer.',\n },\n]\n\nexport const zIndexTokens: TokenDefinition[] = [\n { name: 'z-base', kind: 'number', description: 'In flow, at the document order.' },\n {\n name: 'z-docked',\n kind: 'number',\n description: 'A sticky table header standing above its own scroll body.',\n },\n { name: 'z-sticky', kind: 'number', description: 'The top bar and any other pinned chrome.' },\n { name: 'z-drawer', kind: 'number', description: 'A drawer, below a modal dialog.' },\n { name: 'z-dialog', kind: 'number', description: 'A modal dialog and its scrim.' },\n {\n name: 'z-menu',\n kind: 'number',\n description: 'Menus, popovers and comboboxes. Above dialogs, because a dialog can contain one.',\n },\n {\n name: 'z-tooltip',\n kind: 'number',\n description: 'Tooltips. Above menus, because a menu item can carry one.',\n },\n {\n name: 'z-toast',\n kind: 'number',\n description: 'Notifications. Above everything, so they are never hidden by a dialog.',\n },\n]\n\n/**\n * The accent axis.\n *\n * adea's accent presets, as a selection rather than a constant. `theme` is the\n * default and means \"the variant's own primary\" — monochrome in adea's palette —\n * and each named preset overrides the interactive roles through the\n * `[data-accent]` blocks in `theme.css`.\n *\n * These are the same six presets `accentPresets` exports in adea's own\n * `appearance.ts`, and the values match. A consumer's appearance picker and the\n * workshop's theme toolbar read this one list, so the two cannot disagree about\n * what a preset is called or what colour it is.\n */\nexport type AccentPreset = {\n /** The `data-accent` value. `theme` is the variant's own primary. */\n id: string\n label: string\n /** What the preset is for, in the gallery and in a picker. */\n description: string\n /** The accent as it appears in the light theme. Absent for `theme`. */\n light?: string\n /** The accent as it appears in the dark theme. Absent for `theme`. */\n dark?: string\n}\n\nexport const accentPresets: readonly AccentPreset[] = Object.freeze([\n {\n id: 'theme',\n label: 'Theme',\n description:\n \"The variant's own primary. Neutral in adea's palette, so the interface stays monochrome.\",\n },\n ...ACCENTS,\n])\n\n/**\n * The font axis.\n *\n * The family is a selection, like the accent: `data-font` sits on the same element\n * and each option swaps the interface face. `space-grotesk` is the default because\n * it is the face the visual language was drawn against, and `system` is a\n * first-class option rather than a fallback — an application that wants the\n * platform's own face should be able to say so without losing the rest of the\n * system.\n */\nexport type FontOption = {\n /** The `data-font` value. `space-grotesk` is the default and needs no attribute. */\n id: string\n label: string\n description: string\n /** Which of the two stacks this option sets. */\n stack: 'sans' | 'mono' | 'both'\n}\n\nexport const fontOptions: readonly FontOption[] = Object.freeze([\n {\n id: 'space-grotesk',\n label: 'Space Grotesk',\n description: 'The default, and the face the visual language was drawn against.',\n stack: 'both',\n },\n {\n id: 'system',\n label: 'System',\n description: \"The platform's own face. What a terminal or editor usually wants.\",\n stack: 'both',\n },\n {\n id: 'geist',\n label: 'Geist',\n description: 'The face cortana already ships. Neutral and wide.',\n stack: 'both',\n },\n {\n id: 'geist-mono',\n label: 'Geist Mono',\n description: 'Monospace throughout, for someone who wants a uniform texture.',\n stack: 'both',\n },\n {\n id: 'jetbrains-mono',\n label: 'JetBrains Mono',\n description: 'Monospace throughout, with coding ligatures off.',\n stack: 'both',\n },\n])\n\n/** Every token, in gallery order. */\nexport const designTokens = {\n color: colorTokens,\n radius: radiusTokens,\n typography: typographyTokens,\n density: densityTokens,\n elevation: elevationTokens,\n motion: motionTokens,\n zIndex: zIndexTokens,\n} as const\n\n/** Flat list, for completeness checks and for search. */\nexport const allTokens: TokenDefinition[] = Object.values(designTokens).flat()\n\n/**\n * Aliases that exist only to make a call site read better, and which therefore\n * have no gallery row of their own. Kept explicit so the completeness check\n * below can tell \"deliberately absent\" from \"forgotten\".\n */\nexport const undocumentedTokenAliases: string[] = ['radius']\n"],"mappings":"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"}
1
+ {"version":3,"file":"tokens.js","names":[],"sources":["../../src/lib/tokens.ts"],"sourcesContent":["/**\n * The design system's token manifest.\n *\n * `theme.css` is the source of truth for token *values*. This file is the\n * source of truth for token *names and meaning* — what each one is for, and\n * which ones a theme may vary.\n *\n * It exists because a manifest that is only documentation rots. Two things read\n * it instead:\n *\n * - the token galleries in Storybook, so the review surface shows every token\n * rather than the ones an author remembered;\n * - `tests/tokens.test.ts`, which parses `theme.css` and fails when a token\n * is declared in one place and missing from the other.\n *\n * That pairing is what makes \"every token is documented and every documented\n * token exists\" a property the build enforces rather than a promise.\n */\n\nimport { ACCENTS } from '@adea-ai/themes'\n\nexport type TokenKind =\n | 'color'\n | 'dimension'\n | 'font-family'\n | 'number'\n | 'duration'\n | 'easing'\n | 'shadow'\n | 'text'\n\nexport type TokenDefinition = {\n /** The custom property name, without the leading `--`. */\n name: string\n kind: TokenKind\n /** One line: what this token is for. Shown in the gallery. */\n description: string\n /** True when the light and dark themes give it different values. */\n themed?: boolean\n}\n\n/**\n * Colour roles, in the order they appear in a page: surfaces first, then text,\n * then the lines between them, then the semantic fills. The order is the\n * documentation — reading the gallery top to bottom walks the surface ladder.\n */\nexport const colorTokens: TokenDefinition[] = [\n // Surfaces\n {\n name: 'background',\n kind: 'color',\n themed: true,\n description: 'The canvas every panel sits on.',\n },\n {\n name: 'foreground',\n kind: 'color',\n themed: true,\n description: 'Default body text on the canvas.',\n },\n {\n name: 'card',\n kind: 'color',\n themed: true,\n description: 'A panel or card raised one rung above the canvas.',\n },\n { name: 'card-foreground', kind: 'color', themed: true, description: 'Text on `card`.' },\n {\n name: 'popover',\n kind: 'color',\n themed: true,\n description: 'A floating surface: dialog, menu, popover, tooltip-free.',\n },\n { name: 'popover-foreground', kind: 'color', themed: true, description: 'Text on `popover`.' },\n {\n name: 'surface',\n kind: 'color',\n themed: true,\n description: 'Alias of `background`, for code that means \"a surface\" not \"the page\".',\n },\n {\n name: 'surface-sunken',\n kind: 'color',\n themed: true,\n description: 'A well: code blocks, inset lists, empty states.',\n },\n {\n name: 'surface-raised',\n kind: 'color',\n themed: true,\n description: 'Alias of `card`, for panels that sit on the canvas.',\n },\n {\n name: 'surface-overlay',\n kind: 'color',\n themed: true,\n description: 'Alias of `popover`, for floating layers.',\n },\n {\n name: 'surface-hover',\n kind: 'color',\n themed: true,\n description: 'The hover fill shared by rows, menu items and ghost controls.',\n },\n {\n name: 'surface-active',\n kind: 'color',\n themed: true,\n description: 'The pressed/selected fill, one rung past hover.',\n },\n {\n name: 'chrome',\n kind: 'color',\n themed: true,\n description: 'Window chrome: the top bar and its frosted fill.',\n },\n {\n name: 'chrome-alpha',\n kind: 'number',\n themed: true,\n description: 'Opacity of the chrome fill behind a blur.',\n },\n\n // The brand action\n {\n name: 'primary',\n kind: 'color',\n themed: true,\n description: 'The Adea emerald. The one primary action in a view.',\n },\n {\n name: 'primary-foreground',\n kind: 'color',\n themed: true,\n description: 'Label on `primary`. Black in dark, white in light — the accent flips polarity.',\n },\n {\n name: 'primary-hover',\n kind: 'color',\n themed: true,\n description: 'Hover rung for a primary action.',\n },\n {\n name: 'primary-subtle',\n kind: 'color',\n themed: true,\n description: 'Tinted primary fill: selected rows, focus rings, subtle buttons.',\n },\n\n {\n name: 'secondary',\n kind: 'color',\n themed: true,\n description: 'A quieter filled surface for a secondary action.',\n },\n {\n name: 'secondary-foreground',\n kind: 'color',\n themed: true,\n description: 'Label on `secondary`.',\n },\n {\n name: 'muted',\n kind: 'color',\n themed: true,\n description: 'A neutral fill: skeletons, inert chips, table footers.',\n },\n {\n name: 'muted-foreground',\n kind: 'color',\n themed: true,\n description: 'De-emphasised text. Measured to clear 4.5:1 on both `background` and `card`.',\n },\n {\n name: 'accent',\n kind: 'color',\n themed: true,\n description: \"shadcn's hover-surface accent. Not the brand colour — that is `primary`.\",\n },\n { name: 'accent-foreground', kind: 'color', themed: true, description: 'Text on `accent`.' },\n\n // Status\n {\n name: 'destructive',\n kind: 'color',\n themed: true,\n description: 'Irreversible or dangerous actions.',\n },\n {\n name: 'destructive-foreground',\n kind: 'color',\n themed: true,\n description: 'Label on `destructive`.',\n },\n {\n name: 'destructive-subtle',\n kind: 'color',\n themed: true,\n description: 'Opaque destructive tint against the canvas; subtle labels use foreground.',\n },\n { name: 'success', kind: 'color', themed: true, description: 'A completed or healthy state.' },\n { name: 'success-foreground', kind: 'color', themed: true, description: 'Label on `success`.' },\n {\n name: 'success-subtle',\n kind: 'color',\n themed: true,\n description: 'Opaque success tint against the canvas; subtle labels use foreground.',\n },\n {\n name: 'warning',\n kind: 'color',\n themed: true,\n description: 'Something needs attention but is not broken.',\n },\n { name: 'warning-foreground', kind: 'color', themed: true, description: 'Label on `warning`.' },\n {\n name: 'warning-subtle',\n kind: 'color',\n themed: true,\n description: 'Opaque warning tint against the canvas; subtle labels use foreground.',\n },\n { name: 'info', kind: 'color', themed: true, description: 'Neutral information.' },\n { name: 'info-foreground', kind: 'color', themed: true, description: 'Label on `info`.' },\n {\n name: 'info-subtle',\n kind: 'color',\n themed: true,\n description: 'Opaque info tint against the canvas; subtle labels use foreground.',\n },\n\n // Lines\n {\n name: 'border',\n kind: 'color',\n themed: true,\n description: 'Every hairline: panel edges, dividers, card outlines.',\n },\n {\n name: 'input',\n kind: 'color',\n themed: true,\n description:\n 'The edge of an editable control. A rung stronger than `border` so a field is findable.',\n },\n {\n name: 'ring',\n kind: 'color',\n themed: true,\n description: 'The focus ring. Always paired with `primary-subtle` as its glow.',\n },\n\n // Theme-invariant glass\n {\n name: 'scrim',\n kind: 'color',\n description: 'Dark glass for overlays and on-screen controls. Same in both themes.',\n },\n { name: 'scrim-foreground', kind: 'color', description: 'Text drawn on `scrim`.' },\n { name: 'scrim-edge', kind: 'color', description: 'The hairline drawn on `scrim`.' },\n\n // Diff and code\n { name: 'diff-add', kind: 'color', themed: true, description: 'Background of an added line.' },\n {\n name: 'diff-add-foreground',\n kind: 'color',\n themed: true,\n description: 'Text of an added line.',\n },\n {\n name: 'diff-delete',\n kind: 'color',\n themed: true,\n description: 'Background of a removed line.',\n },\n {\n name: 'diff-delete-foreground',\n kind: 'color',\n themed: true,\n description: 'Text of a removed line.',\n },\n { name: 'diff-hunk', kind: 'color', themed: true, description: 'Background of a hunk header.' },\n {\n name: 'diff-hunk-foreground',\n kind: 'color',\n themed: true,\n description: 'Text of a hunk header.',\n },\n {\n name: 'diff-meta-foreground',\n kind: 'color',\n themed: true,\n description: 'File headers and line numbers in a diff.',\n },\n\n // Charts\n {\n name: 'chart-1',\n kind: 'color',\n themed: true,\n description: 'Categorical series 1. The set is closed at six.',\n },\n { name: 'chart-2', kind: 'color', themed: true, description: 'Categorical series 2.' },\n { name: 'chart-3', kind: 'color', themed: true, description: 'Categorical series 3.' },\n { name: 'chart-4', kind: 'color', themed: true, description: 'Categorical series 4.' },\n { name: 'chart-5', kind: 'color', themed: true, description: 'Categorical series 5.' },\n { name: 'chart-6', kind: 'color', themed: true, description: 'Categorical series 6.' },\n\n // Sidebar (the shadcn contract, kept whole)\n {\n name: 'sidebar',\n kind: 'color',\n themed: true,\n description: 'The rail and sidebar surface, tinted against the canvas.',\n },\n {\n name: 'sidebar-foreground',\n kind: 'color',\n themed: true,\n description: 'Default text in the rail and sidebar.',\n },\n {\n name: 'sidebar-primary',\n kind: 'color',\n themed: true,\n description: 'The active destination in the rail.',\n },\n {\n name: 'sidebar-primary-foreground',\n kind: 'color',\n themed: true,\n description: 'Text on the active rail destination.',\n },\n {\n name: 'sidebar-accent',\n kind: 'color',\n themed: true,\n description: 'Hover and selected fill for rail and sidebar rows.',\n },\n {\n name: 'sidebar-accent-foreground',\n kind: 'color',\n themed: true,\n description: 'Text on `sidebar-accent`.',\n },\n {\n name: 'sidebar-border',\n kind: 'color',\n themed: true,\n description: 'The rule between the rail and the canvas.',\n },\n { name: 'sidebar-ring', kind: 'color', themed: true, description: 'Focus ring inside the rail.' },\n {\n name: 'sidebar-muted-foreground',\n kind: 'color',\n themed: true,\n description: 'Rail labels that are not the current destination.',\n },\n]\n\nexport const radiusTokens: TokenDefinition[] = [\n {\n name: 'radius-lg',\n kind: 'dimension',\n description:\n '10px — cards and panels. Also the knob: move this one value to re-round the whole system.',\n },\n { name: 'radius-sm', kind: 'dimension', description: '6px — badges, keyboard keys, menu items.' },\n {\n name: 'radius-md',\n kind: 'dimension',\n description: '8px — every control: buttons, inputs, selects.',\n },\n { name: 'radius-xl', kind: 'dimension', description: '14px — dialogs, menus, sheets.' },\n { name: 'radius-2xl', kind: 'dimension', description: '18px — full-window surfaces and media.' },\n]\n\nexport const typographyTokens: TokenDefinition[] = [\n {\n name: 'font-sans',\n kind: 'font-family',\n description: 'The selected interface face. Space Grotesk unless the font axis says otherwise.',\n },\n {\n name: 'font-mono',\n kind: 'font-family',\n description: 'The selected monospace face. Code, terminals, ids, paths.',\n },\n {\n name: 'font-family-space-grotesk',\n kind: 'font-family',\n description: 'The interface default, and the face the visual language was drawn against.',\n },\n {\n name: 'font-family-jetbrains-mono',\n kind: 'font-family',\n description: 'The monospace default. Code, terminals, diffs.',\n },\n {\n name: 'font-family-geist',\n kind: 'font-family',\n description: 'An alternative interface face. cortana already ships it.',\n },\n {\n name: 'font-family-geist-mono',\n kind: 'font-family',\n description: 'The monospace counterpart to Geist.',\n },\n {\n name: 'font-family-system',\n kind: 'font-family',\n description: \"The platform's own interface face. First-class, not a fallback.\",\n },\n {\n name: 'font-family-system-mono',\n kind: 'font-family',\n description: \"The platform's own monospace face.\",\n },\n {\n name: 'ui-tracking',\n kind: 'text',\n description:\n 'Letter spacing for measured chrome. `normal` on a proportional face, tightened when the UI font is monospace — which is roughly 20% wider at the same size.',\n },\n {\n name: 'ui-word-spacing',\n kind: 'text',\n description:\n \"Word spacing for measured chrome. Mono's space is a full advance-width cell, so a two-word label reads as two floating words without this.\",\n },\n {\n name: 'text-2xs',\n kind: 'text',\n description: '11px — the smallest label the system permits: kbd keys, status bar.',\n },\n { name: 'text-xs', kind: 'text', description: '12px — metadata, badges, secondary rows.' },\n {\n name: 'text-sm',\n kind: 'text',\n description: '14px — the interface default. Body copy, labels, controls.',\n },\n { name: 'text-base', kind: 'text', description: '16px — card titles and dialog titles.' },\n { name: 'text-lg', kind: 'text', description: '18px — a section heading inside a page.' },\n { name: 'text-xl', kind: 'text', description: '20px — a page title.' },\n { name: 'text-2xl', kind: 'text', description: '24px — a display figure.' },\n {\n name: 'text-3xl',\n kind: 'text',\n description: '30px — the largest size in the system. Reserved for an empty-state headline.',\n },\n]\n\n/** Height tokens also size both axes of icon controls through Tailwind's --size\n * namespace. Padding has its own --spacing mapping. Nominal pixel descriptions\n * use a 16px rem; rendered dimensions follow the consumer's root font size. */\nexport const densityTokens: TokenDefinition[] = [\n { name: 'control-height-2xs', kind: 'dimension', description: '20px — an inline chip control.' },\n { name: 'control-height-xs', kind: 'dimension', description: '24px — a dense table row action.' },\n { name: 'control-height-sm', kind: 'dimension', description: '28px — the toolbar default.' },\n {\n name: 'control-height-md',\n kind: 'dimension',\n description: '32px — the form default. Button and Input are this size unless told otherwise.',\n },\n { name: 'control-height-lg', kind: 'dimension', description: '36px — a primary form action.' },\n {\n name: 'control-height-xl',\n kind: 'dimension',\n description: '40px — a hero control in an empty state.',\n },\n {\n name: 'control-padding-2xs',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 20px control.',\n },\n {\n name: 'control-padding-xs',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 24px control.',\n },\n {\n name: 'control-padding-sm',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 28px control.',\n },\n {\n name: 'control-padding-md',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 32px control.',\n },\n {\n name: 'control-padding-lg',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 36px control.',\n },\n {\n name: 'control-padding-xl',\n kind: 'dimension',\n description: 'Inline padding that pairs with the 40px control.',\n },\n { name: 'row-height-sm', kind: 'dimension', description: '28px — a dense list row.' },\n { name: 'row-height-md', kind: 'dimension', description: '32px — the default list row.' },\n { name: 'row-height-lg', kind: 'dimension', description: '36px — a two-line list row.' },\n { name: 'rail-width', kind: 'dimension', description: '58px — the icon-only rail.' },\n { name: 'rail-width-expanded', kind: 'dimension', description: '236px — the labelled rail.' },\n {\n name: 'rail-item-height',\n kind: 'dimension',\n description: '36px — a rail or sidebar destination.',\n },\n {\n name: 'sidebar-width',\n kind: 'dimension',\n description: '256px — the secondary navigation column.',\n },\n {\n name: 'sidebar-width-compact',\n kind: 'dimension',\n description: '48px — the collapsed secondary column.',\n },\n { name: 'topbar-height', kind: 'dimension', description: '48px — the window title row.' },\n { name: 'statusbar-height', kind: 'dimension', description: '28px — the bottom readout strip.' },\n]\n\nexport const elevationTokens: TokenDefinition[] = [\n {\n name: 'shadow-2xs',\n kind: 'shadow',\n themed: true,\n description: 'Barely there: a chip resting on a card.',\n },\n {\n name: 'shadow-xs',\n kind: 'shadow',\n themed: true,\n description: 'A card or panel on the canvas.',\n },\n {\n name: 'shadow-sm',\n kind: 'shadow',\n themed: true,\n description: 'A control that lifts: a pressed toggle, a thumb.',\n },\n { name: 'shadow-md', kind: 'shadow', themed: true, description: 'A menu or popover.' },\n { name: 'shadow-lg', kind: 'shadow', themed: true, description: 'A dialog or sheet.' },\n {\n name: 'shadow-xl',\n kind: 'shadow',\n themed: true,\n description: 'The command palette, above everything.',\n },\n]\n\nexport const motionTokens: TokenDefinition[] = [\n {\n name: 'duration-fast',\n kind: 'duration',\n description: '120ms — a state change the user is already watching.',\n },\n { name: 'duration-normal', kind: 'duration', description: '200ms — an entrance.' },\n { name: 'duration-slow', kind: 'duration', description: '320ms — a layout settle.' },\n {\n name: 'ease-out',\n kind: 'easing',\n description: 'A fast start and a long settle. Reads as decisive rather than floaty.',\n },\n {\n name: 'ease-in-out',\n kind: 'easing',\n description: 'For a loop that has no start or end, such as a shimmer.',\n },\n]\n\nexport const zIndexTokens: TokenDefinition[] = [\n { name: 'z-base', kind: 'number', description: 'In flow, at the document order.' },\n {\n name: 'z-docked',\n kind: 'number',\n description: 'A sticky table header standing above its own scroll body.',\n },\n { name: 'z-sticky', kind: 'number', description: 'The top bar and any other pinned chrome.' },\n { name: 'z-drawer', kind: 'number', description: 'A drawer, below a modal dialog.' },\n { name: 'z-dialog', kind: 'number', description: 'A modal dialog and its scrim.' },\n {\n name: 'z-menu',\n kind: 'number',\n description: 'Menus, popovers and comboboxes. Above dialogs, because a dialog can contain one.',\n },\n {\n name: 'z-tooltip',\n kind: 'number',\n description: 'Tooltips. Above menus, because a menu item can carry one.',\n },\n {\n name: 'z-toast',\n kind: 'number',\n description: 'Notifications. Above everything, so they are never hidden by a dialog.',\n },\n]\n\n/**\n * The accent axis.\n *\n * adea's accent presets, as a selection rather than a constant. `theme` is the\n * default and means \"the variant's own primary\" — monochrome in adea's palette —\n * and each named preset overrides the interactive roles through the\n * `[data-accent]` blocks in `theme.css`.\n *\n * These are the same six presets `accentPresets` exports in adea's own\n * `appearance.ts`, and the values match. A consumer's appearance picker and the\n * workshop's theme toolbar read this one list, so the two cannot disagree about\n * what a preset is called or what colour it is.\n */\nexport type AccentPreset = {\n /** The `data-accent` value. `theme` is the variant's own primary. */\n id: string\n label: string\n /** What the preset is for, in the gallery and in a picker. */\n description: string\n /** The accent as it appears in the light theme. Absent for `theme`. */\n light?: string\n /** The accent as it appears in the dark theme. Absent for `theme`. */\n dark?: string\n}\n\nexport const accentPresets: readonly AccentPreset[] = Object.freeze([\n {\n id: 'theme',\n label: 'Theme',\n description:\n \"The variant's own primary. Neutral in adea's palette, so the interface stays monochrome.\",\n },\n ...ACCENTS,\n])\n\n/**\n * The font axis.\n *\n * The family is a selection, like the accent: `data-font` sits on the same element\n * and each option swaps the interface face. `space-grotesk` is the default because\n * it is the face the visual language was drawn against, and `system` is a\n * first-class option rather than a fallback — an application that wants the\n * platform's own face should be able to say so without losing the rest of the\n * system.\n */\nexport type FontOption = {\n /** The `data-font` value. `space-grotesk` is the default and needs no attribute. */\n id: string\n label: string\n description: string\n /** Which of the two stacks this option sets. */\n stack: 'sans' | 'mono' | 'both'\n}\n\nexport const fontOptions: readonly FontOption[] = Object.freeze([\n {\n id: 'space-grotesk',\n label: 'Space Grotesk',\n description: 'The default, and the face the visual language was drawn against.',\n stack: 'both',\n },\n {\n id: 'system',\n label: 'System',\n description: \"The platform's own face. What a terminal or editor usually wants.\",\n stack: 'both',\n },\n {\n id: 'geist',\n label: 'Geist',\n description: 'The face cortana already ships. Neutral and wide.',\n stack: 'both',\n },\n {\n id: 'geist-mono',\n label: 'Geist Mono',\n description: 'Monospace throughout, for someone who wants a uniform texture.',\n stack: 'both',\n },\n {\n id: 'jetbrains-mono',\n label: 'JetBrains Mono',\n description: 'Monospace throughout, with coding ligatures off.',\n stack: 'both',\n },\n])\n\n/** Every token, in gallery order. */\nexport const designTokens = {\n color: colorTokens,\n radius: radiusTokens,\n typography: typographyTokens,\n density: densityTokens,\n elevation: elevationTokens,\n motion: motionTokens,\n zIndex: zIndexTokens,\n} as const\n\n/** Flat list, for completeness checks and for search. */\nexport const allTokens: TokenDefinition[] = Object.values(designTokens).flat()\n\n/**\n * Aliases that exist only to make a call site read better, and which therefore\n * have no gallery row of their own. Kept explicit so the completeness check\n * below can tell \"deliberately absent\" from \"forgotten\".\n */\nexport const undocumentedTokenAliases: string[] = ['radius']\n"],"mappings":"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"}
@@ -121,7 +121,7 @@ export function AppearanceEditor(props: AppearanceEditorProps) {
121
121
  onInput={(event) => props.onChange({ accent: event.currentTarget.value })}
122
122
  />
123
123
  <Show when={props.customAccentError}>
124
- <p id={errorId} role="alert" class="mt-1 text-xs text-destructive">
124
+ <p id={errorId} role="alert" class="mt-1 text-xs text-foreground">
125
125
  {props.customAccentError}
126
126
  </p>
127
127
  </Show>
@@ -59,18 +59,15 @@ export function Stat(props: StatProps) {
59
59
  </Show>
60
60
  </div>
61
61
  <Show when={local.delta}>
62
- <div
63
- class={cn('flex items-center gap-1 text-xs', {
64
- 'text-success': local.deltaTone === 'up',
65
- 'text-destructive': local.deltaTone === 'down',
66
- 'text-muted-foreground': local.deltaTone === undefined || local.deltaTone === 'neutral',
67
- })}
68
- >
62
+ <div class="text-foreground flex items-center gap-1 text-xs">
69
63
  <Show when={local.deltaTone === 'up' || local.deltaTone === 'down'}>
70
64
  <Dynamic
71
65
  component={local.deltaTone === 'down' ? ArrowDownRight : ArrowUpRight}
72
66
  aria-hidden="true"
73
- class="size-3"
67
+ class={cn('size-3', {
68
+ 'text-success': local.deltaTone === 'up',
69
+ 'text-destructive': local.deltaTone === 'down',
70
+ })}
74
71
  />
75
72
  </Show>
76
73
  <span class="tabular-nums">{local.delta}</span>
@@ -1,4 +1,13 @@
1
- import { createEffect, createMemo, createSignal, onMount, Show, splitProps } from 'solid-js'
1
+ import {
2
+ createEffect,
3
+ createMemo,
4
+ createSignal,
5
+ onCleanup,
6
+ onMount,
7
+ Show,
8
+ splitProps,
9
+ } from 'solid-js'
10
+ import type { Accessor } from 'solid-js'
2
11
  import { Check, Download, ExternalLink, LoaderCircle, RefreshCw, Sparkles } from 'lucide-solid'
3
12
  import { Badge } from '../../ui/badge'
4
13
  import { Button } from '../../ui/button'
@@ -12,6 +21,7 @@ import {
12
21
  DialogTitle,
13
22
  DialogTrigger,
14
23
  } from '../../ui/dialog'
24
+ import { createDialogFocusRestoration } from '../../ui/dialog/dialog'
15
25
  import { Progress } from '../../ui/progress'
16
26
  import { cn } from '../../../lib/utils'
17
27
  import { formatBytes, formatReleaseDate, plainTextFromMarkdown } from '../../../lib/version-notes'
@@ -131,6 +141,12 @@ export type UpdateDialogProps = {
131
141
  */
132
142
  defaultOpen?: boolean
133
143
  onOpenChange?: (open: boolean) => void
144
+ /**
145
+ * Supplies a stable external control to focus when a controlled dialog closes.
146
+ * Useful when a menu or other layer closes before this dialog opens; when omitted,
147
+ * the element focused immediately before the dialog opens is used when available.
148
+ */
149
+ restoreFocusRef?: Accessor<HTMLElement | undefined>
134
150
  /** Render only the panel, for a caller that provides its own dialog. */
135
151
  class?: string
136
152
  }
@@ -162,6 +178,7 @@ export function UpdateDialog(props: UpdateDialogProps) {
162
178
  'open',
163
179
  'defaultOpen',
164
180
  'onOpenChange',
181
+ 'restoreFocusRef',
165
182
  'class',
166
183
  ])
167
184
 
@@ -172,23 +189,41 @@ export function UpdateDialog(props: UpdateDialogProps) {
172
189
  local.onOpenChange?.(next)
173
190
  }
174
191
 
192
+ const focusRestoration = createDialogFocusRestoration({
193
+ open,
194
+ restoreFocusRef: local.restoreFocusRef,
195
+ })
196
+
175
197
  const appName = () => local.appName ?? 'the application'
176
198
  const desktop = () => local.adapter.isDesktopRuntime()
177
199
  const [state, setState] = createSignal<UpdateState | null>(null)
178
200
  const [busy, setBusy] = createSignal(false)
179
201
  const [error, setError] = createSignal('')
202
+ let lifecycleEpoch = 0
203
+ let activeOpenEpoch: number | undefined
204
+ let disposed = false
205
+
206
+ onCleanup(() => {
207
+ disposed = true
208
+ activeOpenEpoch = undefined
209
+ lifecycleEpoch += 1
210
+ })
180
211
 
181
- const loadStatus = async () => {
182
- if (!desktop()) return
212
+ const loadStatus = async (isCurrent: () => boolean = () => !disposed) => {
213
+ if (!desktop() || !isCurrent()) return
183
214
  try {
184
- setState(await local.adapter.getStatus())
215
+ const status = await local.adapter.getStatus()
216
+ if (isCurrent()) setState(status)
185
217
  } catch (caught) {
186
- setError(errorMessage(caught, 'Version status is unavailable'))
218
+ if (isCurrent()) setError(errorMessage(caught, 'Version status is unavailable'))
187
219
  }
188
220
  }
189
221
 
190
222
  onMount(() => {
191
- if (desktop()) void loadStatus()
223
+ if (desktop() && !open()) {
224
+ const epoch = lifecycleEpoch
225
+ void loadStatus(() => !disposed && lifecycleEpoch === epoch)
226
+ }
192
227
  })
193
228
 
194
229
  const check = async () => {
@@ -196,15 +231,25 @@ export function UpdateDialog(props: UpdateDialogProps) {
196
231
  setError(local.desktopOnlyMessage ?? `Update checks are available from the desktop app.`)
197
232
  return
198
233
  }
234
+ const epoch = activeOpenEpoch
235
+ const isCurrent = () =>
236
+ !disposed &&
237
+ epoch !== undefined &&
238
+ activeOpenEpoch === epoch &&
239
+ lifecycleEpoch === epoch &&
240
+ open()
241
+ if (!isCurrent()) return
199
242
  setBusy(true)
200
243
  setError('')
201
244
  try {
202
- setState(await local.adapter.check())
245
+ const checked = await local.adapter.check()
246
+ if (isCurrent()) setState(checked)
203
247
  } catch (caught) {
248
+ if (!isCurrent()) return
204
249
  setError(errorMessage(caught, 'Could not check for updates'))
205
- await loadStatus()
250
+ await loadStatus(isCurrent)
206
251
  } finally {
207
- setBusy(false)
252
+ if (isCurrent()) setBusy(false)
208
253
  }
209
254
  }
210
255
 
@@ -214,35 +259,57 @@ export function UpdateDialog(props: UpdateDialogProps) {
214
259
  * disposed scope.
215
260
  */
216
261
  createEffect(() => {
217
- if (!open() || !desktop()) return
262
+ if (!open() || !desktop()) {
263
+ if (activeOpenEpoch !== undefined) {
264
+ activeOpenEpoch = undefined
265
+ lifecycleEpoch += 1
266
+ }
267
+ return
268
+ }
269
+ const epoch = ++lifecycleEpoch
270
+ activeOpenEpoch = epoch
218
271
  let active = true
272
+ const isCurrent = () =>
273
+ active && !disposed && activeOpenEpoch === epoch && lifecycleEpoch === epoch && open()
274
+ onCleanup(() => {
275
+ active = false
276
+ if (activeOpenEpoch === epoch) {
277
+ activeOpenEpoch = undefined
278
+ lifecycleEpoch += 1
279
+ }
280
+ })
219
281
  setError('')
220
282
  setBusy(true)
221
283
  void (async () => {
222
284
  try {
223
285
  const current = await local.adapter.getStatus()
224
- if (!active) return
286
+ if (!isCurrent()) return
225
287
  setState(current)
226
288
  const checked = await local.adapter.check()
227
- if (active) setState(checked)
289
+ if (isCurrent()) setState(checked)
228
290
  } catch (caught) {
229
- if (active) setError(errorMessage(caught, 'Could not check for updates'))
291
+ if (isCurrent()) setError(errorMessage(caught, 'Could not check for updates'))
230
292
  } finally {
231
- if (active) setBusy(false)
293
+ if (isCurrent()) setBusy(false)
232
294
  }
233
295
  })()
234
- return () => {
235
- active = false
236
- }
237
296
  })
238
297
 
239
298
  const install = async () => {
240
299
  const version = state()?.availableVersion
241
- if (!version) return
300
+ const epoch = activeOpenEpoch
301
+ const isCurrent = () =>
302
+ !disposed &&
303
+ epoch !== undefined &&
304
+ activeOpenEpoch === epoch &&
305
+ lifecycleEpoch === epoch &&
306
+ open()
307
+ if (!version || !isCurrent()) return
242
308
  setBusy(true)
243
309
  setError('')
244
310
  try {
245
311
  const next = await local.adapter.install(version)
312
+ if (!isCurrent()) return
246
313
  setState(next)
247
314
  // A refused install answers with a normal payload whose phase is `failed`.
248
315
  // Without this the click looked like nothing happened.
@@ -250,10 +317,11 @@ export function UpdateDialog(props: UpdateDialogProps) {
250
317
  setError(errorMessage(next.error, 'Update installation failed'))
251
318
  }
252
319
  } catch (caught) {
320
+ if (!isCurrent()) return
253
321
  setError(errorMessage(caught, 'Update installation failed'))
254
- await loadStatus()
322
+ await loadStatus(isCurrent)
255
323
  } finally {
256
- setBusy(false)
324
+ if (isCurrent()) setBusy(false)
257
325
  }
258
326
  }
259
327
 
@@ -308,7 +376,11 @@ export function UpdateDialog(props: UpdateDialogProps) {
308
376
  </DialogTrigger>
309
377
  </Show>
310
378
 
311
- <DialogContent class={cn('max-w-3xl', local.class)}>
379
+ <DialogContent
380
+ class={cn('max-w-3xl', local.class)}
381
+ onOpenAutoFocus={focusRestoration.onOpenAutoFocus}
382
+ onCloseAutoFocus={focusRestoration.onCloseAutoFocus}
383
+ >
312
384
  <DialogHeader>
313
385
  <div class="flex items-center gap-3">
314
386
  <span class="flex size-10 items-center justify-center rounded-xl bg-primary text-primary-foreground">
@@ -432,15 +504,15 @@ export function UpdateDialog(props: UpdateDialogProps) {
432
504
  </Show>
433
505
 
434
506
  <Show when={state()?.phase === 'current'}>
435
- <p class="flex items-center gap-2 text-sm text-success" role="status">
436
- <Check class="size-4" aria-hidden="true" />
507
+ <p class="text-foreground flex items-center gap-2 text-sm" role="status">
508
+ <Check class="size-4 text-success" aria-hidden="true" />
437
509
  {appName()} is up to date.
438
510
  </p>
439
511
  </Show>
440
512
 
441
513
  <Show when={state()?.phase === 'installed'}>
442
- <p class="flex items-center gap-2 text-sm text-success" role="status">
443
- <Check class="size-4" aria-hidden="true" />
514
+ <p class="text-foreground flex items-center gap-2 text-sm" role="status">
515
+ <Check class="size-4 text-success" aria-hidden="true" />
444
516
  <Show when={state()?.restartRequired} fallback="The update is applied.">
445
517
  Restart {appName()} to finish the update.
446
518
  </Show>
@@ -449,7 +521,7 @@ export function UpdateDialog(props: UpdateDialogProps) {
449
521
 
450
522
  <Show when={error()}>
451
523
  <p
452
- class="rounded-lg border border-destructive/35 bg-destructive-subtle px-3 py-2 text-sm text-destructive"
524
+ class="text-foreground rounded-lg border border-destructive/35 bg-destructive-subtle px-3 py-2 text-sm"
453
525
  role="alert"
454
526
  >
455
527
  {error()}
@@ -237,7 +237,7 @@ export function ChatComposerShell<Extra extends object>(props: ChatComposerShell
237
237
  </Show>
238
238
  <Show when={error()}>
239
239
  {(message) => (
240
- <p role="alert" class="text-destructive mb-1 text-xs">
240
+ <p role="alert" class="text-foreground mb-1 border-s-2 border-destructive ps-2 text-xs">
241
241
  {message()}
242
242
  </p>
243
243
  )}
@@ -197,7 +197,9 @@ export function MessageComposer(props: MessageComposerProps) {
197
197
  field the user is typing in. */}
198
198
  <div aria-live="polite" class="min-h-0">
199
199
  <Show when={error()}>
200
- {(message) => <p class="text-destructive text-xs">{message()}</p>}
200
+ {(message) => (
201
+ <p class="text-foreground border-s-2 border-destructive ps-2 text-xs">{message()}</p>
202
+ )}
201
203
  </Show>
202
204
  </div>
203
205
  </form>
@@ -14,7 +14,9 @@ import { cn } from '../../../lib/utils'
14
14
  *
15
15
  * The glyph follows the tone rather than being passed in, so an alert cannot
16
16
  * be given a green checkmark on a destructive fill. A caller that genuinely
17
- * needs a different icon passes `icon`; `icon={null}` removes it.
17
+ * needs a different icon passes `icon`; `icon={null}` removes it. Text stays on
18
+ * the body foreground over the tinted status surface, while the glyph and edge
19
+ * carry the status hue.
18
20
  */
19
21
  const alertVariants = cva(
20
22
  'relative grid w-full grid-cols-[auto_1fr] items-start gap-x-3 gap-y-1 rounded-lg border px-3 py-2.5 text-sm',
@@ -22,10 +24,10 @@ const alertVariants = cva(
22
24
  variants: {
23
25
  variant: {
24
26
  default: 'bg-card text-card-foreground border-border',
25
- destructive: 'bg-destructive-subtle text-destructive border-destructive/30',
26
- success: 'bg-success-subtle text-success border-success/30',
27
- warning: 'bg-warning-subtle text-warning border-warning/30',
28
- info: 'bg-info-subtle text-info border-info/30',
27
+ destructive: 'bg-destructive-subtle text-foreground border-destructive/30',
28
+ success: 'bg-success-subtle text-foreground border-success/30',
29
+ warning: 'bg-warning-subtle text-foreground border-warning/30',
30
+ info: 'bg-info-subtle text-foreground border-info/30',
29
31
  },
30
32
  },
31
33
  defaultVariants: { variant: 'default' },
@@ -40,6 +42,14 @@ const alertIcons = {
40
42
  info: Info,
41
43
  } as const
42
44
 
45
+ const alertIconTones = {
46
+ default: 'text-muted-foreground',
47
+ destructive: 'text-destructive',
48
+ success: 'text-success',
49
+ warning: 'text-warning',
50
+ info: 'text-info',
51
+ } as const
52
+
43
53
  type AlertVariantProps = VariantProps<typeof alertVariants>
44
54
 
45
55
  export type AlertProps = ComponentProps<'div'> &
@@ -61,7 +71,10 @@ export function Alert(props: AlertProps) {
61
71
  {...rest}
62
72
  >
63
73
  {local.icon === null ? null : (
64
- <span data-slot="alert-icon" class="row-span-2 pt-0.5 [&_svg]:size-4">
74
+ <span
75
+ data-slot="alert-icon"
76
+ class={cn('row-span-2 pt-0.5 [&_svg]:size-4', alertIconTones[tone()])}
77
+ >
65
78
  {local.icon ?? <Dynamic component={alertIcons[tone()]} />}
66
79
  </span>
67
80
  )}
@@ -86,7 +99,7 @@ export function AlertDescription(props: ComponentProps<'div'>) {
86
99
  return (
87
100
  <div
88
101
  data-slot="alert-description"
89
- class={cn('col-start-2 text-sm opacity-90 [&_p]:leading-relaxed', local.class)}
102
+ class={cn('col-start-2 text-sm [&_p]:leading-relaxed', local.class)}
90
103
  {...rest}
91
104
  />
92
105
  )
@@ -20,10 +20,10 @@ export const badgeVariants = cva(
20
20
  secondary: 'bg-secondary text-secondary-foreground',
21
21
  outline: 'border-border text-foreground',
22
22
  /** Tinted status fills, for counts and states rather than actions. */
23
- success: 'bg-success-subtle text-success',
24
- warning: 'bg-warning-subtle text-warning',
25
- destructive: 'bg-destructive-subtle text-destructive',
26
- info: 'bg-info-subtle text-info',
23
+ success: 'bg-success-subtle text-foreground',
24
+ warning: 'bg-warning-subtle text-foreground',
25
+ destructive: 'bg-destructive-subtle text-foreground',
26
+ info: 'bg-info-subtle text-foreground',
27
27
  subtle: 'bg-primary-subtle text-primary',
28
28
  },
29
29
  size: {
@@ -4,6 +4,7 @@ import type { ComponentProps } from 'solid-js'
4
4
  import { splitProps } from 'solid-js'
5
5
  import {
6
6
  menuContentPadding,
7
+ destructiveMenuItem,
7
8
  menuItem,
8
9
  menuLabel,
9
10
  menuSeparator,
@@ -65,8 +66,7 @@ export function ContextMenuItem(
65
66
  class={cn(
66
67
  menuItem,
67
68
  {
68
- 'text-destructive data-[highlighted]:bg-destructive-subtle data-[highlighted]:text-destructive':
69
- local.variant === 'destructive',
69
+ [destructiveMenuItem]: local.variant === 'destructive',
70
70
  },
71
71
  local.class
72
72
  )}