@eos-ui/tokens 0.1.0 → 0.2.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.
- package/README.md +3 -2
- package/dist/generated/defaults.d.ts +15 -7
- package/dist/generated/defaults.js +46 -18
- package/dist/index.d.ts +1 -1
- package/dist/theme.d.ts +7 -2
- package/dist/theme.js +32 -7
- package/dist/tokens.css +13 -5
- package/package.json +1 -1
- package/src/tokens.json +65 -17
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ All variables are prefixed `--e-` (`--e-primary`, `--e-space-4`). Documentation:
|
|
|
24
24
|
|
|
25
25
|
## Inputs
|
|
26
26
|
|
|
27
|
-
`defineTheme()` takes
|
|
27
|
+
`defineTheme()` takes 16 inputs and emits every token. Any token can also be set by name in `tokens`, which wins over everything derived. `name` labels the theme (`data-e-theme`), and `strict` throws on a contrast failure instead of listing it in `issues`.
|
|
28
28
|
|
|
29
29
|
| Input | Derives |
|
|
30
30
|
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
|
|
@@ -33,7 +33,8 @@ All variables are prefixed `--e-` (`--e-primary`, `--e-space-4`). Documentation:
|
|
|
33
33
|
| `background`, `surface`, `foreground` | the grounds, `ink`, `muted`, `border`, `border-strong`; a dark surface lifts the action colours |
|
|
34
34
|
| `fonts`, `radius` | `font-sans`, `font-mono`; `radius-sm` to `radius-lg` |
|
|
35
35
|
| `textScale`, `spaceScale` | `text-xs` to `text-4xl`; `space-1` to `space-8` (1 is the default) |
|
|
36
|
-
| `strokes` `{ hair, focus }`
|
|
36
|
+
| `strokes` `{ hair, focus, edge, card }` | `stroke-hair`, `stroke-card`, `stroke-edge`, `stroke-focus`, `focus-gap`, `focus-gap-field` |
|
|
37
|
+
| `contrast` `"standard" | "high"` | `high`: `border`, `border-strong` = `ink`; `muted` at 15:1; neutral `surface-tint`; darker `scrim` |
|
|
37
38
|
| `motion` `"default" \| "snappy" \| "gentle" \| "none"` | `duration-tap`, `duration-move`, `easing-out` |
|
|
38
39
|
| `elevation` `"outline" \| "lifted" \| "bold"` | `edge`, `well`, `float`; shadow tint follows `background` |
|
|
39
40
|
| `controlHeight` | `control-height`, `chip-height` |
|
|
@@ -14,7 +14,10 @@ export declare const defaults: {
|
|
|
14
14
|
readonly background: "#ffffff";
|
|
15
15
|
readonly surface: "#ffffff";
|
|
16
16
|
readonly "surface-tint": "#eaf4f8";
|
|
17
|
+
readonly "surface-hover": "color-mix(in srgb, var(--e-surface-tint), var(--e-ink) 3%)";
|
|
17
18
|
readonly ink: "#000000";
|
|
19
|
+
readonly "print-ink": "#000000";
|
|
20
|
+
readonly "print-paper": "#ffffff";
|
|
18
21
|
readonly scrim: "rgb(11 40 52 / 0.55)";
|
|
19
22
|
readonly muted: "#515151";
|
|
20
23
|
readonly border: "#7f8f96";
|
|
@@ -43,6 +46,10 @@ export declare const defaults: {
|
|
|
43
46
|
readonly "text-3xl": "30px";
|
|
44
47
|
readonly "text-4xl": "36px";
|
|
45
48
|
readonly "control-height": "48px";
|
|
49
|
+
readonly "shade-hover": "black 8%";
|
|
50
|
+
readonly "shade-press": "black 16%";
|
|
51
|
+
readonly "shade-slab": "black 30%";
|
|
52
|
+
readonly tap: "44px";
|
|
46
53
|
readonly "chip-height": "24px";
|
|
47
54
|
readonly measure: "62ch";
|
|
48
55
|
readonly "stroke-hair": "1px";
|
|
@@ -50,31 +57,32 @@ export declare const defaults: {
|
|
|
50
57
|
readonly "stroke-edge": "1.5px";
|
|
51
58
|
readonly "stroke-focus": "2px";
|
|
52
59
|
readonly "focus-gap": "2px";
|
|
53
|
-
readonly "focus-gap-field": "-
|
|
60
|
+
readonly "focus-gap-field": "calc(-1 * var(--e-stroke-edge))";
|
|
54
61
|
readonly depth: "2px";
|
|
55
62
|
readonly "duration-tap": "80ms";
|
|
56
63
|
readonly "duration-move": "220ms";
|
|
57
64
|
readonly "easing-out": "cubic-bezier(0.2, 0.8, 0.2, 1)";
|
|
58
65
|
readonly "z-raised": "1";
|
|
59
|
-
readonly "z-sticky": "
|
|
66
|
+
readonly "z-sticky": "2";
|
|
67
|
+
readonly "z-focus": "3";
|
|
60
68
|
readonly "z-tooltip": "55";
|
|
61
69
|
readonly "z-modal": "40";
|
|
62
70
|
readonly "z-popover": "45";
|
|
63
71
|
readonly "z-toast": "50";
|
|
64
|
-
readonly "font-sans": "\"
|
|
65
|
-
readonly "font-mono": "\"
|
|
72
|
+
readonly "font-sans": "\"Bricolage Grotesque\", \"Avenir Next\", system-ui, sans-serif";
|
|
73
|
+
readonly "font-mono": "\"Geist Mono\", ui-monospace, Menlo, Consolas, monospace";
|
|
66
74
|
};
|
|
67
75
|
export declare const groups: {
|
|
68
|
-
readonly color: readonly ["brand-blue", "brand-green", "primary", "on-primary", "secondary", "on-secondary", "secondary-soft", "danger", "on-danger", "danger-soft", "warning-strong", "warning-soft", "background", "surface", "surface-tint", "ink", "scrim", "muted", "border", "border-strong", "focus-ring", "focus-field"];
|
|
76
|
+
readonly color: readonly ["brand-blue", "brand-green", "primary", "on-primary", "secondary", "on-secondary", "secondary-soft", "danger", "on-danger", "danger-soft", "warning-strong", "warning-soft", "background", "surface", "surface-tint", "surface-hover", "ink", "print-ink", "print-paper", "scrim", "muted", "border", "border-strong", "focus-ring", "focus-field"];
|
|
69
77
|
readonly spacing: readonly ["space-1", "space-2", "space-3", "space-4", "space-6", "space-8"];
|
|
70
78
|
readonly radius: readonly ["radius-sm", "radius-md", "radius-lg", "radius-pill"];
|
|
71
79
|
readonly shadow: readonly ["edge", "well", "float"];
|
|
72
80
|
readonly fontSize: readonly ["text-xs", "text-sm", "text-md", "text-lg", "text-xl", "text-2xl", "text-3xl", "text-4xl"];
|
|
73
|
-
readonly size: readonly ["control-height", "chip-height", "measure"];
|
|
81
|
+
readonly size: readonly ["control-height", "shade-hover", "shade-press", "shade-slab", "tap", "chip-height", "measure"];
|
|
74
82
|
readonly stroke: readonly ["stroke-hair", "stroke-card", "stroke-edge", "stroke-focus", "focus-gap", "focus-gap-field", "depth"];
|
|
75
83
|
readonly duration: readonly ["duration-tap", "duration-move"];
|
|
76
84
|
readonly easing: readonly ["easing-out"];
|
|
77
|
-
readonly zIndex: readonly ["z-raised", "z-sticky", "z-tooltip", "z-modal", "z-popover", "z-toast"];
|
|
85
|
+
readonly zIndex: readonly ["z-raised", "z-sticky", "z-focus", "z-tooltip", "z-modal", "z-popover", "z-toast"];
|
|
78
86
|
readonly font: readonly ["font-sans", "font-mono"];
|
|
79
87
|
};
|
|
80
88
|
export declare const usage: Record<string, string>;
|
|
@@ -15,7 +15,10 @@ export const defaults = {
|
|
|
15
15
|
"background": "#ffffff",
|
|
16
16
|
"surface": "#ffffff",
|
|
17
17
|
"surface-tint": "#eaf4f8",
|
|
18
|
+
"surface-hover": "color-mix(in srgb, var(--e-surface-tint), var(--e-ink) 3%)",
|
|
18
19
|
"ink": "#000000",
|
|
20
|
+
"print-ink": "#000000",
|
|
21
|
+
"print-paper": "#ffffff",
|
|
19
22
|
"scrim": "rgb(11 40 52 / 0.55)",
|
|
20
23
|
"muted": "#515151",
|
|
21
24
|
"border": "#7f8f96",
|
|
@@ -44,6 +47,10 @@ export const defaults = {
|
|
|
44
47
|
"text-3xl": "30px",
|
|
45
48
|
"text-4xl": "36px",
|
|
46
49
|
"control-height": "48px",
|
|
50
|
+
"shade-hover": "black 8%",
|
|
51
|
+
"shade-press": "black 16%",
|
|
52
|
+
"shade-slab": "black 30%",
|
|
53
|
+
"tap": "44px",
|
|
47
54
|
"chip-height": "24px",
|
|
48
55
|
"measure": "62ch",
|
|
49
56
|
"stroke-hair": "1px",
|
|
@@ -51,19 +58,20 @@ export const defaults = {
|
|
|
51
58
|
"stroke-edge": "1.5px",
|
|
52
59
|
"stroke-focus": "2px",
|
|
53
60
|
"focus-gap": "2px",
|
|
54
|
-
"focus-gap-field": "-
|
|
61
|
+
"focus-gap-field": "calc(-1 * var(--e-stroke-edge))",
|
|
55
62
|
"depth": "2px",
|
|
56
63
|
"duration-tap": "80ms",
|
|
57
64
|
"duration-move": "220ms",
|
|
58
65
|
"easing-out": "cubic-bezier(0.2, 0.8, 0.2, 1)",
|
|
59
66
|
"z-raised": "1",
|
|
60
|
-
"z-sticky": "
|
|
67
|
+
"z-sticky": "2",
|
|
68
|
+
"z-focus": "3",
|
|
61
69
|
"z-tooltip": "55",
|
|
62
70
|
"z-modal": "40",
|
|
63
71
|
"z-popover": "45",
|
|
64
72
|
"z-toast": "50",
|
|
65
|
-
"font-sans": "\"
|
|
66
|
-
"font-mono": "\"
|
|
73
|
+
"font-sans": "\"Bricolage Grotesque\", \"Avenir Next\", system-ui, sans-serif",
|
|
74
|
+
"font-mono": "\"Geist Mono\", ui-monospace, Menlo, Consolas, monospace"
|
|
67
75
|
};
|
|
68
76
|
export const groups = {
|
|
69
77
|
"color": [
|
|
@@ -82,7 +90,10 @@ export const groups = {
|
|
|
82
90
|
"background",
|
|
83
91
|
"surface",
|
|
84
92
|
"surface-tint",
|
|
93
|
+
"surface-hover",
|
|
85
94
|
"ink",
|
|
95
|
+
"print-ink",
|
|
96
|
+
"print-paper",
|
|
86
97
|
"scrim",
|
|
87
98
|
"muted",
|
|
88
99
|
"border",
|
|
@@ -121,6 +132,10 @@ export const groups = {
|
|
|
121
132
|
],
|
|
122
133
|
"size": [
|
|
123
134
|
"control-height",
|
|
135
|
+
"shade-hover",
|
|
136
|
+
"shade-press",
|
|
137
|
+
"shade-slab",
|
|
138
|
+
"tap",
|
|
124
139
|
"chip-height",
|
|
125
140
|
"measure"
|
|
126
141
|
],
|
|
@@ -143,6 +158,7 @@ export const groups = {
|
|
|
143
158
|
"zIndex": [
|
|
144
159
|
"z-raised",
|
|
145
160
|
"z-sticky",
|
|
161
|
+
"z-focus",
|
|
146
162
|
"z-tooltip",
|
|
147
163
|
"z-modal",
|
|
148
164
|
"z-popover",
|
|
@@ -168,12 +184,15 @@ export const usage = {
|
|
|
168
184
|
"warning-soft": "Tinted backdrop of a warning chip, stamp, notice or toast.",
|
|
169
185
|
"background": "The page ground: the colour behind everything, painted by the app shell and the page. White by default, the same as `surface`. The `background` input of `defineTheme` sets it; when only `surface` is given the page ground follows the surface.",
|
|
170
186
|
"surface": "What sits on the page: cards, fields, popovers, dialogs, panels and headers. Every screen starts on white. The `surface` input of `defineTheme` sets it, and with it derives `surface-tint`, the soft tone backdrops and, on a dark surface, the light action colours.",
|
|
171
|
-
"surface-tint": "The surface's second step: wells, hovered rows, table headers, footers, empty slots and the information tone's tint. Derived from `surface` by shifting its lightness 0.045 toward the foreground (0.06 the other way on a dark surface) in the brand hue. About 1.1:1 against white, so never a boundary on its own.",
|
|
187
|
+
"surface-tint": "The surface's second step: wells, hovered rows, table headers, footers, empty slots and the information tone's tint. Derived from `surface` by shifting its lightness 0.045 toward the foreground (0.06 the other way on a dark surface) in the brand hue (a neutral grey with `contrast: \"high\"`). About 1.1:1 against white, so never a boundary on its own.",
|
|
188
|
+
"surface-hover": "The hover tone for rows, items and tiles that sit on `surface`: `surface-tint` pulled 3% toward `ink`: the same fill as the selected nav item, so a hovered item and a selected one match. Follows a dark surface and a custom brand automatically.",
|
|
172
189
|
"ink": "Body copy, headings and icons on `surface`, `surface-tint`, `primary`, `secondary`, `danger` and the soft tints. Also the neutral chip colour. Set by the `foreground` input of `defineTheme`, which also drives `muted`, `border` and `border-strong`.",
|
|
190
|
+
"print-ink": "Text and rules when printing, whatever the theme: black.",
|
|
191
|
+
"print-paper": "The page and fills when printing, whatever the theme: white.",
|
|
173
192
|
"scrim": "The dimmed backdrop behind a dialog or drawer.",
|
|
174
|
-
"muted": "Secondary text, kickers and captions on `surface` (7.9:1) and `surface-tint` (7.1:1): AAA. Close to the grey of the logo's tagline. From a `foreground` input, `ink` softened toward `surface` until it just holds 7:1.",
|
|
175
|
-
"border": "Hairlines between rows, the outline of cards and popovers, and the underside of clickable rows. 3.4:1 on `surface` and 3.0:1 on `surface-tint`, so every edge is visible on white. Control edges use `border-strong`. From a `foreground` input, `ink` softened toward `surface` until it just holds 3.4:1
|
|
176
|
-
"border-strong": "Input, checkbox and other control borders on `surface` (4.5:1, above the 3:1 floor). From a `foreground` input, `ink` softened toward `surface` until it just holds 4.5:1
|
|
193
|
+
"muted": "Secondary text, kickers and captions on `surface` (7.9:1) and `surface-tint` (7.1:1): AAA. Close to the grey of the logo's tagline. From a `foreground` input, `ink` softened toward `surface` until it just holds 7:1 (15:1 with `contrast: \"high\"`).",
|
|
194
|
+
"border": "Hairlines between rows, the outline of cards and popovers, and the underside of clickable rows. 3.4:1 on `surface` and 3.0:1 on `surface-tint`, so every edge is visible on white. Control edges use `border-strong`. From a `foreground` input, `ink` softened toward `surface` until it just holds 3.4:1; `ink` itself with `contrast: \"high\"`.",
|
|
195
|
+
"border-strong": "Input, checkbox and other control borders on `surface` (4.5:1, above the 3:1 floor). From a `foreground` input, `ink` softened toward `surface` until it just holds 4.5:1; `ink` itself with `contrast: \"high\"`.",
|
|
177
196
|
"focus-ring": "Solid 2px focus outline with 2px offset on buttons, links, tabs, rows and every control that is not a text input; 3:1 or better on every surface and fill.",
|
|
178
197
|
"focus-field": "The focus outline and edge of text inputs and everything built on them (Field, Select, Combobox, DatePicker, NumberField, SearchBar, OtpField). Primary teal, 7.9:1 on `surface`. An invalid input keeps `danger`. Buttons and links use `focus-ring`.",
|
|
179
198
|
"space-1": "Icon-to-text gaps, gap inside a chip.",
|
|
@@ -198,20 +217,25 @@ export const usage = {
|
|
|
198
217
|
"text-3xl": "The one amount a statement leads with.",
|
|
199
218
|
"text-4xl": "Page titles (h1).",
|
|
200
219
|
"control-height": "Height of every control that can be tapped: buttons, inputs, selects, date fields, slots, and one row of a multi-select. One height everywhere, so a Button beside an input lines up and a field never shifts when it changes type.",
|
|
220
|
+
"shade-hover": "A mix amount for hover feedback: `color-mix(in srgb, <fill>, var(--e-shade-hover))` darkens the fill by 8%. On a dark surface it lightens by 12% instead, since darkening a dark fill is invisible.",
|
|
221
|
+
"shade-press": "A mix amount for the pressed state, one step past `shade-hover`: `color-mix(in srgb, <fill>, var(--e-shade-press))`. Lightens on a dark surface.",
|
|
222
|
+
"shade-slab": "A mix amount for the raised bottom edge (the slab) under a fill: `color-mix(in srgb, <fill>, var(--e-shade-slab))`. Darkens on light and dark surfaces alike.",
|
|
223
|
+
"tap": "Minimum tap target size. Compact controls pad or extend their hit area up to this size.",
|
|
201
224
|
"chip-height": "Height of a Chip or a small Stamp.",
|
|
202
225
|
"measure": "Longest comfortable line of copy.",
|
|
203
226
|
"stroke-hair": "Dividers and the rule between rows.",
|
|
204
|
-
"stroke-card": "The outline of a card, panel, table or other container that is not clickable, and of a chip or stamp. Follows the hairline; a bold elevation draws it at 2px.",
|
|
205
|
-
"stroke-edge": "The outline of a control, chip or stamp.",
|
|
227
|
+
"stroke-card": "The outline of a card, panel, table or other container that is not clickable, and of a chip or stamp. Follows the hairline; a bold elevation draws it at 2px unless `strokes.card` sets it.",
|
|
228
|
+
"stroke-edge": "The outline of a control, chip or stamp. 1.5 times the hairline unless `strokes.edge` sets it.",
|
|
206
229
|
"stroke-focus": "The focus outline.",
|
|
207
230
|
"focus-gap": "Space between a button or link and its focus outline.",
|
|
208
|
-
"focus-gap-field": "Space between a text input and its focus outline:
|
|
231
|
+
"focus-gap-field": "Space between a text input and its focus outline: minus the control border, so the outline lies exactly over the border with no seam, whatever its width.",
|
|
209
232
|
"depth": "How far a raised or pressed edge reaches. A button, a statement row and a selected time slot stand out by this much of extra thickness on the bottom edge; a pressed button, the selected item of a list or segmented control and a notice are pressed in by the same amount on the top edge.",
|
|
210
233
|
"duration-tap": "Hover and press feedback.",
|
|
211
234
|
"duration-move": "Things that move: a progress fill, a drawer.",
|
|
212
235
|
"easing-out": "Fast start, soft landing. The only easing in the system.",
|
|
213
236
|
"z-raised": "A part that must sit above its sibling inside one component.",
|
|
214
237
|
"z-sticky": "Sticky table headers and columns.",
|
|
238
|
+
"z-focus": "A focused part whose outline must show over its siblings, such as a segment in a joined group.",
|
|
215
239
|
"z-tooltip": "Tooltip bubbles: above everything, including dialogs, popovers and toasts.",
|
|
216
240
|
"z-modal": "Dialogs and drawers with their scrim.",
|
|
217
241
|
"z-popover": "Popovers, menus and option lists. Above modals, so a Select inside a Dialog opens over it.",
|
|
@@ -234,12 +258,13 @@ export const derivedFrom = {
|
|
|
234
258
|
"warning-soft": "warning,surface",
|
|
235
259
|
"background": "background,surface",
|
|
236
260
|
"surface": "surface",
|
|
237
|
-
"surface-tint": "surface,brand",
|
|
261
|
+
"surface-tint": "surface,brand,contrast",
|
|
262
|
+
"surface-hover": "surface-tint,ink",
|
|
238
263
|
"ink": "foreground,surface",
|
|
239
|
-
"scrim": "surface",
|
|
240
|
-
"muted": "foreground,surface",
|
|
241
|
-
"border": "foreground,surface",
|
|
242
|
-
"border-strong": "foreground,surface",
|
|
264
|
+
"scrim": "surface,contrast",
|
|
265
|
+
"muted": "foreground,surface,contrast",
|
|
266
|
+
"border": "foreground,surface,contrast",
|
|
267
|
+
"border-strong": "foreground,surface,contrast",
|
|
243
268
|
"focus-ring": "foreground",
|
|
244
269
|
"focus-field": "brand",
|
|
245
270
|
"space-1": "spaceScale",
|
|
@@ -263,6 +288,9 @@ export const derivedFrom = {
|
|
|
263
288
|
"text-3xl": "textScale",
|
|
264
289
|
"text-4xl": "textScale",
|
|
265
290
|
"control-height": "controlHeight",
|
|
291
|
+
"shade-hover": "surface",
|
|
292
|
+
"shade-press": "surface",
|
|
293
|
+
"shade-slab": "surface",
|
|
266
294
|
"chip-height": "controlHeight",
|
|
267
295
|
"stroke-hair": "strokes",
|
|
268
296
|
"stroke-card": "strokes,elevation",
|
|
@@ -274,6 +302,6 @@ export const derivedFrom = {
|
|
|
274
302
|
"duration-move": "motion",
|
|
275
303
|
"easing-out": "motion"
|
|
276
304
|
};
|
|
277
|
-
export const constants = ["radius-pill", "measure", "depth", "z-raised", "z-sticky", "z-tooltip", "z-modal", "z-popover", "z-toast"];
|
|
305
|
+
export const constants = ["print-ink", "print-paper", "radius-pill", "tap", "measure", "depth", "z-raised", "z-sticky", "z-focus", "z-tooltip", "z-modal", "z-popover", "z-toast"];
|
|
278
306
|
export const inputTokens = ["font-sans", "font-mono", "brand-blue", "brand-green", "background", "surface", "ink", "control-height", "stroke-hair", "stroke-focus"];
|
|
279
|
-
export const colorNames = new Set(["brand-blue", "brand-green", "primary", "on-primary", "secondary", "on-secondary", "secondary-soft", "danger", "on-danger", "danger-soft", "warning-strong", "warning-soft", "background", "surface", "surface-tint", "ink", "scrim", "muted", "border", "border-strong", "focus-ring", "focus-field"]);
|
|
307
|
+
export const colorNames = new Set(["brand-blue", "brand-green", "primary", "on-primary", "secondary", "on-secondary", "secondary-soft", "danger", "on-danger", "danger-soft", "warning-strong", "warning-soft", "background", "surface", "surface-tint", "surface-hover", "ink", "print-ink", "print-paper", "scrim", "muted", "border", "border-strong", "focus-ring", "focus-field"]);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { defineTheme, checkContrast, LAYER_ORDER, defaults, groups } from "./theme.js";
|
|
2
|
-
export type { Theme, ThemeInput, MotionPreset, ElevationPreset, TokenValues, ContrastIssue, CssOptions, TokenName, } from "./theme.js";
|
|
2
|
+
export type { Theme, ThemeInput, MotionPreset, ElevationPreset, ContrastPreset, TokenValues, ContrastIssue, CssOptions, TokenName, } from "./theme.js";
|
|
3
3
|
export { contrast, luminance, reachContrast, settleContrast, withLightness, tint, toOklch, fromOklch, parseHex, toHex, } from "./color.js";
|
|
4
4
|
export { usage, derivedFrom, constants, inputTokens } from "./generated/defaults.js";
|
package/dist/theme.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { defaults, groups, type TokenName } from "./generated/defaults.js";
|
|
|
2
2
|
export type TokenValues = Partial<Record<TokenName, string>>;
|
|
3
3
|
export type MotionPreset = "default" | "snappy" | "gentle" | "none";
|
|
4
4
|
export type ElevationPreset = "outline" | "lifted" | "bold";
|
|
5
|
+
export type ContrastPreset = "standard" | "high";
|
|
5
6
|
export interface ThemeInput {
|
|
6
7
|
/** Identifies the theme. It becomes the value of `data-e-theme` when the theme is scoped to an element. */
|
|
7
8
|
name?: string;
|
|
@@ -34,11 +35,15 @@ export interface ThemeInput {
|
|
|
34
35
|
textScale?: number;
|
|
35
36
|
/** Multiplier for the spacing scale, `space-1` to `space-8`. 1 is the default scale; non-finite or non-positive values are ignored. */
|
|
36
37
|
spaceScale?: number;
|
|
37
|
-
/** Line weights in px. `hair` sets `stroke-hair` and `stroke-edge` (1.5 times it); `focus` sets `stroke-focus
|
|
38
|
+
/** Line weights in px. `hair` sets `stroke-hair`, `stroke-card` and `stroke-edge` (1.5 times it); `focus` sets `stroke-focus` and `focus-gap` (the same). `edge` and `card` set `stroke-edge` (controls) and `stroke-card` (containers, chips) outright and win over what `hair` and a bold `elevation` give. `focus-gap-field` always follows `stroke-edge` in CSS (minus the border width), so a field's focus outline sits exactly over its border. */
|
|
38
39
|
strokes?: {
|
|
39
40
|
hair?: number;
|
|
40
41
|
focus?: number;
|
|
42
|
+
edge?: number;
|
|
43
|
+
card?: number;
|
|
41
44
|
};
|
|
45
|
+
/** `"high"` draws every line and secondary text at full strength: `border` and `border-strong` become the foreground colour, `muted` is softened only until it holds 15:1, `surface-tint` is a neutral grey (no brand tint) and `scrim` is darker. Pair it with heavier `strokes`. Default `"standard"`. */
|
|
46
|
+
contrast?: ContrastPreset;
|
|
42
47
|
/** How state changes feel: sets `duration-tap`, `duration-move` and `easing-out`. */
|
|
43
48
|
motion?: MotionPreset;
|
|
44
49
|
/** How depth is drawn: sets `edge`, `well` and `float` from the border, ink and hairline. `outline` is flat rings, `lifted` adds soft drops, `bold` uses heavy rings and a hard offset shadow. */
|
|
@@ -76,7 +81,7 @@ export interface Theme {
|
|
|
76
81
|
apply(el?: HTMLElement): void;
|
|
77
82
|
}
|
|
78
83
|
/** Cascade order of the library. Later layers win, and each layer only builds on the ones before it. */
|
|
79
|
-
export declare const LAYER_ORDER = "e.reset, e.tokens, e.base, e.primitives, e.blocks, e.controls, e.composites, e.containers, e.
|
|
84
|
+
export declare const LAYER_ORDER = "e.reset, e.tokens, e.base, e.primitives, e.blocks, e.controls, e.composites, e.containers, e.page";
|
|
80
85
|
export declare function checkContrast(tokens: Record<string, string>): ContrastIssue[];
|
|
81
86
|
export declare function defineTheme(input?: ThemeInput): Theme;
|
|
82
87
|
export { defaults, groups };
|
package/dist/theme.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defaults, groups } from "./generated/defaults.js";
|
|
2
2
|
import { contrast, fromOklch, luminance, parseHex, reachContrast, settleContrast, tint, toOklch, withLightness, } from "./color.js";
|
|
3
3
|
/** Cascade order of the library. Later layers win, and each layer only builds on the ones before it. */
|
|
4
|
-
export const LAYER_ORDER = "e.reset, e.tokens, e.base, e.primitives, e.blocks, e.controls, e.composites, e.containers, e.
|
|
4
|
+
export const LAYER_ORDER = "e.reset, e.tokens, e.base, e.primitives, e.blocks, e.controls, e.composites, e.containers, e.page";
|
|
5
5
|
const RADII = {
|
|
6
6
|
sharp: { sm: "0px", md: "2px", lg: "4px" },
|
|
7
7
|
default: { sm: "4px", md: "8px", lg: "16px" },
|
|
@@ -54,6 +54,8 @@ function toneHue(soft, strong, tone) {
|
|
|
54
54
|
function deriveStrokes(input, out) {
|
|
55
55
|
const hair = positive(input.strokes?.hair);
|
|
56
56
|
const focus = positive(input.strokes?.focus);
|
|
57
|
+
const edge = positive(input.strokes?.edge);
|
|
58
|
+
const card = positive(input.strokes?.card);
|
|
57
59
|
if (hair !== undefined) {
|
|
58
60
|
out["stroke-hair"] = px(hair);
|
|
59
61
|
out["stroke-card"] = px(hair);
|
|
@@ -62,8 +64,11 @@ function deriveStrokes(input, out) {
|
|
|
62
64
|
if (focus !== undefined) {
|
|
63
65
|
out["stroke-focus"] = px(focus);
|
|
64
66
|
out["focus-gap"] = px(focus);
|
|
65
|
-
out["focus-gap-field"] = "-1px";
|
|
66
67
|
}
|
|
68
|
+
if (edge !== undefined)
|
|
69
|
+
out["stroke-edge"] = px(edge);
|
|
70
|
+
if (card !== undefined)
|
|
71
|
+
out["stroke-card"] = px(card);
|
|
67
72
|
}
|
|
68
73
|
const SOFT = [
|
|
69
74
|
[1, 2, 0, 0.08],
|
|
@@ -91,10 +96,11 @@ function layers(set, dark, base) {
|
|
|
91
96
|
.map(([y, blur, spread, alpha]) => `0 ${y}px ${blur}px ${spread}px rgba(${base}, ${Math.round(Math.min(0.9, dark ? alpha * 2.4 : alpha) * 100) / 100})`)
|
|
92
97
|
.join(", ");
|
|
93
98
|
}
|
|
94
|
-
function deriveElevation(style, out, dark) {
|
|
99
|
+
function deriveElevation(style, out, dark, strokes) {
|
|
95
100
|
const ring = (w) => `0 0 0 ${w} ${out["border"]}`;
|
|
96
101
|
const hair = out["stroke-hair"];
|
|
97
|
-
const
|
|
102
|
+
const given = positive(strokes?.card);
|
|
103
|
+
const card = given !== undefined ? px(given) : style === "bold" ? "2px" : hair;
|
|
98
104
|
out["stroke-card"] = card;
|
|
99
105
|
const base = shadowRgb(out, dark);
|
|
100
106
|
if (style === "lifted") {
|
|
@@ -135,12 +141,22 @@ function deriveGround(input, out, dark) {
|
|
|
135
141
|
}
|
|
136
142
|
}
|
|
137
143
|
out["background"] = input.background ?? (input.surface ? surface : out["background"]);
|
|
138
|
-
const foreground = input.foreground ?? (input.surface ? (dark ? WHITE : defaults["ink"]) : undefined);
|
|
144
|
+
const foreground = input.foreground ?? (input.surface ? (dark ? WHITE : defaults["ink"]) : input.contrast === "high" ? defaults["ink"] : undefined);
|
|
139
145
|
if (foreground) {
|
|
140
146
|
out["ink"] = foreground;
|
|
141
147
|
out["muted"] = settleContrast(foreground, surface, 7);
|
|
142
148
|
out["border"] = settleContrast(foreground, surface, 3.4);
|
|
143
149
|
out["border-strong"] = settleContrast(foreground, surface, 4.5);
|
|
150
|
+
if (input.contrast === "high") {
|
|
151
|
+
out["muted"] = settleContrast(foreground, surface, 15);
|
|
152
|
+
out["border"] = foreground;
|
|
153
|
+
out["border-strong"] = foreground;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (input.contrast === "high") {
|
|
157
|
+
const l = toOklch(surface).l;
|
|
158
|
+
out["surface-tint"] = fromOklch({ l: Math.min(1, Math.max(0, dark ? l + 0.06 : l - 0.04)), c: 0, h: 0 });
|
|
159
|
+
out["scrim"] = "rgb(0 0 0 / 0.75)";
|
|
144
160
|
}
|
|
145
161
|
}
|
|
146
162
|
function derive(input) {
|
|
@@ -152,6 +168,9 @@ function derive(input) {
|
|
|
152
168
|
out["warning-strong"] = input.warning ?? DARK_WARNING;
|
|
153
169
|
out["scrim"] = "rgb(0 0 0 / 0.7)";
|
|
154
170
|
out["well"] = DARK_WELL;
|
|
171
|
+
out["shade-hover"] = "white 12%";
|
|
172
|
+
out["shade-press"] = "white 20%";
|
|
173
|
+
out["shade-slab"] = "black 45%";
|
|
155
174
|
}
|
|
156
175
|
const dangerBase = input.danger ?? (dark ? DARK_DANGER : undefined);
|
|
157
176
|
if (dangerBase)
|
|
@@ -215,8 +234,14 @@ function derive(input) {
|
|
|
215
234
|
out["control-height"] = px(height);
|
|
216
235
|
out["chip-height"] = px(Math.max(2, Math.round(height / 4) * 2));
|
|
217
236
|
}
|
|
218
|
-
if (input.elevation ||
|
|
219
|
-
|
|
237
|
+
if (input.elevation ||
|
|
238
|
+
input.background ||
|
|
239
|
+
input.surface ||
|
|
240
|
+
input.foreground ||
|
|
241
|
+
input.contrast === "high" ||
|
|
242
|
+
positive(input.strokes?.hair) !== undefined ||
|
|
243
|
+
positive(input.strokes?.card) !== undefined) {
|
|
244
|
+
deriveElevation(input.elevation ?? "outline", out, dark, input.strokes);
|
|
220
245
|
}
|
|
221
246
|
Object.assign(out, input.tokens);
|
|
222
247
|
return out;
|
package/dist/tokens.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Generated from tokens.json. Theme: light. */
|
|
2
|
-
@layer e.reset, e.tokens, e.base, e.primitives, e.blocks, e.controls, e.composites, e.containers, e.
|
|
2
|
+
@layer e.reset, e.tokens, e.base, e.primitives, e.blocks, e.controls, e.composites, e.containers, e.page;
|
|
3
3
|
@layer e.tokens {
|
|
4
4
|
:root {
|
|
5
5
|
--e-brand-blue: #2c95b4;
|
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
--e-background: #ffffff;
|
|
18
18
|
--e-surface: #ffffff;
|
|
19
19
|
--e-surface-tint: #eaf4f8;
|
|
20
|
+
--e-surface-hover: color-mix(in srgb, var(--e-surface-tint), var(--e-ink) 3%);
|
|
20
21
|
--e-ink: #000000;
|
|
22
|
+
--e-print-ink: #000000;
|
|
23
|
+
--e-print-paper: #ffffff;
|
|
21
24
|
--e-scrim: rgb(11 40 52 / 0.55);
|
|
22
25
|
--e-muted: #515151;
|
|
23
26
|
--e-border: #7f8f96;
|
|
@@ -46,6 +49,10 @@
|
|
|
46
49
|
--e-text-3xl: 30px;
|
|
47
50
|
--e-text-4xl: 36px;
|
|
48
51
|
--e-control-height: 48px;
|
|
52
|
+
--e-shade-hover: black 8%;
|
|
53
|
+
--e-shade-press: black 16%;
|
|
54
|
+
--e-shade-slab: black 30%;
|
|
55
|
+
--e-tap: 44px;
|
|
49
56
|
--e-chip-height: 24px;
|
|
50
57
|
--e-measure: 62ch;
|
|
51
58
|
--e-stroke-hair: 1px;
|
|
@@ -53,19 +60,20 @@
|
|
|
53
60
|
--e-stroke-edge: 1.5px;
|
|
54
61
|
--e-stroke-focus: 2px;
|
|
55
62
|
--e-focus-gap: 2px;
|
|
56
|
-
--e-focus-gap-field: -
|
|
63
|
+
--e-focus-gap-field: calc(-1 * var(--e-stroke-edge));
|
|
57
64
|
--e-depth: 2px;
|
|
58
65
|
--e-duration-tap: 80ms;
|
|
59
66
|
--e-duration-move: 220ms;
|
|
60
67
|
--e-easing-out: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
61
68
|
--e-z-raised: 1;
|
|
62
|
-
--e-z-sticky:
|
|
69
|
+
--e-z-sticky: 2;
|
|
70
|
+
--e-z-focus: 3;
|
|
63
71
|
--e-z-tooltip: 55;
|
|
64
72
|
--e-z-modal: 40;
|
|
65
73
|
--e-z-popover: 45;
|
|
66
74
|
--e-z-toast: 50;
|
|
67
|
-
--e-font-sans: "
|
|
68
|
-
--e-font-mono: "
|
|
75
|
+
--e-font-sans: "Bricolage Grotesque", "Avenir Next", system-ui, sans-serif;
|
|
76
|
+
--e-font-mono: "Geist Mono", ui-monospace, Menlo, Consolas, monospace;
|
|
69
77
|
}
|
|
70
78
|
:root, [data-e-theme] {
|
|
71
79
|
--e-wash-hover: color-mix(in srgb, var(--e-ink) 8%, transparent);
|
package/package.json
CHANGED
package/src/tokens.json
CHANGED
|
@@ -100,8 +100,14 @@
|
|
|
100
100
|
{
|
|
101
101
|
"name": "surface-tint",
|
|
102
102
|
"value": "#eaf4f8",
|
|
103
|
-
"usage": "The surface's second step: wells, hovered rows, table headers, footers, empty slots and the information tone's tint. Derived from `surface` by shifting its lightness 0.045 toward the foreground (0.06 the other way on a dark surface) in the brand hue. About 1.1:1 against white, so never a boundary on its own.",
|
|
104
|
-
"from": "surface,brand"
|
|
103
|
+
"usage": "The surface's second step: wells, hovered rows, table headers, footers, empty slots and the information tone's tint. Derived from `surface` by shifting its lightness 0.045 toward the foreground (0.06 the other way on a dark surface) in the brand hue (a neutral grey with `contrast: \"high\"`). About 1.1:1 against white, so never a boundary on its own.",
|
|
104
|
+
"from": "surface,brand,contrast"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "surface-hover",
|
|
108
|
+
"value": "color-mix(in srgb, var(--e-surface-tint), var(--e-ink) 3%)",
|
|
109
|
+
"usage": "The hover tone for rows, items and tiles that sit on `surface`: `surface-tint` pulled 3% toward `ink`: the same fill as the selected nav item, so a hovered item and a selected one match. Follows a dark surface and a custom brand automatically.",
|
|
110
|
+
"from": "surface-tint,ink"
|
|
105
111
|
},
|
|
106
112
|
{
|
|
107
113
|
"name": "ink",
|
|
@@ -110,29 +116,41 @@
|
|
|
110
116
|
"from": "foreground,surface",
|
|
111
117
|
"input": true
|
|
112
118
|
},
|
|
119
|
+
{
|
|
120
|
+
"name": "print-ink",
|
|
121
|
+
"value": "#000000",
|
|
122
|
+
"usage": "Text and rules when printing, whatever the theme: black.",
|
|
123
|
+
"constant": true
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "print-paper",
|
|
127
|
+
"value": "#ffffff",
|
|
128
|
+
"usage": "The page and fills when printing, whatever the theme: white.",
|
|
129
|
+
"constant": true
|
|
130
|
+
},
|
|
113
131
|
{
|
|
114
132
|
"name": "scrim",
|
|
115
133
|
"value": "rgb(11 40 52 / 0.55)",
|
|
116
134
|
"usage": "The dimmed backdrop behind a dialog or drawer.",
|
|
117
|
-
"from": "surface"
|
|
135
|
+
"from": "surface,contrast"
|
|
118
136
|
},
|
|
119
137
|
{
|
|
120
138
|
"name": "muted",
|
|
121
139
|
"value": "#515151",
|
|
122
|
-
"usage": "Secondary text, kickers and captions on `surface` (7.9:1) and `surface-tint` (7.1:1): AAA. Close to the grey of the logo's tagline. From a `foreground` input, `ink` softened toward `surface` until it just holds 7:1.",
|
|
123
|
-
"from": "foreground,surface"
|
|
140
|
+
"usage": "Secondary text, kickers and captions on `surface` (7.9:1) and `surface-tint` (7.1:1): AAA. Close to the grey of the logo's tagline. From a `foreground` input, `ink` softened toward `surface` until it just holds 7:1 (15:1 with `contrast: \"high\"`).",
|
|
141
|
+
"from": "foreground,surface,contrast"
|
|
124
142
|
},
|
|
125
143
|
{
|
|
126
144
|
"name": "border",
|
|
127
145
|
"value": "#7f8f96",
|
|
128
|
-
"usage": "Hairlines between rows, the outline of cards and popovers, and the underside of clickable rows. 3.4:1 on `surface` and 3.0:1 on `surface-tint`, so every edge is visible on white. Control edges use `border-strong`. From a `foreground` input, `ink` softened toward `surface` until it just holds 3.4:1
|
|
129
|
-
"from": "foreground,surface"
|
|
146
|
+
"usage": "Hairlines between rows, the outline of cards and popovers, and the underside of clickable rows. 3.4:1 on `surface` and 3.0:1 on `surface-tint`, so every edge is visible on white. Control edges use `border-strong`. From a `foreground` input, `ink` softened toward `surface` until it just holds 3.4:1; `ink` itself with `contrast: \"high\"`.",
|
|
147
|
+
"from": "foreground,surface,contrast"
|
|
130
148
|
},
|
|
131
149
|
{
|
|
132
150
|
"name": "border-strong",
|
|
133
151
|
"value": "#767676",
|
|
134
|
-
"usage": "Input, checkbox and other control borders on `surface` (4.5:1, above the 3:1 floor). From a `foreground` input, `ink` softened toward `surface` until it just holds 4.5:1
|
|
135
|
-
"from": "foreground,surface"
|
|
152
|
+
"usage": "Input, checkbox and other control borders on `surface` (4.5:1, above the 3:1 floor). From a `foreground` input, `ink` softened toward `surface` until it just holds 4.5:1; `ink` itself with `contrast: \"high\"`.",
|
|
153
|
+
"from": "foreground,surface,contrast"
|
|
136
154
|
},
|
|
137
155
|
{
|
|
138
156
|
"name": "focus-ring",
|
|
@@ -151,8 +169,8 @@
|
|
|
151
169
|
"type": {
|
|
152
170
|
"fonts": [],
|
|
153
171
|
"families": {
|
|
154
|
-
"sans": "\"
|
|
155
|
-
"mono": "\"
|
|
172
|
+
"sans": "\"Bricolage Grotesque\", \"Avenir Next\", system-ui, sans-serif",
|
|
173
|
+
"mono": "\"Geist Mono\", ui-monospace, Menlo, Consolas, monospace"
|
|
156
174
|
},
|
|
157
175
|
"groups": [
|
|
158
176
|
{
|
|
@@ -401,7 +419,7 @@
|
|
|
401
419
|
]
|
|
402
420
|
},
|
|
403
421
|
"size": {
|
|
404
|
-
"note": "Sizes that components share.",
|
|
422
|
+
"note": "Sizes and amounts that components share.",
|
|
405
423
|
"tokens": [
|
|
406
424
|
{
|
|
407
425
|
"name": "control-height",
|
|
@@ -410,6 +428,30 @@
|
|
|
410
428
|
"from": "controlHeight",
|
|
411
429
|
"input": true
|
|
412
430
|
},
|
|
431
|
+
{
|
|
432
|
+
"name": "shade-hover",
|
|
433
|
+
"value": "black 8%",
|
|
434
|
+
"usage": "A mix amount for hover feedback: `color-mix(in srgb, <fill>, var(--e-shade-hover))` darkens the fill by 8%. On a dark surface it lightens by 12% instead, since darkening a dark fill is invisible.",
|
|
435
|
+
"from": "surface"
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"name": "shade-press",
|
|
439
|
+
"value": "black 16%",
|
|
440
|
+
"usage": "A mix amount for the pressed state, one step past `shade-hover`: `color-mix(in srgb, <fill>, var(--e-shade-press))`. Lightens on a dark surface.",
|
|
441
|
+
"from": "surface"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"name": "shade-slab",
|
|
445
|
+
"value": "black 30%",
|
|
446
|
+
"usage": "A mix amount for the raised bottom edge (the slab) under a fill: `color-mix(in srgb, <fill>, var(--e-shade-slab))`. Darkens on light and dark surfaces alike.",
|
|
447
|
+
"from": "surface"
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"name": "tap",
|
|
451
|
+
"value": "44px",
|
|
452
|
+
"usage": "Minimum tap target size. Compact controls pad or extend their hit area up to this size.",
|
|
453
|
+
"constant": true
|
|
454
|
+
},
|
|
413
455
|
{
|
|
414
456
|
"name": "chip-height",
|
|
415
457
|
"value": "24px",
|
|
@@ -437,13 +479,13 @@
|
|
|
437
479
|
{
|
|
438
480
|
"name": "stroke-card",
|
|
439
481
|
"value": "1px",
|
|
440
|
-
"usage": "The outline of a card, panel, table or other container that is not clickable, and of a chip or stamp. Follows the hairline; a bold elevation draws it at 2px.",
|
|
482
|
+
"usage": "The outline of a card, panel, table or other container that is not clickable, and of a chip or stamp. Follows the hairline; a bold elevation draws it at 2px unless `strokes.card` sets it.",
|
|
441
483
|
"from": "strokes,elevation"
|
|
442
484
|
},
|
|
443
485
|
{
|
|
444
486
|
"name": "stroke-edge",
|
|
445
487
|
"value": "1.5px",
|
|
446
|
-
"usage": "The outline of a control, chip or stamp.",
|
|
488
|
+
"usage": "The outline of a control, chip or stamp. 1.5 times the hairline unless `strokes.edge` sets it.",
|
|
447
489
|
"from": "strokes"
|
|
448
490
|
},
|
|
449
491
|
{
|
|
@@ -461,8 +503,8 @@
|
|
|
461
503
|
},
|
|
462
504
|
{
|
|
463
505
|
"name": "focus-gap-field",
|
|
464
|
-
"value": "-
|
|
465
|
-
"usage": "Space between a text input and its focus outline:
|
|
506
|
+
"value": "calc(-1 * var(--e-stroke-edge))",
|
|
507
|
+
"usage": "Space between a text input and its focus outline: minus the control border, so the outline lies exactly over the border with no seam, whatever its width.",
|
|
466
508
|
"from": "strokes"
|
|
467
509
|
},
|
|
468
510
|
{
|
|
@@ -511,10 +553,16 @@
|
|
|
511
553
|
},
|
|
512
554
|
{
|
|
513
555
|
"name": "z-sticky",
|
|
514
|
-
"value": "
|
|
556
|
+
"value": "2",
|
|
515
557
|
"usage": "Sticky table headers and columns.",
|
|
516
558
|
"constant": true
|
|
517
559
|
},
|
|
560
|
+
{
|
|
561
|
+
"name": "z-focus",
|
|
562
|
+
"value": "3",
|
|
563
|
+
"usage": "A focused part whose outline must show over its siblings, such as a segment in a joined group.",
|
|
564
|
+
"constant": true
|
|
565
|
+
},
|
|
518
566
|
{
|
|
519
567
|
"name": "z-tooltip",
|
|
520
568
|
"value": "55",
|