@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.
- package/dist/accents.d.ts +150 -0
- package/dist/accents.d.ts.map +1 -0
- package/dist/accents.js +205 -0
- package/dist/accents.js.map +1 -0
- package/dist/adapters/base24.d.ts +117 -0
- package/dist/adapters/base24.d.ts.map +1 -0
- package/dist/adapters/base24.js +313 -0
- package/dist/adapters/base24.js.map +1 -0
- package/dist/adapters/css.d.ts +68 -0
- package/dist/adapters/css.d.ts.map +1 -0
- package/dist/adapters/css.js +107 -0
- package/dist/adapters/css.js.map +1 -0
- package/dist/adapters/shadcn.d.ts +51 -0
- package/dist/adapters/shadcn.d.ts.map +1 -0
- package/dist/adapters/shadcn.js +120 -0
- package/dist/adapters/shadcn.js.map +1 -0
- package/dist/adapters/shiki.d.ts +60 -0
- package/dist/adapters/shiki.d.ts.map +1 -0
- package/dist/adapters/shiki.js +139 -0
- package/dist/adapters/shiki.js.map +1 -0
- package/dist/adapters/tailwind.d.ts +35 -0
- package/dist/adapters/tailwind.d.ts.map +1 -0
- package/dist/adapters/tailwind.js +58 -0
- package/dist/adapters/tailwind.js.map +1 -0
- package/dist/adapters/xterm.d.ts +64 -0
- package/dist/adapters/xterm.d.ts.map +1 -0
- package/dist/adapters/xterm.js +112 -0
- package/dist/adapters/xterm.js.map +1 -0
- package/dist/catalogue.d.ts +66 -0
- package/dist/catalogue.d.ts.map +1 -0
- package/dist/catalogue.js +110 -0
- package/dist/catalogue.js.map +1 -0
- package/dist/derive.d.ts +89 -0
- package/dist/derive.d.ts.map +1 -0
- package/dist/derive.js +172 -0
- package/dist/derive.js.map +1 -0
- package/dist/generated/schemes.d.ts +16 -0
- package/dist/generated/schemes.d.ts.map +1 -0
- package/dist/generated/schemes.js +880 -0
- package/dist/generated/schemes.js.map +1 -0
- package/dist/generated/themes.d.ts +11 -0
- package/dist/generated/themes.d.ts.map +1 -0
- package/dist/generated/themes.js +1658 -0
- package/dist/generated/themes.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +192 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +958 -0
- package/dist/normalize.js.map +1 -0
- package/dist/oklch.d.ts +141 -0
- package/dist/oklch.d.ts.map +1 -0
- package/dist/oklch.js +311 -0
- package/dist/oklch.js.map +1 -0
- package/dist/schema.d.ts +178 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +69 -0
- package/dist/schema.js.map +1 -0
- package/dist/sources.d.ts +296 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +634 -0
- package/dist/sources.js.map +1 -0
- package/dist/validate.d.ts +121 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +255 -0
- package/dist/validate.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The accent axis.
|
|
3
|
+
*
|
|
4
|
+
* A theme has one interactive colour — its primary — and the accent axis lets a
|
|
5
|
+
* user replace it without changing the theme. That is a different question from
|
|
6
|
+
* "which palette do you want": a user may like Catppuccin's surfaces and still want
|
|
7
|
+
* a violet primary, and a product may ship a brand colour that has to survive every
|
|
8
|
+
* theme in the catalogue.
|
|
9
|
+
*
|
|
10
|
+
* ## Why the presets live here
|
|
11
|
+
*
|
|
12
|
+
* They are colour data with a light/dark pair per preset — structurally the same
|
|
13
|
+
* thing as a theme's primary, and the last colour a consumer should have to author
|
|
14
|
+
* itself. Keeping them in a consumer meant two things that must agree lived in two
|
|
15
|
+
* places: the preset list, and the CSS blocks generated from it. They were written
|
|
16
|
+
* by hand in both, and they drifted — the generated default moved its hover *toward*
|
|
17
|
+
* the canvas while every hand-written accent moved *away*, so the default primary
|
|
18
|
+
* button hovered backwards and picking any accent silently fixed it.
|
|
19
|
+
*
|
|
20
|
+
* Here the values and the derivation are one module, so a consumer emits both from
|
|
21
|
+
* the same rule and cannot produce that disagreement.
|
|
22
|
+
*
|
|
23
|
+
* ## The hover rule
|
|
24
|
+
*
|
|
25
|
+
* A hovered primary moves **away from the canvas**, which is what makes it read as
|
|
26
|
+
* hovered rather than as a second, slightly different colour.
|
|
27
|
+
*
|
|
28
|
+
* Two rules were tried here before this one, and both are worth recording because
|
|
29
|
+
* each looks right until it is measured:
|
|
30
|
+
*
|
|
31
|
+
* - **Toward `--background`** — what the consumer used to do. Inverted in both
|
|
32
|
+
* appearances: it moves the button toward the page it sits on, so a hovered button
|
|
33
|
+
* recedes.
|
|
34
|
+
* - **Toward `--foreground`** — correct in principle, since the foreground is
|
|
35
|
+
* normally away from the canvas, and wrong in practice: a dark theme's foreground
|
|
36
|
+
* is mid-lightness (`0.79` in the default), so an accent lighter than that — the
|
|
37
|
+
* dark green is `0.80` — moves *toward* the canvas by a hair.
|
|
38
|
+
* - **Toward white or black** — always the right direction, but a *proportional*
|
|
39
|
+
* step: a mid-lightness light accent moves ~0.10 and a pale dark accent ~0.03, so
|
|
40
|
+
* the same rule gives one appearance a hover twice as strong as the other's.
|
|
41
|
+
*
|
|
42
|
+
* A uniform step needs a resolved value, which is why {@link primaryHover} returns
|
|
43
|
+
* one and why the tint below can stay an expression. `shiftLightness` is what keeps
|
|
44
|
+
* the step uniform *and* the hue intact — a mix toward a neutral cannot do both.
|
|
45
|
+
*/
|
|
46
|
+
import type { ThemeAppearance } from './schema';
|
|
47
|
+
/** One accent preset: a named primary, per appearance. */
|
|
48
|
+
export type AccentPreset = {
|
|
49
|
+
/** The `data-accent` value. */
|
|
50
|
+
id: string;
|
|
51
|
+
label: string;
|
|
52
|
+
/** What the preset is for, in a gallery or a picker. */
|
|
53
|
+
description: string;
|
|
54
|
+
/** The accent as it appears on a light theme. */
|
|
55
|
+
light: string;
|
|
56
|
+
/** The accent as it appears on a dark theme. */
|
|
57
|
+
dark: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* The presets.
|
|
61
|
+
*
|
|
62
|
+
* Each is a pair rather than one colour, because the same accent cannot be one
|
|
63
|
+
* value across both appearances: a violet that reads as vivid on a dark canvas is
|
|
64
|
+
* muddy on a light one, and the deep form that works on light is dull on dark. The
|
|
65
|
+
* pairs below are chosen so each appearance gets the vibrancy the other's value
|
|
66
|
+
* would lose.
|
|
67
|
+
*/
|
|
68
|
+
export declare const ACCENTS: readonly AccentPreset[];
|
|
69
|
+
/** The accent ids, for validating a stored preference without loading the data. */
|
|
70
|
+
export declare const ACCENT_IDS: readonly string[];
|
|
71
|
+
/** Look a preset up by id. */
|
|
72
|
+
export declare function getAccent(id: string): AccentPreset | undefined;
|
|
73
|
+
/** The accent's value for one appearance. */
|
|
74
|
+
export declare function accentValue(preset: AccentPreset, appearance: ThemeAppearance): string;
|
|
75
|
+
/**
|
|
76
|
+
* The label to draw on an accent fill: black or white, whichever wins on contrast.
|
|
77
|
+
*
|
|
78
|
+
* Measured rather than conventional. The usual convention is "white on a coloured
|
|
79
|
+
* fill", which is wrong for the bright half of this set — white on `#a78bfa` is
|
|
80
|
+
* about 2.1:1, and black on it is about 9.9:1. That is why the same accent carries a
|
|
81
|
+
* black label in dark mode and a white one in light: the pair is designed so the
|
|
82
|
+
* polarity flips, and the label has to flip with it.
|
|
83
|
+
*/
|
|
84
|
+
export declare function accentForeground(accent: string): string;
|
|
85
|
+
/** The contrast the chosen label achieves, for validation and reporting. */
|
|
86
|
+
export declare function accentForegroundContrast(accent: string): number;
|
|
87
|
+
/**
|
|
88
|
+
* How far a hovered primary moves along lightness.
|
|
89
|
+
*
|
|
90
|
+
* A **uniform step**, not a proportional one, and the difference matters. Mixing a
|
|
91
|
+
* fixed share toward white or black moves an accent by a share of its headroom, so
|
|
92
|
+
* the same rule gives a mid-lightness light accent a step of ~0.10 and a pale dark
|
|
93
|
+
* accent one of ~0.03 — a hover that feels twice as strong in one appearance as the
|
|
94
|
+
* other, and nearly invisible on the palest accent.
|
|
95
|
+
*
|
|
96
|
+
* 0.05 is the step this system's accents were already hand-written with, so the
|
|
97
|
+
* accents keep the appearance they had while the rule becomes one value.
|
|
98
|
+
*/
|
|
99
|
+
export declare const ACCENT_HOVER_STEP = 0.05;
|
|
100
|
+
/**
|
|
101
|
+
* The hovered primary, as a resolved colour.
|
|
102
|
+
*
|
|
103
|
+
* Resolved rather than expressed as a `color-mix()`, because a uniform step cannot
|
|
104
|
+
* be written as a mix — see {@link ACCENT_HOVER_STEP}. That means it does **not**
|
|
105
|
+
* follow `--primary` on its own, so a consumer that applies themes at runtime has to
|
|
106
|
+
* write this token too; the alternative is a hover left over from the previous
|
|
107
|
+
* theme's primary. `themeCssVariables` includes it for that reason.
|
|
108
|
+
*
|
|
109
|
+
* The direction is away from the canvas: darker on a light theme, lighter on a dark
|
|
110
|
+
* one. `shiftLightness` keeps chroma and hue and damps chroma near the extremes, so a
|
|
111
|
+
* hovered accent stays the same colour rather than washing out toward grey.
|
|
112
|
+
*/
|
|
113
|
+
export declare function primaryHover(primary: string, appearance: ThemeAppearance): string;
|
|
114
|
+
/**
|
|
115
|
+
* How much of the primary a tint carries, per appearance.
|
|
116
|
+
*
|
|
117
|
+
* Not one value, because a tint's visibility depends on what it is tinted onto: the
|
|
118
|
+
* same alpha over a near-black surface reads as nothing, and over a near-white one
|
|
119
|
+
* reads as a wash. The dark value is the larger for exactly that reason.
|
|
120
|
+
*
|
|
121
|
+
* This one *is* a `color-mix()`, because a tint is a share of the primary by nature
|
|
122
|
+
* and follows `--primary` correctly at runtime.
|
|
123
|
+
*/
|
|
124
|
+
export declare const ACCENT_SUBTLE_ALPHA: Readonly<Record<ThemeAppearance, number>>;
|
|
125
|
+
/**
|
|
126
|
+
* The tint expression, for any primary.
|
|
127
|
+
*
|
|
128
|
+
* Takes the appearance because the alpha is appearance-dependent — see
|
|
129
|
+
* {@link ACCENT_SUBTLE_ALPHA}.
|
|
130
|
+
*/
|
|
131
|
+
export declare function primarySubtleCss(appearance: ThemeAppearance, primaryVariable?: string): string;
|
|
132
|
+
/**
|
|
133
|
+
* The five declarations an accent sets, as CSS values.
|
|
134
|
+
*
|
|
135
|
+
* `primary`, `primaryForeground` and `ring` are resolved colours; `primaryHover` and
|
|
136
|
+
* `primarySubtle` are expressions, for the reason in the module comment. A consumer
|
|
137
|
+
* writes them as custom properties and the rules hold for every theme and every
|
|
138
|
+
* accent at once.
|
|
139
|
+
*/
|
|
140
|
+
export type AccentRoles = {
|
|
141
|
+
primary: string;
|
|
142
|
+
primaryForeground: string;
|
|
143
|
+
primaryHover: string;
|
|
144
|
+
primarySubtle: string;
|
|
145
|
+
ring: string;
|
|
146
|
+
};
|
|
147
|
+
export declare function accentRoles(preset: AccentPreset, appearance: ThemeAppearance,
|
|
148
|
+
/** The property the subtle tint is built from. A consumer may pass its own alias. */
|
|
149
|
+
primaryVariable?: string): AccentRoles;
|
|
150
|
+
//# sourceMappingURL=accents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accents.d.ts","sourceRoot":"","sources":["../src/accents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAI/C,0DAA0D;AAC1D,MAAM,MAAM,YAAY,GAAG;IACzB,+BAA+B;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,EAAE,SAAS,YAAY,EA2CzC,CAAA;AAEF,mFAAmF;AACnF,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAAsD,CAAA;AAE9F,8BAA8B;AAC9B,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAE9D;AAED,6CAA6C;AAC7C,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,GAAG,MAAM,CAErF;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,4EAA4E;AAC5E,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAI/D;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,GAAG,MAAM,CAKjF;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAGxE,CAAA;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,eAAe,EAAE,eAAe,SAAc,GAAG,MAAM,CAEnG;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,eAAe;AAC3B,qFAAqF;AACrF,eAAe,SAAc,GAC5B,WAAW,CAYb"}
|
package/dist/accents.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The accent axis.
|
|
3
|
+
*
|
|
4
|
+
* A theme has one interactive colour — its primary — and the accent axis lets a
|
|
5
|
+
* user replace it without changing the theme. That is a different question from
|
|
6
|
+
* "which palette do you want": a user may like Catppuccin's surfaces and still want
|
|
7
|
+
* a violet primary, and a product may ship a brand colour that has to survive every
|
|
8
|
+
* theme in the catalogue.
|
|
9
|
+
*
|
|
10
|
+
* ## Why the presets live here
|
|
11
|
+
*
|
|
12
|
+
* They are colour data with a light/dark pair per preset — structurally the same
|
|
13
|
+
* thing as a theme's primary, and the last colour a consumer should have to author
|
|
14
|
+
* itself. Keeping them in a consumer meant two things that must agree lived in two
|
|
15
|
+
* places: the preset list, and the CSS blocks generated from it. They were written
|
|
16
|
+
* by hand in both, and they drifted — the generated default moved its hover *toward*
|
|
17
|
+
* the canvas while every hand-written accent moved *away*, so the default primary
|
|
18
|
+
* button hovered backwards and picking any accent silently fixed it.
|
|
19
|
+
*
|
|
20
|
+
* Here the values and the derivation are one module, so a consumer emits both from
|
|
21
|
+
* the same rule and cannot produce that disagreement.
|
|
22
|
+
*
|
|
23
|
+
* ## The hover rule
|
|
24
|
+
*
|
|
25
|
+
* A hovered primary moves **away from the canvas**, which is what makes it read as
|
|
26
|
+
* hovered rather than as a second, slightly different colour.
|
|
27
|
+
*
|
|
28
|
+
* Two rules were tried here before this one, and both are worth recording because
|
|
29
|
+
* each looks right until it is measured:
|
|
30
|
+
*
|
|
31
|
+
* - **Toward `--background`** — what the consumer used to do. Inverted in both
|
|
32
|
+
* appearances: it moves the button toward the page it sits on, so a hovered button
|
|
33
|
+
* recedes.
|
|
34
|
+
* - **Toward `--foreground`** — correct in principle, since the foreground is
|
|
35
|
+
* normally away from the canvas, and wrong in practice: a dark theme's foreground
|
|
36
|
+
* is mid-lightness (`0.79` in the default), so an accent lighter than that — the
|
|
37
|
+
* dark green is `0.80` — moves *toward* the canvas by a hair.
|
|
38
|
+
* - **Toward white or black** — always the right direction, but a *proportional*
|
|
39
|
+
* step: a mid-lightness light accent moves ~0.10 and a pale dark accent ~0.03, so
|
|
40
|
+
* the same rule gives one appearance a hover twice as strong as the other's.
|
|
41
|
+
*
|
|
42
|
+
* A uniform step needs a resolved value, which is why {@link primaryHover} returns
|
|
43
|
+
* one and why the tint below can stay an expression. `shiftLightness` is what keeps
|
|
44
|
+
* the step uniform *and* the hue intact — a mix toward a neutral cannot do both.
|
|
45
|
+
*/
|
|
46
|
+
import { contrastRatio, formatOklch, parseColor, shiftLightness } from './oklch';
|
|
47
|
+
/**
|
|
48
|
+
* The presets.
|
|
49
|
+
*
|
|
50
|
+
* Each is a pair rather than one colour, because the same accent cannot be one
|
|
51
|
+
* value across both appearances: a violet that reads as vivid on a dark canvas is
|
|
52
|
+
* muddy on a light one, and the deep form that works on light is dull on dark. The
|
|
53
|
+
* pairs below are chosen so each appearance gets the vibrancy the other's value
|
|
54
|
+
* would lose.
|
|
55
|
+
*/
|
|
56
|
+
export const ACCENTS = Object.freeze([
|
|
57
|
+
{
|
|
58
|
+
id: 'violet',
|
|
59
|
+
label: 'Violet',
|
|
60
|
+
description: 'The default brand accent.',
|
|
61
|
+
light: '#6d28d9',
|
|
62
|
+
dark: '#a78bfa',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'blue',
|
|
66
|
+
label: 'Blue',
|
|
67
|
+
description: 'Cool and conventional. Reads as informational.',
|
|
68
|
+
light: '#2563eb',
|
|
69
|
+
dark: '#60a5fa',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'green',
|
|
73
|
+
label: 'Green',
|
|
74
|
+
description: 'Reads as confirmatory, which competes with the success status.',
|
|
75
|
+
light: '#15803d',
|
|
76
|
+
dark: '#4ade80',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'amber',
|
|
80
|
+
label: 'Amber',
|
|
81
|
+
description: 'Warm and attention-drawing. Competes with the warning status.',
|
|
82
|
+
light: '#b45309',
|
|
83
|
+
dark: '#fbbf24',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'cyan',
|
|
87
|
+
label: 'Cyan',
|
|
88
|
+
description: 'Quiet and technical. The least saturated of the set.',
|
|
89
|
+
light: '#0e7490',
|
|
90
|
+
dark: '#22d3ee',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'pink',
|
|
94
|
+
label: 'Pink',
|
|
95
|
+
description: 'The loudest of the set. Use where the accent is decorative.',
|
|
96
|
+
light: '#be185d',
|
|
97
|
+
dark: '#f472b6',
|
|
98
|
+
},
|
|
99
|
+
]);
|
|
100
|
+
/** The accent ids, for validating a stored preference without loading the data. */
|
|
101
|
+
export const ACCENT_IDS = Object.freeze(ACCENTS.map((accent) => accent.id));
|
|
102
|
+
/** Look a preset up by id. */
|
|
103
|
+
export function getAccent(id) {
|
|
104
|
+
return ACCENTS.find((accent) => accent.id === id);
|
|
105
|
+
}
|
|
106
|
+
/** The accent's value for one appearance. */
|
|
107
|
+
export function accentValue(preset, appearance) {
|
|
108
|
+
return appearance === 'light' ? preset.light : preset.dark;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The label to draw on an accent fill: black or white, whichever wins on contrast.
|
|
112
|
+
*
|
|
113
|
+
* Measured rather than conventional. The usual convention is "white on a coloured
|
|
114
|
+
* fill", which is wrong for the bright half of this set — white on `#a78bfa` is
|
|
115
|
+
* about 2.1:1, and black on it is about 9.9:1. That is why the same accent carries a
|
|
116
|
+
* black label in dark mode and a white one in light: the pair is designed so the
|
|
117
|
+
* polarity flips, and the label has to flip with it.
|
|
118
|
+
*/
|
|
119
|
+
export function accentForeground(accent) {
|
|
120
|
+
const fill = parseColor(accent);
|
|
121
|
+
if (!fill)
|
|
122
|
+
return 'oklch(1 0 0)';
|
|
123
|
+
const black = { l: 0, c: 0, h: 0 };
|
|
124
|
+
const white = { l: 1, c: 0, h: 0 };
|
|
125
|
+
const best = contrastRatio(black, fill) >= contrastRatio(white, fill) ? black : white;
|
|
126
|
+
return formatOklch(best);
|
|
127
|
+
}
|
|
128
|
+
/** The contrast the chosen label achieves, for validation and reporting. */
|
|
129
|
+
export function accentForegroundContrast(accent) {
|
|
130
|
+
const fill = parseColor(accent);
|
|
131
|
+
if (!fill)
|
|
132
|
+
return 0;
|
|
133
|
+
return contrastRatio(parseColor(accentForeground(accent)), fill);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* How far a hovered primary moves along lightness.
|
|
137
|
+
*
|
|
138
|
+
* A **uniform step**, not a proportional one, and the difference matters. Mixing a
|
|
139
|
+
* fixed share toward white or black moves an accent by a share of its headroom, so
|
|
140
|
+
* the same rule gives a mid-lightness light accent a step of ~0.10 and a pale dark
|
|
141
|
+
* accent one of ~0.03 — a hover that feels twice as strong in one appearance as the
|
|
142
|
+
* other, and nearly invisible on the palest accent.
|
|
143
|
+
*
|
|
144
|
+
* 0.05 is the step this system's accents were already hand-written with, so the
|
|
145
|
+
* accents keep the appearance they had while the rule becomes one value.
|
|
146
|
+
*/
|
|
147
|
+
export const ACCENT_HOVER_STEP = 0.05;
|
|
148
|
+
/**
|
|
149
|
+
* The hovered primary, as a resolved colour.
|
|
150
|
+
*
|
|
151
|
+
* Resolved rather than expressed as a `color-mix()`, because a uniform step cannot
|
|
152
|
+
* be written as a mix — see {@link ACCENT_HOVER_STEP}. That means it does **not**
|
|
153
|
+
* follow `--primary` on its own, so a consumer that applies themes at runtime has to
|
|
154
|
+
* write this token too; the alternative is a hover left over from the previous
|
|
155
|
+
* theme's primary. `themeCssVariables` includes it for that reason.
|
|
156
|
+
*
|
|
157
|
+
* The direction is away from the canvas: darker on a light theme, lighter on a dark
|
|
158
|
+
* one. `shiftLightness` keeps chroma and hue and damps chroma near the extremes, so a
|
|
159
|
+
* hovered accent stays the same colour rather than washing out toward grey.
|
|
160
|
+
*/
|
|
161
|
+
export function primaryHover(primary, appearance) {
|
|
162
|
+
const parsed = parseColor(primary);
|
|
163
|
+
if (!parsed)
|
|
164
|
+
return primary;
|
|
165
|
+
const delta = appearance === 'light' ? -ACCENT_HOVER_STEP : ACCENT_HOVER_STEP;
|
|
166
|
+
return formatOklch(shiftLightness(parsed, delta));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* How much of the primary a tint carries, per appearance.
|
|
170
|
+
*
|
|
171
|
+
* Not one value, because a tint's visibility depends on what it is tinted onto: the
|
|
172
|
+
* same alpha over a near-black surface reads as nothing, and over a near-white one
|
|
173
|
+
* reads as a wash. The dark value is the larger for exactly that reason.
|
|
174
|
+
*
|
|
175
|
+
* This one *is* a `color-mix()`, because a tint is a share of the primary by nature
|
|
176
|
+
* and follows `--primary` correctly at runtime.
|
|
177
|
+
*/
|
|
178
|
+
export const ACCENT_SUBTLE_ALPHA = Object.freeze({
|
|
179
|
+
light: 10,
|
|
180
|
+
dark: 16,
|
|
181
|
+
});
|
|
182
|
+
/**
|
|
183
|
+
* The tint expression, for any primary.
|
|
184
|
+
*
|
|
185
|
+
* Takes the appearance because the alpha is appearance-dependent — see
|
|
186
|
+
* {@link ACCENT_SUBTLE_ALPHA}.
|
|
187
|
+
*/
|
|
188
|
+
export function primarySubtleCss(appearance, primaryVariable = '--primary') {
|
|
189
|
+
return `color-mix(in oklch, var(${primaryVariable}) ${ACCENT_SUBTLE_ALPHA[appearance]}%, transparent)`;
|
|
190
|
+
}
|
|
191
|
+
export function accentRoles(preset, appearance,
|
|
192
|
+
/** The property the subtle tint is built from. A consumer may pass its own alias. */
|
|
193
|
+
primaryVariable = '--primary') {
|
|
194
|
+
const value = accentValue(preset, appearance);
|
|
195
|
+
const parsed = parseColor(value);
|
|
196
|
+
const primary = parsed ? formatOklch(parsed) : value;
|
|
197
|
+
return {
|
|
198
|
+
primary,
|
|
199
|
+
primaryForeground: accentForeground(value),
|
|
200
|
+
primaryHover: primaryHover(value, appearance),
|
|
201
|
+
primarySubtle: primarySubtleCss(appearance, primaryVariable),
|
|
202
|
+
ring: primary,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=accents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accents.js","sourceRoot":"","sources":["../src/accents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
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 type { AdeaTheme, AdeaThemeColors } from '../schema';
|
|
30
|
+
import type { Oklch } from '../oklch';
|
|
31
|
+
/** The twenty-four Base24 slots, in the order the specification lists them. */
|
|
32
|
+
export declare const BASE24_SLOTS: readonly ["base00", "base01", "base02", "base03", "base04", "base05", "base06", "base07", "base08", "base09", "base0A", "base0B", "base0C", "base0D", "base0E", "base0F", "base10", "base11", "base12", "base13", "base14", "base15", "base16", "base17"];
|
|
33
|
+
export type Base24Slot = (typeof BASE24_SLOTS)[number];
|
|
34
|
+
/** A Base24 palette. Values are colours in any notation {@link parseColor} accepts. */
|
|
35
|
+
export type Base24Palette = Readonly<Record<Base24Slot, string>>;
|
|
36
|
+
/** A Base24 scheme: the palette plus the metadata the specification defines. */
|
|
37
|
+
export interface Base24Scheme {
|
|
38
|
+
system: 'base24';
|
|
39
|
+
name: string;
|
|
40
|
+
author: string;
|
|
41
|
+
variant: 'dark' | 'light';
|
|
42
|
+
palette: Base24Palette;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* What each slot means, in the specification's own terms.
|
|
46
|
+
*
|
|
47
|
+
* Kept as data because the normalizer reads it rather than hard-coding slot names
|
|
48
|
+
* in its logic, and because it is the documentation a reader needs to check that
|
|
49
|
+
* the mapping is right.
|
|
50
|
+
*/
|
|
51
|
+
export declare const BASE24_SLOT_MEANING: Readonly<Record<Base24Slot, string>>;
|
|
52
|
+
/**
|
|
53
|
+
* Base24 slot → ANSI role.
|
|
54
|
+
*
|
|
55
|
+
* `black`, `white` and `brightBlack` are absent because Base24 does not name them:
|
|
56
|
+
* the background and foreground slots do double duty. The normalizer decides those
|
|
57
|
+
* three; see its `ANSI_FROM_BASE24` note for why the choice is the one it is.
|
|
58
|
+
*/
|
|
59
|
+
export declare const BASE24_TO_ANSI: Readonly<{
|
|
60
|
+
readonly red: "base08";
|
|
61
|
+
readonly yellow: "base0A";
|
|
62
|
+
readonly green: "base0B";
|
|
63
|
+
readonly cyan: "base0C";
|
|
64
|
+
readonly blue: "base0D";
|
|
65
|
+
readonly magenta: "base0E";
|
|
66
|
+
readonly brightRed: "base12";
|
|
67
|
+
readonly brightYellow: "base13";
|
|
68
|
+
readonly brightGreen: "base14";
|
|
69
|
+
readonly brightCyan: "base15";
|
|
70
|
+
readonly brightBlue: "base16";
|
|
71
|
+
readonly brightMagenta: "base17";
|
|
72
|
+
}>;
|
|
73
|
+
/** The inverse of {@link BASE24_TO_ANSI}, for export. */
|
|
74
|
+
export declare const ANSI_TO_BASE24: Readonly<Record<string, Base24Slot>>;
|
|
75
|
+
/**
|
|
76
|
+
* How each semantic role is written back to a Base24 slot on export.
|
|
77
|
+
*
|
|
78
|
+
* The choices are not arbitrary. `base01` receives `black` rather than the
|
|
79
|
+
* background because an ANSI black that equals the background is invisible as
|
|
80
|
+
* foreground text — which is precisely the defect the import side documents. The
|
|
81
|
+
* surface ladder has no Base24 slot at all, so it is deliberately absent here:
|
|
82
|
+
* Base24 cannot express it, and pretending otherwise by packing four rungs into
|
|
83
|
+
* `base01`/`base02` would make the export lie about what it preserves.
|
|
84
|
+
*/
|
|
85
|
+
export declare const THEME_TO_BASE24: Readonly<Record<keyof AdeaThemeColors, Base24Slot | undefined>>;
|
|
86
|
+
/** Thrown when a palette is missing a slot or holds an unparseable colour. */
|
|
87
|
+
export declare class Base24ParseError extends Error {
|
|
88
|
+
readonly slot: string;
|
|
89
|
+
constructor(message: string, slot: string);
|
|
90
|
+
}
|
|
91
|
+
/** Parses every slot of a palette into OKLCH, or throws naming the offending slot. */
|
|
92
|
+
export declare function parseBase24Palette(palette: Base24Palette): Record<Base24Slot, Oklch>;
|
|
93
|
+
/**
|
|
94
|
+
* Writes a theme back to Base24.
|
|
95
|
+
*
|
|
96
|
+
* `base09` and `base0F` are synthesised — see this module's header. `base10` and
|
|
97
|
+
* `base11` are the two rungs below `base00`, which is what the specification
|
|
98
|
+
* defines them as and what a terminal needs in order to draw a black that is
|
|
99
|
+
* darker than the background.
|
|
100
|
+
*/
|
|
101
|
+
export declare function toBase24(theme: AdeaTheme, options?: {
|
|
102
|
+
author?: string;
|
|
103
|
+
name?: string;
|
|
104
|
+
}): Base24Scheme;
|
|
105
|
+
/** Serialises a scheme to the YAML dialect Base24 schemes are published in. */
|
|
106
|
+
export declare function formatBase24Scheme(scheme: Base24Scheme): string;
|
|
107
|
+
/**
|
|
108
|
+
* Reads the YAML dialect Base24 schemes are published in.
|
|
109
|
+
*
|
|
110
|
+
* Hand-written rather than pulled from a YAML library: the format is a fixed set
|
|
111
|
+
* of scalar keys, the package has no runtime dependencies and no build-time
|
|
112
|
+
* dependencies beyond the TypeScript compiler, and a general parser would accept
|
|
113
|
+
* documents this bridge cannot actually honour. Anything outside the specification
|
|
114
|
+
* is rejected loudly instead of being parsed into a half-scheme.
|
|
115
|
+
*/
|
|
116
|
+
export declare function parseBase24Scheme(source: string): Base24Scheme;
|
|
117
|
+
//# sourceMappingURL=base24.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base24.d.ts","sourceRoot":"","sources":["../../src/adapters/base24.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAY,SAAS,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AACrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAGrC,+EAA+E;AAC/E,eAAO,MAAM,YAAY,2PAyBf,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAEtD,uFAAuF;AACvF,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;AAEhE,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,QAAQ,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;IACzB,OAAO,EAAE,aAAa,CAAA;CACvB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAyBnE,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;EAasC,CAAA;AAEjE,yDAAyD;AACzD,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAI/D,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,eAAe,EAAE,UAAU,GAAG,SAAS,CAAC,CAmBxF,CAAA;AAEJ,8EAA8E;AAC9E,qBAAa,gBAAiB,SAAQ,KAAK;IAGvC,QAAQ,CAAC,IAAI,EAAE,MAAM;gBADrB,OAAO,EAAE,MAAM,EACN,IAAI,EAAE,MAAM;CAKxB;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAcpF;AAcD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,YAAY,CAgDd;AAQD,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAU/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAwD9D"}
|