@adea-ai/themes 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +110 -0
  3. package/README.md +157 -0
  4. package/dist/adapters/base24.d.ts +117 -0
  5. package/dist/adapters/base24.d.ts.map +1 -0
  6. package/dist/adapters/base24.js +313 -0
  7. package/dist/adapters/base24.js.map +1 -0
  8. package/dist/adapters/css.d.ts +68 -0
  9. package/dist/adapters/css.d.ts.map +1 -0
  10. package/dist/adapters/css.js +107 -0
  11. package/dist/adapters/css.js.map +1 -0
  12. package/dist/adapters/shadcn.d.ts +43 -0
  13. package/dist/adapters/shadcn.d.ts.map +1 -0
  14. package/dist/adapters/shadcn.js +89 -0
  15. package/dist/adapters/shadcn.js.map +1 -0
  16. package/dist/adapters/shiki.d.ts +60 -0
  17. package/dist/adapters/shiki.d.ts.map +1 -0
  18. package/dist/adapters/shiki.js +135 -0
  19. package/dist/adapters/shiki.js.map +1 -0
  20. package/dist/adapters/tailwind.d.ts +35 -0
  21. package/dist/adapters/tailwind.d.ts.map +1 -0
  22. package/dist/adapters/tailwind.js +58 -0
  23. package/dist/adapters/tailwind.js.map +1 -0
  24. package/dist/adapters/xterm.d.ts +64 -0
  25. package/dist/adapters/xterm.d.ts.map +1 -0
  26. package/dist/adapters/xterm.js +112 -0
  27. package/dist/adapters/xterm.js.map +1 -0
  28. package/dist/catalogue.d.ts +66 -0
  29. package/dist/catalogue.d.ts.map +1 -0
  30. package/dist/catalogue.js +110 -0
  31. package/dist/catalogue.js.map +1 -0
  32. package/dist/derive.d.ts +89 -0
  33. package/dist/derive.d.ts.map +1 -0
  34. package/dist/derive.js +165 -0
  35. package/dist/derive.js.map +1 -0
  36. package/dist/generated/schemes.d.ts +16 -0
  37. package/dist/generated/schemes.d.ts.map +1 -0
  38. package/dist/generated/schemes.js +880 -0
  39. package/dist/generated/schemes.js.map +1 -0
  40. package/dist/generated/themes.d.ts +11 -0
  41. package/dist/generated/themes.d.ts.map +1 -0
  42. package/dist/generated/themes.js +1650 -0
  43. package/dist/generated/themes.js.map +1 -0
  44. package/dist/index.d.ts +67 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +58 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/normalize.d.ts +160 -0
  49. package/dist/normalize.d.ts.map +1 -0
  50. package/dist/normalize.js +795 -0
  51. package/dist/normalize.js.map +1 -0
  52. package/dist/oklch.d.ts +141 -0
  53. package/dist/oklch.d.ts.map +1 -0
  54. package/dist/oklch.js +306 -0
  55. package/dist/oklch.js.map +1 -0
  56. package/dist/schema.d.ts +178 -0
  57. package/dist/schema.d.ts.map +1 -0
  58. package/dist/schema.js +69 -0
  59. package/dist/schema.js.map +1 -0
  60. package/dist/sources.d.ts +171 -0
  61. package/dist/sources.d.ts.map +1 -0
  62. package/dist/sources.js +559 -0
  63. package/dist/sources.js.map +1 -0
  64. package/dist/validate.d.ts +121 -0
  65. package/dist/validate.d.ts.map +1 -0
  66. package/dist/validate.js +255 -0
  67. package/dist/validate.js.map +1 -0
  68. package/package.json +106 -0
  69. package/palettes/ayu-light.json +38 -0
  70. package/palettes/ayu-mirage.json +38 -0
  71. package/palettes/ayu.json +38 -0
  72. package/palettes/catppuccin-frappe.json +38 -0
  73. package/palettes/catppuccin-latte.json +38 -0
  74. package/palettes/catppuccin-macchiato.json +38 -0
  75. package/palettes/catppuccin-mocha.json +38 -0
  76. package/palettes/dracula.json +38 -0
  77. package/palettes/everforest-dark.json +38 -0
  78. package/palettes/everforest-light.json +38 -0
  79. package/palettes/gruvbox-dark.json +38 -0
  80. package/palettes/gruvbox-light.json +38 -0
  81. package/palettes/kanagawa.json +38 -0
  82. package/palettes/monokai.json +38 -0
  83. package/palettes/nord.json +38 -0
  84. package/palettes/one-dark.json +38 -0
  85. package/palettes/rosepine-dawn.json +38 -0
  86. package/palettes/rosepine-moon.json +38 -0
  87. package/palettes/rosepine.json +38 -0
  88. package/palettes/solarized-dark.json +38 -0
  89. package/palettes/solarized-light.json +38 -0
  90. package/palettes/tokyonight-day.json +38 -0
  91. package/palettes/tokyonight-night.json +38 -0
  92. package/palettes/tokyonight-storm.json +38 -0
  93. package/palettes/vesper.json +38 -0
  94. package/src/adapters/base24.ts +355 -0
  95. package/src/adapters/css.ts +149 -0
  96. package/src/adapters/shadcn.ts +99 -0
  97. package/src/adapters/shiki.ts +168 -0
  98. package/src/adapters/tailwind.ts +79 -0
  99. package/src/adapters/xterm.ts +159 -0
  100. package/src/catalogue.ts +129 -0
  101. package/src/derive.ts +203 -0
  102. package/src/generated/schemes.ts +882 -0
  103. package/src/generated/themes.ts +1652 -0
  104. package/src/index.ts +146 -0
  105. package/src/normalize.ts +1010 -0
  106. package/src/oklch.ts +366 -0
  107. package/src/schema.ts +222 -0
  108. package/src/sources.ts +682 -0
  109. package/src/validate.ts +325 -0
@@ -0,0 +1,313 @@
1
+ /**
2
+ * The Base24 bridge.
3
+ *
4
+ * Base24 is the interchange format this package speaks to the outside world, in
5
+ * both directions. Importing is the normalizer's first step for every theme that
6
+ * is not authored here ({@link "./normalize"}); exporting is how a theme reaches a
7
+ * terminal, a tmux theme, or another tool that has never heard of Adea.
8
+ *
9
+ * ## The slot order is not the ANSI order
10
+ *
11
+ * Base24's `base12`–`base17` are *bright red, bright yellow, bright green, bright
12
+ * cyan, bright blue, bright magenta* — the order Base16 needed to keep its ramps
13
+ * monotonic, not the ANSI order of yellow before green. Reading them positionally
14
+ * as ANSI 1–6 silently swaps green and yellow and blue and cyan, which is the kind
15
+ * of mistake that survives review because the theme still *looks* like itself.
16
+ * {@link BASE24_TO_ANSI} names the mapping explicitly so it cannot be inferred
17
+ * wrongly.
18
+ *
19
+ * ## The two slots with no Adea role
20
+ *
21
+ * `base09` (orange) and `base0F` (brown) have no counterpart in the canonical
22
+ * schema: Adea has no "constant" or "deprecated" role, because a UI does not. On
23
+ * export they are re-derived from `red` and `yellow` by a fixed rotation, and
24
+ * {@link AdeaThemeRecord} carries the vendored schemes separately for callers who
25
+ * need the originals byte-for-byte. Round-tripping is therefore lossless for every
26
+ * role Adea models, and explicitly approximate for the two it does not — rather
27
+ * than silently lossy, which is what an unnamed slot would have been.
28
+ */
29
+ import { formatOklch, parseColor } from '../oklch';
30
+ /** The twenty-four Base24 slots, in the order the specification lists them. */
31
+ export const BASE24_SLOTS = [
32
+ 'base00',
33
+ 'base01',
34
+ 'base02',
35
+ 'base03',
36
+ 'base04',
37
+ 'base05',
38
+ 'base06',
39
+ 'base07',
40
+ 'base08',
41
+ 'base09',
42
+ 'base0A',
43
+ 'base0B',
44
+ 'base0C',
45
+ 'base0D',
46
+ 'base0E',
47
+ 'base0F',
48
+ 'base10',
49
+ 'base11',
50
+ 'base12',
51
+ 'base13',
52
+ 'base14',
53
+ 'base15',
54
+ 'base16',
55
+ 'base17',
56
+ ];
57
+ /**
58
+ * What each slot means, in the specification's own terms.
59
+ *
60
+ * Kept as data because the normalizer reads it rather than hard-coding slot names
61
+ * in its logic, and because it is the documentation a reader needs to check that
62
+ * the mapping is right.
63
+ */
64
+ export const BASE24_SLOT_MEANING = Object.freeze({
65
+ base00: 'Background',
66
+ base01: 'Lighter background (status bars, line numbers)',
67
+ base02: 'Selection background',
68
+ base03: 'Comments, invisibles',
69
+ base04: 'Dark foreground (status bars)',
70
+ base05: 'Default foreground, caret, delimiters',
71
+ base06: 'Light foreground',
72
+ base07: 'Light background',
73
+ base08: 'Variables, XML tags, diff deleted',
74
+ base09: 'Constants, numbers, XML attributes',
75
+ base0A: 'Classes, search background, diff changed',
76
+ base0B: 'Strings, inserted',
77
+ base0C: 'Support, regex, escape characters',
78
+ base0D: 'Functions, methods, headings',
79
+ base0E: 'Keywords, storage, selector',
80
+ base0F: 'Deprecated, embedded tags',
81
+ base10: 'Dark black',
82
+ base11: 'Darker than base10',
83
+ base12: 'Bright red',
84
+ base13: 'Bright yellow',
85
+ base14: 'Bright green',
86
+ base15: 'Bright cyan',
87
+ base16: 'Bright blue',
88
+ base17: 'Bright magenta',
89
+ });
90
+ /**
91
+ * Base24 slot → ANSI role.
92
+ *
93
+ * `black`, `white` and `brightBlack` are absent because Base24 does not name them:
94
+ * the background and foreground slots do double duty. The normalizer decides those
95
+ * three; see its `ANSI_FROM_BASE24` note for why the choice is the one it is.
96
+ */
97
+ export const BASE24_TO_ANSI = Object.freeze({
98
+ red: 'base08',
99
+ yellow: 'base0A',
100
+ green: 'base0B',
101
+ cyan: 'base0C',
102
+ blue: 'base0D',
103
+ magenta: 'base0E',
104
+ brightRed: 'base12',
105
+ brightYellow: 'base13',
106
+ brightGreen: 'base14',
107
+ brightCyan: 'base15',
108
+ brightBlue: 'base16',
109
+ brightMagenta: 'base17',
110
+ });
111
+ /** The inverse of {@link BASE24_TO_ANSI}, for export. */
112
+ export const ANSI_TO_BASE24 = Object.freeze(Object.fromEntries(Object.entries(BASE24_TO_ANSI).map(([ansi, slot]) => [slot, ansi])));
113
+ /**
114
+ * How each semantic role is written back to a Base24 slot on export.
115
+ *
116
+ * The choices are not arbitrary. `base01` receives `black` rather than the
117
+ * background because an ANSI black that equals the background is invisible as
118
+ * foreground text — which is precisely the defect the import side documents. The
119
+ * surface ladder has no Base24 slot at all, so it is deliberately absent here:
120
+ * Base24 cannot express it, and pretending otherwise by packing four rungs into
121
+ * `base01`/`base02` would make the export lie about what it preserves.
122
+ */
123
+ export const THEME_TO_BASE24 = Object.freeze({
124
+ background: 'base00',
125
+ foreground: 'base05',
126
+ surface: undefined,
127
+ surfaceElevated: undefined,
128
+ surfaceHover: undefined,
129
+ surfaceActive: undefined,
130
+ border: undefined,
131
+ borderMuted: undefined,
132
+ text: 'base06',
133
+ textMuted: 'base04',
134
+ textSubtle: 'base03',
135
+ accent: 'base0D',
136
+ accentForeground: undefined,
137
+ success: 'base0B',
138
+ warning: 'base0A',
139
+ error: 'base08',
140
+ info: 'base0C',
141
+ });
142
+ /** Thrown when a palette is missing a slot or holds an unparseable colour. */
143
+ export class Base24ParseError extends Error {
144
+ slot;
145
+ constructor(message, slot) {
146
+ super(message);
147
+ this.slot = slot;
148
+ this.name = 'Base24ParseError';
149
+ }
150
+ }
151
+ /** Parses every slot of a palette into OKLCH, or throws naming the offending slot. */
152
+ export function parseBase24Palette(palette) {
153
+ const parsed = {};
154
+ for (const slot of BASE24_SLOTS) {
155
+ const raw = palette[slot];
156
+ if (typeof raw !== 'string' || raw.length === 0) {
157
+ throw new Base24ParseError(`Base24 slot ${slot} is missing`, slot);
158
+ }
159
+ const color = parseColor(raw);
160
+ if (!color) {
161
+ throw new Base24ParseError(`Base24 slot ${slot} is not a colour: ${String(raw)}`, slot);
162
+ }
163
+ parsed[slot] = color;
164
+ }
165
+ return parsed;
166
+ }
167
+ /**
168
+ * Rotates a hue by a fixed number of degrees.
169
+ *
170
+ * Used only for the two Base24 slots Adea has no role for. A rotation is chosen
171
+ * over an interpolation toward grey because both source colours are already
172
+ * saturated, and a rotation keeps saturation while moving the hue far enough to
173
+ * read as a distinct token.
174
+ */
175
+ function rotateHue(color, degrees) {
176
+ return { ...color, h: (color.h + degrees + 360) % 360 };
177
+ }
178
+ /**
179
+ * Writes a theme back to Base24.
180
+ *
181
+ * `base09` and `base0F` are synthesised — see this module's header. `base10` and
182
+ * `base11` are the two rungs below `base00`, which is what the specification
183
+ * defines them as and what a terminal needs in order to draw a black that is
184
+ * darker than the background.
185
+ */
186
+ export function toBase24(theme, options = {}) {
187
+ const background = requireColor(theme.colors.background, 'background');
188
+ const red = requireColor(theme.ansi.red, 'ansi.red');
189
+ const yellow = requireColor(theme.ansi.yellow, 'ansi.yellow');
190
+ const text = requireColor(theme.colors.text, 'text');
191
+ const palette = {
192
+ base00: theme.colors.background,
193
+ base01: theme.ansi.black,
194
+ base02: theme.selection,
195
+ base03: theme.colors.textSubtle,
196
+ base04: theme.colors.textMuted,
197
+ base05: theme.colors.foreground,
198
+ base06: theme.colors.text,
199
+ base07: theme.ansi.brightWhite,
200
+ base08: theme.ansi.red,
201
+ // Synthesised: Base24's constants/orange slot and its deprecated/brown slot
202
+ // have no Adea role. See the module header.
203
+ base09: formatOklch(rotateHue(red, -18)),
204
+ base0A: theme.ansi.yellow,
205
+ base0B: theme.ansi.green,
206
+ base0C: theme.ansi.cyan,
207
+ base0D: theme.ansi.blue,
208
+ base0E: theme.ansi.magenta,
209
+ base0F: formatOklch(rotateHue(yellow, 22)),
210
+ base10: formatOklch({ ...background, l: Math.max(0, background.l - 0.03) }),
211
+ base11: formatOklch({ ...background, l: Math.max(0, background.l - 0.06) }),
212
+ base12: theme.ansi.brightRed,
213
+ base13: theme.ansi.brightYellow,
214
+ base14: theme.ansi.brightGreen,
215
+ base15: theme.ansi.brightCyan,
216
+ base16: theme.ansi.brightBlue,
217
+ base17: theme.ansi.brightMagenta,
218
+ };
219
+ // `base05` is the default foreground and the caret; a palette whose text role
220
+ // differs from its ANSI white means the two disagree about which is the body
221
+ // colour. The foreground role wins, because every contrast floor is defined
222
+ // against it.
223
+ void text;
224
+ return {
225
+ system: 'base24',
226
+ name: options.name ?? theme.name,
227
+ author: options.author ?? 'Adea',
228
+ variant: theme.appearance,
229
+ palette,
230
+ };
231
+ }
232
+ function requireColor(value, role) {
233
+ const color = parseColor(value);
234
+ if (!color)
235
+ throw new Error(`Theme role ${role} is not a colour: ${value}`);
236
+ return color;
237
+ }
238
+ /** Serialises a scheme to the YAML dialect Base24 schemes are published in. */
239
+ export function formatBase24Scheme(scheme) {
240
+ const lines = [
241
+ 'system: "base24"',
242
+ `name: ${JSON.stringify(scheme.name)}`,
243
+ `author: ${JSON.stringify(scheme.author)}`,
244
+ `variant: ${JSON.stringify(scheme.variant)}`,
245
+ 'palette:',
246
+ ...BASE24_SLOTS.map((slot) => ` ${slot}: ${JSON.stringify(scheme.palette[slot])}`),
247
+ ];
248
+ return `${lines.join('\n')}\n`;
249
+ }
250
+ /**
251
+ * Reads the YAML dialect Base24 schemes are published in.
252
+ *
253
+ * Hand-written rather than pulled from a YAML library: the format is a fixed set
254
+ * of scalar keys, the package has no runtime dependencies and no build-time
255
+ * dependencies beyond the TypeScript compiler, and a general parser would accept
256
+ * documents this bridge cannot actually honour. Anything outside the specification
257
+ * is rejected loudly instead of being parsed into a half-scheme.
258
+ */
259
+ export function parseBase24Scheme(source) {
260
+ const scalars = new Map();
261
+ const palette = new Map();
262
+ let inPalette = false;
263
+ for (const rawLine of source.split('\n')) {
264
+ // Strip comments before trimming so the dataset's provenance comments, which
265
+ // sit on the same line as a value, do not end up inside the colour string.
266
+ const line = rawLine.replace(/\s+#.*$/, '').trimEnd();
267
+ if (line.trim().length === 0)
268
+ continue;
269
+ const indented = /^\s/.test(line);
270
+ const separator = line.indexOf(':');
271
+ if (separator === -1)
272
+ continue;
273
+ const key = (indented ? line.slice(0, separator) : line.slice(0, separator)).trim();
274
+ const value = line
275
+ .slice(separator + 1)
276
+ .trim()
277
+ .replace(/^["']|["']$/g, '');
278
+ if (!indented) {
279
+ inPalette = key === 'palette';
280
+ if (!inPalette)
281
+ scalars.set(key, value);
282
+ continue;
283
+ }
284
+ if (inPalette)
285
+ palette.set(key, value);
286
+ }
287
+ const missing = ['name', 'variant'].filter((key) => !scalars.get(key));
288
+ if (missing.length > 0) {
289
+ throw new Error(`Base24 scheme is missing required keys: ${missing.join(', ')}`);
290
+ }
291
+ const variant = scalars.get('variant');
292
+ if (variant !== 'dark' && variant !== 'light') {
293
+ throw new Error(`Base24 scheme variant must be dark or light, got: ${String(variant)}`);
294
+ }
295
+ const resolved = {};
296
+ for (const slot of BASE24_SLOTS) {
297
+ const value = palette.get(slot);
298
+ if (!value)
299
+ throw new Base24ParseError(`Base24 scheme is missing ${slot}`, slot);
300
+ if (!parseColor(value)) {
301
+ throw new Base24ParseError(`Base24 scheme has an unparseable ${slot}: ${value}`, slot);
302
+ }
303
+ resolved[slot] = value;
304
+ }
305
+ return {
306
+ system: 'base24',
307
+ name: scalars.get('name') ?? '',
308
+ author: scalars.get('author') ?? 'unknown',
309
+ variant,
310
+ palette: resolved,
311
+ };
312
+ }
313
+ //# sourceMappingURL=base24.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base24.js","sourceRoot":"","sources":["../../src/adapters/base24.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The application adapter: a theme as CSS custom properties.
3
+ *
4
+ * This is the adapter an application uses. Everything a component needs is written
5
+ * onto a selector as a custom property, in OKLCH, so the browser does the colour
6
+ * work and a theme switch is an attribute change rather than a re-render.
7
+ *
8
+ * ## Two names for the same values
9
+ *
10
+ * {@link themeCssVariables} emits the canonical names — `--adea-background`,
11
+ * `--adea-surface` — and is what a new consumer should use.
12
+ * `adapters/shadcn.ts` emits the shadcn vocabulary this organisation's components
13
+ * are already written against. Both are generated from the same theme object, so
14
+ * the two can never disagree about what `surface` is; that is the entire reason to
15
+ * have one source.
16
+ *
17
+ * ## What is derived rather than stored
18
+ *
19
+ * A handful of variables have no role in the canonical schema and are computed:
20
+ * the chart series (see `syntax.ts`), the status tints used behind status text, and
21
+ * the ANSI variables. They are derived on every call rather than cached, because
22
+ * they are pure functions of the theme and caching them would put a second copy of
23
+ * the truth in the module.
24
+ *
25
+ * ## Why `oklch()` strings and not hex
26
+ *
27
+ * Custom properties are evaluated by the browser. Writing OKLCH means the values
28
+ * stay on the perceptual axis all the way to paint, so a consumer can compose them
29
+ * — `color-mix(in oklch, var(--adea-accent), transparent 20%)` — and get a
30
+ * predictable result. Converted to hex on the way out, that composition would be
31
+ * an sRGB blend, which is what makes hand-mixed tints go muddy.
32
+ */
33
+ import type { AdeaTheme, AdeaThemeColors } from '../schema';
34
+ /** How the variables are named. */
35
+ export interface CssOptions {
36
+ /** The custom-property namespace. Defaults to `adea`. */
37
+ prefix?: string;
38
+ /** The selector the variables are written on. Defaults to `:root`. */
39
+ selector?: string;
40
+ /** Also emit the derived status tints, chart series and ansi ramp. Defaults to true. */
41
+ includeDerived?: boolean;
42
+ /** Indent each declaration. Used by {@link catalogueCss}. */
43
+ indent?: string;
44
+ }
45
+ /**
46
+ * The literal roles, plus the derived ones.
47
+ *
48
+ * `borderMuted` is emitted for completeness even though shadcn's vocabulary has no
49
+ * equivalent; a consumer that wants a quieter rule can use it directly.
50
+ */
51
+ export declare function themeCssVariables(theme: AdeaTheme, options?: Omit<CssOptions, 'selector' | 'indent'>): Record<string, string>;
52
+ /** A CSS rule for one theme. */
53
+ export declare function themeCss(theme: AdeaTheme, options?: CssOptions): string;
54
+ /**
55
+ * One rule per theme, selected by attribute.
56
+ *
57
+ * This is what a consumer ships when it wants the whole catalogue without running
58
+ * JavaScript: every theme's variables are in the stylesheet, and switching is
59
+ * `document.documentElement.dataset.theme = id`. The cost is that all of them
60
+ * download; an application that prefers a smaller bundle should call
61
+ * {@link themeCss} for one theme at a time instead.
62
+ */
63
+ export declare function catalogueCss(themes: readonly AdeaTheme[], options?: CssOptions & {
64
+ attribute?: string;
65
+ }): string;
66
+ /** The canonical variable name for a role, so consumers need not build the string. */
67
+ export declare function cssVariableName(role: keyof AdeaThemeColors, prefix?: string): string;
68
+ //# sourceMappingURL=css.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../src/adapters/css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAI3D,mCAAmC;AACnC,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wFAAwF;IACxF,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAaD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAM,GACpD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0CxB;AAED,gCAAgC;AAChC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM,CAU3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,OAAO,GAAE,UAAU,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,MAAM,CAKR;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,eAAe,EAAE,MAAM,SAAiB,GAAG,MAAM,CAE5F"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The application adapter: a theme as CSS custom properties.
3
+ *
4
+ * This is the adapter an application uses. Everything a component needs is written
5
+ * onto a selector as a custom property, in OKLCH, so the browser does the colour
6
+ * work and a theme switch is an attribute change rather than a re-render.
7
+ *
8
+ * ## Two names for the same values
9
+ *
10
+ * {@link themeCssVariables} emits the canonical names — `--adea-background`,
11
+ * `--adea-surface` — and is what a new consumer should use.
12
+ * `adapters/shadcn.ts` emits the shadcn vocabulary this organisation's components
13
+ * are already written against. Both are generated from the same theme object, so
14
+ * the two can never disagree about what `surface` is; that is the entire reason to
15
+ * have one source.
16
+ *
17
+ * ## What is derived rather than stored
18
+ *
19
+ * A handful of variables have no role in the canonical schema and are computed:
20
+ * the chart series (see `syntax.ts`), the status tints used behind status text, and
21
+ * the ANSI variables. They are derived on every call rather than cached, because
22
+ * they are pure functions of the theme and caching them would put a second copy of
23
+ * the truth in the module.
24
+ *
25
+ * ## Why `oklch()` strings and not hex
26
+ *
27
+ * Custom properties are evaluated by the browser. Writing OKLCH means the values
28
+ * stay on the perceptual axis all the way to paint, so a consumer can compose them
29
+ * — `color-mix(in oklch, var(--adea-accent), transparent 20%)` — and get a
30
+ * predictable result. Converted to hex on the way out, that composition would be
31
+ * an sRGB blend, which is what makes hand-mixed tints go muddy.
32
+ */
33
+ import { THEME_COLOR_KEYS, ANSI_KEYS } from '../schema';
34
+ import { STATUS_ROLES, chartSeries, statusForeground, tint } from '../derive';
35
+ const DEFAULT_PREFIX = 'adea';
36
+ function variableName(name, prefix) {
37
+ return prefix ? `--${prefix}-${name}` : `--${name}`;
38
+ }
39
+ /** camelCase to kebab-case, the way the property names read in CSS. */
40
+ function kebab(name) {
41
+ return name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
42
+ }
43
+ /**
44
+ * The literal roles, plus the derived ones.
45
+ *
46
+ * `borderMuted` is emitted for completeness even though shadcn's vocabulary has no
47
+ * equivalent; a consumer that wants a quieter rule can use it directly.
48
+ */
49
+ export function themeCssVariables(theme, options = {}) {
50
+ const prefix = options.prefix ?? DEFAULT_PREFIX;
51
+ const includeDerived = options.includeDerived ?? true;
52
+ const variables = {};
53
+ for (const key of THEME_COLOR_KEYS) {
54
+ variables[variableName(kebab(key), prefix)] = theme.colors[key];
55
+ }
56
+ variables[variableName('cursor', prefix)] = theme.cursor;
57
+ variables[variableName('selection', prefix)] = theme.selection;
58
+ if (!includeDerived)
59
+ return variables;
60
+ for (const key of ANSI_KEYS) {
61
+ variables[variableName(`ansi-${kebab(key)}`, prefix)] = theme.ansi[key];
62
+ }
63
+ chartSeries(theme).forEach((value, index) => {
64
+ variables[variableName(`chart-${index + 1}`, prefix)] = value;
65
+ });
66
+ // Status fills and the text that goes on them. The fill is the role at low
67
+ // strength against the canvas; the foreground is the theme's legible extreme for
68
+ // that fill, not the theme's body text — see `derive.statusForeground`.
69
+ for (const role of STATUS_ROLES) {
70
+ variables[variableName(`${role}-subtle`, prefix)] = tint(theme.colors[role], theme.colors.background);
71
+ variables[variableName(`${role}-foreground`, prefix)] = statusForeground(theme, role);
72
+ }
73
+ // A dimmer rule for tables and inner separators, and the surface one step below
74
+ // the canvas that a well or a code block sits in.
75
+ variables[variableName('surface-sunken', prefix)] = tint(theme.colors.text, theme.colors.background, 0.03);
76
+ return variables;
77
+ }
78
+ /** A CSS rule for one theme. */
79
+ export function themeCss(theme, options = {}) {
80
+ const selector = options.selector ?? ':root';
81
+ const indent = options.indent ?? ' ';
82
+ const entries = Object.entries(themeCssVariables(theme, options));
83
+ const body = entries
84
+ .map(([name, value]) => `${indent}${name}: ${value};`)
85
+ .join('\n');
86
+ return `${selector} {\n${body}\n}`;
87
+ }
88
+ /**
89
+ * One rule per theme, selected by attribute.
90
+ *
91
+ * This is what a consumer ships when it wants the whole catalogue without running
92
+ * JavaScript: every theme's variables are in the stylesheet, and switching is
93
+ * `document.documentElement.dataset.theme = id`. The cost is that all of them
94
+ * download; an application that prefers a smaller bundle should call
95
+ * {@link themeCss} for one theme at a time instead.
96
+ */
97
+ export function catalogueCss(themes, options = {}) {
98
+ const attribute = options.attribute ?? 'data-theme';
99
+ return themes
100
+ .map((theme) => themeCss(theme, { ...options, selector: `[${attribute}='${theme.id}']` }))
101
+ .join('\n\n');
102
+ }
103
+ /** The canonical variable name for a role, so consumers need not build the string. */
104
+ export function cssVariableName(role, prefix = DEFAULT_PREFIX) {
105
+ return variableName(kebab(role), prefix);
106
+ }
107
+ //# sourceMappingURL=css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/adapters/css.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * The shadcn bridge.
3
+ *
4
+ * This organisation's components are written against shadcn's vocabulary —
5
+ * `--background`, `--card`, `--muted-foreground`, `--primary`, `--ring` — and that
6
+ * vocabulary is not the canonical schema. Rather than rename every component, the
7
+ * two are bridged here, in one place, from one theme object.
8
+ *
9
+ * The mapping is not a rename and the two places it is not are worth reading:
10
+ *
11
+ * - **Adea's `accent` becomes shadcn's `primary`.** In shadcn, `--primary` is the
12
+ * main action colour and `--accent` is a *subtle hover background*. Adea's
13
+ * `accent` is the interactive colour — what a primary button is filled with,
14
+ * what a focus ring is drawn in — so it is shadcn's `primary`. Mapping it to
15
+ * `--accent` instead would turn every primary button into a hover wash. The
16
+ * shadcn `accent` slot is filled from `surfaceHover`, which is what it is
17
+ * actually used for.
18
+ * - **Adea's `surface` ladder becomes `card` and `popover`.** shadcn has two
19
+ * surfaces rather than four, so `surface` maps to `card` and `surfaceElevated`
20
+ * to `popover`, and the remaining two rungs keep their own names.
21
+ *
22
+ * A table of the whole mapping is in `docs/shadcn-bridge.md`.
23
+ */
24
+ import type { AdeaTheme, AdeaThemeColors } from '../schema';
25
+ /**
26
+ * Canonical role → shadcn custom-property name.
27
+ *
28
+ * Every entry is a deliberate correspondence, and the ones that are not a plain
29
+ * rename carry the reason here rather than in the output.
30
+ */
31
+ export declare const SHADCN_MAPPING: Readonly<Record<keyof AdeaThemeColors, string>>;
32
+ /**
33
+ * The shadcn custom properties for a theme.
34
+ *
35
+ * `--accent` is filled from `surfaceHover` because that is what shadcn components
36
+ * use it for — the background of a hovered menu item — and `--ring` from the
37
+ * accent, because that is what a focus ring must be drawn in for the focus state
38
+ * to be visible.
39
+ */
40
+ export declare function shadcnVariables(theme: AdeaTheme): Record<string, string>;
41
+ /** The shadcn variables as a CSS rule. */
42
+ export declare function shadcnCss(theme: AdeaTheme, selector?: string): string;
43
+ //# sourceMappingURL=shadcn.d.ts.map
@@ -0,0 +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,MAAM,WAAW,CAAA;AAG3D;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,eAAe,EAAE,MAAM,CAAC,CAsBzE,CAAA;AAEF;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBxE;AAED,0CAA0C;AAC1C,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,SAAU,GAAG,MAAM,CAKtE"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The shadcn bridge.
3
+ *
4
+ * This organisation's components are written against shadcn's vocabulary —
5
+ * `--background`, `--card`, `--muted-foreground`, `--primary`, `--ring` — and that
6
+ * vocabulary is not the canonical schema. Rather than rename every component, the
7
+ * two are bridged here, in one place, from one theme object.
8
+ *
9
+ * The mapping is not a rename and the two places it is not are worth reading:
10
+ *
11
+ * - **Adea's `accent` becomes shadcn's `primary`.** In shadcn, `--primary` is the
12
+ * main action colour and `--accent` is a *subtle hover background*. Adea's
13
+ * `accent` is the interactive colour — what a primary button is filled with,
14
+ * what a focus ring is drawn in — so it is shadcn's `primary`. Mapping it to
15
+ * `--accent` instead would turn every primary button into a hover wash. The
16
+ * shadcn `accent` slot is filled from `surfaceHover`, which is what it is
17
+ * actually used for.
18
+ * - **Adea's `surface` ladder becomes `card` and `popover`.** shadcn has two
19
+ * surfaces rather than four, so `surface` maps to `card` and `surfaceElevated`
20
+ * to `popover`, and the remaining two rungs keep their own names.
21
+ *
22
+ * A table of the whole mapping is in `docs/shadcn-bridge.md`.
23
+ */
24
+ import { STATUS_ROLES, statusForeground } from '../derive';
25
+ /**
26
+ * Canonical role → shadcn custom-property name.
27
+ *
28
+ * Every entry is a deliberate correspondence, and the ones that are not a plain
29
+ * rename carry the reason here rather than in the output.
30
+ */
31
+ export const SHADCN_MAPPING = Object.freeze({
32
+ background: 'background',
33
+ foreground: 'foreground',
34
+ // The first two rungs are the two surfaces shadcn names.
35
+ surface: 'card',
36
+ surfaceElevated: 'popover',
37
+ surfaceHover: 'surface-hover',
38
+ surfaceActive: 'surface-active',
39
+ border: 'border',
40
+ borderMuted: 'border-muted',
41
+ // `text` is `foreground` in shadcn; `--foreground` is what body text reads.
42
+ text: 'foreground',
43
+ textMuted: 'muted-foreground',
44
+ textSubtle: 'subtle-foreground',
45
+ // See the header: the interactive colour is shadcn's `primary`.
46
+ accent: 'primary',
47
+ accentForeground: 'primary-foreground',
48
+ success: 'success',
49
+ warning: 'warning',
50
+ // shadcn's destructive slot is in the same position as Adea's error.
51
+ error: 'destructive',
52
+ info: 'info',
53
+ });
54
+ /**
55
+ * The shadcn custom properties for a theme.
56
+ *
57
+ * `--accent` is filled from `surfaceHover` because that is what shadcn components
58
+ * use it for — the background of a hovered menu item — and `--ring` from the
59
+ * accent, because that is what a focus ring must be drawn in for the focus state
60
+ * to be visible.
61
+ */
62
+ export function shadcnVariables(theme) {
63
+ const variables = {};
64
+ for (const [role, name] of Object.entries(SHADCN_MAPPING)) {
65
+ variables[`--${name}`] = theme.colors[role];
66
+ }
67
+ variables['--accent'] = theme.colors.surfaceHover;
68
+ variables['--accent-foreground'] = theme.colors.text;
69
+ variables['--ring'] = theme.colors.accent;
70
+ variables['--input'] = theme.colors.border;
71
+ for (const role of STATUS_ROLES) {
72
+ variables[`--${role}-foreground`] = statusForeground(theme, role);
73
+ variables[`--${role}-subtle`] = `color-mix(in oklch, var(--${role}) 12%, transparent)`;
74
+ }
75
+ variables['--surface-sunken'] = theme.colors.background;
76
+ variables['--surface-raised'] = theme.colors.surfaceElevated;
77
+ variables['--surface-overlay'] = theme.colors.surfaceElevated;
78
+ variables['--cursor'] = theme.cursor;
79
+ variables['--selection'] = theme.selection;
80
+ return variables;
81
+ }
82
+ /** The shadcn variables as a CSS rule. */
83
+ export function shadcnCss(theme, selector = ':root') {
84
+ const body = Object.entries(shadcnVariables(theme))
85
+ .map(([name, value]) => ` ${name}: ${value};`)
86
+ .join('\n');
87
+ return `${selector} {\n${body}\n}`;
88
+ }
89
+ //# sourceMappingURL=shadcn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadcn.js","sourceRoot":"","sources":["../../src/adapters/shadcn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAE1D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAoD,MAAM,CAAC,MAAM,CAAC;IAC3F,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,yDAAyD;IACzD,OAAO,EAAE,MAAM;IACf,eAAe,EAAE,SAAS;IAC1B,YAAY,EAAE,eAAe;IAC7B,aAAa,EAAE,gBAAgB;IAC/B,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,cAAc;IAC3B,4EAA4E;IAC5E,IAAI,EAAE,YAAY;IAClB,SAAS,EAAE,kBAAkB;IAC7B,UAAU,EAAE,mBAAmB;IAC/B,gEAAgE;IAChE,MAAM,EAAE,SAAS;IACjB,gBAAgB,EAAE,oBAAoB;IACtC,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,qEAAqE;IACrE,KAAK,EAAE,aAAa;IACpB,IAAI,EAAE,MAAM;CACb,CAAC,CAAA;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgB;IAC9C,MAAM,SAAS,GAA2B,EAAE,CAAA;IAE5C,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAsC,EAAE,CAAC;QAC/F,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC7C,CAAC;IAED,SAAS,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,YAAY,CAAA;IACjD,SAAS,CAAC,qBAAqB,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAA;IACpD,SAAS,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAA;IACzC,SAAS,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAA;IAE1C,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,SAAS,CAAC,KAAK,IAAI,aAAa,CAAC,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QACjE,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,6BAA6B,IAAI,qBAAqB,CAAA;IACxF,CAAC;IAED,SAAS,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAA;IACvD,SAAS,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,eAAe,CAAA;IAC5D,SAAS,CAAC,mBAAmB,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,eAAe,CAAA;IAE7D,SAAS,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,MAAM,CAAA;IACpC,SAAS,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,SAAS,CAAA;IAE1C,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,SAAS,CAAC,KAAgB,EAAE,QAAQ,GAAG,OAAO;IAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;SAChD,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,KAAK,KAAK,GAAG,CAAC;SAC9C,IAAI,CAAC,IAAI,CAAC,CAAA;IACb,OAAO,GAAG,QAAQ,OAAO,IAAI,KAAK,CAAA;AACpC,CAAC"}