@getvitops/core 0.9.0 → 1.0.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/CHANGELOG.md +108 -0
- package/css/animation.css +2 -2
- package/css/patterns/carousel.css +3 -3
- package/css/patterns/code.css +2 -2
- package/css/patterns/combobox.css +3 -3
- package/css/patterns/comment.css +1 -1
- package/css/patterns/copy.css +3 -3
- package/css/patterns/dialog.css +2 -2
- package/css/patterns/drawer.css +2 -2
- package/css/patterns/forms.css +11 -11
- package/css/patterns/grouped.css +1 -1
- package/css/patterns/icon.css +2 -2
- package/css/patterns/list.css +5 -5
- package/css/patterns/media.css +1 -1
- package/css/patterns/nav.css +5 -5
- package/css/patterns/notification.css +3 -3
- package/css/patterns/scroll-based.css +1 -1
- package/css/patterns/scroll-target.css +3 -3
- package/css/patterns/sitenav.css +14 -14
- package/css/patterns/split-link.css +4 -4
- package/css/patterns/tag.css +1 -1
- package/css/patterns/text-effects.css +1 -1
- package/css/patterns/theme-editor.css +6 -6
- package/css/patterns/tooltip.css +2 -2
- package/css/patterns/tree.css +3 -3
- package/dist/editor.js +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,113 @@
|
|
|
1
1
|
# @getvitops/core
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- bb92a14: **The colour system is rebuilt on a target-prefixed grammar and a shared lightness ladder.**
|
|
8
|
+
This is a breaking change to every colour token and utility class.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
Two axes shared one class namespace — functional _planes_ (`--<role>-bg-muted`) and
|
|
13
|
+
appearance-relative _stops_ (`--color-<role>-muted`) — arbitrated by a "plane wins" rule. The
|
|
14
|
+
result was not a scale. On the shipped palette, light mode:
|
|
15
|
+
|
|
16
|
+
| class | resolved to | step |
|
|
17
|
+
| ---------------------------------- | ------------ | --------------------------------------------- |
|
|
18
|
+
| `bg-ui-accent-x-muted` | stop | 100 |
|
|
19
|
+
| `bg-ui-accent-muted` | plane | 100 — identical, so `x-muted` was a dead rung |
|
|
20
|
+
| `bg-ui-accent` | plane | 50 — _lighter_ than both its "muted" rungs |
|
|
21
|
+
| `border-ui-accent-muted` / `-bold` | stop / plane | 300 / 300 — identical |
|
|
22
|
+
| `text-ui-accent-bold` | stop | 700 — _lighter_ than `text-…-muted` (800) |
|
|
23
|
+
|
|
24
|
+
Every family was non-monotonic, two had duplicate rungs, and `--color-<role>-muted` was
|
|
25
|
+
unreachable through any `bg-` class.
|
|
26
|
+
|
|
27
|
+
## The new grammar
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
--color-<target>-<role>[-<variant>] target ∈ bg | text | icon | border
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The target is **inside** the name, so `bg-danger-muted` and `text-danger-muted` are different
|
|
34
|
+
tokens and there is nothing left to arbitrate. **The class name is the token name minus
|
|
35
|
+
`--color-`** — one vocabulary instead of two.
|
|
36
|
+
|
|
37
|
+
Variants are ordinal (`xx-muted` < `x-muted` < `muted` < bare < `bold` < `x-bold`) and the
|
|
38
|
+
tables are sparse: only cells that hold their contrast target exist.
|
|
39
|
+
|
|
40
|
+
## Role kinds
|
|
41
|
+
|
|
42
|
+
`colors.roles` values may now be `{ hue, kind }` as well as a bare hue string:
|
|
43
|
+
|
|
44
|
+
```jsonc
|
|
45
|
+
"roles": {
|
|
46
|
+
"danger": "rust", // shorthand => chromatic
|
|
47
|
+
"surface": { "hue": "navy", "kind": "surface" }
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **`surface`** — a page/panel colour: `bg-<role>` is the card, `bg-<role>-muted` the page
|
|
52
|
+
behind it, `bg-<role>-x-muted` a well, `bg-<role>-bold` the inverse surface. Full text scale.
|
|
53
|
+
- **`chromatic`** (default) — a signal colour: tints (`bg-<role>-x-muted`/`-muted`) and solids
|
|
54
|
+
(`bg-<role>-solid[-bold|-x-bold]`), with **no bare `bg-<role>`** — say how loud you mean.
|
|
55
|
+
`text-on-<role>` is the guaranteed foreground for the solid family.
|
|
56
|
+
|
|
57
|
+
## Palette generation
|
|
58
|
+
|
|
59
|
+
Every ramp now sits on one **fixed lightness ladder** (50 → L 0.98 … 950 → L 0.21); only chroma
|
|
60
|
+
and hue vary. That is what makes a step mean the same lightness in every hue. Previously each
|
|
61
|
+
seed transposed the curve, so relative luminance at step 300 ranged from 0.253 to 0.384 across
|
|
62
|
+
the shipped palette — the same variant read differently depending on the role.
|
|
63
|
+
|
|
64
|
+
Authored colours are still reproduced **exactly**. A `seed`, an `anchors` entry or a `tones`
|
|
65
|
+
value is pinned verbatim at its nearest step; every other step takes the ladder. Snapping brand
|
|
66
|
+
colours to the ladder was measured and rejected: 11 of 18 real brand hexes moved beyond a
|
|
67
|
+
just-noticeable difference (worst ΔE-OK 0.050 — Facebook's `#1877F2` → `#0067e1`) and six left
|
|
68
|
+
sRGB gamut. Deviation is now bounded and local to pinned steps, and warns past ~0.03 L.
|
|
69
|
+
|
|
70
|
+
Two tones that claim the same step now **error** instead of one silently overwriting the other;
|
|
71
|
+
the record form (`tones: { "600": "…", "700": "…" }`) is how you resolve it.
|
|
72
|
+
|
|
73
|
+
## New
|
|
74
|
+
- **`icon-<role>`** — a non-text tier, so a glyph may run more vivid than text. `icon` is now a
|
|
75
|
+
default utility family alongside `bg`/`text`/`border`.
|
|
76
|
+
- **`--color-border-focus`** — the focus-ring tone, taken from `ui-primary`'s solid.
|
|
77
|
+
- **Contrast is enforced at build time**, not only in tests: text ≥ APCA Lc 75 on its primary
|
|
78
|
+
background, ≥ 60 on secondary planes, icons and surface boundaries ≥ 45, both appearances.
|
|
79
|
+
A violation now fails `generate`. Chromatic text is checked against the _surface_ planes it
|
|
80
|
+
actually sits on, not only its own tints. `text-<role>-x-muted` (placeholder) and `-xx-muted`
|
|
81
|
+
(disabled) are explicitly exempt; nothing else is.
|
|
82
|
+
|
|
83
|
+
## Migrating
|
|
84
|
+
|
|
85
|
+
Rename `--<role>-<suffix>` → `--color-<target>-<role>[-<variant>]`, and the same for classes:
|
|
86
|
+
|
|
87
|
+
| before | after |
|
|
88
|
+
| --------------------------------------- | ---------------------------------------------------------------- |
|
|
89
|
+
| `--<role>-bg` / `bg-<role>` (chromatic) | `--color-bg-<role>-x-muted` / `bg-<role>-x-muted` |
|
|
90
|
+
| `--<role>-bg-muted` | `--color-bg-<role>-muted` |
|
|
91
|
+
| `--<role>-solid` / `-solid-bold` | `--color-bg-<role>-solid` / `-solid-bold` |
|
|
92
|
+
| `--<role>-on-solid` / `text-on-<role>` | `--color-text-on-<role>` (class unchanged) |
|
|
93
|
+
| `--<role>-text` / `-text-muted` | `--color-text-<role>` / `-muted` |
|
|
94
|
+
| `--<role>-border` / `-border-bold` | `--color-border-<role>` / `-bold` |
|
|
95
|
+
| `--color-<role>-muted` (stop) | judge by use: `--color-bg-<role>-muted` or `--color-text-<role>` |
|
|
96
|
+
|
|
97
|
+
**`surface` background names rotate**, value-preserving: what was `--surface-bg` (the page) is
|
|
98
|
+
now `--color-bg-surface-muted`; what was `--surface-bg-bold` (raised) is now
|
|
99
|
+
`--color-bg-surface`. Elevation is expressed by which token you reach for — page `bg-muted`,
|
|
100
|
+
card `bg` — rather than a raised/sunken pair, which is what lets a future surfaces axis flatten
|
|
101
|
+
it without touching markup.
|
|
102
|
+
|
|
103
|
+
`vitops lint` reports role classes that no longer resolve, and now derives its suggestions from
|
|
104
|
+
what the generator actually emits rather than a hand-maintained list.
|
|
105
|
+
|
|
106
|
+
### Patch Changes
|
|
107
|
+
|
|
108
|
+
- Updated dependencies [bb92a14]
|
|
109
|
+
- @getvitops/utils@1.0.0
|
|
110
|
+
|
|
3
111
|
## 0.9.0
|
|
4
112
|
|
|
5
113
|
### Minor Changes
|
package/css/animation.css
CHANGED
|
@@ -311,8 +311,8 @@
|
|
|
311
311
|
@supports block it resolves to that transparent value. So default to the
|
|
312
312
|
functional text tokens (they flip with the appearance) with a literal
|
|
313
313
|
backstop, since this is precisely the declaration that must never fail. */
|
|
314
|
-
--_reveal-from: var(--text-reveal-color-from, var(--
|
|
315
|
-
--_reveal-to: var(--text-reveal-color-to, var(--
|
|
314
|
+
--_reveal-from: var(--text-reveal-color-from, var(--color-text-neutral-x-muted, #9099a8));
|
|
315
|
+
--_reveal-to: var(--text-reveal-color-to, var(--color-text-neutral, #05070d));
|
|
316
316
|
/* Fallback baseline: ordinary visible text in the start color. */
|
|
317
317
|
color: var(--text-reveal-color-from, currentColor);
|
|
318
318
|
}
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
border: none;
|
|
65
65
|
border-radius: 50%;
|
|
66
66
|
color: var(--carousel-button-color, currentColor);
|
|
67
|
-
background: var(--
|
|
67
|
+
background: var(--color-bg-surface-muted);
|
|
68
68
|
opacity: 0.9;
|
|
69
69
|
transition:
|
|
70
70
|
opacity 0.2s ease,
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
|
|
74
74
|
&::scroll-button(*):hover {
|
|
75
75
|
opacity: 1;
|
|
76
|
-
background: var(--color-surface-muted);
|
|
76
|
+
background: var(--color-bg-surface-muted);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
&::scroll-button(*):focus-visible {
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
block-size: 2rem;
|
|
212
212
|
border: none;
|
|
213
213
|
border-radius: 50%;
|
|
214
|
-
background: var(--
|
|
214
|
+
background: var(--color-bg-surface-muted);
|
|
215
215
|
color: var(--carousel-button-color, currentColor);
|
|
216
216
|
opacity: 0.7;
|
|
217
217
|
cursor: pointer;
|
package/css/patterns/code.css
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
:where(:not(pre) > code) {
|
|
11
11
|
font-family: var(--font-mono);
|
|
12
12
|
font-size: 0.85em;
|
|
13
|
-
background: var(--
|
|
14
|
-
color: var(--
|
|
13
|
+
background: var(--color-border-neutral);
|
|
14
|
+
color: var(--color-text-neutral);
|
|
15
15
|
padding: 0.1em 0.4em;
|
|
16
16
|
border-radius: var(--br-default);
|
|
17
17
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
border-radius: var(--_br);
|
|
21
21
|
|
|
22
22
|
&:focus {
|
|
23
|
-
outline: 2px solid var(--combobox-focus-color, var(--color-
|
|
23
|
+
outline: 2px solid var(--combobox-focus-color, var(--color-border-focus));
|
|
24
24
|
outline-offset: 2px;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
border: var(--_b);
|
|
36
36
|
border-radius: var(--_br);
|
|
37
37
|
box-shadow: var(--_ds);
|
|
38
|
-
background: var(--
|
|
38
|
+
background: var(--color-bg-surface);
|
|
39
39
|
max-block-size: 15rem;
|
|
40
40
|
overflow-y: auto;
|
|
41
41
|
list-style: none;
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
&:hover,
|
|
57
57
|
&[aria-selected='true'] {
|
|
58
|
-
background: var(--color-surface-muted);
|
|
58
|
+
background: var(--color-bg-surface-muted);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
&[aria-disabled='true'] {
|
package/css/patterns/comment.css
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
grid-column: 1 / -1;
|
|
63
63
|
margin-inline-start: var(--comment-indent, 2rem);
|
|
64
64
|
padding-inline-start: var(--comment-indent, 2rem);
|
|
65
|
-
border-inline-start: 2px solid var(--color-surface-muted);
|
|
65
|
+
border-inline-start: 2px solid var(--color-bg-surface-muted);
|
|
66
66
|
display: flex;
|
|
67
67
|
flex-direction: column;
|
|
68
68
|
gap: 1rem;
|
package/css/patterns/copy.css
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
&:focus-visible {
|
|
41
|
-
outline: 2px solid var(--copy-focus-color, var(--color-
|
|
41
|
+
outline: 2px solid var(--copy-focus-color, var(--color-border-focus));
|
|
42
42
|
outline-offset: 2px;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
font-size: 0.75rem;
|
|
67
67
|
border-radius: 0.25rem;
|
|
68
68
|
white-space: nowrap;
|
|
69
|
-
background: var(--
|
|
70
|
-
color: var(--
|
|
69
|
+
background: var(--color-text-surface);
|
|
70
|
+
color: var(--color-bg-surface);
|
|
71
71
|
opacity: 0;
|
|
72
72
|
visibility: hidden;
|
|
73
73
|
transition:
|
package/css/patterns/dialog.css
CHANGED
|
@@ -25,8 +25,8 @@ dialog.dialog {
|
|
|
25
25
|
border: var(--_b);
|
|
26
26
|
border-radius: var(--_br);
|
|
27
27
|
box-shadow: var(--_ds);
|
|
28
|
-
background: var(--
|
|
29
|
-
color: var(--
|
|
28
|
+
background: var(--color-bg-surface);
|
|
29
|
+
color: var(--color-text-surface);
|
|
30
30
|
max-block-size: calc(100vh - 2rem);
|
|
31
31
|
|
|
32
32
|
&::backdrop {
|
package/css/patterns/drawer.css
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
padding: var(--_p);
|
|
16
16
|
border: var(--_b);
|
|
17
17
|
box-shadow: var(--_ds);
|
|
18
|
-
background: var(--
|
|
19
|
-
color: var(--
|
|
18
|
+
background: var(--color-bg-surface);
|
|
19
|
+
color: var(--color-text-surface);
|
|
20
20
|
max-inline-size: none;
|
|
21
21
|
max-block-size: none;
|
|
22
22
|
|
package/css/patterns/forms.css
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
.form-group__error {
|
|
34
34
|
font-size: var(--form-error-size, 0.75rem);
|
|
35
|
-
color: var(--color-danger
|
|
35
|
+
color: var(--color-text-danger);
|
|
36
36
|
display: flex;
|
|
37
37
|
align-items: center;
|
|
38
38
|
gap: 0.25rem;
|
|
@@ -87,7 +87,7 @@ fieldset.fieldset,
|
|
|
87
87
|
border: var(--_b);
|
|
88
88
|
border-radius: var(--_br);
|
|
89
89
|
padding: var(--_p);
|
|
90
|
-
background: var(--
|
|
90
|
+
background: var(--color-bg-surface);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/* ── Range + colour controls ───────────────────────────────────────────────── */
|
|
@@ -95,7 +95,7 @@ fieldset.fieldset,
|
|
|
95
95
|
* natively, in both appearances, with no pseudo-element rewriting. The colour
|
|
96
96
|
* swatch only needs its chrome removed so the well fills the control box. */
|
|
97
97
|
input[type='range'] {
|
|
98
|
-
accent-color: var(--range-accent, var(--ui-primary-solid));
|
|
98
|
+
accent-color: var(--range-accent, var(--color-bg-ui-primary-solid));
|
|
99
99
|
inline-size: 100%;
|
|
100
100
|
min-inline-size: 0;
|
|
101
101
|
}
|
|
@@ -202,7 +202,7 @@ input[type='color'] {
|
|
|
202
202
|
block-size: var(--_check-size);
|
|
203
203
|
border: var(--_b);
|
|
204
204
|
border-radius: var(--_br);
|
|
205
|
-
background: var(--
|
|
205
|
+
background: var(--color-bg-surface);
|
|
206
206
|
color: #fff;
|
|
207
207
|
display: flex;
|
|
208
208
|
align-items: center;
|
|
@@ -225,8 +225,8 @@ input[type='color'] {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
input:checked + .custom-check__box {
|
|
228
|
-
background: var(--brand-primary-solid);
|
|
229
|
-
border-color: var(--brand-primary-solid);
|
|
228
|
+
background: var(--color-bg-brand-primary-solid);
|
|
229
|
+
border-color: var(--color-bg-brand-primary-solid);
|
|
230
230
|
|
|
231
231
|
.custom-check__indicator {
|
|
232
232
|
opacity: 1;
|
|
@@ -235,7 +235,7 @@ input[type='color'] {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
input:focus-visible + .custom-check__box {
|
|
238
|
-
outline: 2px solid var(--check-focus-color, var(--color-
|
|
238
|
+
outline: 2px solid var(--check-focus-color, var(--color-border-focus));
|
|
239
239
|
outline-offset: 2px;
|
|
240
240
|
}
|
|
241
241
|
|
|
@@ -288,7 +288,7 @@ input[type='color'] {
|
|
|
288
288
|
inline-size: var(--_switch-width);
|
|
289
289
|
block-size: var(--_switch-height);
|
|
290
290
|
border-radius: var(--br-switch-track, var(--br-pill, 999px));
|
|
291
|
-
background: var(--color-surface-muted);
|
|
291
|
+
background: var(--color-bg-surface-muted);
|
|
292
292
|
transition: background-color 0.2s ease;
|
|
293
293
|
}
|
|
294
294
|
|
|
@@ -306,7 +306,7 @@ input[type='color'] {
|
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
input:checked + .switch__track {
|
|
309
|
-
background: var(--brand-primary-solid);
|
|
309
|
+
background: var(--color-bg-brand-primary-solid);
|
|
310
310
|
|
|
311
311
|
.switch__thumb {
|
|
312
312
|
inset-inline-start: calc(100% - var(--_switch-thumb-size) - 2px);
|
|
@@ -314,7 +314,7 @@ input[type='color'] {
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
input:focus-visible + .switch__track {
|
|
317
|
-
outline: 2px solid var(--switch-focus-color, var(--color-
|
|
317
|
+
outline: 2px solid var(--switch-focus-color, var(--color-border-focus));
|
|
318
318
|
outline-offset: 2px;
|
|
319
319
|
}
|
|
320
320
|
|
|
@@ -360,7 +360,7 @@ select.custom-select {
|
|
|
360
360
|
cursor: pointer;
|
|
361
361
|
|
|
362
362
|
&:focus-visible {
|
|
363
|
-
outline: 2px solid var(--select-focus-color, var(--color-
|
|
363
|
+
outline: 2px solid var(--select-focus-color, var(--color-border-focus));
|
|
364
364
|
outline-offset: 2px;
|
|
365
365
|
}
|
|
366
366
|
}
|
package/css/patterns/grouped.css
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
--_bs: var(--bs, solid);
|
|
10
10
|
border-width: var(--_bw);
|
|
11
11
|
border-style: var(--_bs);
|
|
12
|
-
border-color: var(--bc, var(--
|
|
12
|
+
border-color: var(--bc, var(--color-border-surface, currentColor));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/* ── Group — collapse border-radius (+ shared borders) across direct children ─
|
package/css/patterns/icon.css
CHANGED
|
@@ -57,11 +57,11 @@
|
|
|
57
57
|
transition: background-color 0.15s ease;
|
|
58
58
|
|
|
59
59
|
&:hover {
|
|
60
|
-
background: var(--color-surface-muted);
|
|
60
|
+
background: var(--color-bg-surface-muted);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
&:focus-visible {
|
|
64
|
-
outline: 2px solid var(--icon-button-focus-color, var(--color-
|
|
64
|
+
outline: 2px solid var(--icon-button-focus-color, var(--color-border-focus));
|
|
65
65
|
outline-offset: 2px;
|
|
66
66
|
}
|
|
67
67
|
|
package/css/patterns/list.css
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
&.list--divided .list__item + .list__item {
|
|
65
|
-
border-block-start: 1px solid var(--list-divider-color, var(--color-surface-muted));
|
|
65
|
+
border-block-start: 1px solid var(--list-divider-color, var(--color-bg-surface-muted));
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
&.list--bordered {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
font-size: 0.75em;
|
|
111
111
|
padding: 0.125rem 0.375rem;
|
|
112
112
|
border-radius: var(--br-count, var(--br-pill, 999px));
|
|
113
|
-
background: var(--color-surface-muted);
|
|
113
|
+
background: var(--color-bg-surface-muted);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
.facet-list__item--active .facet-list__name {
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
border-radius: var(--_br);
|
|
141
141
|
|
|
142
142
|
&:focus {
|
|
143
|
-
outline: 2px solid var(--filter-focus-color, var(--color-
|
|
143
|
+
outline: 2px solid var(--filter-focus-color, var(--color-border-focus));
|
|
144
144
|
outline-offset: 2px;
|
|
145
145
|
}
|
|
146
146
|
}
|
|
@@ -185,7 +185,7 @@
|
|
|
185
185
|
.filtered-list__match {
|
|
186
186
|
padding-inline: 0.125rem;
|
|
187
187
|
border-radius: 0.125rem;
|
|
188
|
-
background: var(--color-warning-muted);
|
|
188
|
+
background: var(--color-bg-warning-muted);
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
&:focus-within {
|
|
249
|
-
outline: 2px solid var(--tag-list-focus-color, var(--color-
|
|
249
|
+
outline: 2px solid var(--tag-list-focus-color, var(--color-border-focus));
|
|
250
250
|
outline-offset: 2px;
|
|
251
251
|
}
|
|
252
252
|
}
|
package/css/patterns/media.css
CHANGED
package/css/patterns/nav.css
CHANGED
|
@@ -13,7 +13,7 @@ nav:has(> .nav-items) {
|
|
|
13
13
|
|
|
14
14
|
.nav-header {
|
|
15
15
|
padding-bottom: 1rem;
|
|
16
|
-
border-bottom: 1px solid var(--nav-border-color, var(--color-surface-muted));
|
|
16
|
+
border-bottom: 1px solid var(--nav-border-color, var(--color-bg-surface-muted));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.nav-items {
|
|
@@ -49,7 +49,7 @@ nav:has(> .nav-items) {
|
|
|
49
49
|
flex-direction: column;
|
|
50
50
|
gap: 1rem;
|
|
51
51
|
padding-top: 1rem;
|
|
52
|
-
border-top: 1px solid var(--nav-border-color, var(--color-surface-muted));
|
|
52
|
+
border-top: 1px solid var(--nav-border-color, var(--color-bg-surface-muted));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/* ── Dropdown submenu ─────────────────────────────────────────────────────── */
|
|
@@ -106,7 +106,7 @@ nav:has(> .nav-items) {
|
|
|
106
106
|
border-radius: 0.375rem;
|
|
107
107
|
|
|
108
108
|
&:hover {
|
|
109
|
-
background-color: var(--color-surface-muted);
|
|
109
|
+
background-color: var(--color-bg-surface-muted);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -131,8 +131,8 @@ nav:has(> .nav-items) {
|
|
|
131
131
|
inset: 0;
|
|
132
132
|
height: 100dvh;
|
|
133
133
|
width: 100%;
|
|
134
|
-
background: var(--
|
|
135
|
-
color: var(--
|
|
134
|
+
background: var(--color-bg-surface);
|
|
135
|
+
color: var(--color-text-surface);
|
|
136
136
|
opacity: 0;
|
|
137
137
|
translate: -100%;
|
|
138
138
|
transition-timing-function: var(--interact-easing, ease);
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
border: var(--_b);
|
|
19
19
|
border-radius: var(--_br);
|
|
20
20
|
box-shadow: var(--_ds);
|
|
21
|
-
background: var(--
|
|
22
|
-
color: var(--
|
|
21
|
+
background: var(--color-bg-surface);
|
|
22
|
+
color: var(--color-text-surface);
|
|
23
23
|
animation: notification-enter 0.3s ease;
|
|
24
24
|
|
|
25
25
|
&.notification--exiting {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
inset-block-end: 0;
|
|
78
78
|
inset-inline: 0;
|
|
79
79
|
block-size: 3px;
|
|
80
|
-
background: var(--brand-primary-solid);
|
|
80
|
+
background: var(--color-bg-brand-primary-solid);
|
|
81
81
|
border-radius: 0 0 var(--_br) var(--_br);
|
|
82
82
|
transform-origin: left;
|
|
83
83
|
animation: notification-progress var(--notification-duration, 5s) linear forwards;
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
|
|
124
124
|
.scroll-progress__bar {
|
|
125
125
|
block-size: 100%;
|
|
126
|
-
background: var(--scroll-progress-color, var(--brand-primary-solid));
|
|
126
|
+
background: var(--scroll-progress-color, var(--color-bg-brand-primary-solid));
|
|
127
127
|
transform-origin: left;
|
|
128
128
|
animation: scroll-progress-grow linear;
|
|
129
129
|
animation-timeline: scroll(root);
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
(deferred.ts) on engines without `scroll-target-group` support. */
|
|
19
19
|
.scroll-target-group a:target-current,
|
|
20
20
|
.scroll-target-group a.is-current {
|
|
21
|
-
color: var(--scroll-target-active-color, var(--brand-primary-solid));
|
|
21
|
+
color: var(--scroll-target-active-color, var(--color-bg-brand-primary-solid));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
.scroll-target-group--indicator a {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
.scroll-target-group--bar a:target-current::before,
|
|
48
48
|
.scroll-target-group--indicator a.is-current::before,
|
|
49
49
|
.scroll-target-group--bar a.is-current::before {
|
|
50
|
-
background-color: var(--scroll-target-active-color, var(--brand-primary-solid));
|
|
50
|
+
background-color: var(--scroll-target-active-color, var(--color-bg-brand-primary-solid));
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
.scroll-target-group--bar a {
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
|
|
108
108
|
.toc-sidebar a:target-current,
|
|
109
109
|
.toc-sidebar a.is-current {
|
|
110
|
-
color: var(--scroll-target-active-color, var(--brand-primary-solid));
|
|
110
|
+
color: var(--scroll-target-active-color, var(--color-bg-brand-primary-solid));
|
|
111
111
|
font-weight: 500;
|
|
112
112
|
}
|
|
113
113
|
|
package/css/patterns/sitenav.css
CHANGED
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
border-radius: var(--br-control, 0.375rem);
|
|
48
48
|
|
|
49
49
|
&:hover {
|
|
50
|
-
background: var(--color-surface-muted);
|
|
50
|
+
background: var(--color-bg-surface-muted);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
&:focus-visible {
|
|
54
|
-
outline: 2px solid var(--sitenav-focus-color, var(--color-
|
|
54
|
+
outline: 2px solid var(--sitenav-focus-color, var(--color-border-focus));
|
|
55
55
|
outline-offset: 2px;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
max-inline-size: 100dvw;
|
|
74
74
|
padding: 1.5rem;
|
|
75
75
|
padding-block-start: 3.5rem; /* clearance for the close button */
|
|
76
|
-
background: var(--
|
|
77
|
-
color: var(--
|
|
76
|
+
background: var(--color-bg-surface);
|
|
77
|
+
color: var(--color-text-surface);
|
|
78
78
|
border: none;
|
|
79
79
|
box-shadow: var(--ds-panel);
|
|
80
80
|
overflow-y: auto;
|
|
@@ -149,11 +149,11 @@
|
|
|
149
149
|
border-radius: var(--br-control, 0.375rem);
|
|
150
150
|
|
|
151
151
|
&:hover {
|
|
152
|
-
background: var(--color-surface-muted);
|
|
152
|
+
background: var(--color-bg-surface-muted);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
&:focus-visible {
|
|
156
|
-
outline: 2px solid var(--sitenav-focus-color, var(--color-
|
|
156
|
+
outline: 2px solid var(--sitenav-focus-color, var(--color-border-focus));
|
|
157
157
|
outline-offset: 2px;
|
|
158
158
|
}
|
|
159
159
|
}
|
|
@@ -280,8 +280,8 @@
|
|
|
280
280
|
min-inline-size: 13rem;
|
|
281
281
|
padding: 0.5rem;
|
|
282
282
|
overflow: visible;
|
|
283
|
-
background: var(--
|
|
284
|
-
color: var(--
|
|
283
|
+
background: var(--color-bg-surface);
|
|
284
|
+
color: var(--color-text-surface);
|
|
285
285
|
border: var(--b-panel);
|
|
286
286
|
border-radius: var(--br-panel);
|
|
287
287
|
box-shadow: var(--ds-panel);
|
|
@@ -366,8 +366,8 @@
|
|
|
366
366
|
min-inline-size: 13rem;
|
|
367
367
|
padding: 0.5rem;
|
|
368
368
|
overflow: visible;
|
|
369
|
-
background: var(--
|
|
370
|
-
color: var(--
|
|
369
|
+
background: var(--color-bg-surface);
|
|
370
|
+
color: var(--color-text-surface);
|
|
371
371
|
border: var(--b-panel);
|
|
372
372
|
border-radius: var(--br-panel);
|
|
373
373
|
box-shadow: var(--ds-panel);
|
|
@@ -453,8 +453,8 @@
|
|
|
453
453
|
min-inline-size: 13rem;
|
|
454
454
|
padding: 0.5rem;
|
|
455
455
|
overflow: visible;
|
|
456
|
-
background: var(--
|
|
457
|
-
color: var(--
|
|
456
|
+
background: var(--color-bg-surface);
|
|
457
|
+
color: var(--color-text-surface);
|
|
458
458
|
border: var(--b-panel);
|
|
459
459
|
border-radius: var(--br-panel);
|
|
460
460
|
box-shadow: var(--ds-panel);
|
|
@@ -540,8 +540,8 @@
|
|
|
540
540
|
min-inline-size: 13rem;
|
|
541
541
|
padding: 0.5rem;
|
|
542
542
|
overflow: visible;
|
|
543
|
-
background: var(--
|
|
544
|
-
color: var(--
|
|
543
|
+
background: var(--color-bg-surface);
|
|
544
|
+
color: var(--color-text-surface);
|
|
545
545
|
border: var(--b-panel);
|
|
546
546
|
border-radius: var(--br-panel);
|
|
547
547
|
box-shadow: var(--ds-panel);
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
transition: background-color 0.15s ease;
|
|
39
39
|
|
|
40
40
|
&:hover {
|
|
41
|
-
background: var(--color-surface-muted);
|
|
41
|
+
background: var(--color-bg-surface-muted);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
&:focus-visible {
|
|
45
|
-
outline: 2px solid var(--split-link-focus-color, var(--color-
|
|
45
|
+
outline: 2px solid var(--split-link-focus-color, var(--color-border-focus));
|
|
46
46
|
outline-offset: 2px;
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
border: var(--_b);
|
|
72
72
|
border-radius: var(--_br);
|
|
73
73
|
box-shadow: var(--_ds);
|
|
74
|
-
background: var(--
|
|
75
|
-
color: var(--
|
|
74
|
+
background: var(--color-bg-surface);
|
|
75
|
+
color: var(--color-text-surface);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/* Top-layer popover: anchored + placed via position-area. */
|
package/css/patterns/tag.css
CHANGED
|
@@ -225,7 +225,7 @@
|
|
|
225
225
|
|
|
226
226
|
/* ── Highlight sweep ──────────────────────────────────────────────────────── */
|
|
227
227
|
.text-highlight {
|
|
228
|
-
--_highlight-color: var(--text-highlight-color, var(--color-warning-muted));
|
|
228
|
+
--_highlight-color: var(--text-highlight-color, var(--color-bg-warning-muted));
|
|
229
229
|
--_highlight-duration: var(--text-highlight-duration, 0.5s);
|
|
230
230
|
--_highlight-pad-block: var(--text-highlight-pad-block, 0.1em);
|
|
231
231
|
--_highlight-pad-inline: var(--text-highlight-pad-inline, 0);
|
|
@@ -64,7 +64,7 @@ wc-theme-editor {
|
|
|
64
64
|
overflow: hidden;
|
|
65
65
|
font-family: var(--font-mono, monospace);
|
|
66
66
|
font-size: 0.9em;
|
|
67
|
-
color: var(--
|
|
67
|
+
color: var(--color-text-surface-x-muted);
|
|
68
68
|
text-overflow: ellipsis;
|
|
69
69
|
white-space: nowrap;
|
|
70
70
|
}
|
|
@@ -74,7 +74,7 @@ wc-theme-editor {
|
|
|
74
74
|
padding: 0.3em 0.5em;
|
|
75
75
|
border: var(--b-default);
|
|
76
76
|
border-radius: var(--br-default);
|
|
77
|
-
background: var(--
|
|
77
|
+
background: var(--color-bg-surface);
|
|
78
78
|
color: inherit;
|
|
79
79
|
font: inherit;
|
|
80
80
|
}
|
|
@@ -107,16 +107,16 @@ wc-theme-editor {
|
|
|
107
107
|
inset-block-start: 0;
|
|
108
108
|
z-index: 1;
|
|
109
109
|
padding-block: 0.5rem;
|
|
110
|
-
background: var(--
|
|
110
|
+
background: var(--color-bg-surface);
|
|
111
111
|
}
|
|
112
112
|
.ed-segwrap {
|
|
113
113
|
display: inline-flex;
|
|
114
114
|
}
|
|
115
115
|
.ed-seg.is-active {
|
|
116
|
-
background: var(--ui-primary-solid);
|
|
117
|
-
color: var(--
|
|
116
|
+
background: var(--color-bg-ui-primary-solid);
|
|
117
|
+
color: var(--color-text-on-ui-primary);
|
|
118
118
|
}
|
|
119
119
|
.ed-danger {
|
|
120
|
-
color: var(--
|
|
120
|
+
color: var(--color-text-danger);
|
|
121
121
|
}
|
|
122
122
|
}
|
package/css/patterns/tooltip.css
CHANGED
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
padding: var(--_p);
|
|
45
45
|
border-radius: var(--_br);
|
|
46
46
|
box-shadow: var(--_ds);
|
|
47
|
-
background: var(--
|
|
48
|
-
color: var(--
|
|
47
|
+
background: var(--color-text-surface);
|
|
48
|
+
color: var(--color-bg-surface);
|
|
49
49
|
font-size: var(--_fs);
|
|
50
50
|
white-space: nowrap;
|
|
51
51
|
max-inline-size: 20rem;
|
package/css/patterns/tree.css
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
.tree__item > .tree {
|
|
19
19
|
margin-inline-start: var(--tree-indent, 1.5rem);
|
|
20
20
|
padding-inline-start: var(--tree-indent, 1.5rem);
|
|
21
|
-
border-inline-start: 1px solid var(--color-surface-muted);
|
|
21
|
+
border-inline-start: 1px solid var(--color-bg-surface-muted);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
.tree__content,
|
|
@@ -115,8 +115,8 @@
|
|
|
115
115
|
inset-block-start: 0;
|
|
116
116
|
block-size: 1rem;
|
|
117
117
|
inline-size: calc(var(--tree-indent, 1.5rem) - 0.5rem);
|
|
118
|
-
border-inline-start: 1px solid var(--color-surface-muted);
|
|
119
|
-
border-block-end: 1px solid var(--color-surface-muted);
|
|
118
|
+
border-inline-start: 1px solid var(--color-bg-surface-muted);
|
|
119
|
+
border-block-end: 1px solid var(--color-bg-surface-muted);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
package/dist/editor.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=`vitops:ds-overrides`,t=`/__vitops/design-system`,n=(e,t)=>t.startsWith(`
|
|
2
|
-
`)}\n}\n`:``}serializeCSS(){return this.block(`:root`,this.store.light)+this.block(`:root[data-brx-theme="dark"], :root[data-theme="dark"]`,this.store.dark)}render(){this.styleEl&&(this.styleEl.textContent=this.serializeCSS())}persist(){try{localStorage.setItem(e,JSON.stringify({light:[...this.store.light],dark:[...this.store.dark],roles:[...this.roles]}))}catch{}}hydrate(){try{let t=localStorage.getItem(e);if(!t)return;let n=JSON.parse(t);this.store.light=new Map(n.light??[]),this.store.dark=new Map(n.dark??[]),this.roles=new Map(n.roles??[]);for(let[e,t]of this.roles)this.markRoleVars(e,t)}catch{}}setOverride(e,t,n){let r=this.store[n];t==null||t===``?r.delete(e):r.set(e,t),this.render(),this.persist()}effective(e,t,n){return this.store[t].has(e)?this.store[t].get(e):t===`dark`&&this.store.light.has(e)?this.store.light.get(e):n}reset(){this.store.light.clear(),this.store.dark.clear(),this.roles.clear(),this.roleVars.clear(),this.render(),this.persist(),this.syncers.forEach(e=>e())}currentScheme(){let e=document.documentElement;return e.dataset.theme===`dark`||e.getAttribute(`data-brx-theme`)===`dark`?`dark`:`light`}setScheme(e){this.scheme=e,document.documentElement.dataset.theme=e,document.documentElement.style.colorScheme=`${e} only`;try{localStorage.setItem(`vitops-color-scheme`,e)}catch{}this.syncers.forEach(e=>e())}roleTokenNames(e,t,r){let i=t===`surface`?`surface`:`default`,a=e.colors.roleTokens?.[r]?.[i];if(!a)return[];let o=[];for(let e of[`light`,`dark`])for(let[r,i]of Object.entries(a[e]))o.push([n(t,r),i,e]);return o}markRoleVars(e,t){if(this.manifest)for(let[n]of this.roleTokenNames(this.manifest,e,t))this.roleVars.add(n)}remapRole(e,t,n){let r=this.roleTokenNames(e,t,n);if(r.length){this.roles.set(t,n);for(let[e,t,n]of r)this.roleVars.add(e),this.store[n].set(e,t);this.render(),this.persist()}}deepSet(e,t,n){let r=t.split(`.`),i=e;for(let e=0;e<r.length-1;e++){let t=r[e];(typeof i[t]!=`object`||i[t]==null)&&(i[t]={}),i=i[t]}i[r[r.length-1]]=n}buildPatch(e){let t={},n=[];for(let[e,n]of this.roles)this.deepSet(t,`colors.roles.${e}`,n);for(let[r,i]of this.store.light){if(this.roleVars.has(r))continue;let a=e.reverseIndex[r];a?this.deepSet(t,a,i):n.push(r)}for(let e of this.store.dark.keys())this.roleVars.has(e)||n.push(`${e} (dark)`);return{patch:t,skipped:n}}el(e,t={},n=[]){let r=document.createElement(e),i=r;for(let[e,n]of Object.entries(t))n===!0?i.setAttribute(e,``):n!==!1&&i.setAttribute(e,String(n));for(let e of n)i.append(e);return r}row(e,t,n){return this.syncers.add(n),n(),this.el(`label`,{class:`ed-row`},[this.el(`span`,{class:`ed-label`,title:e},[e.replace(/^--/,``)]),t])}textInput(e,t,n=``){let r=this.el(`input`,{type:`text`,class:`ed-input`});return r.addEventListener(`input`,()=>this.setOverride(e,r.value.trim()||null,this.scheme)),this.row(e,r,()=>{r.value=this.store[this.scheme].get(e)??``,r.placeholder=n||t})}colorInput(e,t){let n=this.el(`input`,{type:`color`,class:`ed-color`}),r=this.el(`input`,{type:`text`,class:`ed-input ed-mono`}),i=t=>this.setOverride(e,t||null,`light`);n.addEventListener(`input`,()=>{r.value=n.value,i(n.value)}),r.addEventListener(`input`,()=>{/^#[0-9a-f]{6}$/i.test(r.value)&&(n.value=r.value),i(r.value.trim())});let a=this.el(`span`,{class:`ed-pair`},[n,r]);return this.row(e,a,()=>{let i=this.store.light.get(e)??t;r.value=i,/^#[0-9a-f]{6}$/i.test(i)&&(n.value=i)})}selectInput(e,t){let n=this.el(`select`,{class:`ed-input`});n.append(this.el(`option`,{value:``},[`— default —`]));for(let e of t)n.append(this.el(`option`,{value:e.value},[e.label]));return n.addEventListener(`change`,()=>this.setOverride(e,n.value||null,this.scheme)),this.row(e,n,()=>{n.value=this.store[this.scheme].get(e)??``})}remSlider(e,t){let n=parseFloat(t)||1,r=this.el(`input`,{type:`range`,class:`ed-range`,min:`0`,max:String(Math.max(4,Math.ceil(n*2))),step:`0.05`}),i=this.el(`output`,{class:`ed-out`});r.addEventListener(`input`,()=>{i.textContent=`${r.value}rem`,this.setOverride(e,`${r.value}rem`,this.scheme)});let a=this.el(`span`,{class:`ed-pair`},[r,i]);return this.row(e,a,()=>{r.value=String(parseFloat(this.effective(e,this.scheme,t))||n),i.textContent=this.store[this.scheme].get(e)??`auto`})}slider(e,t){let n=t.toValue??(e=>`${e}${t.unit??``}`),r=t.fromValue??(e=>Number.isNaN(parseFloat(e))?t.def:parseFloat(e)),i=this.el(`input`,{type:`range`,class:`ed-range`,min:String(t.min),max:String(t.max),step:String(t.step)}),a=this.el(`output`,{class:`ed-out`});i.addEventListener(`input`,()=>{let t=n(parseFloat(i.value));a.textContent=t,this.setOverride(e,t,this.scheme)});let o=this.el(`span`,{class:`ed-pair`},[i,a]);return this.row(e,o,()=>{let n=this.store[this.scheme].get(e);i.value=String(n==null?t.def:r(n)),a.textContent=n??`${t.def}${t.unit??``}`})}section(e,t=!1){let n=this.el(`div`,{class:`ed-body rhythm`});return{details:this.el(`details`,{class:`details details--marker-start ed-section`,...t?{open:!0}:{}},[this.el(`summary`,{class:`font-eyebrow`},[this.el(`span`,{class:`details-icon`,"aria-hidden":`true`},[`▸`]),e]),n]),body:n}}hint(e){return this.el(`p`,{class:`font-footnote text-surface-x-muted`},[e])}sub(e){let t=this.section(e);return t.details.classList.add(`ed-sub`),t}buildPalette(e){let{details:t,body:n}=this.section(`Palette`,!0);n.append(this.hint(`Hues feed the semantic roles below — edit a hue and every role mapped to it follows. Hue edits are scheme-global: dark mode re-points which step a token reads, it never redefines the hue itself.`));for(let t of e.colors.ramps){let i=this.sub(t);for(let n of e.colors.steps){let a=e.colors.palette[t]?.[n];a!=null&&i.body.append(this.colorInput(r(t,n),a))}n.append(i.details)}return n.append(this.buildRoles(e)),t}buildRoles(e){let{details:t,body:n}=this.sub(`Semantic roles`);n.append(this.hint(`Point a role at another hue — its whole functional token set (bg / border / solid / on-solid / text) is rewritten for both appearances.`));let r=e.colors.ramps;for(let{name:t,ramp:i}of e.colors.roles){let a=this.el(`select`,{class:`ed-input`});for(let e of r)a.append(this.el(`option`,{value:e},[e]));a.addEventListener(`change`,()=>this.remapRole(e,t,a.value)),n.append(this.row(`--${t}`,a,()=>{a.value=this.roles.get(t)??i}))}return t}buildTypography(e){let{details:t,body:n}=this.section(`Typography`),r=Object.keys(e.fonts).map(e=>({label:e,value:`var(--font-${e})`})),i=e.scales.text.map(e=>({label:e.name,value:`var(--text-${e.name})`})),a={tt:[`none`,`uppercase`,`lowercase`,`capitalize`],fst:[`normal`,`italic`,`oblique`],td:[`none`,`underline`,`line-through`],tw:[`wrap`,`balance`,`pretty`,`nowrap`]};for(let t of e.typography.roles){let o=e.typography.specs[t]??{},s=this.sub(t);for(let[n,{key:c}]of Object.entries(e.typography.hooks)){let e=`--${t}-${n}`,l=o[c]==null?``:String(o[c]);n===`ff`?s.body.append(this.selectInput(e,r)):n===`fs`?s.body.append(this.selectInput(e,i)):a[n]?s.body.append(this.selectInput(e,a[n].map(e=>({label:e,value:e})))):s.body.append(this.textInput(e,l,l||c))}n.append(s.details)}return t}buildSpacing(e){let{details:t,body:n}=this.section(`Spacing`);n.append(this.hint(`Each step overrides to a fixed rem (dropping the fluid clamp). Reset restores it.`));for(let t of e.scales.space)n.append(this.remSlider(`--space-${t.name}`,t.max));return t}buildLayout(){let{details:e,body:t}=this.section(`Layout`);return t.append(this.hint(`Vertical rhythm and the .centered track widths — global structure.`)),t.append(this.slider(`--rhythm-scale`,{min:.5,max:2.5,step:.05,def:1}),this.slider(`--width-measure`,{min:30,max:110,step:1,def:65,unit:`ch`}),this.slider(`--width-breakout`,{min:40,max:150,step:1,def:90,unit:`ch`}),this.slider(`--width-spotlight`,{min:60,max:200,step:1,def:120,unit:`ch`}),this.slider(`--gutter`,{min:0,max:6,step:.1,def:3,toValue:e=>`clamp(1rem, 4cqi, ${e}rem)`,fromValue:e=>{let t=/clamp\([^,]+,[^,]+,\s*([\d.]+)/.exec(e);return t?parseFloat(t[1]):3}})),e}buildPatterns(e){let t=this.section(`Pattern defaults`);for(let[n,r]of Object.entries(e.patterns.defaults))t.body.append(this.textInput(`--${n}-default`,r,r));let n=this.section(`Radii`);for(let[t,r]of Object.entries(e.patterns.radii))n.body.append(this.textInput(`--br-${t}`,r,r));let r=this.section(`Pattern groups`);for(let[t,n]of Object.entries(e.patterns.groups)){let e=this.sub(t);for(let[r,i]of Object.entries(n))e.body.append(this.textInput(`--${r}-${t}`,i,i));r.body.append(e.details)}let i=this.section(`Components`);i.body.append(this.hint(`Per-component geometry — overrides the group defaults for just this component.`));for(let t of e.patterns.items){if(!t.wrappable.length)continue;let e=this.sub(t.name);for(let{sfx:n,prop:r}of t.wrappable){let i=t.base[r]??``;e.body.append(this.textInput(`--${n}-${t.name}`,i,i))}i.body.append(e.details)}let a=this.section(`Shadows`);for(let[t,n]of Object.entries(e.shadows))a.body.append(this.textInput(`--shadow-${t}`,n,n));return[t.details,n.details,r.details,i.details,a.details]}async flash(e,t){let n=e.textContent;e.textContent=t,setTimeout(()=>e.textContent=n,1400)}async copy(e,t){try{await navigator.clipboard.writeText(e),this.flash(t,`Copied ✓`)}catch{this.flash(t,`Copy failed`)}}async save(e,n){let{patch:r}=this.buildPatch(e);if(!Object.keys(r).length)return void this.flash(n,`Nothing to save`);try{let e=await fetch(t,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({patch:r})});if(!e.ok){let t=await e.json().catch(()=>({}));console.error(`[wc-theme-editor] save rejected`,t.errors??e.statusText),this.flash(n,`Rejected ✗`);return}this.reset(),this.flash(n,`Saved ✓`)}catch(e){console.error(`[wc-theme-editor] save failed`,e),this.flash(n,`Failed ✗`)}}buildToolbar(e){let t=this.el(`div`,{class:`cluster-start ed-toolbar`}),n=this.el(`button`,{type:`button`,class:`btn ed-seg`},[`Light`]),r=this.el(`button`,{type:`button`,class:`btn ed-seg`},[`Dark`]),i=()=>{n.classList.toggle(`is-active`,this.scheme===`light`),r.classList.toggle(`is-active`,this.scheme===`dark`)};this.syncers.add(i),n.addEventListener(`click`,()=>this.setScheme(`light`)),r.addEventListener(`click`,()=>this.setScheme(`dark`)),i(),t.append(this.el(`span`,{class:`ed-segwrap`,role:`group`},[n,r]));let a=this.el(`button`,{type:`button`,class:`btn`},[`Copy CSS`]);a.addEventListener(`click`,()=>this.copy(this.serializeCSS()||`/* no overrides yet */`,a));let o=this.el(`button`,{type:`button`,class:`btn`},[`Copy JSON patch`]);if(o.addEventListener(`click`,()=>{let{patch:t,skipped:n}=this.buildPatch(e),r=n.length?`\n// runtime-only (no source mapping): ${n.join(`, `)}`:``;this.copy(JSON.stringify(t,null,2)+r,o)}),t.append(a,o),this.canSave){let n=this.el(`button`,{type:`button`,class:`cta`},[`Save to source`]);n.addEventListener(`click`,()=>void this.save(e,n)),t.append(n)}let s=this.el(`button`,{type:`button`,class:`btn ed-danger`},[`Reset all`]);return s.addEventListener(`click`,()=>this.reset()),t.append(s),t}build(e){let t=`ds-editor-panel`,n=this.el(`div`,{id:t,popover:`manual`,class:`drawer drawer--right drawer--modeless ed-panel bg-surface text-surface rhythm`,"aria-label":`Design-system editor`});n.append(this.el(`header`,{class:`cluster-between`},[this.el(`strong`,{class:`font-heading`},[`Theme editor`]),(()=>{let e=this.el(`button`,{type:`button`,class:`btn`,popovertarget:t,popovertargetaction:`hide`},[`×`]);return e.setAttribute(`aria-label`,`Close editor`),e})()]),this.buildToolbar(e),this.buildPalette(e),this.buildTypography(e),this.buildSpacing(e),this.buildLayout(),...this.buildPatterns(e));let r=this.el(`button`,{type:`button`,class:`cta ed-launch`,popovertarget:t},[`🎨 Theme`]);document.addEventListener(`keydown`,e=>{e.key===`Escape`&&n.matches(`:popover-open`)&&n.hidePopover()}),this.append(r,n)}};customElements.get(`wc-theme-editor`)||customElements.define(`wc-theme-editor`,i);
|
|
1
|
+
const e=`vitops:ds-overrides`,t=`/__vitops/design-system`,n=(e,t)=>{let n=t.indexOf(`-`),r=n===-1?t:t.slice(0,n),i=n===-1?``:t.slice(n+1);return i===`on`?`--color-${r}-on-${e}`:i.startsWith(`on-`)?`--color-${r}-on-${e}-${i.slice(3)}`:i?`--color-${r}-${e}-${i}`:`--color-${r}-${e}`},r=(e,t)=>`--color-${e}-${t}`;var i=class extends HTMLElement{constructor(...e){super(...e),this.store={light:new Map,dark:new Map},this.roles=new Map,this.roleVars=new Set,this.syncers=new Set,this.scheme=`light`,this.canSave=!1}static{this.observedAttributes=[`manifest`]}connectedCallback(){this.boot()}async boot(){let e=this.getAttribute(`manifest`)??`/vitops/design-manifest.json`;try{let t=await fetch(e);if(!t.ok)throw Error(`manifest ${t.status}`);this.manifest=await t.json()}catch(t){console.warn(`[wc-theme-editor] manifest unavailable at ${e} — editor disabled`,t);return}this.styleEl=document.createElement(`style`),this.styleEl.id=`ds-overrides`,document.head.append(this.styleEl),this.hydrate(),this.render(),this.scheme=this.currentScheme(),new MutationObserver(()=>{let e=this.currentScheme();e!==this.scheme&&(this.scheme=e,this.syncers.forEach(e=>e()))}).observe(document.documentElement,{attributes:!0,attributeFilter:[`data-theme`]}),this.canSave=await this.probeSave(),this.build(this.manifest)}async probeSave(){try{let e=await fetch(t);return e.ok?(await e.json()).writable===!0:!1}catch{return!1}}block(e,t){return t.size?`${e} {\n${[...t].map(([e,t])=>` ${e}: ${t};`).join(`
|
|
2
|
+
`)}\n}\n`:``}serializeCSS(){return this.block(`:root`,this.store.light)+this.block(`:root[data-brx-theme="dark"], :root[data-theme="dark"]`,this.store.dark)}render(){this.styleEl&&(this.styleEl.textContent=this.serializeCSS())}persist(){try{localStorage.setItem(e,JSON.stringify({light:[...this.store.light],dark:[...this.store.dark],roles:[...this.roles]}))}catch{}}hydrate(){try{let t=localStorage.getItem(e);if(!t)return;let n=JSON.parse(t);this.store.light=new Map(n.light??[]),this.store.dark=new Map(n.dark??[]),this.roles=new Map(n.roles??[]);for(let[e,t]of this.roles)this.markRoleVars(e,t)}catch{}}setOverride(e,t,n){let r=this.store[n];t==null||t===``?r.delete(e):r.set(e,t),this.render(),this.persist()}effective(e,t,n){return this.store[t].has(e)?this.store[t].get(e):t===`dark`&&this.store.light.has(e)?this.store.light.get(e):n}reset(){this.store.light.clear(),this.store.dark.clear(),this.roles.clear(),this.roleVars.clear(),this.render(),this.persist(),this.syncers.forEach(e=>e())}currentScheme(){let e=document.documentElement;return e.dataset.theme===`dark`||e.getAttribute(`data-brx-theme`)===`dark`?`dark`:`light`}setScheme(e){this.scheme=e,document.documentElement.dataset.theme=e,document.documentElement.style.colorScheme=`${e} only`;try{localStorage.setItem(`vitops-color-scheme`,e)}catch{}this.syncers.forEach(e=>e())}roleTokenNames(e,t,r){let i=e.colors.roles.find(e=>e.name===t)?.kind??`chromatic`,a=e.colors.roleTokens?.[r]?.[i];if(!a)return[];let o=[];for(let e of[`light`,`dark`])for(let[r,i]of Object.entries(a[e]))o.push([n(t,r),i,e]);return o}markRoleVars(e,t){if(this.manifest)for(let[n]of this.roleTokenNames(this.manifest,e,t))this.roleVars.add(n)}remapRole(e,t,n){let r=this.roleTokenNames(e,t,n);if(r.length){this.roles.set(t,n);for(let[e,t,n]of r)this.roleVars.add(e),this.store[n].set(e,t);this.render(),this.persist()}}deepSet(e,t,n){let r=t.split(`.`),i=e;for(let e=0;e<r.length-1;e++){let t=r[e];(typeof i[t]!=`object`||i[t]==null)&&(i[t]={}),i=i[t]}i[r[r.length-1]]=n}buildPatch(e){let t={},n=[];for(let[n,r]of this.roles){let i=e.colors.roles.find(e=>e.name===n)?.kind??`chromatic`;this.deepSet(t,`colors.roles.${n}`,{hue:r,kind:i})}for(let[r,i]of this.store.light){if(this.roleVars.has(r))continue;let a=e.reverseIndex[r];a?this.deepSet(t,a,i):n.push(r)}for(let e of this.store.dark.keys())this.roleVars.has(e)||n.push(`${e} (dark)`);return{patch:t,skipped:n}}el(e,t={},n=[]){let r=document.createElement(e),i=r;for(let[e,n]of Object.entries(t))n===!0?i.setAttribute(e,``):n!==!1&&i.setAttribute(e,String(n));for(let e of n)i.append(e);return r}row(e,t,n){return this.syncers.add(n),n(),this.el(`label`,{class:`ed-row`},[this.el(`span`,{class:`ed-label`,title:e},[e.replace(/^--/,``)]),t])}textInput(e,t,n=``){let r=this.el(`input`,{type:`text`,class:`ed-input`});return r.addEventListener(`input`,()=>this.setOverride(e,r.value.trim()||null,this.scheme)),this.row(e,r,()=>{r.value=this.store[this.scheme].get(e)??``,r.placeholder=n||t})}colorInput(e,t){let n=this.el(`input`,{type:`color`,class:`ed-color`}),r=this.el(`input`,{type:`text`,class:`ed-input ed-mono`}),i=t=>this.setOverride(e,t||null,`light`);n.addEventListener(`input`,()=>{r.value=n.value,i(n.value)}),r.addEventListener(`input`,()=>{/^#[0-9a-f]{6}$/i.test(r.value)&&(n.value=r.value),i(r.value.trim())});let a=this.el(`span`,{class:`ed-pair`},[n,r]);return this.row(e,a,()=>{let i=this.store.light.get(e)??t;r.value=i,/^#[0-9a-f]{6}$/i.test(i)&&(n.value=i)})}selectInput(e,t){let n=this.el(`select`,{class:`ed-input`});n.append(this.el(`option`,{value:``},[`— default —`]));for(let e of t)n.append(this.el(`option`,{value:e.value},[e.label]));return n.addEventListener(`change`,()=>this.setOverride(e,n.value||null,this.scheme)),this.row(e,n,()=>{n.value=this.store[this.scheme].get(e)??``})}remSlider(e,t){let n=parseFloat(t)||1,r=this.el(`input`,{type:`range`,class:`ed-range`,min:`0`,max:String(Math.max(4,Math.ceil(n*2))),step:`0.05`}),i=this.el(`output`,{class:`ed-out`});r.addEventListener(`input`,()=>{i.textContent=`${r.value}rem`,this.setOverride(e,`${r.value}rem`,this.scheme)});let a=this.el(`span`,{class:`ed-pair`},[r,i]);return this.row(e,a,()=>{r.value=String(parseFloat(this.effective(e,this.scheme,t))||n),i.textContent=this.store[this.scheme].get(e)??`auto`})}slider(e,t){let n=t.toValue??(e=>`${e}${t.unit??``}`),r=t.fromValue??(e=>Number.isNaN(parseFloat(e))?t.def:parseFloat(e)),i=this.el(`input`,{type:`range`,class:`ed-range`,min:String(t.min),max:String(t.max),step:String(t.step)}),a=this.el(`output`,{class:`ed-out`});i.addEventListener(`input`,()=>{let t=n(parseFloat(i.value));a.textContent=t,this.setOverride(e,t,this.scheme)});let o=this.el(`span`,{class:`ed-pair`},[i,a]);return this.row(e,o,()=>{let n=this.store[this.scheme].get(e);i.value=String(n==null?t.def:r(n)),a.textContent=n??`${t.def}${t.unit??``}`})}section(e,t=!1){let n=this.el(`div`,{class:`ed-body rhythm`});return{details:this.el(`details`,{class:`details details--marker-start ed-section`,...t?{open:!0}:{}},[this.el(`summary`,{class:`font-eyebrow`},[this.el(`span`,{class:`details-icon`,"aria-hidden":`true`},[`▸`]),e]),n]),body:n}}hint(e){return this.el(`p`,{class:`font-footnote text-surface-x-muted`},[e])}sub(e){let t=this.section(e);return t.details.classList.add(`ed-sub`),t}buildPalette(e){let{details:t,body:n}=this.section(`Palette`,!0);n.append(this.hint(`Hues feed the semantic roles below — edit a hue and every role mapped to it follows. Hue edits are scheme-global: dark mode re-points which step a token reads, it never redefines the hue itself.`));for(let t of e.colors.ramps){let i=this.sub(t);for(let n of e.colors.steps){let a=e.colors.palette[t]?.[n];a!=null&&i.body.append(this.colorInput(r(t,n),a))}n.append(i.details)}return n.append(this.buildRoles(e)),t}buildRoles(e){let{details:t,body:n}=this.sub(`Semantic roles`);n.append(this.hint(`Point a role at another hue — its whole functional token set (bg / border / solid / on-solid / text) is rewritten for both appearances.`));let r=e.colors.ramps;for(let{name:t,ramp:i}of e.colors.roles){let a=this.el(`select`,{class:`ed-input`});for(let e of r)a.append(this.el(`option`,{value:e},[e]));a.addEventListener(`change`,()=>this.remapRole(e,t,a.value)),n.append(this.row(`--${t}`,a,()=>{a.value=this.roles.get(t)??i}))}return t}buildTypography(e){let{details:t,body:n}=this.section(`Typography`),r=Object.keys(e.fonts).map(e=>({label:e,value:`var(--font-${e})`})),i=e.scales.text.map(e=>({label:e.name,value:`var(--text-${e.name})`})),a={tt:[`none`,`uppercase`,`lowercase`,`capitalize`],fst:[`normal`,`italic`,`oblique`],td:[`none`,`underline`,`line-through`],tw:[`wrap`,`balance`,`pretty`,`nowrap`]};for(let t of e.typography.roles){let o=e.typography.specs[t]??{},s=this.sub(t);for(let[n,{key:c}]of Object.entries(e.typography.hooks)){let e=`--${t}-${n}`,l=o[c]==null?``:String(o[c]);n===`ff`?s.body.append(this.selectInput(e,r)):n===`fs`?s.body.append(this.selectInput(e,i)):a[n]?s.body.append(this.selectInput(e,a[n].map(e=>({label:e,value:e})))):s.body.append(this.textInput(e,l,l||c))}n.append(s.details)}return t}buildSpacing(e){let{details:t,body:n}=this.section(`Spacing`);n.append(this.hint(`Each step overrides to a fixed rem (dropping the fluid clamp). Reset restores it.`));for(let t of e.scales.space)n.append(this.remSlider(`--space-${t.name}`,t.max));return t}buildLayout(){let{details:e,body:t}=this.section(`Layout`);return t.append(this.hint(`Vertical rhythm and the .centered track widths — global structure.`)),t.append(this.slider(`--rhythm-scale`,{min:.5,max:2.5,step:.05,def:1}),this.slider(`--width-measure`,{min:30,max:110,step:1,def:65,unit:`ch`}),this.slider(`--width-breakout`,{min:40,max:150,step:1,def:90,unit:`ch`}),this.slider(`--width-spotlight`,{min:60,max:200,step:1,def:120,unit:`ch`}),this.slider(`--gutter`,{min:0,max:6,step:.1,def:3,toValue:e=>`clamp(1rem, 4cqi, ${e}rem)`,fromValue:e=>{let t=/clamp\([^,]+,[^,]+,\s*([\d.]+)/.exec(e);return t?parseFloat(t[1]):3}})),e}buildPatterns(e){let t=this.section(`Pattern defaults`);for(let[n,r]of Object.entries(e.patterns.defaults))t.body.append(this.textInput(`--${n}-default`,r,r));let n=this.section(`Radii`);for(let[t,r]of Object.entries(e.patterns.radii))n.body.append(this.textInput(`--br-${t}`,r,r));let r=this.section(`Pattern groups`);for(let[t,n]of Object.entries(e.patterns.groups)){let e=this.sub(t);for(let[r,i]of Object.entries(n))e.body.append(this.textInput(`--${r}-${t}`,i,i));r.body.append(e.details)}let i=this.section(`Components`);i.body.append(this.hint(`Per-component geometry — overrides the group defaults for just this component.`));for(let t of e.patterns.items){if(!t.wrappable.length)continue;let e=this.sub(t.name);for(let{sfx:n,prop:r}of t.wrappable){let i=t.base[r]??``;e.body.append(this.textInput(`--${n}-${t.name}`,i,i))}i.body.append(e.details)}let a=this.section(`Shadows`);for(let[t,n]of Object.entries(e.shadows))a.body.append(this.textInput(`--shadow-${t}`,n,n));return[t.details,n.details,r.details,i.details,a.details]}async flash(e,t){let n=e.textContent;e.textContent=t,setTimeout(()=>e.textContent=n,1400)}async copy(e,t){try{await navigator.clipboard.writeText(e),this.flash(t,`Copied ✓`)}catch{this.flash(t,`Copy failed`)}}async save(e,n){let{patch:r}=this.buildPatch(e);if(!Object.keys(r).length)return void this.flash(n,`Nothing to save`);try{let e=await fetch(t,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({patch:r})});if(!e.ok){let t=await e.json().catch(()=>({}));console.error(`[wc-theme-editor] save rejected`,t.errors??e.statusText),this.flash(n,`Rejected ✗`);return}this.reset(),this.flash(n,`Saved ✓`)}catch(e){console.error(`[wc-theme-editor] save failed`,e),this.flash(n,`Failed ✗`)}}buildToolbar(e){let t=this.el(`div`,{class:`cluster-start ed-toolbar`}),n=this.el(`button`,{type:`button`,class:`btn ed-seg`},[`Light`]),r=this.el(`button`,{type:`button`,class:`btn ed-seg`},[`Dark`]),i=()=>{n.classList.toggle(`is-active`,this.scheme===`light`),r.classList.toggle(`is-active`,this.scheme===`dark`)};this.syncers.add(i),n.addEventListener(`click`,()=>this.setScheme(`light`)),r.addEventListener(`click`,()=>this.setScheme(`dark`)),i(),t.append(this.el(`span`,{class:`ed-segwrap`,role:`group`},[n,r]));let a=this.el(`button`,{type:`button`,class:`btn`},[`Copy CSS`]);a.addEventListener(`click`,()=>this.copy(this.serializeCSS()||`/* no overrides yet */`,a));let o=this.el(`button`,{type:`button`,class:`btn`},[`Copy JSON patch`]);if(o.addEventListener(`click`,()=>{let{patch:t,skipped:n}=this.buildPatch(e),r=n.length?`\n// runtime-only (no source mapping): ${n.join(`, `)}`:``;this.copy(JSON.stringify(t,null,2)+r,o)}),t.append(a,o),this.canSave){let n=this.el(`button`,{type:`button`,class:`cta`},[`Save to source`]);n.addEventListener(`click`,()=>void this.save(e,n)),t.append(n)}let s=this.el(`button`,{type:`button`,class:`btn ed-danger`},[`Reset all`]);return s.addEventListener(`click`,()=>this.reset()),t.append(s),t}build(e){let t=`ds-editor-panel`,n=this.el(`div`,{id:t,popover:`manual`,class:`drawer drawer--right drawer--modeless ed-panel bg-surface text-surface rhythm`,"aria-label":`Design-system editor`});n.append(this.el(`header`,{class:`cluster-between`},[this.el(`strong`,{class:`font-heading`},[`Theme editor`]),(()=>{let e=this.el(`button`,{type:`button`,class:`btn`,popovertarget:t,popovertargetaction:`hide`},[`×`]);return e.setAttribute(`aria-label`,`Close editor`),e})()]),this.buildToolbar(e),this.buildPalette(e),this.buildTypography(e),this.buildSpacing(e),this.buildLayout(),...this.buildPatterns(e));let r=this.el(`button`,{type:`button`,class:`cta ed-launch`,popovertarget:t},[`🎨 Theme`]);document.addEventListener(`keydown`,e=>{e.key===`Escape`&&n.matches(`:popover-open`)&&n.hidePopover()}),this.append(r,n)}};customElements.get(`wc-theme-editor`)||customElements.define(`wc-theme-editor`,i);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getvitops/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "The Vitops design-system framework — CSS partials, Lit web components, and browser polyfills.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -31,6 +31,6 @@
|
|
|
31
31
|
"lit": "^3.3.3",
|
|
32
32
|
"scroll-timeline-polyfill": "^1.1.0",
|
|
33
33
|
"temporal-polyfill": "^1.0.1",
|
|
34
|
-
"@getvitops/utils": "0.
|
|
34
|
+
"@getvitops/utils": "1.0.0"
|
|
35
35
|
}
|
|
36
36
|
}
|