@adea-ai/themes 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -91,6 +91,11 @@ terminal.options.theme = toXtermTheme(theme)
91
91
  const highlighter = await createHighlighter({ themes: [toShikiTheme(theme)], langs: [...] })
92
92
  ```
93
93
 
94
+ `syntaxRolesHex(theme)` keeps comments at the catalogue's intentionally quiet default.
95
+ For editor palettes where comments and diff markers are small content text,
96
+ `editorRolesHex(theme)` returns the editor roles with every rounded hex value checked
97
+ against a 4.5:1 contrast floor. The source syntax palette remains unchanged.
98
+
94
99
  Every exported theme value is an `oklch()` string, which means the browser does the
95
100
  colour work and a consumer can compose — `color-mix(in oklch, var(--adea-accent),
96
101
  transparent 20%)` — and get a predictable result. The adapters that need hex (xterm,
@@ -26,6 +26,24 @@ import type { AdeaTheme, AdeaThemeColors, ShadcnThemeProjection } from '../schem
26
26
  export type ShadcnTheme = AdeaTheme & {
27
27
  shadcn?: ShadcnThemeProjection;
28
28
  };
29
+ /** The solid destructive pair consumed by filled shadcn actions. */
30
+ export interface ShadcnDestructiveProjection {
31
+ /** Presentation fill derived from, but distinct from, the canonical error role. */
32
+ readonly fill: string;
33
+ /** Text color that clears the solid and 90%-hover presentation floors. */
34
+ readonly foreground: string;
35
+ }
36
+ /**
37
+ * The shared destructive solid fill and foreground as rendered by the UI.
38
+ *
39
+ * A filled destructive button uses `--destructive/90` on hover. A foreground that
40
+ * clears the original fill can fall below AA when that color is alpha-composited
41
+ * over a light or dark surface. This projection keeps the canonical error color
42
+ * untouched, adjusts only the presentation lightness along its hue, and tests the
43
+ * rounded sRGB output against the canvas and both card surfaces. The 5:1 internal
44
+ * margin protects the 4.5:1 AA floor from browser quantization.
45
+ */
46
+ export declare function shadcnDestructiveProjection(theme: ShadcnTheme): ShadcnDestructiveProjection;
29
47
  /**
30
48
  * Canonical role → shadcn custom-property name.
31
49
  *
@@ -1 +1 @@
1
- {"version":3,"file":"shadcn.d.ts","sourceRoot":"","sources":["../../src/adapters/shadcn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAGrF,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,qBAAqB,CAAA;CAAE,CAAA;AAExE;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,eAAe,EAAE,MAAM,CAAC,CAsBzE,CAAA;AAEF;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAItE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyD1E;AAED,0CAA0C;AAC1C,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,SAAU,GAAG,MAAM,CAKxE"}
1
+ {"version":3,"file":"shadcn.d.ts","sourceRoot":"","sources":["../../src/adapters/shadcn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAWrF,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,qBAAqB,CAAA;CAAE,CAAA;AAExE,oEAAoE;AACpE,MAAM,WAAW,2BAA2B;IAC1C,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,2BAA2B,CA6D3F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,eAAe,EAAE,MAAM,CAAC,CAsBzE,CAAA;AAEF;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAItE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6D1E;AAED,0CAA0C;AAC1C,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,SAAU,GAAG,MAAM,CAKxE"}
@@ -22,6 +22,90 @@
22
22
  * A table of the whole mapping is in `docs/shadcn-bridge.md`.
23
23
  */
24
24
  import { STATUS_ROLES, statusForeground, tint } from '../derive.js';
25
+ import { contrastRatio, formatOklch, gamutMap, hexToOklch, oklchToHex, parseColor, } from '../oklch.js';
26
+ const DESTRUCTIVE_PRESENTATION_FLOOR = 5;
27
+ const DESTRUCTIVE_HOVER_OPACITY = 0.9;
28
+ const DESTRUCTIVE_PRESENTATION_SURFACES = ['background', 'surface', 'surfaceElevated'];
29
+ function renderedColor(value) {
30
+ const color = parseColor(value);
31
+ return color ? hexToOklch(oklchToHex(color)) : undefined;
32
+ }
33
+ function compositeSrgb(foreground, background, alpha) {
34
+ const foregroundHex = oklchToHex(parseColor(foreground));
35
+ const backgroundHex = oklchToHex(parseColor(background));
36
+ const channels = [1, 3, 5].map((offset) => {
37
+ const front = Number.parseInt(foregroundHex.slice(offset, offset + 2), 16);
38
+ const back = Number.parseInt(backgroundHex.slice(offset, offset + 2), 16);
39
+ return Math.round(front * alpha + back * (1 - alpha))
40
+ .toString(16)
41
+ .padStart(2, '0');
42
+ });
43
+ return hexToOklch(`#${channels.join('')}`);
44
+ }
45
+ /**
46
+ * The shared destructive solid fill and foreground as rendered by the UI.
47
+ *
48
+ * A filled destructive button uses `--destructive/90` on hover. A foreground that
49
+ * clears the original fill can fall below AA when that color is alpha-composited
50
+ * over a light or dark surface. This projection keeps the canonical error color
51
+ * untouched, adjusts only the presentation lightness along its hue, and tests the
52
+ * rounded sRGB output against the canvas and both card surfaces. The 5:1 internal
53
+ * margin protects the 4.5:1 AA floor from browser quantization.
54
+ */
55
+ export function shadcnDestructiveProjection(theme) {
56
+ const sourceFill = parseColor(theme.colors.error);
57
+ const sourceForeground = parseColor(theme.colors.foreground);
58
+ const sourceBackground = parseColor(theme.colors.background);
59
+ if (!sourceFill || !sourceForeground || !sourceBackground) {
60
+ throw new Error(`theme ${theme.id} has an invalid destructive color pair`);
61
+ }
62
+ const preferredForeground = statusForeground(theme, 'error');
63
+ const alternateForeground = contrastRatio(sourceForeground, sourceFill) >= contrastRatio(sourceBackground, sourceFill)
64
+ ? theme.colors.background
65
+ : theme.colors.foreground;
66
+ const foregrounds = [preferredForeground, alternateForeground]
67
+ .map((value) => ({ value, rendered: renderedColor(value) }))
68
+ .filter((entry) => Boolean(entry.rendered));
69
+ const surfaceValues = [
70
+ ...DESTRUCTIVE_PRESENTATION_SURFACES.map((role) => theme.colors[role]),
71
+ theme.shadcn?.card ?? theme.colors.surface,
72
+ theme.shadcn?.popover ?? theme.colors.surfaceElevated,
73
+ ];
74
+ const surfaces = surfaceValues
75
+ .map((value) => ({ value, rendered: renderedColor(value) }))
76
+ .filter((entry) => Boolean(entry.rendered));
77
+ if (surfaces.length !== surfaceValues.length) {
78
+ throw new Error(`theme ${theme.id} has an invalid destructive presentation surface`);
79
+ }
80
+ for (let step = 0; step <= 250; step += 1) {
81
+ const directions = step === 0 ? [0] : [-1, 1];
82
+ for (const direction of directions) {
83
+ const candidate = gamutMap({
84
+ ...sourceFill,
85
+ l: sourceFill.l + direction * step * 0.001,
86
+ });
87
+ if (candidate.l < 0.02 || candidate.l > 0.98)
88
+ continue;
89
+ const fill = formatOklch(candidate);
90
+ const renderedFill = renderedColor(fill);
91
+ if (!renderedFill)
92
+ continue;
93
+ for (const foreground of foregrounds) {
94
+ const solidRatio = contrastRatio(foreground.rendered, renderedFill);
95
+ if (solidRatio < DESTRUCTIVE_PRESENTATION_FLOOR)
96
+ continue;
97
+ const clearsHoverFloor = surfaces.every(({ rendered }) => {
98
+ const composite = compositeSrgb(fill, formatOklch(rendered), DESTRUCTIVE_HOVER_OPACITY);
99
+ return (composite !== undefined &&
100
+ contrastRatio(foreground.rendered, composite) >= DESTRUCTIVE_PRESENTATION_FLOOR);
101
+ });
102
+ if (clearsHoverFloor)
103
+ return { fill, foreground: foreground.value };
104
+ }
105
+ }
106
+ }
107
+ throw new Error(`theme ${theme.id} cannot meet the shared destructive presentation floor`);
108
+ }
25
109
  /**
26
110
  * Canonical role → shadcn custom-property name.
27
111
  *
@@ -71,8 +155,9 @@ export function shadcnRoles(theme) {
71
155
  */
72
156
  export function shadcnVariables(theme) {
73
157
  const variables = {};
158
+ const destructive = shadcnDestructiveProjection(theme);
74
159
  for (const [role, name] of Object.entries(SHADCN_MAPPING)) {
75
- variables[`--${name}`] = theme.colors[role];
160
+ variables[`--${name}`] = role === 'error' ? destructive.fill : theme.colors[role];
76
161
  }
77
162
  variables['--accent'] = theme.colors.surfaceHover;
78
163
  variables['--accent-foreground'] = theme.colors.text;
@@ -99,13 +184,15 @@ export function shadcnVariables(theme) {
99
184
  variables['--sidebar-primary-foreground'] = theme.colors.accentForeground;
100
185
  variables['--sidebar-ring'] = theme.colors.accent;
101
186
  variables['--sidebar-muted-foreground'] = theme.colors.textMuted;
187
+ variables['--destructive-foreground'] = destructive.foreground;
102
188
  for (const role of STATUS_ROLES) {
103
189
  // Status labels on a subtle fill use the theme's body foreground; this
104
190
  // foreground is reserved for text on the role's solid colour. Keep the
105
191
  // generated shadcn names aligned with SHADCN_MAPPING, especially error →
106
192
  // destructive, and resolve the tint against a real canvas so it is opaque.
107
193
  const shadcnRole = SHADCN_MAPPING[role];
108
- variables[`--${shadcnRole}-foreground`] = statusForeground(theme, role);
194
+ variables[`--${shadcnRole}-foreground`] =
195
+ role === 'error' ? destructive.foreground : statusForeground(theme, role);
109
196
  variables[`--${shadcnRole}-subtle`] = tint(theme.colors[role], theme.colors.background);
110
197
  }
111
198
  variables['--surface-sunken'] = theme.colors.background;
@@ -1 +1 @@
1
- {"version":3,"file":"shadcn.js","sourceRoot":"","sources":["../../src/adapters/shadcn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shadcn.js","sourceRoot":"","sources":["../../src/adapters/shadcn.ts"],"names":[],"mappings":"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"}
package/dist/derive.d.ts CHANGED
@@ -31,6 +31,8 @@
31
31
  import type { AdeaTheme } from './schema.js';
32
32
  /** The syntax roles, matching the names Shiki's theme contract expects. */
33
33
  export type SyntaxRole = 'keyword' | 'string' | 'number' | 'comment' | 'function' | 'variable' | 'type' | 'tag' | 'attribute' | 'operator' | 'heading' | 'link' | 'constant' | 'punctuation' | 'diffAdd' | 'diffDelete' | 'diffHunk' | 'searchMatch';
34
+ /** Roles in the product's editor palette, which are all read as small text. */
35
+ export type EditorRole = Exclude<SyntaxRole, 'constant' | 'punctuation'>;
34
36
  /**
35
37
  * The syntax palette for a theme, as OKLCH strings.
36
38
  *
@@ -45,6 +47,13 @@ export declare function syntaxRoles(theme: AdeaTheme, options?: {
45
47
  }): Record<SyntaxRole, string>;
46
48
  /** The syntax palette as hex, for engines that cannot evaluate `oklch()`. */
47
49
  export declare function syntaxRolesHex(theme: AdeaTheme): Record<SyntaxRole, string>;
50
+ /**
51
+ * The hex role set for code editors, where comments and diffs are rendered as
52
+ * content text rather than decorative syntax. The quiet syntax API stays at its
53
+ * palette-selected comment level; this projection explicitly holds every editor
54
+ * role to WCAG AA on the canvas.
55
+ */
56
+ export declare function editorRolesHex(theme: AdeaTheme): Record<EditorRole, string>;
48
57
  /**
49
58
  * The categorical chart series, derived from the ANSI hues.
50
59
  *
@@ -1 +1 @@
1
- {"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAI5C,2EAA2E;AAC3E,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,UAAU,GACV,UAAU,GACV,MAAM,GACN,KAAK,GACL,WAAW,GACX,UAAU,GACV,SAAS,GACT,MAAM,GACN,UAAU,GACV,aAAa,GACb,SAAS,GACT,YAAY,GACZ,UAAU,GACV,aAAa,CAAA;AA+BjB;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GACtC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAgC5B;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAQ3E;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC,EAOlD,CAAA;AAEX,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,MAAM,EAAE,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,MAAM,CAK7E;AAED,qEAAqE;AACrE,eAAO,MAAM,YAAY,kDAAmD,CAAA;AAC5E,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAEtD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAS3E;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAG9E"}
1
+ {"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAI5C,2EAA2E;AAC3E,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,UAAU,GACV,UAAU,GACV,MAAM,GACN,KAAK,GACL,WAAW,GACX,UAAU,GACV,SAAS,GACT,MAAM,GACN,UAAU,GACV,aAAa,GACb,SAAS,GACT,YAAY,GACZ,UAAU,GACV,aAAa,CAAA;AAEjB,+EAA+E;AAC/E,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,CAAC,CAAA;AAkDxE;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GACtC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAgC5B;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAQ3E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAiC3E;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC,EAOlD,CAAA;AAEX,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,MAAM,EAAE,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,MAAM,CAK7E;AAED,qEAAqE;AACrE,eAAO,MAAM,YAAY,kDAAmD,CAAA;AAC5E,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAEtD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAS3E;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAG9E"}
package/dist/derive.js CHANGED
@@ -29,6 +29,24 @@
29
29
  * palettes today.
30
30
  */
31
31
  import { contrastRatio, formatOklch, mix, oklchToHex, parseColor, repairContrast } from './oklch.js';
32
+ const EDITOR_ROLES = [
33
+ 'keyword',
34
+ 'string',
35
+ 'number',
36
+ 'comment',
37
+ 'function',
38
+ 'variable',
39
+ 'type',
40
+ 'tag',
41
+ 'attribute',
42
+ 'operator',
43
+ 'heading',
44
+ 'link',
45
+ 'diffAdd',
46
+ 'diffDelete',
47
+ 'diffHunk',
48
+ 'searchMatch',
49
+ ];
32
50
  /** Which ANSI role each syntax role is read from, and why. */
33
51
  const SYNTAX_SOURCE = Object.freeze({
34
52
  // Magenta is the slot palettes spend on the most distinctive hue they have, and
@@ -101,6 +119,43 @@ export function syntaxRolesHex(theme) {
101
119
  return [role, parsed ? oklchToHex(parsed) : value];
102
120
  }));
103
121
  }
122
+ /**
123
+ * The hex role set for code editors, where comments and diffs are rendered as
124
+ * content text rather than decorative syntax. The quiet syntax API stays at its
125
+ * palette-selected comment level; this projection explicitly holds every editor
126
+ * role to WCAG AA on the canvas.
127
+ */
128
+ export function editorRolesHex(theme) {
129
+ const roles = syntaxRolesHex(theme);
130
+ const background = parseColor(theme.colors.background);
131
+ if (!background)
132
+ throw new Error(`theme ${theme.id} has no valid editor background`);
133
+ return Object.fromEntries(EDITOR_ROLES.map((role) => {
134
+ const source = parseColor(roles[role]);
135
+ if (!source)
136
+ throw new Error(`theme ${theme.id} has no valid editor.${role}`);
137
+ const initial = oklchToHex(source);
138
+ const renderedInitial = parseColor(initial);
139
+ if (renderedInitial && contrastRatio(renderedInitial, background) >= 4.5 - 1e-9) {
140
+ return [role, initial];
141
+ }
142
+ // Repair against the exact role the editor receives. A repair at precisely
143
+ // 4.5:1 in OKLCH can round to a hex value just below that floor, so advance
144
+ // the requested threshold by the smallest measured step until the encoded
145
+ // value itself clears 4.5:1. No source palette value or hue is rewritten.
146
+ for (let margin = 0.001; margin <= 0.05; margin += 0.001) {
147
+ const repaired = repairContrast(source, background, 4.5 + margin);
148
+ if (!repaired.satisfied)
149
+ continue;
150
+ const candidate = oklchToHex(repaired.color);
151
+ const renderedCandidate = parseColor(candidate);
152
+ if (renderedCandidate && contrastRatio(renderedCandidate, background) >= 4.5 - 1e-9) {
153
+ return [role, candidate];
154
+ }
155
+ }
156
+ throw new Error(`cannot encode editor.${role} for ${theme.id} above 4.5:1 contrast`);
157
+ }));
158
+ }
104
159
  /**
105
160
  * The categorical chart series, derived from the ANSI hues.
106
161
  *
@@ -1 +1 @@
1
- {"version":3,"file":"derive.js","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"derive.js","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -53,8 +53,8 @@ export type { AnsiInvariant, ContrastFinding, Pairing } from './validate.js';
53
53
  export { REQUIRED_PAIRINGS, STATUS_PAIRINGS, checkAnsiRamp, formatFindings, validateCatalogue, validateTheme, } from './validate.js';
54
54
  export type { NormalizationFinding, NormalizedTheme, ThemeSourceSpec } from './normalize.js';
55
55
  export { CONTRAST_FLOORS, normalizeTheme } from './normalize.js';
56
- export type { StatusRole, SyntaxRole } from './derive.js';
57
- export { CHART_SERIES, STATUS_ROLES, chartSeries, statusForeground, statusForegroundHex, syntaxRoles, syntaxRolesHex, tint, } from './derive.js';
56
+ export type { EditorRole, StatusRole, SyntaxRole } from './derive.js';
57
+ export { CHART_SERIES, STATUS_ROLES, chartSeries, editorRolesHex, statusForeground, statusForegroundHex, syntaxRoles, syntaxRolesHex, tint, } from './derive.js';
58
58
  export type { Base24Palette, Base24Scheme, Base24Slot } from './adapters/base24.js';
59
59
  export { BASE24_SLOTS, BASE24_SLOT_MEANING, BASE24_TO_ANSI, Base24ParseError, formatBase24Scheme, parseBase24Palette, parseBase24Scheme, toBase24, } from './adapters/base24.js';
60
60
  export type { XtermTheme } from './adapters/xterm.js';
@@ -65,5 +65,6 @@ export type { TailwindOptions } from './adapters/tailwind.js';
65
65
  export { toTailwindTheme } from './adapters/tailwind.js';
66
66
  export type { ShikiThemeRegistration, ShikiTokenSetting } from './adapters/shiki.js';
67
67
  export { toShikiTheme, toShikiThemes } from './adapters/shiki.js';
68
- export { SHADCN_MAPPING, shadcnCss, shadcnRoles, shadcnVariables } from './adapters/shadcn.js';
68
+ export type { ShadcnDestructiveProjection } from './adapters/shadcn.js';
69
+ export { SHADCN_MAPPING, shadcnCss, shadcnDestructiveProjection, shadcnRoles, shadcnVariables, } from './adapters/shadcn.js';
69
70
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,YAAY,EACV,QAAQ,EACR,SAAS,EACT,eAAe,EACf,eAAe,EACf,OAAO,EACP,eAAe,EACf,aAAa,EACb,WAAW,EACX,aAAa,EACb,eAAe,EACf,qBAAqB,GACtB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEzD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EACL,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,aAAa,EACb,QAAQ,EACR,MAAM,EACN,kBAAkB,EAClB,OAAO,GACR,MAAM,gBAAgB,CAAA;AAGvB,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EACL,aAAa,EACb,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,UAAU,EACV,OAAO,EACP,GAAG,EACH,UAAU,EACV,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAA;AAGnB,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,aAAa,GACd,MAAM,eAAe,CAAA;AAGtB,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC5F,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAGhE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,IAAI,GACL,MAAM,aAAa,CAAA;AAGpB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACnF,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE9F,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,YAAY,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACpF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,YAAY,EACV,QAAQ,EACR,SAAS,EACT,eAAe,EACf,eAAe,EACf,OAAO,EACP,eAAe,EACf,aAAa,EACb,WAAW,EACX,aAAa,EACb,eAAe,EACf,qBAAqB,GACtB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEzD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EACL,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,aAAa,EACb,QAAQ,EACR,MAAM,EACN,kBAAkB,EAClB,OAAO,GACR,MAAM,gBAAgB,CAAA;AAGvB,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EACL,aAAa,EACb,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,UAAU,EACV,OAAO,EACP,GAAG,EACH,UAAU,EACV,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAA;AAGnB,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,aAAa,GACd,MAAM,eAAe,CAAA;AAGtB,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC5F,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAGhE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,IAAI,GACL,MAAM,aAAa,CAAA;AAGpB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACnF,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE9F,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,YAAY,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACpF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEjE,YAAY,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,EACL,cAAc,EACd,SAAS,EACT,2BAA2B,EAC3B,WAAW,EACX,eAAe,GAChB,MAAM,sBAAsB,CAAA"}
package/dist/index.js CHANGED
@@ -49,11 +49,11 @@ export { DEFAULT_THEME_IDS, getBase24Scheme, getTheme, hasTheme, resolveTheme, t
49
49
  export { contrastRatio, deltaEok, formatOklch, gamutMap, hexToOklch, inGamut, mix, oklchToHex, parseColor, parseOklch, relativeLuminance, repairContrast, shiftLightness, } from './oklch.js';
50
50
  export { REQUIRED_PAIRINGS, STATUS_PAIRINGS, checkAnsiRamp, formatFindings, validateCatalogue, validateTheme, } from './validate.js';
51
51
  export { CONTRAST_FLOORS, normalizeTheme } from './normalize.js';
52
- export { CHART_SERIES, STATUS_ROLES, chartSeries, statusForeground, statusForegroundHex, syntaxRoles, syntaxRolesHex, tint, } from './derive.js';
52
+ export { CHART_SERIES, STATUS_ROLES, chartSeries, editorRolesHex, statusForeground, statusForegroundHex, syntaxRoles, syntaxRolesHex, tint, } from './derive.js';
53
53
  export { BASE24_SLOTS, BASE24_SLOT_MEANING, BASE24_TO_ANSI, Base24ParseError, formatBase24Scheme, parseBase24Palette, parseBase24Scheme, toBase24, } from './adapters/base24.js';
54
54
  export { toXtermTheme } from './adapters/xterm.js';
55
55
  export { catalogueCss, cssVariableName, themeCss, themeCssVariables } from './adapters/css.js';
56
56
  export { toTailwindTheme } from './adapters/tailwind.js';
57
57
  export { toShikiTheme, toShikiThemes } from './adapters/shiki.js';
58
- export { SHADCN_MAPPING, shadcnCss, shadcnRoles, shadcnVariables } from './adapters/shadcn.js';
58
+ export { SHADCN_MAPPING, shadcnCss, shadcnDestructiveProjection, shadcnRoles, shadcnVariables, } from './adapters/shadcn.js';
59
59
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAgBH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGzD,OAAO,EACL,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAA;AAErB,8EAA8E;AAC9E,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,aAAa,EACb,QAAQ,EACR,MAAM,EACN,kBAAkB,EAClB,OAAO,GACR,MAAM,gBAAgB,CAAA;AAIvB,OAAO,EACL,aAAa,EACb,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,UAAU,EACV,OAAO,EACP,GAAG,EACH,UAAU,EACV,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAA;AAInB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,aAAa,GACd,MAAM,eAAe,CAAA;AAItB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAIhE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,IAAI,GACL,MAAM,aAAa,CAAA;AAIpB,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAG9F,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAgBH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGzD,OAAO,EACL,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAA;AAErB,8EAA8E;AAC9E,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,aAAa,EACb,QAAQ,EACR,MAAM,EACN,kBAAkB,EAClB,OAAO,GACR,MAAM,gBAAgB,CAAA;AAIvB,OAAO,EACL,aAAa,EACb,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,UAAU,EACV,OAAO,EACP,GAAG,EACH,UAAU,EACV,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAA;AAInB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,aAAa,GACd,MAAM,eAAe,CAAA;AAItB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAIhE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,IAAI,GACL,MAAM,aAAa,CAAA;AAIpB,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAG9F,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAGxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGjE,OAAO,EACL,cAAc,EACd,SAAS,EACT,2BAA2B,EAC3B,WAAW,EACX,eAAe,GAChB,MAAM,sBAAsB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/themes",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "The Adea theme catalogue: first-party and imported semantic OKLCH themes, with Base24, terminal, CSS and syntax adapters.",
5
5
  "keywords": [
6
6
  "adea",
@@ -24,10 +24,121 @@
24
24
 
25
25
  import type { AdeaTheme, AdeaThemeColors, ShadcnThemeProjection } from '../schema.js'
26
26
  import { STATUS_ROLES, statusForeground, tint } from '../derive.js'
27
+ import {
28
+ contrastRatio,
29
+ formatOklch,
30
+ gamutMap,
31
+ hexToOklch,
32
+ oklchToHex,
33
+ parseColor,
34
+ } from '../oklch.js'
27
35
 
28
36
  /** A canonical theme with optional owner-authored shadcn presentation values. */
29
37
  export type ShadcnTheme = AdeaTheme & { shadcn?: ShadcnThemeProjection }
30
38
 
39
+ /** The solid destructive pair consumed by filled shadcn actions. */
40
+ export interface ShadcnDestructiveProjection {
41
+ /** Presentation fill derived from, but distinct from, the canonical error role. */
42
+ readonly fill: string
43
+ /** Text color that clears the solid and 90%-hover presentation floors. */
44
+ readonly foreground: string
45
+ }
46
+
47
+ const DESTRUCTIVE_PRESENTATION_FLOOR = 5
48
+ const DESTRUCTIVE_HOVER_OPACITY = 0.9
49
+ const DESTRUCTIVE_PRESENTATION_SURFACES = ['background', 'surface', 'surfaceElevated'] as const
50
+
51
+ function renderedColor(value: string) {
52
+ const color = parseColor(value)
53
+ return color ? hexToOklch(oklchToHex(color)) : undefined
54
+ }
55
+
56
+ function compositeSrgb(foreground: string, background: string, alpha: number) {
57
+ const foregroundHex = oklchToHex(parseColor(foreground)!)
58
+ const backgroundHex = oklchToHex(parseColor(background)!)
59
+ const channels = [1, 3, 5].map((offset) => {
60
+ const front = Number.parseInt(foregroundHex.slice(offset, offset + 2), 16)
61
+ const back = Number.parseInt(backgroundHex.slice(offset, offset + 2), 16)
62
+ return Math.round(front * alpha + back * (1 - alpha))
63
+ .toString(16)
64
+ .padStart(2, '0')
65
+ })
66
+ return hexToOklch(`#${channels.join('')}`)
67
+ }
68
+
69
+ /**
70
+ * The shared destructive solid fill and foreground as rendered by the UI.
71
+ *
72
+ * A filled destructive button uses `--destructive/90` on hover. A foreground that
73
+ * clears the original fill can fall below AA when that color is alpha-composited
74
+ * over a light or dark surface. This projection keeps the canonical error color
75
+ * untouched, adjusts only the presentation lightness along its hue, and tests the
76
+ * rounded sRGB output against the canvas and both card surfaces. The 5:1 internal
77
+ * margin protects the 4.5:1 AA floor from browser quantization.
78
+ */
79
+ export function shadcnDestructiveProjection(theme: ShadcnTheme): ShadcnDestructiveProjection {
80
+ const sourceFill = parseColor(theme.colors.error)
81
+ const sourceForeground = parseColor(theme.colors.foreground)
82
+ const sourceBackground = parseColor(theme.colors.background)
83
+ if (!sourceFill || !sourceForeground || !sourceBackground) {
84
+ throw new Error(`theme ${theme.id} has an invalid destructive color pair`)
85
+ }
86
+
87
+ const preferredForeground = statusForeground(theme, 'error')
88
+ const alternateForeground =
89
+ contrastRatio(sourceForeground, sourceFill) >= contrastRatio(sourceBackground, sourceFill)
90
+ ? theme.colors.background
91
+ : theme.colors.foreground
92
+ const foregrounds = [preferredForeground, alternateForeground]
93
+ .map((value) => ({ value, rendered: renderedColor(value) }))
94
+ .filter((entry): entry is { value: string; rendered: NonNullable<typeof entry.rendered> } =>
95
+ Boolean(entry.rendered)
96
+ )
97
+ const surfaceValues = [
98
+ ...DESTRUCTIVE_PRESENTATION_SURFACES.map((role) => theme.colors[role]),
99
+ theme.shadcn?.card ?? theme.colors.surface,
100
+ theme.shadcn?.popover ?? theme.colors.surfaceElevated,
101
+ ]
102
+ const surfaces = surfaceValues
103
+ .map((value) => ({ value, rendered: renderedColor(value) }))
104
+ .filter((entry): entry is { value: string; rendered: NonNullable<typeof entry.rendered> } =>
105
+ Boolean(entry.rendered)
106
+ )
107
+ if (surfaces.length !== surfaceValues.length) {
108
+ throw new Error(`theme ${theme.id} has an invalid destructive presentation surface`)
109
+ }
110
+
111
+ for (let step = 0; step <= 250; step += 1) {
112
+ const directions = step === 0 ? [0] : [-1, 1]
113
+ for (const direction of directions) {
114
+ const candidate = gamutMap({
115
+ ...sourceFill,
116
+ l: sourceFill.l + direction * step * 0.001,
117
+ })
118
+ if (candidate.l < 0.02 || candidate.l > 0.98) continue
119
+ const fill = formatOklch(candidate)
120
+ const renderedFill = renderedColor(fill)
121
+ if (!renderedFill) continue
122
+
123
+ for (const foreground of foregrounds) {
124
+ const solidRatio = contrastRatio(foreground.rendered, renderedFill)
125
+ if (solidRatio < DESTRUCTIVE_PRESENTATION_FLOOR) continue
126
+
127
+ const clearsHoverFloor = surfaces.every(({ rendered }) => {
128
+ const composite = compositeSrgb(fill, formatOklch(rendered), DESTRUCTIVE_HOVER_OPACITY)
129
+ return (
130
+ composite !== undefined &&
131
+ contrastRatio(foreground.rendered, composite) >= DESTRUCTIVE_PRESENTATION_FLOOR
132
+ )
133
+ })
134
+ if (clearsHoverFloor) return { fill, foreground: foreground.value }
135
+ }
136
+ }
137
+ }
138
+
139
+ throw new Error(`theme ${theme.id} cannot meet the shared destructive presentation floor`)
140
+ }
141
+
31
142
  /**
32
143
  * Canonical role → shadcn custom-property name.
33
144
  *
@@ -81,9 +192,10 @@ export function shadcnRoles(theme: ShadcnTheme): Record<string, string> {
81
192
  */
82
193
  export function shadcnVariables(theme: ShadcnTheme): Record<string, string> {
83
194
  const variables: Record<string, string> = {}
195
+ const destructive = shadcnDestructiveProjection(theme)
84
196
 
85
197
  for (const [role, name] of Object.entries(SHADCN_MAPPING) as [keyof AdeaThemeColors, string][]) {
86
- variables[`--${name}`] = theme.colors[role]
198
+ variables[`--${name}`] = role === 'error' ? destructive.fill : theme.colors[role]
87
199
  }
88
200
 
89
201
  variables['--accent'] = theme.colors.surfaceHover
@@ -113,13 +225,16 @@ export function shadcnVariables(theme: ShadcnTheme): Record<string, string> {
113
225
  variables['--sidebar-ring'] = theme.colors.accent
114
226
  variables['--sidebar-muted-foreground'] = theme.colors.textMuted
115
227
 
228
+ variables['--destructive-foreground'] = destructive.foreground
229
+
116
230
  for (const role of STATUS_ROLES) {
117
231
  // Status labels on a subtle fill use the theme's body foreground; this
118
232
  // foreground is reserved for text on the role's solid colour. Keep the
119
233
  // generated shadcn names aligned with SHADCN_MAPPING, especially error →
120
234
  // destructive, and resolve the tint against a real canvas so it is opaque.
121
235
  const shadcnRole = SHADCN_MAPPING[role]
122
- variables[`--${shadcnRole}-foreground`] = statusForeground(theme, role)
236
+ variables[`--${shadcnRole}-foreground`] =
237
+ role === 'error' ? destructive.foreground : statusForeground(theme, role)
123
238
  variables[`--${shadcnRole}-subtle`] = tint(theme.colors[role], theme.colors.background)
124
239
  }
125
240
 
package/src/derive.ts CHANGED
@@ -54,6 +54,28 @@ export type SyntaxRole =
54
54
  | 'diffHunk'
55
55
  | 'searchMatch'
56
56
 
57
+ /** Roles in the product's editor palette, which are all read as small text. */
58
+ export type EditorRole = Exclude<SyntaxRole, 'constant' | 'punctuation'>
59
+
60
+ const EDITOR_ROLES = [
61
+ 'keyword',
62
+ 'string',
63
+ 'number',
64
+ 'comment',
65
+ 'function',
66
+ 'variable',
67
+ 'type',
68
+ 'tag',
69
+ 'attribute',
70
+ 'operator',
71
+ 'heading',
72
+ 'link',
73
+ 'diffAdd',
74
+ 'diffDelete',
75
+ 'diffHunk',
76
+ 'searchMatch',
77
+ ] as const satisfies readonly EditorRole[]
78
+
57
79
  /** Which ANSI role each syntax role is read from, and why. */
58
80
  const SYNTAX_SOURCE: Readonly<Record<SyntaxRole, keyof AdeaTheme['ansi']>> = Object.freeze({
59
81
  // Magenta is the slot palettes spend on the most distinctive hue they have, and
@@ -140,6 +162,47 @@ export function syntaxRolesHex(theme: AdeaTheme): Record<SyntaxRole, string> {
140
162
  ) as Record<SyntaxRole, string>
141
163
  }
142
164
 
165
+ /**
166
+ * The hex role set for code editors, where comments and diffs are rendered as
167
+ * content text rather than decorative syntax. The quiet syntax API stays at its
168
+ * palette-selected comment level; this projection explicitly holds every editor
169
+ * role to WCAG AA on the canvas.
170
+ */
171
+ export function editorRolesHex(theme: AdeaTheme): Record<EditorRole, string> {
172
+ const roles = syntaxRolesHex(theme)
173
+ const background = parseColor(theme.colors.background)
174
+ if (!background) throw new Error(`theme ${theme.id} has no valid editor background`)
175
+
176
+ return Object.fromEntries(
177
+ EDITOR_ROLES.map((role) => {
178
+ const source = parseColor(roles[role])
179
+ if (!source) throw new Error(`theme ${theme.id} has no valid editor.${role}`)
180
+
181
+ const initial = oklchToHex(source)
182
+ const renderedInitial = parseColor(initial)
183
+ if (renderedInitial && contrastRatio(renderedInitial, background) >= 4.5 - 1e-9) {
184
+ return [role, initial]
185
+ }
186
+
187
+ // Repair against the exact role the editor receives. A repair at precisely
188
+ // 4.5:1 in OKLCH can round to a hex value just below that floor, so advance
189
+ // the requested threshold by the smallest measured step until the encoded
190
+ // value itself clears 4.5:1. No source palette value or hue is rewritten.
191
+ for (let margin = 0.001; margin <= 0.05; margin += 0.001) {
192
+ const repaired = repairContrast(source, background, 4.5 + margin)
193
+ if (!repaired.satisfied) continue
194
+ const candidate = oklchToHex(repaired.color)
195
+ const renderedCandidate = parseColor(candidate)
196
+ if (renderedCandidate && contrastRatio(renderedCandidate, background) >= 4.5 - 1e-9) {
197
+ return [role, candidate]
198
+ }
199
+ }
200
+
201
+ throw new Error(`cannot encode editor.${role} for ${theme.id} above 4.5:1 contrast`)
202
+ })
203
+ ) as Record<EditorRole, string>
204
+ }
205
+
143
206
  /**
144
207
  * The categorical chart series, derived from the ANSI hues.
145
208
  *
package/src/index.ts CHANGED
@@ -123,11 +123,12 @@ export type { NormalizationFinding, NormalizedTheme, ThemeSourceSpec } from './n
123
123
  export { CONTRAST_FLOORS, normalizeTheme } from './normalize.js'
124
124
 
125
125
  /* --- Derived colours --------------------------------------------------- */
126
- export type { StatusRole, SyntaxRole } from './derive.js'
126
+ export type { EditorRole, StatusRole, SyntaxRole } from './derive.js'
127
127
  export {
128
128
  CHART_SERIES,
129
129
  STATUS_ROLES,
130
130
  chartSeries,
131
+ editorRolesHex,
131
132
  statusForeground,
132
133
  statusForegroundHex,
133
134
  syntaxRoles,
@@ -160,4 +161,11 @@ export { toTailwindTheme } from './adapters/tailwind.js'
160
161
  export type { ShikiThemeRegistration, ShikiTokenSetting } from './adapters/shiki.js'
161
162
  export { toShikiTheme, toShikiThemes } from './adapters/shiki.js'
162
163
 
163
- export { SHADCN_MAPPING, shadcnCss, shadcnRoles, shadcnVariables } from './adapters/shadcn.js'
164
+ export type { ShadcnDestructiveProjection } from './adapters/shadcn.js'
165
+ export {
166
+ SHADCN_MAPPING,
167
+ shadcnCss,
168
+ shadcnDestructiveProjection,
169
+ shadcnRoles,
170
+ shadcnVariables,
171
+ } from './adapters/shadcn.js'