@adea-ai/themes 0.4.0 → 0.4.1

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 (69) hide show
  1. package/dist/accents.d.ts +150 -0
  2. package/dist/accents.d.ts.map +1 -0
  3. package/dist/accents.js +205 -0
  4. package/dist/accents.js.map +1 -0
  5. package/dist/adapters/base24.d.ts +117 -0
  6. package/dist/adapters/base24.d.ts.map +1 -0
  7. package/dist/adapters/base24.js +313 -0
  8. package/dist/adapters/base24.js.map +1 -0
  9. package/dist/adapters/css.d.ts +68 -0
  10. package/dist/adapters/css.d.ts.map +1 -0
  11. package/dist/adapters/css.js +107 -0
  12. package/dist/adapters/css.js.map +1 -0
  13. package/dist/adapters/shadcn.d.ts +51 -0
  14. package/dist/adapters/shadcn.d.ts.map +1 -0
  15. package/dist/adapters/shadcn.js +120 -0
  16. package/dist/adapters/shadcn.js.map +1 -0
  17. package/dist/adapters/shiki.d.ts +60 -0
  18. package/dist/adapters/shiki.d.ts.map +1 -0
  19. package/dist/adapters/shiki.js +139 -0
  20. package/dist/adapters/shiki.js.map +1 -0
  21. package/dist/adapters/tailwind.d.ts +35 -0
  22. package/dist/adapters/tailwind.d.ts.map +1 -0
  23. package/dist/adapters/tailwind.js +58 -0
  24. package/dist/adapters/tailwind.js.map +1 -0
  25. package/dist/adapters/xterm.d.ts +64 -0
  26. package/dist/adapters/xterm.d.ts.map +1 -0
  27. package/dist/adapters/xterm.js +112 -0
  28. package/dist/adapters/xterm.js.map +1 -0
  29. package/dist/catalogue.d.ts +66 -0
  30. package/dist/catalogue.d.ts.map +1 -0
  31. package/dist/catalogue.js +110 -0
  32. package/dist/catalogue.js.map +1 -0
  33. package/dist/derive.d.ts +89 -0
  34. package/dist/derive.d.ts.map +1 -0
  35. package/dist/derive.js +172 -0
  36. package/dist/derive.js.map +1 -0
  37. package/dist/generated/schemes.d.ts +16 -0
  38. package/dist/generated/schemes.d.ts.map +1 -0
  39. package/dist/generated/schemes.js +880 -0
  40. package/dist/generated/schemes.js.map +1 -0
  41. package/dist/generated/themes.d.ts +11 -0
  42. package/dist/generated/themes.d.ts.map +1 -0
  43. package/dist/generated/themes.js +1658 -0
  44. package/dist/generated/themes.js.map +1 -0
  45. package/dist/index.d.ts +69 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +59 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/normalize.d.ts +192 -0
  50. package/dist/normalize.d.ts.map +1 -0
  51. package/dist/normalize.js +958 -0
  52. package/dist/normalize.js.map +1 -0
  53. package/dist/oklch.d.ts +141 -0
  54. package/dist/oklch.d.ts.map +1 -0
  55. package/dist/oklch.js +311 -0
  56. package/dist/oklch.js.map +1 -0
  57. package/dist/schema.d.ts +178 -0
  58. package/dist/schema.d.ts.map +1 -0
  59. package/dist/schema.js +69 -0
  60. package/dist/schema.js.map +1 -0
  61. package/dist/sources.d.ts +296 -0
  62. package/dist/sources.d.ts.map +1 -0
  63. package/dist/sources.js +634 -0
  64. package/dist/sources.js.map +1 -0
  65. package/dist/validate.d.ts +121 -0
  66. package/dist/validate.d.ts.map +1 -0
  67. package/dist/validate.js +255 -0
  68. package/dist/validate.js.map +1 -0
  69. package/package.json +2 -1
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The catalogue's public surface.
3
+ *
4
+ * The generated data is a flat, sorted array; everything a consumer wants to *do*
5
+ * with it — find one theme, group it by family, list what exists, check that a
6
+ * stored preference still names a real theme — is here.
7
+ *
8
+ * ## Lookups answer, they do not throw
9
+ *
10
+ * `getTheme` returns `undefined` rather than throwing, because the overwhelmingly
11
+ * common caller is restoring a stored preference and the overwhelmingly common
12
+ * failure is a preference naming a theme that has since been removed. A component
13
+ * that has to wrap a lookup in a try/catch to survive a stale preference is a
14
+ * component that will eventually ship without the try/catch.
15
+ */
16
+ import type { AdeaTheme, AdeaThemeRecord, ThemeAppearance, ThemeFamily } from './schema';
17
+ import type { Base24Scheme } from './adapters/base24';
18
+ /**
19
+ * Every theme in the catalogue, ordered by id.
20
+ *
21
+ * The full records, including provenance and tags, because a picker needs the
22
+ * labels and an audit needs the licences. Consumers that only want the theme
23
+ * contract can treat each entry as an {@link AdeaTheme}; the extra keys are
24
+ * additive.
25
+ */
26
+ export declare const themes: readonly AdeaThemeRecord[];
27
+ /** The default theme for each appearance. */
28
+ export declare const DEFAULT_THEME_IDS: Readonly<Record<ThemeAppearance, string>>;
29
+ /** Looks a theme up by id. Returns `undefined` for an id the catalogue does not have. */
30
+ export declare function getTheme(id: string): AdeaThemeRecord | undefined;
31
+ /**
32
+ * Looks a theme up, falling back to the default for an appearance.
33
+ *
34
+ * This is the function a preference restore should call: a stored id that no longer
35
+ * exists resolves to the default rather than to nothing, so removing a theme from
36
+ * the catalogue degrades to a theme change instead of a blank window.
37
+ */
38
+ export declare function resolveTheme(id: string | undefined | null, appearance: ThemeAppearance): AdeaThemeRecord;
39
+ /** True when the catalogue still contains this id. */
40
+ export declare function hasTheme(id: string): boolean;
41
+ /**
42
+ * The themes grouped by project, in the order the source list declares.
43
+ *
44
+ * Grouping is by family rather than by appearance so that a picker can show
45
+ * "Catppuccin: Latte, Frappé, Macchiato, Mocha" the way the project itself presents
46
+ * its flavours, which is how someone who wants Mocha looks for it.
47
+ */
48
+ export declare function themeFamilies(themesList?: readonly AdeaThemeRecord[]): ThemeFamily[];
49
+ /** The catalogued themes that match an appearance. */
50
+ export declare function themesByAppearance(appearance: ThemeAppearance, themesList?: readonly AdeaThemeRecord[]): AdeaThemeRecord[];
51
+ /**
52
+ * The vendored Base24 scheme for a theme, untouched.
53
+ *
54
+ * Present for interop and for licence auditing. `toBase24()` writes a scheme too,
55
+ * but it has to re-derive Base24's orange and brown slots — the canonical schema
56
+ * has no role for them — so it is not a byte-exact round trip. This returns the
57
+ * artefact as it was reproduced, so a caller that needs exactness has it.
58
+ */
59
+ export declare function getBase24Scheme(id: string): Base24Scheme | undefined;
60
+ /** The ids of every theme, for validation and for a preference guard. */
61
+ export declare function themeIds(): string[];
62
+ /** The catalogue's size, so a test can assert it without importing the data. */
63
+ export declare function themeCount(): number;
64
+ /** Narrows a theme record to the published contract, dropping catalogue metadata. */
65
+ export declare function toTheme(record: AdeaThemeRecord): AdeaTheme;
66
+ //# sourceMappingURL=catalogue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalogue.d.ts","sourceRoot":"","sources":["../src/catalogue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIrD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAAE,SAAS,eAAe,EAAoB,CAAA;AAEjE,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAGtE,CAAA;AAEF,yFAAyF;AACzF,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEhE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAC7B,UAAU,EAAE,eAAe,GAC1B,eAAe,CAIjB;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,GAAE,SAAS,eAAe,EAAoB,GAAG,WAAW,EAAE,CAerG;AAED,sDAAsD;AACtD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,eAAe,EAC3B,UAAU,GAAE,SAAS,eAAe,EAAoB,GACvD,eAAe,EAAE,CAEnB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEpE;AAED,yEAAyE;AACzE,wBAAgB,QAAQ,IAAI,MAAM,EAAE,CAEnC;AAED,gFAAgF;AAChF,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,qFAAqF;AACrF,wBAAgB,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAU1D"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The catalogue's public surface.
3
+ *
4
+ * The generated data is a flat, sorted array; everything a consumer wants to *do*
5
+ * with it — find one theme, group it by family, list what exists, check that a
6
+ * stored preference still names a real theme — is here.
7
+ *
8
+ * ## Lookups answer, they do not throw
9
+ *
10
+ * `getTheme` returns `undefined` rather than throwing, because the overwhelmingly
11
+ * common caller is restoring a stored preference and the overwhelmingly common
12
+ * failure is a preference naming a theme that has since been removed. A component
13
+ * that has to wrap a lookup in a try/catch to survive a stale preference is a
14
+ * component that will eventually ship without the try/catch.
15
+ */
16
+ import { generatedSchemes } from './generated/schemes';
17
+ import { generatedThemes } from './generated/themes';
18
+ /**
19
+ * Every theme in the catalogue, ordered by id.
20
+ *
21
+ * The full records, including provenance and tags, because a picker needs the
22
+ * labels and an audit needs the licences. Consumers that only want the theme
23
+ * contract can treat each entry as an {@link AdeaTheme}; the extra keys are
24
+ * additive.
25
+ */
26
+ export const themes = generatedThemes;
27
+ /** The default theme for each appearance. */
28
+ export const DEFAULT_THEME_IDS = Object.freeze({
29
+ dark: 'adea-dark',
30
+ light: 'adea-light',
31
+ });
32
+ /** Looks a theme up by id. Returns `undefined` for an id the catalogue does not have. */
33
+ export function getTheme(id) {
34
+ return generatedThemes.find((theme) => theme.id === id);
35
+ }
36
+ /**
37
+ * Looks a theme up, falling back to the default for an appearance.
38
+ *
39
+ * This is the function a preference restore should call: a stored id that no longer
40
+ * exists resolves to the default rather than to nothing, so removing a theme from
41
+ * the catalogue degrades to a theme change instead of a blank window.
42
+ */
43
+ export function resolveTheme(id, appearance) {
44
+ const found = id ? getTheme(id) : undefined;
45
+ if (found)
46
+ return found;
47
+ return getTheme(DEFAULT_THEME_IDS[appearance]);
48
+ }
49
+ /** True when the catalogue still contains this id. */
50
+ export function hasTheme(id) {
51
+ return generatedThemes.some((theme) => theme.id === id);
52
+ }
53
+ /**
54
+ * The themes grouped by project, in the order the source list declares.
55
+ *
56
+ * Grouping is by family rather than by appearance so that a picker can show
57
+ * "Catppuccin: Latte, Frappé, Macchiato, Mocha" the way the project itself presents
58
+ * its flavours, which is how someone who wants Mocha looks for it.
59
+ */
60
+ export function themeFamilies(themesList = generatedThemes) {
61
+ const families = [];
62
+ const index = new Map();
63
+ for (const theme of themesList) {
64
+ let family = index.get(theme.family);
65
+ if (!family) {
66
+ family = { id: theme.family, label: theme.familyLabel, themes: [] };
67
+ index.set(theme.family, family);
68
+ families.push(family);
69
+ }
70
+ ;
71
+ family.themes.push(theme);
72
+ }
73
+ return families;
74
+ }
75
+ /** The catalogued themes that match an appearance. */
76
+ export function themesByAppearance(appearance, themesList = generatedThemes) {
77
+ return themesList.filter((theme) => theme.appearance === appearance);
78
+ }
79
+ /**
80
+ * The vendored Base24 scheme for a theme, untouched.
81
+ *
82
+ * Present for interop and for licence auditing. `toBase24()` writes a scheme too,
83
+ * but it has to re-derive Base24's orange and brown slots — the canonical schema
84
+ * has no role for them — so it is not a byte-exact round trip. This returns the
85
+ * artefact as it was reproduced, so a caller that needs exactness has it.
86
+ */
87
+ export function getBase24Scheme(id) {
88
+ return generatedSchemes[id];
89
+ }
90
+ /** The ids of every theme, for validation and for a preference guard. */
91
+ export function themeIds() {
92
+ return generatedThemes.map((theme) => theme.id);
93
+ }
94
+ /** The catalogue's size, so a test can assert it without importing the data. */
95
+ export function themeCount() {
96
+ return generatedThemes.length;
97
+ }
98
+ /** Narrows a theme record to the published contract, dropping catalogue metadata. */
99
+ export function toTheme(record) {
100
+ return {
101
+ id: record.id,
102
+ name: record.name,
103
+ appearance: record.appearance,
104
+ colors: record.colors,
105
+ ansi: record.ansi,
106
+ cursor: record.cursor,
107
+ selection: record.selection,
108
+ };
109
+ }
110
+ //# sourceMappingURL=catalogue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalogue.js","sourceRoot":"","sources":["../src/catalogue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Colours a theme does not store, derived from the ones it does.
3
+ *
4
+ * The canonical schema is deliberately small — seventeen surface roles, sixteen
5
+ * ANSI colours, a cursor and a selection — and three things an application needs
6
+ * are deliberately absent from it: the **syntax roles** a code view wants, the
7
+ * **chart series** a graph wants, and the **fills and foregrounds** a status chip
8
+ * wants.
9
+ *
10
+ * They are absent because each is a *function of* the roles that are present, and a
11
+ * schema that stored them would be a schema with three ways to say the same thing.
12
+ * Deriving them here, once, means every consumer derives them identically — the
13
+ * alternative, which this replaces, is each application inventing its own mapping
14
+ * and two applications disagreeing about what colour a type is.
15
+ *
16
+ * ## Why syntax roles come from ANSI
17
+ *
18
+ * A theme carries no syntax palette, and Base24's editor-oriented slots are not
19
+ * one: `base08` is documented as "variables" and `base0D` as "functions", but every
20
+ * palette's author filled those slots for a terminal, where the question is "what
21
+ * colour is `ls` output". Importing them as syntax roles would colour a diff by
22
+ * accident.
23
+ *
24
+ * Reading the roles off the sixteen ANSI colours instead has a property worth more
25
+ * than per-theme tuning: the ANSI set is the part of a palette its author *did*
26
+ * choose carefully, every theme in the catalogue has one, and it is already tuned
27
+ * for legibility against that theme's background — the same requirement a code view
28
+ * has. It is the reasoning that makes `ls --color` readable in each of these
29
+ * palettes today.
30
+ */
31
+ import type { AdeaTheme } from './schema';
32
+ /** The syntax roles, matching the names Shiki's theme contract expects. */
33
+ export type SyntaxRole = 'keyword' | 'string' | 'number' | 'comment' | 'function' | 'variable' | 'type' | 'tag' | 'attribute' | 'operator' | 'heading' | 'link' | 'constant' | 'punctuation' | 'diffAdd' | 'diffDelete' | 'diffHunk' | 'searchMatch';
34
+ /**
35
+ * The syntax palette for a theme, as OKLCH strings.
36
+ *
37
+ * Comment and punctuation are additionally measured against the canvas: a
38
+ * palette's dim grey is chosen to be read against its *terminal* background, which
39
+ * is the same colour as the canvas here, so the measurement normally passes — but
40
+ * when it does not, the same minimal lightness repair the semantic roles use is
41
+ * applied rather than leaving unreadable comments.
42
+ */
43
+ export declare function syntaxRoles(theme: AdeaTheme, options?: {
44
+ commentFloor?: number;
45
+ }): Record<SyntaxRole, string>;
46
+ /** The syntax palette as hex, for engines that cannot evaluate `oklch()`. */
47
+ export declare function syntaxRolesHex(theme: AdeaTheme): Record<SyntaxRole, string>;
48
+ /**
49
+ * The categorical chart series, derived from the ANSI hues.
50
+ *
51
+ * Six series, taken in the order that keeps adjacent ones furthest apart on the
52
+ * hue circle: blue, magenta, cyan, green, yellow, red. A palette's own ordering
53
+ * would put red next to green, which is the pair a pie chart most needs to
54
+ * separate. Constant across themes by construction — every theme has these six
55
+ * slots — so a chart's series colours mean the same thing in every theme.
56
+ */
57
+ export declare const CHART_SERIES: readonly (keyof AdeaTheme['ansi'])[];
58
+ /** The chart series for a theme, as OKLCH strings. */
59
+ export declare function chartSeries(theme: AdeaTheme): readonly string[];
60
+ /**
61
+ * A tint of a role for use as a background behind text of that role.
62
+ *
63
+ * Status chips need a fill that is the role's colour at low strength, and doing
64
+ * that with alpha would put a translucent colour into a token whose contrast was
65
+ * measured as opaque — and a translucent fill's real contrast depends on whatever
66
+ * happens to be behind it. Blending toward the canvas in OKLCH keeps the result
67
+ * opaque, so the chip's own text pairing can be asserted like any other.
68
+ */
69
+ export declare function tint(color: string, background: string, amount?: number): string;
70
+ /** The four status roles, in the order an alert stack shows them. */
71
+ export declare const STATUS_ROLES: readonly ["success", "warning", "error", "info"];
72
+ export type StatusRole = (typeof STATUS_ROLES)[number];
73
+ /**
74
+ * The text colour to draw on a **solid** fill of a status role.
75
+ *
76
+ * Not the appearance's `foreground`, which is the shortcut and is wrong half the
77
+ * time: a dark theme's foreground is near-white, and near-white on AdEA Dark's
78
+ * `success` at `#3fb950` measures 2.6:1 — illegible. The correct answer is
79
+ * whichever of the theme's two extremes measures better against the fill, which
80
+ * for a bright green is black and for a deep red is white.
81
+ *
82
+ * Where neither clears the floor — a mid-tone fill, which some palettes have —
83
+ * the better of the two is returned and {@link validateTheme} is what reports the
84
+ * pairing as failing, rather than a silent blend being substituted here.
85
+ */
86
+ export declare function statusForeground(theme: AdeaTheme, role: StatusRole): string;
87
+ /** {@link statusForeground} as hex, for engines that cannot evaluate `oklch()`. */
88
+ export declare function statusForegroundHex(theme: AdeaTheme, role: StatusRole): string;
89
+ //# sourceMappingURL=derive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAIzC,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,CA+B5B;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"}
package/dist/derive.js ADDED
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Colours a theme does not store, derived from the ones it does.
3
+ *
4
+ * The canonical schema is deliberately small — seventeen surface roles, sixteen
5
+ * ANSI colours, a cursor and a selection — and three things an application needs
6
+ * are deliberately absent from it: the **syntax roles** a code view wants, the
7
+ * **chart series** a graph wants, and the **fills and foregrounds** a status chip
8
+ * wants.
9
+ *
10
+ * They are absent because each is a *function of* the roles that are present, and a
11
+ * schema that stored them would be a schema with three ways to say the same thing.
12
+ * Deriving them here, once, means every consumer derives them identically — the
13
+ * alternative, which this replaces, is each application inventing its own mapping
14
+ * and two applications disagreeing about what colour a type is.
15
+ *
16
+ * ## Why syntax roles come from ANSI
17
+ *
18
+ * A theme carries no syntax palette, and Base24's editor-oriented slots are not
19
+ * one: `base08` is documented as "variables" and `base0D` as "functions", but every
20
+ * palette's author filled those slots for a terminal, where the question is "what
21
+ * colour is `ls` output". Importing them as syntax roles would colour a diff by
22
+ * accident.
23
+ *
24
+ * Reading the roles off the sixteen ANSI colours instead has a property worth more
25
+ * than per-theme tuning: the ANSI set is the part of a palette its author *did*
26
+ * choose carefully, every theme in the catalogue has one, and it is already tuned
27
+ * for legibility against that theme's background — the same requirement a code view
28
+ * has. It is the reasoning that makes `ls --color` readable in each of these
29
+ * palettes today.
30
+ */
31
+ import { contrastRatio, formatOklch, mix, oklchToHex, parseColor, repairContrast } from './oklch';
32
+ /** Which ANSI role each syntax role is read from, and why. */
33
+ const SYNTAX_SOURCE = Object.freeze({
34
+ // Magenta is the slot palettes spend on the most distinctive hue they have, and
35
+ // a keyword is the token most worth making distinctive.
36
+ keyword: 'magenta',
37
+ string: 'green',
38
+ number: 'yellow',
39
+ // The dim grey every palette defines specifically for text it wants present but
40
+ // quiet. Comments are the one role where "quiet" is the requirement.
41
+ comment: 'brightBlack',
42
+ function: 'blue',
43
+ variable: 'white',
44
+ type: 'cyan',
45
+ tag: 'red',
46
+ attribute: 'yellow',
47
+ operator: 'white',
48
+ heading: 'magenta',
49
+ link: 'blue',
50
+ constant: 'brightMagenta',
51
+ punctuation: 'brightBlack',
52
+ // The diff roles read the ANSI colours a `git diff` already uses, so a change
53
+ // rendered in the editor and the same change rendered in a conversation are the
54
+ // same two greens and reds.
55
+ diffAdd: 'green',
56
+ diffDelete: 'red',
57
+ diffHunk: 'cyan',
58
+ searchMatch: 'yellow',
59
+ });
60
+ /**
61
+ * The syntax palette for a theme, as OKLCH strings.
62
+ *
63
+ * Comment and punctuation are additionally measured against the canvas: a
64
+ * palette's dim grey is chosen to be read against its *terminal* background, which
65
+ * is the same colour as the canvas here, so the measurement normally passes — but
66
+ * when it does not, the same minimal lightness repair the semantic roles use is
67
+ * applied rather than leaving unreadable comments.
68
+ */
69
+ export function syntaxRoles(theme, options = {}) {
70
+ const background = parseColor(theme.colors.background);
71
+ /**
72
+ * Comments and punctuation are held to a *visibility* floor rather than a
73
+ * legibility one.
74
+ *
75
+ * Their whole purpose is to be the faintest thing on screen, and every palette
76
+ * here defines its comment colour that way on purpose: Everforest Light's is
77
+ * 1.9:1 against its own canvas. Holding them to 3:1 could only be satisfied by
78
+ * promoting comments to the body text's colour, which inverts the role — and the
79
+ * floors that *do* carry text are measured separately and are not relaxed.
80
+ */
81
+ const floor = options.commentFloor ?? 2;
82
+ const roles = {};
83
+ for (const [role, source] of Object.entries(SYNTAX_SOURCE)) {
84
+ const value = parseColor(theme.ansi[source]);
85
+ if (!value)
86
+ continue;
87
+ if (role === 'comment' || role === 'punctuation') {
88
+ const repaired = background
89
+ ? repairContrast(value, background, floor, 0.3)
90
+ : { color: value };
91
+ roles[role] = formatOklch(repaired.color);
92
+ continue;
93
+ }
94
+ roles[role] = formatOklch(value);
95
+ }
96
+ return roles;
97
+ }
98
+ /** The syntax palette as hex, for engines that cannot evaluate `oklch()`. */
99
+ export function syntaxRolesHex(theme) {
100
+ const roles = syntaxRoles(theme);
101
+ return Object.fromEntries(Object.entries(roles).map(([role, value]) => {
102
+ const parsed = parseColor(value);
103
+ return [role, parsed ? oklchToHex(parsed) : value];
104
+ }));
105
+ }
106
+ /**
107
+ * The categorical chart series, derived from the ANSI hues.
108
+ *
109
+ * Six series, taken in the order that keeps adjacent ones furthest apart on the
110
+ * hue circle: blue, magenta, cyan, green, yellow, red. A palette's own ordering
111
+ * would put red next to green, which is the pair a pie chart most needs to
112
+ * separate. Constant across themes by construction — every theme has these six
113
+ * slots — so a chart's series colours mean the same thing in every theme.
114
+ */
115
+ export const CHART_SERIES = Object.freeze([
116
+ 'blue',
117
+ 'magenta',
118
+ 'cyan',
119
+ 'green',
120
+ 'yellow',
121
+ 'red',
122
+ ]);
123
+ /** The chart series for a theme, as OKLCH strings. */
124
+ export function chartSeries(theme) {
125
+ return CHART_SERIES.map((role) => formatOklch(parseColor(theme.ansi[role])));
126
+ }
127
+ /**
128
+ * A tint of a role for use as a background behind text of that role.
129
+ *
130
+ * Status chips need a fill that is the role's colour at low strength, and doing
131
+ * that with alpha would put a translucent colour into a token whose contrast was
132
+ * measured as opaque — and a translucent fill's real contrast depends on whatever
133
+ * happens to be behind it. Blending toward the canvas in OKLCH keeps the result
134
+ * opaque, so the chip's own text pairing can be asserted like any other.
135
+ */
136
+ export function tint(color, background, amount = 0.14) {
137
+ const foreground = parseColor(color);
138
+ const canvas = parseColor(background);
139
+ if (!foreground || !canvas)
140
+ return color;
141
+ return formatOklch(mix(canvas, foreground, amount));
142
+ }
143
+ /** The four status roles, in the order an alert stack shows them. */
144
+ export const STATUS_ROLES = ['success', 'warning', 'error', 'info'];
145
+ /**
146
+ * The text colour to draw on a **solid** fill of a status role.
147
+ *
148
+ * Not the appearance's `foreground`, which is the shortcut and is wrong half the
149
+ * time: a dark theme's foreground is near-white, and near-white on AdEA Dark's
150
+ * `success` at `#3fb950` measures 2.6:1 — illegible. The correct answer is
151
+ * whichever of the theme's two extremes measures better against the fill, which
152
+ * for a bright green is black and for a deep red is white.
153
+ *
154
+ * Where neither clears the floor — a mid-tone fill, which some palettes have —
155
+ * the better of the two is returned and {@link validateTheme} is what reports the
156
+ * pairing as failing, rather than a silent blend being substituted here.
157
+ */
158
+ export function statusForeground(theme, role) {
159
+ const fill = parseColor(theme.colors[role]);
160
+ const background = parseColor(theme.colors.background);
161
+ const foreground = parseColor(theme.colors.foreground);
162
+ if (!fill || !background || !foreground)
163
+ return theme.colors.foreground;
164
+ const best = contrastRatio(foreground, fill) >= contrastRatio(background, fill) ? foreground : background;
165
+ return formatOklch(best);
166
+ }
167
+ /** {@link statusForeground} as hex, for engines that cannot evaluate `oklch()`. */
168
+ export function statusForegroundHex(theme, role) {
169
+ const parsed = parseColor(statusForeground(theme, role));
170
+ return parsed ? oklchToHex(parsed) : theme.colors.foreground;
171
+ }
172
+ //# sourceMappingURL=derive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive.js","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generated by `bun run catalogue:build`. Do not edit.
3
+ *
4
+ * The catalogue is committed so that a palette change is a reviewable diff, and
5
+ * `bun run catalogue:check` fails the build when this file and its inputs
6
+ * disagree.
7
+ */
8
+ import type { Base24Scheme } from '../adapters/base24';
9
+ /**
10
+ * The Base24 schemes as they were vendored, keyed by theme id.
11
+ *
12
+ * Untouched, so a consumer that needs the original bytes — an interop export, a
13
+ * licence audit — gets them rather than a re-derivation.
14
+ */
15
+ export declare const generatedSchemes: Readonly<Record<string, Base24Scheme>>;
16
+ //# sourceMappingURL=schemes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemes.d.ts","sourceRoot":"","sources":["../../src/generated/schemes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAi2BlE,CAAA"}