@ponchia/ui 0.4.1 → 0.6.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 +552 -8
- package/MIGRATIONS.json +106 -0
- package/README.md +34 -8
- package/annotations/index.d.ts +402 -0
- package/annotations/index.d.ts.map +1 -0
- package/annotations/index.js +792 -0
- package/behaviors/carousel.js +198 -0
- package/behaviors/combobox.js +226 -0
- package/behaviors/command.js +190 -0
- package/behaviors/connectors.js +95 -0
- package/behaviors/crosshair.js +57 -0
- package/behaviors/dialog.js +74 -0
- package/behaviors/disclosure.js +26 -0
- package/behaviors/dismissible.js +25 -0
- package/behaviors/forms.js +186 -0
- package/behaviors/glyph.js +108 -0
- package/behaviors/index.d.ts +79 -0
- package/behaviors/index.js +18 -1409
- package/behaviors/internal.js +97 -0
- package/behaviors/legend.js +67 -0
- package/behaviors/menu.js +47 -0
- package/behaviors/popover.js +179 -0
- package/behaviors/spotlight.js +52 -0
- package/behaviors/table.js +136 -0
- package/behaviors/tabs.js +103 -0
- package/behaviors/theme.js +84 -0
- package/behaviors/toast.js +164 -0
- package/classes/classes.json +1857 -0
- package/classes/index.d.ts +306 -13
- package/classes/index.js +339 -12
- package/classes/vscode.css-custom-data.json +12 -0
- package/connectors/index.d.ts +191 -0
- package/connectors/index.d.ts.map +1 -0
- package/connectors/index.js +275 -0
- package/css/analytical.css +21 -0
- package/css/annotations.css +292 -0
- package/css/app.css +43 -13
- package/css/base.css +15 -10
- package/css/command.css +97 -0
- package/css/connectors.css +110 -0
- package/css/content.css +7 -1
- package/css/crosshair.css +100 -0
- package/css/dataviz.css +5 -1
- package/css/disclosure.css +38 -6
- package/css/dots.css +57 -0
- package/css/feedback.css +111 -2
- package/css/fonts.css +11 -7
- package/css/forms.css +42 -1
- package/css/generated.css +117 -0
- package/css/legend.css +272 -0
- package/css/marks.css +174 -0
- package/css/motion.css +24 -44
- package/css/navigation.css +7 -0
- package/css/overlay.css +31 -1
- package/css/primitives.css +109 -5
- package/css/report.css +39 -81
- package/css/selection.css +46 -0
- package/css/site.css +16 -2
- package/css/sources.css +221 -0
- package/css/spotlight.css +104 -0
- package/css/state.css +121 -0
- package/css/tokens.css +60 -37
- package/css/workbench.css +83 -0
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -0
- package/dist/css/annotations.css +1 -0
- package/dist/css/app.css +1 -1
- package/dist/css/base.css +1 -1
- package/dist/css/command.css +1 -0
- package/dist/css/connectors.css +1 -0
- package/dist/css/content.css +1 -1
- package/dist/css/crosshair.css +1 -0
- package/dist/css/disclosure.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/fonts.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/generated.css +1 -0
- package/dist/css/legend.css +1 -0
- package/dist/css/marks.css +1 -0
- package/dist/css/motion.css +1 -1
- package/dist/css/navigation.css +1 -1
- package/dist/css/overlay.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/report.css +1 -1
- package/dist/css/selection.css +1 -0
- package/dist/css/site.css +1 -1
- package/dist/css/sources.css +1 -0
- package/dist/css/spotlight.css +1 -0
- package/dist/css/state.css +1 -0
- package/dist/css/tokens.css +1 -1
- package/dist/css/workbench.css +1 -0
- package/docs/adr/0003-theme-model.md +7 -4
- package/docs/annotations.md +425 -0
- package/docs/architecture.md +246 -0
- package/docs/command.md +95 -0
- package/docs/connectors.md +91 -0
- package/docs/contrast.md +116 -92
- package/docs/crosshair.md +63 -0
- package/docs/d2.md +195 -0
- package/docs/generated.md +91 -0
- package/docs/legends.md +184 -0
- package/docs/marks.md +93 -0
- package/docs/mermaid.md +152 -0
- package/docs/reference.md +385 -23
- package/docs/reporting.md +436 -63
- package/docs/selection.md +40 -0
- package/docs/sources.md +137 -0
- package/docs/spotlight.md +78 -0
- package/docs/stability.md +24 -2
- package/docs/state.md +85 -0
- package/docs/usage.md +123 -4
- package/docs/vega.md +225 -0
- package/docs/workbench.md +78 -0
- package/fonts/doto-400.woff2 +0 -0
- package/fonts/doto-500.woff2 +0 -0
- package/fonts/doto-600.woff2 +0 -0
- package/fonts/doto-700.woff2 +0 -0
- package/fonts/doto-800.woff2 +0 -0
- package/fonts/doto-900.woff2 +0 -0
- package/glyphs/glyphs.js +6 -4
- package/llms.txt +362 -14
- package/package.json +115 -12
- package/qwik/index.d.ts +42 -54
- package/qwik/index.d.ts.map +1 -0
- package/qwik/index.js +75 -3
- package/react/index.d.ts +39 -56
- package/react/index.d.ts.map +1 -0
- package/react/index.js +67 -3
- package/solid/index.d.ts +64 -56
- package/solid/index.d.ts.map +1 -0
- package/solid/index.js +70 -3
- package/tokens/d2.d.ts +38 -0
- package/tokens/d2.js +71 -0
- package/tokens/d2.json +43 -0
- package/tokens/index.d.ts +5 -5
- package/tokens/index.js +23 -5
- package/tokens/index.json +9 -0
- package/tokens/mermaid.d.ts +23 -0
- package/tokens/mermaid.js +181 -0
- package/tokens/mermaid.json +163 -0
- package/tokens/resolved.json +45 -1
- package/tokens/skins.js +3 -2
- package/tokens/tokens.dtcg.json +26 -0
- package/tokens/vega.d.ts +34 -0
- package/tokens/vega.js +155 -0
- package/tokens/vega.json +179 -0
- package/fonts/doto-400.ttf +0 -0
- package/fonts/doto-500.ttf +0 -0
- package/fonts/doto-600.ttf +0 -0
- package/fonts/doto-700.ttf +0 -0
- package/fonts/doto-800.ttf +0 -0
- package/fonts/doto-900.ttf +0 -0
package/css/feedback.css
CHANGED
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
block-size: 0.5rem;
|
|
28
28
|
margin-block-start: 0.32rem;
|
|
29
29
|
inline-size: 0.5rem;
|
|
30
|
+
|
|
31
|
+
/* Keep the tone dot when printing (matches the legend swatch). */
|
|
32
|
+
print-color-adjust: exact;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
.ui-alert > * {
|
|
@@ -174,6 +177,9 @@
|
|
|
174
177
|
block-size: 0.5rem;
|
|
175
178
|
margin-block-start: 0.3rem;
|
|
176
179
|
inline-size: 0.5rem;
|
|
180
|
+
|
|
181
|
+
/* Keep the tone dot when printing (matches the legend swatch). */
|
|
182
|
+
print-color-adjust: exact;
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
.ui-toast__title {
|
|
@@ -206,8 +212,27 @@
|
|
|
206
212
|
line-height: 1;
|
|
207
213
|
}
|
|
208
214
|
|
|
209
|
-
|
|
210
|
-
|
|
215
|
+
/* Touch: enlarge the dismiss/close hit areas to the project's coarse-pointer
|
|
216
|
+
tap-target floor (2.9rem, as in primitives.css / forms.css) without changing
|
|
217
|
+
the desktop glyph size. The box is centred so the glyph stays put. */
|
|
218
|
+
@media (pointer: coarse) {
|
|
219
|
+
.ui-alert__dismiss,
|
|
220
|
+
.ui-toast__close {
|
|
221
|
+
display: inline-grid;
|
|
222
|
+
place-items: center;
|
|
223
|
+
min-block-size: 2.9rem;
|
|
224
|
+
min-inline-size: 2.9rem;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.ui-alert__dismiss {
|
|
228
|
+
padding: 0;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@media (hover: hover) {
|
|
233
|
+
.ui-toast__close:hover {
|
|
234
|
+
color: var(--text);
|
|
235
|
+
}
|
|
211
236
|
}
|
|
212
237
|
|
|
213
238
|
.ui-toast--accent::before {
|
|
@@ -230,6 +255,51 @@
|
|
|
230
255
|
background: var(--info);
|
|
231
256
|
}
|
|
232
257
|
|
|
258
|
+
/* Forced-colors (Windows HCM): system colours override the rationed tone
|
|
259
|
+
colour on the dot + border, so all tones would collapse to one appearance
|
|
260
|
+
(WCAG 1.4.1 — colour as the sole channel). Carry the tone as a distinct
|
|
261
|
+
glyph instead; rendered as text it survives HCM as CanvasText. The glyph is
|
|
262
|
+
inherited via --tone-glyph so one rule covers both alert and toast. */
|
|
263
|
+
@media (forced-colors: active) {
|
|
264
|
+
.ui-alert::before,
|
|
265
|
+
.ui-toast::before {
|
|
266
|
+
background: none;
|
|
267
|
+
border-radius: 0;
|
|
268
|
+
content: var(--tone-glyph, '\2022'); /* • neutral default */
|
|
269
|
+
block-size: auto;
|
|
270
|
+
inline-size: auto;
|
|
271
|
+
margin-block-start: 0;
|
|
272
|
+
font-family: var(--mono);
|
|
273
|
+
font-weight: 700;
|
|
274
|
+
line-height: 1.1;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.ui-alert--accent,
|
|
278
|
+
.ui-toast--accent {
|
|
279
|
+
--tone-glyph: '\25C6'; /* ◆ */
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.ui-alert--success,
|
|
283
|
+
.ui-toast--success {
|
|
284
|
+
--tone-glyph: '\2713'; /* ✓ */
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.ui-alert--warning,
|
|
288
|
+
.ui-toast--warning {
|
|
289
|
+
--tone-glyph: '\0021'; /* ! */
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.ui-alert--danger,
|
|
293
|
+
.ui-toast--danger {
|
|
294
|
+
--tone-glyph: '\2715'; /* ✕ */
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.ui-alert--info,
|
|
298
|
+
.ui-toast--info {
|
|
299
|
+
--tone-glyph: '\69'; /* i */
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
233
303
|
/* --- Tooltip — CSS-only, hover/focus, no JS --- */
|
|
234
304
|
|
|
235
305
|
.ui-tooltip {
|
|
@@ -369,6 +439,7 @@
|
|
|
369
439
|
.ui-progress__bar {
|
|
370
440
|
background: var(--accent);
|
|
371
441
|
block-size: 100%;
|
|
442
|
+
display: block;
|
|
372
443
|
transition: inline-size var(--duration-base) var(--ease-out);
|
|
373
444
|
inline-size: calc(clamp(0, var(--value, 0), 100) * 1%);
|
|
374
445
|
}
|
|
@@ -414,6 +485,7 @@
|
|
|
414
485
|
.ui-meter__fill {
|
|
415
486
|
background: var(--text-dim);
|
|
416
487
|
block-size: 100%;
|
|
488
|
+
display: block;
|
|
417
489
|
transition: inline-size var(--duration-base) var(--ease-out);
|
|
418
490
|
inline-size: calc(clamp(0, var(--value, 0), 100) * 1%);
|
|
419
491
|
}
|
|
@@ -434,6 +506,10 @@
|
|
|
434
506
|
background: var(--danger);
|
|
435
507
|
}
|
|
436
508
|
|
|
509
|
+
.ui-meter--info .ui-meter__fill {
|
|
510
|
+
background: var(--info);
|
|
511
|
+
}
|
|
512
|
+
|
|
437
513
|
/* --- Steps — progress through a multi-step flow. Use an <ol>; the
|
|
438
514
|
current step is aria-current="step" (no class), completed steps take
|
|
439
515
|
--done. Counter-numbered markers, hairline connectors. --- */
|
|
@@ -502,3 +578,36 @@
|
|
|
502
578
|
border-color: var(--accent);
|
|
503
579
|
color: var(--button-text);
|
|
504
580
|
}
|
|
581
|
+
|
|
582
|
+
/* Print: the progress/meter fill is the data (a measured proportion), so its
|
|
583
|
+
painted background must survive the print "economy" default. The fill tokens
|
|
584
|
+
are re-pointed to print-legible inks by the global print remap in base.css. */
|
|
585
|
+
@media print {
|
|
586
|
+
.ui-progress__bar,
|
|
587
|
+
.ui-meter__fill {
|
|
588
|
+
-webkit-print-color-adjust: exact;
|
|
589
|
+
print-color-adjust: exact;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* Forced-colors flattens the fill's tone to the system palette and can erase it
|
|
594
|
+
against the track, dropping the only visual cue of the measured proportion.
|
|
595
|
+
Re-assert a system colour so the bar stays visible; the tone's *semantic* is
|
|
596
|
+
carried by the author-written label beside it, not the colour. (a11y C10.)
|
|
597
|
+
The toned `.ui-meter--TONE .ui-meter__fill` rules are (0,2,0); the bare
|
|
598
|
+
`.ui-meter__fill` reset is only (0,1,0), so it lost — a toned fill stayed
|
|
599
|
+
`var(--TONE)` and was forced to black-on-black (component-audit C3). Match the
|
|
600
|
+
tone specificity here (and set `forced-color-adjust: none`) so every meter,
|
|
601
|
+
toned or not, paints `Highlight`, mirroring the `.ui-dot` precedent. */
|
|
602
|
+
@media (forced-colors: active) {
|
|
603
|
+
.ui-progress__bar,
|
|
604
|
+
.ui-meter__fill,
|
|
605
|
+
.ui-meter--accent .ui-meter__fill,
|
|
606
|
+
.ui-meter--success .ui-meter__fill,
|
|
607
|
+
.ui-meter--warning .ui-meter__fill,
|
|
608
|
+
.ui-meter--danger .ui-meter__fill,
|
|
609
|
+
.ui-meter--info .ui-meter__fill {
|
|
610
|
+
background: Highlight;
|
|
611
|
+
forced-color-adjust: none;
|
|
612
|
+
}
|
|
613
|
+
}
|
package/css/fonts.css
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
@ponchia/ui — Doto webfont (dot-matrix display face)
|
|
3
3
|
|
|
4
4
|
URLs are relative to this file. When the package is consumed through a
|
|
5
|
-
bundler (Vite/astro/webpack) the `../fonts/*.
|
|
5
|
+
bundler (Vite/astro/webpack) the `../fonts/*.woff2` references are rewritten
|
|
6
6
|
and the files emitted automatically. When served statically, ship the
|
|
7
7
|
package's `fonts/` directory next to `css/` and it resolves as-is.
|
|
8
8
|
|
|
9
|
+
Shipped as woff2 only (Brotli-compressed) — ~5.7 kB per weight vs ~137 kB
|
|
10
|
+
uncompressed TTF. woff2 is supported by the whole browser floor (ADR-0002:
|
|
11
|
+
Chrome 125 / Safari 18 / Firefox 129), so no TTF fallback is carried.
|
|
12
|
+
|
|
9
13
|
This file is optional: it is bundled into core.css/index.css, but a
|
|
10
14
|
consumer that hosts Doto itself (or overrides `--display` / `--dot-font`)
|
|
11
15
|
can import the rest of the framework without it.
|
|
@@ -16,7 +20,7 @@
|
|
|
16
20
|
font-style: normal;
|
|
17
21
|
font-weight: 400;
|
|
18
22
|
font-display: swap;
|
|
19
|
-
src: url('../fonts/doto-400.
|
|
23
|
+
src: url('../fonts/doto-400.woff2') format('woff2');
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
@font-face {
|
|
@@ -24,7 +28,7 @@
|
|
|
24
28
|
font-style: normal;
|
|
25
29
|
font-weight: 500;
|
|
26
30
|
font-display: swap;
|
|
27
|
-
src: url('../fonts/doto-500.
|
|
31
|
+
src: url('../fonts/doto-500.woff2') format('woff2');
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
@font-face {
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
font-style: normal;
|
|
33
37
|
font-weight: 600;
|
|
34
38
|
font-display: swap;
|
|
35
|
-
src: url('../fonts/doto-600.
|
|
39
|
+
src: url('../fonts/doto-600.woff2') format('woff2');
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
@font-face {
|
|
@@ -40,7 +44,7 @@
|
|
|
40
44
|
font-style: normal;
|
|
41
45
|
font-weight: 700;
|
|
42
46
|
font-display: swap;
|
|
43
|
-
src: url('../fonts/doto-700.
|
|
47
|
+
src: url('../fonts/doto-700.woff2') format('woff2');
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
@font-face {
|
|
@@ -48,7 +52,7 @@
|
|
|
48
52
|
font-style: normal;
|
|
49
53
|
font-weight: 800;
|
|
50
54
|
font-display: swap;
|
|
51
|
-
src: url('../fonts/doto-800.
|
|
55
|
+
src: url('../fonts/doto-800.woff2') format('woff2');
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
@font-face {
|
|
@@ -56,7 +60,7 @@
|
|
|
56
60
|
font-style: normal;
|
|
57
61
|
font-weight: 900;
|
|
58
62
|
font-display: swap;
|
|
59
|
-
src: url('../fonts/doto-900.
|
|
63
|
+
src: url('../fonts/doto-900.woff2') format('woff2');
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
/* Data-saver: never *use* Doto, so the browser never fetches it. The
|
package/css/forms.css
CHANGED
|
@@ -77,6 +77,29 @@
|
|
|
77
77
|
opacity: 0.5;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/* Disabled affordance parity. The text inputs above style :disabled directly;
|
|
81
|
+
the controls that WRAP a native input (switch/check/segmented) showed no
|
|
82
|
+
disabled cue and their label kept cursor:pointer — a lie. Mirror the cue via
|
|
83
|
+
:has(input:disabled); the native-element controls (range/file) take :disabled
|
|
84
|
+
directly. (a11y/forms review C4.) */
|
|
85
|
+
.ui-range:disabled,
|
|
86
|
+
.ui-file:disabled,
|
|
87
|
+
.ui-switch:has(input:disabled),
|
|
88
|
+
.ui-check:has(input:disabled),
|
|
89
|
+
.ui-segmented__option:has(input:disabled) {
|
|
90
|
+
cursor: not-allowed;
|
|
91
|
+
opacity: 0.5;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Keep autofilled fields on-theme — the UA's yellow fill otherwise paints over
|
|
95
|
+
the monochrome surface and breaks the contrast story. (forms review C24.) */
|
|
96
|
+
.ui-input:autofill,
|
|
97
|
+
.ui-search input:autofill {
|
|
98
|
+
-webkit-text-fill-color: var(--text);
|
|
99
|
+
box-shadow: inset 0 0 0 100rem var(--bg-elevated);
|
|
100
|
+
caret-color: var(--text);
|
|
101
|
+
}
|
|
102
|
+
|
|
80
103
|
.ui-input[aria-invalid='true'],
|
|
81
104
|
.ui-select[aria-invalid='true'],
|
|
82
105
|
.ui-textarea[aria-invalid='true'] {
|
|
@@ -221,7 +244,10 @@
|
|
|
221
244
|
|
|
222
245
|
.ui-error-summary__title {
|
|
223
246
|
color: var(--danger);
|
|
224
|
-
|
|
247
|
+
|
|
248
|
+
/* The must-be-read failure heading uses the legible sans, not the low-legibility
|
|
249
|
+
Doto display face — reserve --display for decorative numerals. (forms C27.) */
|
|
250
|
+
font-family: var(--sans);
|
|
225
251
|
font-size: var(--text-sm);
|
|
226
252
|
font-weight: 700;
|
|
227
253
|
letter-spacing: var(--tracking-wide);
|
|
@@ -262,6 +288,14 @@
|
|
|
262
288
|
border-color: var(--accent);
|
|
263
289
|
}
|
|
264
290
|
|
|
291
|
+
/* Keyboard focus ring to match every sibling input (which use a 2px ring); the
|
|
292
|
+
border-colour shift alone read markedly fainter on this one control. Keyed to
|
|
293
|
+
:focus-visible on the inner input so it stays keyboard-only. (a11y review C12.) */
|
|
294
|
+
.ui-search:has(input:focus-visible) {
|
|
295
|
+
outline: 2px solid var(--focus-ring);
|
|
296
|
+
outline-offset: 1px;
|
|
297
|
+
}
|
|
298
|
+
|
|
265
299
|
.ui-search:focus-within::before {
|
|
266
300
|
background: var(--accent);
|
|
267
301
|
}
|
|
@@ -384,6 +418,13 @@
|
|
|
384
418
|
min-block-size: 2.9rem;
|
|
385
419
|
}
|
|
386
420
|
|
|
421
|
+
/* The whole label is the toggle target — float it to the ~44px floor so the
|
|
422
|
+
small track/box isn't a sub-target on touch (WCAG 2.5.8 — C24). */
|
|
423
|
+
.ui-switch,
|
|
424
|
+
.ui-check {
|
|
425
|
+
min-block-size: 2.9rem;
|
|
426
|
+
}
|
|
427
|
+
|
|
387
428
|
.ui-check input {
|
|
388
429
|
block-size: 1.15rem;
|
|
389
430
|
inline-size: 1.15rem;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
generated — opt-in trust surfaces for AI / system-generated content.
|
|
3
|
+
|
|
4
|
+
AI interfaces are becoming common, but most UI systems ship chat bubbles or
|
|
5
|
+
nothing. Bronto is not a chat framework — it owns the *trust* surfaces around
|
|
6
|
+
generated content: a marked region, an origin label, and quiet collapsible
|
|
7
|
+
reasoning / tool-call logs. Pairs with the source/citation layer
|
|
8
|
+
(css/sources.css). The host owns model metadata, reasoning-visibility policy,
|
|
9
|
+
tool execution, traces, redaction, and safety. Not imported by core.css.
|
|
10
|
+
========================================================================== */
|
|
11
|
+
|
|
12
|
+
/* --- Generated region — a marked wrapper for machine-authored content. --- */
|
|
13
|
+
.ui-generated {
|
|
14
|
+
background: color-mix(in srgb, var(--accent) 4%, transparent);
|
|
15
|
+
border: 1px solid var(--line);
|
|
16
|
+
border-inline-start: 2px solid var(--accent);
|
|
17
|
+
border-radius: var(--radius-md);
|
|
18
|
+
display: grid;
|
|
19
|
+
gap: var(--space-xs);
|
|
20
|
+
padding: 0.85rem 1rem;
|
|
21
|
+
print-color-adjust: exact;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.ui-generated__label {
|
|
25
|
+
align-items: center;
|
|
26
|
+
color: var(--text-dim);
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
font-family: var(--mono);
|
|
29
|
+
font-size: var(--text-2xs);
|
|
30
|
+
gap: 0.4rem;
|
|
31
|
+
letter-spacing: var(--tracking-wide);
|
|
32
|
+
text-transform: uppercase;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* --- Origin label — "AI assisted" / "model output" / "human reviewed". --- */
|
|
36
|
+
.ui-origin-label {
|
|
37
|
+
align-items: center;
|
|
38
|
+
border: 1px solid var(--line);
|
|
39
|
+
border-radius: var(--radius-pill);
|
|
40
|
+
color: var(--text-soft);
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
font-family: var(--mono);
|
|
43
|
+
font-size: var(--text-2xs);
|
|
44
|
+
gap: 0.35rem;
|
|
45
|
+
letter-spacing: var(--tracking-wide);
|
|
46
|
+
padding: 0.08rem 0.55rem;
|
|
47
|
+
text-transform: uppercase;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.ui-origin-label--ai {
|
|
51
|
+
border-color: var(--accent);
|
|
52
|
+
color: var(--accent-text);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* --- Reasoning — a quiet, collapsible "how this was produced" block. --- */
|
|
56
|
+
.ui-reasoning {
|
|
57
|
+
color: var(--text-dim);
|
|
58
|
+
font-size: var(--text-sm);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.ui-reasoning > summary {
|
|
62
|
+
color: var(--text-soft);
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
font-family: var(--mono);
|
|
65
|
+
font-size: var(--text-2xs);
|
|
66
|
+
letter-spacing: var(--tracking-wide);
|
|
67
|
+
text-transform: uppercase;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.ui-reasoning__body {
|
|
71
|
+
margin-block-start: var(--space-xs);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* --- Tool log — a quiet, document-grade record of tool invocations. --- */
|
|
75
|
+
.ui-tool-log {
|
|
76
|
+
display: grid;
|
|
77
|
+
gap: var(--space-2xs);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.ui-tool-call {
|
|
81
|
+
border: 1px solid var(--line);
|
|
82
|
+
border-radius: var(--radius-sm);
|
|
83
|
+
font-family: var(--mono);
|
|
84
|
+
font-size: var(--text-2xs);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.ui-tool-call > summary {
|
|
88
|
+
align-items: center;
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
display: flex;
|
|
91
|
+
gap: 0.5rem;
|
|
92
|
+
padding: 0.4rem 0.6rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.ui-tool-call__name {
|
|
96
|
+
color: var(--text);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.ui-tool-call__status {
|
|
100
|
+
color: var(--text-dim);
|
|
101
|
+
margin-inline-start: auto;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ui-tool-call__body {
|
|
105
|
+
border-block-start: 1px solid var(--line);
|
|
106
|
+
color: var(--text-soft);
|
|
107
|
+
margin: 0;
|
|
108
|
+
overflow-x: auto;
|
|
109
|
+
padding: 0.5rem 0.6rem;
|
|
110
|
+
white-space: pre-wrap;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@media (forced-colors: active) {
|
|
114
|
+
.ui-generated {
|
|
115
|
+
border-inline-start-color: CanvasText;
|
|
116
|
+
}
|
|
117
|
+
}
|
package/css/legend.css
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
legend — opt-in data keys for charts, reports, and analytical figures.
|
|
3
|
+
|
|
4
|
+
A standalone, portable data key: `.ui-legend` reads the Tier-4 `--chart-*`
|
|
5
|
+
tokens and pairs with any chart (a token-themed inline SVG/canvas figure, or
|
|
6
|
+
an external engine like Vega-Lite — see docs/vega.md). Not imported by
|
|
7
|
+
core.css — import it beside css/dataviz.css.
|
|
8
|
+
|
|
9
|
+
Bronto paints and positions; it owns no scales, data mapping, or series
|
|
10
|
+
state. Colour is never the sole channel: a swatch mirrors its chart mark
|
|
11
|
+
(its colour, plus a `--chart-pattern-*` where the mark uses one) and is
|
|
12
|
+
always read out by its text label (WCAG 1.4.1). An interactive,
|
|
13
|
+
series-toggling legend is an optional behavior; the host owns what a
|
|
14
|
+
toggle hides and announces.
|
|
15
|
+
========================================================================== */
|
|
16
|
+
|
|
17
|
+
.ui-legend {
|
|
18
|
+
color: var(--text-soft);
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-wrap: wrap;
|
|
21
|
+
font-family: var(--mono);
|
|
22
|
+
font-size: var(--text-xs);
|
|
23
|
+
gap: var(--space-2xs) var(--space-md);
|
|
24
|
+
list-style: none;
|
|
25
|
+
margin: 0;
|
|
26
|
+
padding: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.ui-legend--vertical {
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.ui-legend--compact {
|
|
34
|
+
font-size: var(--text-2xs);
|
|
35
|
+
gap: var(--space-2xs) var(--space-sm);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.ui-legend__title {
|
|
39
|
+
color: var(--text-dim);
|
|
40
|
+
font-size: var(--text-2xs);
|
|
41
|
+
letter-spacing: 0;
|
|
42
|
+
margin: 0;
|
|
43
|
+
text-transform: uppercase;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ui-legend__item {
|
|
47
|
+
align-items: center;
|
|
48
|
+
color: inherit;
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
gap: 0.45rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.ui-legend__label {
|
|
54
|
+
color: inherit;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.ui-legend__value {
|
|
58
|
+
color: var(--text-dim);
|
|
59
|
+
font-variant-numeric: tabular-nums;
|
|
60
|
+
margin-inline-start: auto;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ui-legend__caption {
|
|
64
|
+
color: var(--text-dim);
|
|
65
|
+
font-size: var(--text-2xs);
|
|
66
|
+
letter-spacing: 0;
|
|
67
|
+
text-transform: uppercase;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Swatch — same token contract as the chart fill: set `--chart-color` (and,
|
|
71
|
+
where the mark is patterned, `--chart-pattern`) inline, or use a `--N` index
|
|
72
|
+
helper for the categorical palette. */
|
|
73
|
+
.ui-legend__swatch {
|
|
74
|
+
background: var(--chart-color, var(--chart-1, var(--accent)));
|
|
75
|
+
background-image: var(--chart-pattern, none);
|
|
76
|
+
background-size: var(--chart-pattern-size, 8px);
|
|
77
|
+
block-size: 0.8rem;
|
|
78
|
+
border: 1px solid var(--line-strong);
|
|
79
|
+
flex: 0 0 auto;
|
|
80
|
+
inline-size: 0.8rem;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.ui-legend__swatch--circle {
|
|
84
|
+
border-radius: 50%;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.ui-legend__swatch--line {
|
|
88
|
+
block-size: 0.2rem;
|
|
89
|
+
border: 0;
|
|
90
|
+
inline-size: 1.1rem;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Glyph/symbol swatch — fill an `.ui-icon` mask with the series colour. */
|
|
94
|
+
.ui-legend__symbol {
|
|
95
|
+
block-size: 0.95rem;
|
|
96
|
+
color: var(--chart-color, var(--accent));
|
|
97
|
+
flex: 0 0 auto;
|
|
98
|
+
inline-size: 0.95rem;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Categorical index helpers: exactly one per palette series (gated against
|
|
102
|
+
tokens/charts.js by check-legend). They set only the colour, so a swatch
|
|
103
|
+
stays a faithful key — add `--chart-pattern` (inline, or from dataviz.css)
|
|
104
|
+
only where the chart mark itself is patterned. */
|
|
105
|
+
.ui-legend__swatch--1 {
|
|
106
|
+
--chart-color: var(--chart-1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.ui-legend__swatch--2 {
|
|
110
|
+
--chart-color: var(--chart-2);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.ui-legend__swatch--3 {
|
|
114
|
+
--chart-color: var(--chart-3);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.ui-legend__swatch--4 {
|
|
118
|
+
--chart-color: var(--chart-4);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.ui-legend__swatch--5 {
|
|
122
|
+
--chart-color: var(--chart-5);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.ui-legend__swatch--6 {
|
|
126
|
+
--chart-color: var(--chart-6);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.ui-legend__swatch--7 {
|
|
130
|
+
--chart-color: var(--chart-7);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.ui-legend__swatch--8 {
|
|
134
|
+
--chart-color: var(--chart-8);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Continuous colour ramp. Author supplies the min/mid/max tick *text*; the
|
|
138
|
+
track interpolates the sequential ramp in OKLCH (a single perceptual hue,
|
|
139
|
+
so no banding and no muddy midpoint). `--diverging` swaps in the 7-stop
|
|
140
|
+
diverging ramp around its neutral centre. */
|
|
141
|
+
.ui-legend--gradient {
|
|
142
|
+
display: grid;
|
|
143
|
+
gap: var(--space-2xs);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.ui-legend__track {
|
|
147
|
+
background: linear-gradient(
|
|
148
|
+
90deg in oklch,
|
|
149
|
+
var(--chart-seq-1),
|
|
150
|
+
var(--chart-seq-2),
|
|
151
|
+
var(--chart-seq-3),
|
|
152
|
+
var(--chart-seq-4),
|
|
153
|
+
var(--chart-seq-5),
|
|
154
|
+
var(--chart-seq-6)
|
|
155
|
+
);
|
|
156
|
+
block-size: 0.7rem;
|
|
157
|
+
border: 1px solid var(--line);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.ui-legend--diverging .ui-legend__track {
|
|
161
|
+
background: linear-gradient(
|
|
162
|
+
90deg in oklch,
|
|
163
|
+
var(--chart-div-1),
|
|
164
|
+
var(--chart-div-2),
|
|
165
|
+
var(--chart-div-3),
|
|
166
|
+
var(--chart-div-4),
|
|
167
|
+
var(--chart-div-5),
|
|
168
|
+
var(--chart-div-6),
|
|
169
|
+
var(--chart-div-7)
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.ui-legend__ticks {
|
|
174
|
+
color: var(--text-dim);
|
|
175
|
+
display: flex;
|
|
176
|
+
font-size: var(--text-2xs);
|
|
177
|
+
justify-content: space-between;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.ui-legend__tick {
|
|
181
|
+
font-variant-numeric: tabular-nums;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Threshold / binned key — a `swatch | range-label` grid. Author the swatch
|
|
185
|
+
and label as direct children (no `__item` wrapper) so the columns align. */
|
|
186
|
+
.ui-legend--threshold {
|
|
187
|
+
align-items: center;
|
|
188
|
+
display: grid;
|
|
189
|
+
gap: 0.35rem var(--space-sm);
|
|
190
|
+
grid-template-columns: auto 1fr;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* With-values — align swatch | label | value columns across every row. */
|
|
194
|
+
.ui-legend--with-values {
|
|
195
|
+
display: grid;
|
|
196
|
+
gap: 0.35rem var(--space-md);
|
|
197
|
+
grid-template-columns: auto 1fr auto;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.ui-legend--with-values .ui-legend__item {
|
|
201
|
+
display: grid;
|
|
202
|
+
grid-column: 1 / -1;
|
|
203
|
+
grid-template-columns: subgrid;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.ui-legend--with-values .ui-legend__value {
|
|
207
|
+
margin-inline-start: 0;
|
|
208
|
+
text-align: end;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* Interactive entries are real <button aria-pressed> controls. Bronto styles
|
|
212
|
+
the control + the inactive state; behaviors/legend.js (optional) flips
|
|
213
|
+
aria-pressed and emits an event. The host hides the series and announces it.
|
|
214
|
+
Scoped to button/role=button so a non-button entry never gets cursor:pointer
|
|
215
|
+
— a pointer-only affordance with no keyboard path is a lie (WCAG 2.1.1 — C11;
|
|
216
|
+
the behavior ignores and warns about non-button entries to match). */
|
|
217
|
+
.ui-legend--interactive .ui-legend__item:is(button, [role='button']) {
|
|
218
|
+
background: none;
|
|
219
|
+
border: 0;
|
|
220
|
+
border-radius: var(--radius-sm);
|
|
221
|
+
color: inherit;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
font: inherit;
|
|
224
|
+
padding-block: 0.15rem;
|
|
225
|
+
padding-inline: 0.3rem;
|
|
226
|
+
text-align: start;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.ui-legend--interactive .ui-legend__item:is(button, [role='button']):focus-visible {
|
|
230
|
+
outline: 2px solid var(--accent);
|
|
231
|
+
outline-offset: 2px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.ui-legend__item.is-inactive,
|
|
235
|
+
.ui-legend__item[aria-pressed='false'] {
|
|
236
|
+
opacity: 0.45;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.ui-legend__item.is-inactive .ui-legend__label,
|
|
240
|
+
.ui-legend__item[aria-pressed='false'] .ui-legend__label {
|
|
241
|
+
text-decoration: line-through;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Forced colours: keep the real swatch hue (it mirrors the chart mark) behind
|
|
245
|
+
a system-coloured border so it survives, and drop the opacity dim (it does
|
|
246
|
+
not read) — the line-through still marks an inactive series. */
|
|
247
|
+
@media (forced-colors: active) {
|
|
248
|
+
.ui-legend__swatch {
|
|
249
|
+
border: 1px solid CanvasText;
|
|
250
|
+
forced-color-adjust: none;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Keep the ramp's hues instead of collapsing to one system colour (the tick
|
|
254
|
+
labels still carry the scale either way). */
|
|
255
|
+
.ui-legend__track {
|
|
256
|
+
forced-color-adjust: none;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.ui-legend__item.is-inactive,
|
|
260
|
+
.ui-legend__item[aria-pressed='false'] {
|
|
261
|
+
opacity: 1;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* Print: meaning-carrying colour must survive the "economy" default. */
|
|
266
|
+
@media print {
|
|
267
|
+
.ui-legend__swatch,
|
|
268
|
+
.ui-legend__track {
|
|
269
|
+
-webkit-print-color-adjust: exact;
|
|
270
|
+
print-color-adjust: exact;
|
|
271
|
+
}
|
|
272
|
+
}
|