@ponchia/ui 0.5.0 → 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 +322 -0
- package/MIGRATIONS.json +14 -0
- package/README.md +28 -5
- package/annotations/index.d.ts +398 -276
- package/annotations/index.d.ts.map +1 -0
- package/annotations/index.js +315 -45
- package/behaviors/carousel.js +17 -16
- package/behaviors/combobox.js +47 -16
- package/behaviors/command.js +18 -15
- package/behaviors/connectors.js +4 -5
- package/behaviors/crosshair.js +4 -5
- package/behaviors/dialog.js +3 -2
- package/behaviors/disclosure.js +3 -2
- package/behaviors/dismissible.js +3 -2
- package/behaviors/forms.js +41 -13
- package/behaviors/glyph.js +4 -5
- package/behaviors/internal.js +47 -0
- package/behaviors/legend.js +23 -2
- package/behaviors/menu.js +3 -2
- package/behaviors/popover.js +78 -7
- package/behaviors/spotlight.js +4 -5
- package/behaviors/table.js +39 -12
- package/behaviors/tabs.js +14 -14
- package/behaviors/theme.js +5 -3
- package/behaviors/toast.js +13 -1
- package/classes/classes.json +1857 -0
- package/classes/index.d.ts +28 -13
- package/classes/index.js +34 -18
- package/classes/vscode.css-custom-data.json +12 -0
- package/connectors/index.d.ts +189 -69
- package/connectors/index.d.ts.map +1 -0
- package/connectors/index.js +120 -24
- package/css/app.css +43 -13
- package/css/base.css +15 -10
- package/css/connectors.css +17 -0
- package/css/content.css +7 -1
- package/css/dataviz.css +5 -1
- package/css/disclosure.css +38 -6
- package/css/dots.css +57 -0
- package/css/feedback.css +60 -2
- package/css/forms.css +42 -1
- package/css/legend.css +11 -7
- package/css/marks.css +38 -8
- package/css/motion.css +24 -44
- package/css/navigation.css +7 -0
- package/css/overlay.css +31 -1
- package/css/primitives.css +91 -5
- package/css/report.css +40 -63
- package/css/site.css +16 -2
- package/css/sources.css +43 -1
- package/css/spotlight.css +1 -1
- package/css/tokens.css +36 -1
- package/css/workbench.css +1 -1
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -1
- package/dist/css/app.css +1 -1
- package/dist/css/base.css +1 -1
- package/dist/css/connectors.css +1 -1
- package/dist/css/content.css +1 -1
- package/dist/css/disclosure.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/legend.css +1 -1
- package/dist/css/marks.css +1 -1
- 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/site.css +1 -1
- package/dist/css/sources.css +1 -1
- package/dist/css/spotlight.css +1 -1
- package/dist/css/tokens.css +1 -1
- package/dist/css/workbench.css +1 -1
- package/docs/adr/0003-theme-model.md +1 -1
- package/docs/annotations.md +94 -14
- package/docs/architecture.md +50 -6
- package/docs/contrast.md +116 -92
- package/docs/d2.md +195 -0
- package/docs/legends.md +18 -2
- package/docs/marks.md +9 -2
- package/docs/mermaid.md +152 -0
- package/docs/reference.md +78 -22
- package/docs/reporting.md +395 -57
- package/docs/sources.md +27 -0
- package/docs/stability.md +9 -2
- package/docs/usage.md +101 -4
- package/docs/vega.md +225 -0
- package/docs/workbench.md +7 -1
- package/glyphs/glyphs.js +6 -4
- package/llms.txt +139 -14
- package/package.json +50 -12
- package/qwik/index.d.ts +42 -59
- package/qwik/index.d.ts.map +1 -0
- package/qwik/index.js +55 -3
- package/react/index.d.ts +39 -61
- package/react/index.d.ts.map +1 -0
- package/react/index.js +57 -3
- package/solid/index.d.ts +64 -61
- package/solid/index.d.ts.map +1 -0
- package/solid/index.js +60 -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 +15 -1
- 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/docs/usage.md
CHANGED
|
@@ -39,6 +39,14 @@ All three are small. They are **not** interchangeable:
|
|
|
39
39
|
Rule of thumb: state → dot, classification → badge, user-controlled value
|
|
40
40
|
→ chip.
|
|
41
41
|
|
|
42
|
+
**Tone vocabulary varies by family — by design.** Colour is rationed, so not
|
|
43
|
+
every component carries every tone: `--info`/`--muted` exist on some families
|
|
44
|
+
(badge, dot, state) and not others (alert/toast/meter lead with
|
|
45
|
+
`--success`/`--warning`/`--danger`). The authoritative per-component tone list is
|
|
46
|
+
each base's `modifiers` array in
|
|
47
|
+
[`@ponchia/ui/classes.json`](../classes/classes.json) — read it rather than
|
|
48
|
+
extrapolating a tone you saw on one component onto another.
|
|
49
|
+
|
|
42
50
|
## Numbers: `ui-num` vs the table state classes
|
|
43
51
|
|
|
44
52
|
- Inside `.ui-table`, a numeric cell is `.is-num` (+ `.is-pos` /
|
|
@@ -70,10 +78,11 @@ for narrative body content you do not fully control.
|
|
|
70
78
|
|
|
71
79
|
Do not turn every report block into a card. Use `ui-report__summary`,
|
|
72
80
|
`ui-report__finding`, and `ui-report__evidence` for document structure; use
|
|
73
|
-
`ui-card` only when the block is genuinely a repeated card item.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
`ui-card` only when the block is genuinely a repeated card item. bronto ships
|
|
82
|
+
**no chart component**: for a chart, theme Vega-Lite (`@ponchia/ui/vega`, see
|
|
83
|
+
[vega.md](vega.md)) or hand-author a token-themed inline SVG painted from the
|
|
84
|
+
data-viz palette tokens. Always wrap it in a `ui-report__figure` with a caption,
|
|
85
|
+
a `.ui-legend` key, and fallback data. Full LLM/static report cookbook:
|
|
77
86
|
[reporting.md](reporting.md).
|
|
78
87
|
|
|
79
88
|
## Buttons: variant and size
|
|
@@ -102,6 +111,13 @@ destructive action).
|
|
|
102
111
|
| toast | transient, out-of-flow, system-initiated. Danger toasts route to an assertive live region; everything else polite. |
|
|
103
112
|
| tooltip | supplemental, hover/focus, never essential info (it's not announced reliably; don't hide required content in it). |
|
|
104
113
|
|
|
114
|
+
The CSS `ui-tooltip` is hover/focus-only and CSS can't wire it to assistive
|
|
115
|
+
tech for you — associate the bubble with its trigger yourself, or it conveys
|
|
116
|
+
nothing to a screen reader: give `.ui-tooltip__bubble` an `id`, point the
|
|
117
|
+
trigger's `aria-describedby` at it, and keep the bubble `role="tooltip"`. For a
|
|
118
|
+
tooltip that must stay visible near a viewport edge or inside a scroll
|
|
119
|
+
container, use `initPopover` (a real focus-managed panel) instead.
|
|
120
|
+
|
|
105
121
|
## Meter vs progress
|
|
106
122
|
|
|
107
123
|
Both are a thin horizontal bar; they mean different things.
|
|
@@ -135,6 +151,37 @@ this much* → meter.
|
|
|
135
151
|
(`aria-hidden`) and the input keeps its full width. Don't hand-roll an
|
|
136
152
|
absolute overlay.
|
|
137
153
|
|
|
154
|
+
## Navigation: the landmarks and names the classes don't carry
|
|
155
|
+
|
|
156
|
+
The navigation classes are styling only — the ARIA scaffolding is yours, and
|
|
157
|
+
without it these widgets are unlabelled or unannounced:
|
|
158
|
+
|
|
159
|
+
- **`ui-breadcrumb`** — wrap it in `<nav aria-label="Breadcrumb">` and mark the
|
|
160
|
+
last (current) crumb with `aria-current="page"`.
|
|
161
|
+
- **`ui-pagination`** — wrap it in `<nav aria-label="Pagination">`; give the
|
|
162
|
+
current page `aria-current="page"`; label icon-only prev/next controls
|
|
163
|
+
(`aria-label="Previous page"`). Disable a control with native `disabled`
|
|
164
|
+
(a `<button>`) **or** `aria-disabled="true"` — both now render disabled and
|
|
165
|
+
are non-interactive; don't ship an `aria-disabled` control that still acts.
|
|
166
|
+
- **`ui-tabs`** — `initTabs` adds the full APG wiring (roles, roving tabindex,
|
|
167
|
+
`aria-selected`, panel `hidden`, focusable panel). If you wire tabs yourself,
|
|
168
|
+
name the `ui-tabs__list` (`role="tablist"` + an `aria-label`) and pair each
|
|
169
|
+
tab with its panel via `aria-controls`/`aria-labelledby`.
|
|
170
|
+
- **`ui-sitenav` / `ui-app-nav`** — signal the current link with
|
|
171
|
+
`aria-current="page"` (both honour it; `ui-app-nav` also accepts the
|
|
172
|
+
visual-only `.is-active`, but prefer `aria-current`).
|
|
173
|
+
- **`ui-skiplink`** — keep it the first focusable element and point its `href`
|
|
174
|
+
at the `id` of your main landmark.
|
|
175
|
+
|
|
176
|
+
## Avatar: it's an unlabelled blob until you name it
|
|
177
|
+
|
|
178
|
+
`ui-avatar` is a presentation box. Give it an accessible name yourself: an
|
|
179
|
+
image avatar needs real `alt` text (`alt=""` only if it's purely decorative
|
|
180
|
+
beside a visible name); an initials avatar needs an accessible name on the
|
|
181
|
+
element (e.g. `aria-label="Ada Lovelace"`) because the initials alone don't
|
|
182
|
+
convey identity to AT. Keep initials to ~2 characters — the box is
|
|
183
|
+
`overflow: hidden` and silently clips a third.
|
|
184
|
+
|
|
138
185
|
## Modal: native `<dialog>` vs `is-open`
|
|
139
186
|
|
|
140
187
|
Prefer the **native `<dialog>`** path — you get top-layer, backdrop and
|
|
@@ -181,6 +228,13 @@ that fuses the cells into a square, gapless pixel glyph that stays crisp and
|
|
|
181
228
|
legible down to **~16px** — so the same set doubles as real inline UI icons,
|
|
182
229
|
not just decoration. (Below the dot fragments into dot-soup; solid does not.)
|
|
183
230
|
|
|
231
|
+
One caveat on ink: `solid` cells inherit the dot palette (`--field-dot-hot`,
|
|
232
|
+
~40% alpha), so at small sizes a solid glyph reads as a soft grey, not full
|
|
233
|
+
ink. When you want a crisp, full-strength small icon (toolbar, button affordance),
|
|
234
|
+
use the one-node mask renderer instead — `renderGlyph(name, { render: 'mask' })`
|
|
235
|
+
paints the glyph in `currentColor` on a `.ui-icon`, so it tracks text colour at
|
|
236
|
+
any size.
|
|
237
|
+
|
|
184
238
|
`renderGlyph(name, { label })` returns an SSR-safe string: decorative
|
|
185
239
|
(`aria-hidden`) by default, or `role="img"` + `aria-label` when you pass a
|
|
186
240
|
`label` — which is how it conveys meaning to assistive tech. Prefer the
|
|
@@ -285,6 +339,49 @@ authoring engine.
|
|
|
285
339
|
- Annotation text must be visible or represented in the figure caption, SVG
|
|
286
340
|
`<desc>`, or fallback table. Full detail in [annotations.md](annotations.md).
|
|
287
341
|
|
|
342
|
+
## Forms: the contracts the markup alone won't tell you
|
|
343
|
+
|
|
344
|
+
- **Disabled — pick one mechanism.** Use the native `disabled` attribute for a
|
|
345
|
+
genuinely inert control (`ui-input`, `ui-select`, `ui-textarea`, `ui-switch`
|
|
346
|
+
/`ui-check`/`ui-segmented` wrapping a native input, `ui-range`, `ui-file`,
|
|
347
|
+
`ui-button`): the browser greys it, blocks activation, and skips it in tab
|
|
348
|
+
order, and bronto styles the disabled cue. Use `aria-disabled="true"` **only**
|
|
349
|
+
when the control must stay focusable/announced — bronto then adds
|
|
350
|
+
`pointer-events: none` to `ui-button`/`ui-link` so it can't be activated, but
|
|
351
|
+
you still own removing it from the submit logic.
|
|
352
|
+
- **Combobox** (`data-bronto-combobox`) reads its options from the DOM at
|
|
353
|
+
`initCombobox()` time — re-run it after you replace the option list. The
|
|
354
|
+
`<input>` owns the value; the listbox is a view.
|
|
355
|
+
- **Validation** is opt-in via `data-bronto-validate` on the form plus
|
|
356
|
+
`initFormValidation()`; it surfaces messages into a `ui-error-summary` you
|
|
357
|
+
provide. The summary's title is the legible sans, not the display face — it's
|
|
358
|
+
meant to be read.
|
|
359
|
+
|
|
360
|
+
## Reveal: `ui-reveal` needs JS, `ui-scroll-reveal` doesn't
|
|
361
|
+
|
|
362
|
+
`ui-scroll-reveal` is scroll-driven and **zero-JS** — reach for it in a static
|
|
363
|
+
or LLM-authored report. `ui-reveal` is the JS variant: it starts hidden and you
|
|
364
|
+
toggle `is-visible` (e.g. from an `IntersectionObserver` you own) to play it in.
|
|
365
|
+
With scripting disabled it degrades to fully visible, but if scripting is *on*
|
|
366
|
+
and nothing toggles `is-visible`, the content stays hidden — so only use
|
|
367
|
+
`ui-reveal` when you are wiring that toggle.
|
|
368
|
+
|
|
369
|
+
## Loading affordances need a role you supply
|
|
370
|
+
|
|
371
|
+
`ui-spinner`, `ui-dotspinner`, `ui-skeleton`, and an indeterminate `ui-progress`
|
|
372
|
+
are decorative animations — bronto can't know their semantics. Give the busy
|
|
373
|
+
region `aria-busy="true"` (or `role="status"` with an `aria-live` text label like
|
|
374
|
+
"Loading…"), and mark a purely decorative spinner `aria-hidden="true"`. Without
|
|
375
|
+
one of these a screen reader announces nothing while the user waits.
|
|
376
|
+
|
|
377
|
+
## Popover: prefer the native top layer
|
|
378
|
+
|
|
379
|
+
`initPopover()` shows a `.ui-popover` in the browser **top layer** when the panel
|
|
380
|
+
carries the native `popover` attribute (never clipped by `overflow`/stacking);
|
|
381
|
+
without it, it falls back to an `is-open` class that a clipping ancestor can cut
|
|
382
|
+
off. Add `popover` to the panel for the robust path — the `is-open` form is a
|
|
383
|
+
fallback, not the default to copy.
|
|
384
|
+
|
|
288
385
|
## When to add a behavior
|
|
289
386
|
|
|
290
387
|
The CSS is the framework; `@ponchia/ui/behaviors` is the *sanctioned*
|
package/docs/vega.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Vega-Lite
|
|
2
|
+
|
|
3
|
+
[Vega-Lite](https://vega.github.io/vega-lite/) is a **declarative JSON grammar
|
|
4
|
+
of graphics** — you describe a chart as data and it compiles (through
|
|
5
|
+
[Vega](https://vega.github.io/vega/)) to **SVG or canvas**. Like the
|
|
6
|
+
[Mermaid](./mermaid.md) and [D2](./d2.md) integrations, `@ponchia/ui` doesn't
|
|
7
|
+
render charts — it **themes** them from your tokens. Two things ship:
|
|
8
|
+
|
|
9
|
+
- `@ponchia/ui/vega` — `brontoVegaConfig(theme)`, the on-brand Vega-Lite
|
|
10
|
+
[`config`](https://vega.github.io/vega-lite/docs/config.html) object.
|
|
11
|
+
- `@ponchia/ui/vega.json` — the resolved per-theme config, for any consumer.
|
|
12
|
+
|
|
13
|
+
This is the idiomatic Vega theme shape — a `config`, the same kind the
|
|
14
|
+
[`vega-themes`](https://github.com/vega/vega-themes) package ships. Vega stays
|
|
15
|
+
the consumer's renderer; this is config only, and **Vega is not a dependency**
|
|
16
|
+
of bronto (the dev-only render-probe aside).
|
|
17
|
+
|
|
18
|
+
> Why Vega-Lite and not a bronto chart component? A chart needs **scales**
|
|
19
|
+
> (data → pixels) and **data binding** — the two things the analytical layer
|
|
20
|
+
> [refuses to own](./architecture.md). A spec is also something an
|
|
21
|
+
> LLM-from-another-system can emit as data, the same way it emits Mermaid/D2.
|
|
22
|
+
> So bronto themes a real charting grammar instead of shipping a fragile one.
|
|
23
|
+
|
|
24
|
+
## Theme a chart
|
|
25
|
+
|
|
26
|
+
`brontoVegaConfig(theme)` returns a `config` object. Spread it into a spec, or
|
|
27
|
+
hand it to [vega-embed](https://github.com/vega/vega-embed):
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import vegaEmbed from 'vega-embed';
|
|
31
|
+
import { brontoVegaConfig } from '@ponchia/ui/vega';
|
|
32
|
+
|
|
33
|
+
const theme = document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light';
|
|
34
|
+
|
|
35
|
+
vegaEmbed('#chart', {
|
|
36
|
+
data: { values: [
|
|
37
|
+
{ quarter: 'Q1', value: 42 },
|
|
38
|
+
{ quarter: 'Q2', value: 58 },
|
|
39
|
+
{ quarter: 'Q3', value: 50 },
|
|
40
|
+
] },
|
|
41
|
+
mark: 'bar',
|
|
42
|
+
encoding: {
|
|
43
|
+
x: { field: 'quarter', type: 'nominal' },
|
|
44
|
+
y: { field: 'value', type: 'quantitative' },
|
|
45
|
+
},
|
|
46
|
+
}, { config: brontoVegaConfig(theme), renderer: 'svg', actions: false });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Pass **`renderer: 'svg'`** (not vega-embed's `canvas` default): an SVG chart is
|
|
50
|
+
inspectable, themeable, survives the print/PDF pipeline, and is what the
|
|
51
|
+
[annotation layer](#annotate-a-chart) composes onto — a canvas chart prints as a
|
|
52
|
+
raster and carries no text alternative.
|
|
53
|
+
|
|
54
|
+
### From a CDN, no bundler
|
|
55
|
+
|
|
56
|
+
Load Vega + Vega-Lite + vega-embed from **pinned `/build/*.min.js` UMD files**,
|
|
57
|
+
then pass the config. Pin exact versions and use the `/build/` path — a bare
|
|
58
|
+
`cdn.jsdelivr.net/npm/vega@6` redirect resolves to a module bundle that does
|
|
59
|
+
**not** register the global `window.vega`, so vega-embed throws and nothing
|
|
60
|
+
renders. Keep the three majors aligned: **Vega-Lite 6 targets Vega 6** (and
|
|
61
|
+
vega-embed 7), so don't mix a Vega-Lite 6 with a Vega 5 runtime:
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<script src="https://cdn.jsdelivr.net/npm/vega@6.2.0/build/vega.min.js"></script>
|
|
65
|
+
<script src="https://cdn.jsdelivr.net/npm/vega-lite@6.4.3/build/vega-lite.min.js"></script>
|
|
66
|
+
<script src="https://cdn.jsdelivr.net/npm/vega-embed@7.1.0/build/vega-embed.min.js"></script>
|
|
67
|
+
<script>
|
|
68
|
+
// INLINE the config (copy the object for your theme from @ponchia/ui/vega.json).
|
|
69
|
+
// This is the only path that also works from a file:// report — see below.
|
|
70
|
+
const brontoLight = {
|
|
71
|
+
/* …paste tokens/vega.json → light here… */
|
|
72
|
+
};
|
|
73
|
+
vegaEmbed('#chart', spec, { config: brontoLight, renderer: 'svg', actions: false });
|
|
74
|
+
</script>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
> **file:// portability.** A report opened straight from disk (`file://`) cannot
|
|
78
|
+
> `import` the `@ponchia/ui/vega` module **nor** `fetch('…/vega.json')` — the
|
|
79
|
+
> browser blocks both across the `null`/file origin (CORS). So for a
|
|
80
|
+
> double-clickable or PDF-bound report, **inline the resolved config object**
|
|
81
|
+
> (as above) rather than fetching it. Over an `http(s)` origin (a dev server, a
|
|
82
|
+
> static host, a bundler), the `import { brontoVegaConfig }` form and a
|
|
83
|
+
> `fetch('https://cdn.jsdelivr.net/npm/@ponchia/ui@VERSION/tokens/vega.json')`
|
|
84
|
+
> both work — pin the package version in the URL, since the unversioned latest
|
|
85
|
+
> may predate this target.
|
|
86
|
+
|
|
87
|
+
For a build step or non-JS host, read `@ponchia/ui/vega.json` directly
|
|
88
|
+
(`{ light, dark }`, each a ready Vega-Lite `config`).
|
|
89
|
+
|
|
90
|
+
### Why resolved colours, not `var(--x)`
|
|
91
|
+
|
|
92
|
+
Vega-Lite compiles a spec to a Vega scene that renders to **SVG or canvas** —
|
|
93
|
+
colours are **baked into the output** and parsed by `d3-color`, which understands
|
|
94
|
+
real hex/rgb but **not** `var()` (nor `oklch()`). So the config ships **resolved
|
|
95
|
+
hex per theme**, projected from the same token source as
|
|
96
|
+
[`tokens/resolved.json`](./architecture.md) / [`charts.json`](./theming.md).
|
|
97
|
+
Re-call `brontoVegaConfig()` when the theme toggles and re-embed.
|
|
98
|
+
|
|
99
|
+
### What the slots paint
|
|
100
|
+
|
|
101
|
+
The config keeps a chart **monochrome by default** — the rationed accent is the
|
|
102
|
+
one chromatic default (series 1 / the lone mark), never the chrome:
|
|
103
|
+
|
|
104
|
+
| Slot | Paint | bronto token |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `background` | Chart canvas | `--bg` |
|
|
107
|
+
| `view.stroke` | Plot frame | `--line` |
|
|
108
|
+
| `mark.color` | Default / single-series mark | `--accent` |
|
|
109
|
+
| `rule.color` | Reference rules, annotations | `--line-strong` |
|
|
110
|
+
| `axis.domainColor` · `tickColor` | Axis line · ticks | `--line-strong` |
|
|
111
|
+
| `axis.gridColor` | Gridlines | `--line` |
|
|
112
|
+
| `axis.labelColor` · `titleColor` | Tick labels · axis title | `--text-soft` · `--text` |
|
|
113
|
+
| `text.color` | Free `text`/`label` marks | `--text` |
|
|
114
|
+
| `legend.*` · `header.*` · `title.*` | Legend, facet headers, title | `--text-soft` / `--text` / `--text-dim` |
|
|
115
|
+
| `*.font` / `*Font` | All text | `--sans` |
|
|
116
|
+
| `range.category` | 8-series categorical palette | `charts.json` categorical (series 1 = accent) |
|
|
117
|
+
| `range.ordinal` · `ramp` · `heatmap` | Single-hue sequential ramp | `charts.json` sequential |
|
|
118
|
+
| `range.diverging` | − … neutral … + ramp | `charts.json` diverging |
|
|
119
|
+
|
|
120
|
+
The palette is the same CVD-safe, pattern-paired set documented in
|
|
121
|
+
[theming](./theming.md#data-viz) — colour is never the sole channel. When a
|
|
122
|
+
series needs the redundant second channel, drive the mark's fill from the
|
|
123
|
+
`--chart-pattern-*` tokens or pair a [legend](./legends.md) swatch.
|
|
124
|
+
|
|
125
|
+
### Spending the accent
|
|
126
|
+
|
|
127
|
+
Series 1 of `range.category` **is** the live accent, so a single-series chart and
|
|
128
|
+
the first category re-skin for free with `--accent`. To emphasise one mark in a
|
|
129
|
+
multi-series chart, paint just that mark with the accent and leave the rest
|
|
130
|
+
neutral — the same "reserve the accent for the one thing a reader must not miss"
|
|
131
|
+
rule the rest of the system follows. Two small helpers hand you the exact
|
|
132
|
+
per-theme hexes so you never hard-code a palette array index:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
import { brontoVegaAccent, brontoVegaNeutral } from '@ponchia/ui/vega';
|
|
136
|
+
|
|
137
|
+
// e.g. a bar chart where only the 'Alert' category is loud:
|
|
138
|
+
const spec = {
|
|
139
|
+
/* …data… */
|
|
140
|
+
mark: 'bar',
|
|
141
|
+
encoding: {
|
|
142
|
+
x: { field: 'name', type: 'nominal' },
|
|
143
|
+
y: { field: 'value', type: 'quantitative' },
|
|
144
|
+
color: {
|
|
145
|
+
condition: { test: "datum.name === 'Alert'", value: brontoVegaAccent(theme) },
|
|
146
|
+
value: brontoVegaNeutral(theme),
|
|
147
|
+
},
|
|
148
|
+
legend: null,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`brontoVegaAccent(theme)` is `range.category[0]` (the live accent) and
|
|
154
|
+
`brontoVegaNeutral(theme)` is the last category (the quiet neutral); re-read both
|
|
155
|
+
when the theme toggles. Prefer them over digging the hex out of
|
|
156
|
+
`tokens/resolved.json` — they are guaranteed to match the palette the config
|
|
157
|
+
already ships. In token terms the accent is `--chart-1` and the neutral is
|
|
158
|
+
`--chart-8`, so a [legend](./legends.md#swatch-colour) for an accent-rationed
|
|
159
|
+
chart keys those two series with `ui-legend__swatch--1` and
|
|
160
|
+
`ui-legend__swatch--8` — the swatches mirror the marks exactly.
|
|
161
|
+
|
|
162
|
+
### Selecting the themed ramp in a spec
|
|
163
|
+
|
|
164
|
+
The config registers the ramps as **named ranges**, so a quantitative encoding
|
|
165
|
+
opts in with `scale: { range: 'heatmap' }` (or `'ramp'` / `'diverging'`) — the
|
|
166
|
+
range **name**, not a colour scheme:
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
{
|
|
170
|
+
mark: 'rect',
|
|
171
|
+
encoding: {
|
|
172
|
+
x: { field: 'x', type: 'nominal' },
|
|
173
|
+
y: { field: 'y', type: 'nominal' },
|
|
174
|
+
color: { field: 'v', type: 'quantitative', scale: { range: 'heatmap' } },
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
> Use `scale: { range: 'heatmap' }`, **not** `scale: { scheme: 'heatmap' }`.
|
|
180
|
+
> `scheme:` looks up a registered Vega/d3 scheme by name and **throws** for
|
|
181
|
+
> `'heatmap'` (no such scheme) — the ramp is a custom `range` the bronto config
|
|
182
|
+
> defines, addressed by range name. A `quantitative` colour encoding already
|
|
183
|
+
> defaults to `range.heatmap`; name it explicitly only when a chart has several
|
|
184
|
+
> quantitative scales and you want a specific one (`'diverging'` for a signed
|
|
185
|
+
> domain around a neutral centre).
|
|
186
|
+
|
|
187
|
+
### Sequential & diverging ramps invert by theme
|
|
188
|
+
|
|
189
|
+
`range.heatmap` / `ramp` / `ordinal` is a single-hue ramp that runs **pale → deep
|
|
190
|
+
as the value rises in light theme, and deep → pale in dark theme** (the bg flips,
|
|
191
|
+
so the ramp flips to stay legible against it). Two consequences:
|
|
192
|
+
|
|
193
|
+
- **Don't hard-code ink on a heatmap cell.** A fixed black (or white) label is
|
|
194
|
+
readable at one end of the ramp and invisible at the other — and the readable
|
|
195
|
+
end swaps between themes. Either omit per-cell labels and rely on the fallback
|
|
196
|
+
`ui-table`, or compute the label colour from the cell's luminance at render
|
|
197
|
+
time. bronto themes the ramp; it can't know your data domain, so it does not
|
|
198
|
+
ship a cell-ink helper.
|
|
199
|
+
- **A CSS gradient key won't pixel-match the Vega ramp.** A native
|
|
200
|
+
[`ui-legend--gradient`](./legends.md) track is interpolated in OKLCH; Vega
|
|
201
|
+
interpolates its `range.*` ramp in d3's RGB space. They share endpoints but
|
|
202
|
+
drift in the mid-tones, so a continuous gradient key placed beside a Vega
|
|
203
|
+
heatmap will not match its mid cells exactly. Use a **stepped** legend (one
|
|
204
|
+
swatch per band, each from the same `charts.json` ramp stop) when the key sits
|
|
205
|
+
next to the chart.
|
|
206
|
+
|
|
207
|
+
## Annotate a chart
|
|
208
|
+
|
|
209
|
+
Vega renders to SVG, so the [annotation layer](./annotations.md) composes onto it
|
|
210
|
+
exactly as in the [Mermaid recipe](./mermaid.md#annotate-a-diagram): render to a
|
|
211
|
+
frozen SVG (vega-embed's `view.toSVG()`, or the Vega CLI), read the target mark's
|
|
212
|
+
box, and paste a `<g class="ui-annotation">` computed with
|
|
213
|
+
`@ponchia/ui/annotations`. The same caveat applies — Vega's internal SVG (element
|
|
214
|
+
ids, the `role`/`aria` structure, the scene transform) is **not a public
|
|
215
|
+
contract**, so pin your Vega version and key off the data, not generated ids.
|
|
216
|
+
|
|
217
|
+
## Scope
|
|
218
|
+
|
|
219
|
+
bronto owns the theme config — gated structurally by `check:vega` (every colour
|
|
220
|
+
slot resolves, both themes, no `var()` leaks, every `range.*` ramp populated),
|
|
221
|
+
and separately a dev-only render-probe (`npm test`, via the `vega`/`vega-lite`
|
|
222
|
+
dev deps) asserts the colours actually land on a rendered chart — and the
|
|
223
|
+
annotation geometry. It does not own Vega's grammar, its rendering, or its internal SVG —
|
|
224
|
+
those stay Vega's, and the chart is a documented composition, not a shipped
|
|
225
|
+
runtime binding.
|
package/docs/workbench.md
CHANGED
|
@@ -22,7 +22,7 @@ a `__body` of property rows.
|
|
|
22
22
|
|
|
23
23
|
```html
|
|
24
24
|
<aside class="ui-inspector">
|
|
25
|
-
<div class="ui-
|
|
25
|
+
<div class="ui-inspector__head">
|
|
26
26
|
<h2 class="ui-eyebrow">Rectangle</h2>
|
|
27
27
|
<button class="ui-button ui-button--subtle ui-button--sm" type="button">Reset</button>
|
|
28
28
|
</div>
|
|
@@ -50,6 +50,12 @@ A label/value pair, denser than `ui-key-value` and tuned for an inspector. The
|
|
|
50
50
|
|
|
51
51
|
## Selection bar — `.ui-selectionbar`
|
|
52
52
|
|
|
53
|
+
> **Name note:** `.ui-selectionbar` is the workbench bulk-action bar (this
|
|
54
|
+
> section). It is unrelated to the `.ui-sel--on` / `.ui-sel--off` /
|
|
55
|
+
> `.ui-sel--maybe` selection-emphasis state classes in
|
|
56
|
+
> [`css/selection.css`](./selection.md), which style host-managed selection
|
|
57
|
+
> state on individual items.
|
|
58
|
+
|
|
53
59
|
A raised bar of actions on the current selection: a `__count` on one side,
|
|
54
60
|
`__actions` on the other. The host owns what is selected and what the actions do.
|
|
55
61
|
|
package/glyphs/glyphs.js
CHANGED
|
@@ -23,7 +23,7 @@ export const GLYPH_SIZE = 16;
|
|
|
23
23
|
|
|
24
24
|
// Raw bitmaps. Each is GLYPH_SIZE rows of GLYPH_SIZE chars over [.#*]:
|
|
25
25
|
// `.` off · `#` hot · `*` accent. Only `spark` uses accent dots — it is the
|
|
26
|
-
// canonical two-tone demo;
|
|
26
|
+
// canonical two-tone demo; test/glyphs.test.mjs asserts the spark-only-* rule.
|
|
27
27
|
const RAW = {
|
|
28
28
|
circle: [
|
|
29
29
|
'................',
|
|
@@ -941,9 +941,9 @@ function esc(s) {
|
|
|
941
941
|
.replace(/"/g, '"');
|
|
942
942
|
}
|
|
943
943
|
|
|
944
|
-
// `dot
|
|
945
|
-
//
|
|
946
|
-
//
|
|
944
|
+
// `dot`, `gap`, and `size` land in an inline-CSS context (`style="…"`), where
|
|
945
|
+
// HTML-escaping a `"` stops attribute breakout but a `;` would still open a
|
|
946
|
+
// second CSS declaration (overlay/clickjacking, selector exfil). So restrict
|
|
947
947
|
// them to length/calc syntax — digits, units, %, whitespace and `()+-*/.,` for
|
|
948
948
|
// calc()/clamp()/var() — and drop anything else rather than emit it.
|
|
949
949
|
function cssLen(v) {
|
|
@@ -1004,6 +1004,8 @@ function maskUrl(rows) {
|
|
|
1004
1004
|
* bitmap (one DOM node, not GLYPH_SIZE²) — the icon-at-scale path: it sizes to
|
|
1005
1005
|
* `size` (or `--icon-size` / `1em`) and inherits `currentColor`. The
|
|
1006
1006
|
* cell-mode options (grid/solid/anim/dot/gap) don't apply; `label` does.
|
|
1007
|
+
* Mask mode is single-tone: accent `*` cells (used by `spark`) render
|
|
1008
|
+
* identically to hot `#` cells — both become opaque mask regions.
|
|
1007
1009
|
* Needs `@ponchia/ui/css` (the `.ui-icon` rule).
|
|
1008
1010
|
*/
|
|
1009
1011
|
export function renderGlyph(name, options = {}) {
|
package/llms.txt
CHANGED
|
@@ -31,6 +31,23 @@ later layer) always win over framework styles regardless of selector
|
|
|
31
31
|
specificity — this is the intended override mechanism; do not fight it
|
|
32
32
|
with `!important`.
|
|
33
33
|
|
|
34
|
+
Loading a stylesheet — read before copying a `<link>` below. The opt-in
|
|
35
|
+
leaves are written as `@ponchia/ui/css/<leaf>.css` for brevity. That
|
|
36
|
+
package-specifier form resolves ONLY inside a CSS-aware bundler
|
|
37
|
+
(Vite/webpack); in a standalone `.html` file it does not resolve. For plain
|
|
38
|
+
HTML (the usual case when an LLM emits a report) use a real URL — and note
|
|
39
|
+
the path changes from source `css/` to built `dist/css/`:
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<!-- installed locally -->
|
|
43
|
+
<link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/<leaf>.css" />
|
|
44
|
+
<!-- or from a CDN; pin the version (pre-1.0, breaking changes ship in the minor) -->
|
|
45
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.0/dist/css/<leaf>.css" />
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The flattened default bundle is `dist/bronto.css` (bundler shorthand
|
|
49
|
+
`@ponchia/ui`). A complete, copy-pasteable CDN report is in `docs/reporting.md`.
|
|
50
|
+
|
|
34
51
|
Typed class vocabulary (returns plain strings — works in any framework):
|
|
35
52
|
|
|
36
53
|
```js
|
|
@@ -69,6 +86,29 @@ import { renderGlyph, GLYPH_NAMES } from '@ponchia/ui/glyphs';
|
|
|
69
86
|
el.innerHTML = renderGlyph('check', { label: 'Done' });
|
|
70
87
|
```
|
|
71
88
|
|
|
89
|
+
Layout primitives (core bundle, no media queries — intrinsic Every-Layout
|
|
90
|
+
composition that responds to content + available space): `ui-stack` (vertical
|
|
91
|
+
rhythm), `ui-cluster` (wrapping inline row), `ui-grid` (auto-fit columns),
|
|
92
|
+
`ui-sidebar` (sidebar + main that stacks when cramped), `ui-switcher` (row →
|
|
93
|
+
column together), `ui-center` (measure-bounded column), `ui-ratio` (aspect-ratio
|
|
94
|
+
box), and the `ui-app-shell`/`ui-app-rail`/`ui-app-nav` admin shell. Each is
|
|
95
|
+
tuned with an inline custom property rather than a modifier — set
|
|
96
|
+
`style="--grid-min: 12rem"`, `--sidebar-width`, `--switcher-min`, `--center-max`
|
|
97
|
+
(the INNER measure; gutters add to the total), `--ratio`, `--stack-gap`,
|
|
98
|
+
`--cluster-gap`, `--app-rail`, etc. The full list with defaults is in
|
|
99
|
+
`classes.json` `customProperties`. App-shell/sitenav current page is
|
|
100
|
+
`aria-current="page"`.
|
|
101
|
+
|
|
102
|
+
Motion utilities (core bundle, all reduced-motion-safe — they collapse to the
|
|
103
|
+
static end state, not just a zeroed duration): `ui-animate-in`,
|
|
104
|
+
`ui-animate-fade`, `ui-animate-dot`, `ui-animate-matrix` (enter animations),
|
|
105
|
+
`ui-stagger` (+ `--i` per child, or `ui-stagger--auto` to
|
|
106
|
+
derive the delay from `:nth-child`), `ui-reveal` (JS/IntersectionObserver — adds
|
|
107
|
+
`is-visible`), `ui-scroll-reveal` and `ui-scroll-progress` (zero-JS,
|
|
108
|
+
scroll-driven; the recommended reveal for static reports), and `ui-vt` (View
|
|
109
|
+
Transitions — needs the required `--ui-vt-name`). Prefer `ui-scroll-reveal` over
|
|
110
|
+
`ui-reveal` when no JS will run. Details: `docs/usage.md`.
|
|
111
|
+
|
|
72
112
|
Optional display colorways — opt-in, never in the default bundle. Root-level,
|
|
73
113
|
like `data-theme` (the derived accent family only recomputes at `:root`):
|
|
74
114
|
|
|
@@ -92,6 +132,54 @@ import charts from '@ponchia/ui/charts.json' with { type: 'json' };
|
|
|
92
132
|
// charts.dark.categorical → ['#ff3b41', …] (series 0 = the resolved accent)
|
|
93
133
|
```
|
|
94
134
|
|
|
135
|
+
On-brand Mermaid diagrams use the same tokens-as-data path — Mermaid is the
|
|
136
|
+
consumer's renderer, bronto just hands it a resolved `base` theme (Mermaid can't
|
|
137
|
+
read `var(--x)`):
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
import { brontoMermaidTheme } from '@ponchia/ui/mermaid';
|
|
141
|
+
mermaid.initialize(brontoMermaidTheme('dark')); // { theme: 'base', themeVariables }
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Annotate a rendered diagram with the SVG annotation layer as a build-time
|
|
145
|
+
recipe. Details: `docs/mermaid.md`.
|
|
146
|
+
|
|
147
|
+
D2 (d2lang.com) is themed the same way — it compiles to a frozen SVG, so the
|
|
148
|
+
slots take resolved hex; the base ramp is monochrome and the accent is opt-in
|
|
149
|
+
per node:
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
import { brontoD2Vars } from '@ponchia/ui/d2';
|
|
153
|
+
const source = brontoD2Vars() + 'a -> b'; // prepend the vars block, then render
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Details: `docs/d2.md`.
|
|
157
|
+
|
|
158
|
+
Charting is the same path: bronto does NOT ship a chart component (a chart needs
|
|
159
|
+
scales + data binding, which the analytical layer refuses). For charts, recommend
|
|
160
|
+
Vega-Lite — a declarative JSON spec an external system can emit — themed by the
|
|
161
|
+
on-brand `config` (resolved hex; Vega bakes colours into SVG/canvas, can't read
|
|
162
|
+
`var()`). `range.category` is the `--chart-*` palette, series 1 = accent:
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
import { brontoVegaConfig, brontoVegaAccent, brontoVegaNeutral } from '@ponchia/ui/vega';
|
|
166
|
+
vegaEmbed('#chart', spec, { config: brontoVegaConfig('dark'), renderer: 'svg', actions: false });
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Pass `renderer: 'svg'` (canvas is the wrong default for print/inspection).
|
|
170
|
+
`brontoVegaAccent(theme)`/`brontoVegaNeutral(theme)` give the exact hexes to spend
|
|
171
|
+
the accent on one mark. From a CDN, pin the `/build/*.min.js` UMD bundles (a bare
|
|
172
|
+
`vega@6` tag has no `window.vega`; keep Vega-Lite 6 / Vega 6 / vega-embed 7
|
|
173
|
+
aligned) and INLINE the config from `vega.json` — a
|
|
174
|
+
`file://` report can't `import`/`fetch` it (CORS). A label on an accent fill in a
|
|
175
|
+
foreign renderer (a themed Vega/D2/Mermaid node or bar) reads the `--on-accent`
|
|
176
|
+
token, never `--accent-text` (that is accent-coloured text for a neutral bg).
|
|
177
|
+
`--on-accent` is a READ-ONLY export for those renderers — no in-DOM `.ui-*` rule
|
|
178
|
+
consumes it, so setting it does not re-ink a component; to colour text on an
|
|
179
|
+
accent-filled DOM control, set `--button-text`. Details: `docs/vega.md`. (Observable
|
|
180
|
+
Plot works too — it inherits the page CSS, so it needs even less theming;
|
|
181
|
+
Vega-Lite is the recommended LLM-emittable path.)
|
|
182
|
+
|
|
95
183
|
`--chart-1..8` (categorical; series 1 = accent; colourblind-safe, gated under
|
|
96
184
|
simulated protan/deutan/tritan), `--chart-seq-*` (sequential), `--chart-div-*`
|
|
97
185
|
(diverging), and `--chart-pattern-1..8` (dot-matrix fills — pair colour N with
|
|
@@ -245,12 +333,15 @@ reports/AI output:
|
|
|
245
333
|
```
|
|
246
334
|
|
|
247
335
|
`ui-citation` (inline ref on a real `<a>`/`<button>`; `--chip` = named-source
|
|
248
|
-
pill), `ui-source-card` (+`__title`/`__origin`/`__time`/`__excerpt`/`__actions
|
|
249
|
-
`
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
336
|
+
pill), `ui-source-card` (+`__title`/`__origin`/`__time`/`__excerpt`/`__actions`;
|
|
337
|
+
the body part is `__excerpt`, not `__detail`), `ui-source-list` (+`__item`),
|
|
338
|
+
`ui-provenance` (+`__item`), and `ui-src` (a standalone trust pill). A
|
|
339
|
+
cross-cutting trust state sets the tone: `ui-src--verified`/`--reviewed`/
|
|
340
|
+
`--generated`/`--unverified`/`--stale`/`--conflict` — always paired with an
|
|
341
|
+
author-written label (never colour alone). A tone class **needs a host**:
|
|
342
|
+
`ui-src--verified` on its own renders nothing — put it on `ui-src`,
|
|
343
|
+
`ui-citation`, `ui-source-card`, or `ui-provenance__item`. Bronto styles +
|
|
344
|
+
states; the host owns fetching, numbering, and trust. `ui.citation({chip,state})` / `ui.source({state})` /
|
|
254
345
|
`ui.provenance({state})`. Details: `docs/sources.md`.
|
|
255
346
|
|
|
256
347
|
Optional lifecycle/system-state vocabulary — opt-in, CSS only, never in the
|
|
@@ -351,10 +442,18 @@ Canonical report skeleton:
|
|
|
351
442
|
Report rules for agents: static output by default; do not initialize behaviors
|
|
352
443
|
over untrusted generated content; sanitize arbitrary LLM/CMS/user HTML before
|
|
353
444
|
rendering; use semantic headings; give tables captions and header cells; give
|
|
354
|
-
charts captions, legends/direct labels, and fallback data;
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
445
|
+
charts captions, legends/direct labels, and fallback data; for a chart, theme
|
|
446
|
+
Vega-Lite with `@ponchia/ui/vega` (or hand-author a token-themed inline `<svg>`)
|
|
447
|
+
inside a `ui-report__figure` — bronto ships no chart component; use
|
|
448
|
+
`ui-delta` (`--up`/`--down`/`--flat`, `--invert` when up is bad) for a
|
|
449
|
+
trend figure and `ui-compare` (`--2up`) for an A/B / before-after section; use
|
|
450
|
+
`ui-report__section--unnumbered` for appendices in numbered reports; never
|
|
451
|
+
use raw chromatic inline colors. Format numbers/dates yourself (the framework
|
|
452
|
+
aligns figures, it does not format them) — see the reporting cookbook. To make
|
|
453
|
+
a PDF, render with `chrome-headless-shell` (or any Chromium) using
|
|
454
|
+
`printBackground: true` so figure fills survive — reports are static/zero-JS, so
|
|
455
|
+
it is just load → print; see "Print and PDF" in `docs/reporting.md`. Full
|
|
456
|
+
cookbook: `docs/reporting.md`.
|
|
358
457
|
|
|
359
458
|
## Authoritative offline references (shipped in this package)
|
|
360
459
|
|
|
@@ -363,6 +462,11 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
|
|
|
363
462
|
- `classes/index.d.ts` — literal-typed `cls` map (exact class strings),
|
|
364
463
|
every `ui.*()` recipe signature, every `*Opts` interface. The complete
|
|
365
464
|
class surface; an agent should read this to know valid class names.
|
|
465
|
+
- `classes/classes.json` — the same vocabulary as language-neutral data, to
|
|
466
|
+
VALIDATE markup without executing ESM/parsing TS: `groups` (base →
|
|
467
|
+
modifiers/parts, the BEM structure), `classes` (flat list), `states` (the
|
|
468
|
+
`is-*` hooks that live outside `cls` by design, with their scope), and
|
|
469
|
+
`customProperties` (the author-set inline-style knobs like `--chart-color` / `--value`).
|
|
366
470
|
- `docs/reference.md` — the full class catalog as prose tables (every
|
|
367
471
|
class grouped by component, with registry key + kind). Generated from
|
|
368
472
|
the same source as the types and CI-drift-checked.
|
|
@@ -378,6 +482,13 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
|
|
|
378
482
|
boundaries.
|
|
379
483
|
- `docs/annotations.md` — SVG annotation recipes and helper guidance for
|
|
380
484
|
analytical figures.
|
|
485
|
+
- `docs/mermaid.md` — theme Mermaid diagrams from bronto tokens (resolved
|
|
486
|
+
`base` themeVariables, gated) and annotate the rendered SVG.
|
|
487
|
+
- `docs/d2.md` — theme D2 diagrams from bronto tokens (theme-override slots,
|
|
488
|
+
monochrome base + opt-in accent, gated) and annotate the rendered SVG.
|
|
489
|
+
- `docs/vega.md` — theme Vega-Lite charts from bronto tokens (resolved `config`,
|
|
490
|
+
gated + render-probed) — the recommended path when a report needs a chart,
|
|
491
|
+
since bronto ships no chart component.
|
|
381
492
|
- `docs/contrast.md` — the published, CI-gated WCAG 2.1 contrast matrix
|
|
382
493
|
for every contractual token pairing, per theme. Generated from the
|
|
383
494
|
resolved palette; the build fails below the declared floor.
|
|
@@ -385,8 +496,11 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
|
|
|
385
496
|
- `tokens/index.json` — tokens as plain data (global / light / dark).
|
|
386
497
|
- `tokens/tokens.dtcg.json` — same tokens in W3C DTCG format.
|
|
387
498
|
- `tokens/resolved.json` — every colour token resolved to a static
|
|
388
|
-
`#rrggbb` / `rgba(...)` per theme (var() + color-mix() evaluated)
|
|
389
|
-
|
|
499
|
+
`#rrggbb` / `rgba(...)` per theme (var() + color-mix() evaluated) in
|
|
500
|
+
`light`/`dark`, plus a `scale` block of the non-colour scales
|
|
501
|
+
(spacing/radius/type/z/motion, var() chains flattened). The complete token
|
|
502
|
+
contract for non-CSS render targets: MapLibre/canvas/WebGL/SVG, or a
|
|
503
|
+
non-JS host (Python/Go) building a themed report.
|
|
390
504
|
- `behaviors/index.d.ts` — typed signatures for the optional behaviors.
|
|
391
505
|
- `glyphs/glyphs.d.ts` — the `GlyphName` literal union plus `renderGlyph` /
|
|
392
506
|
`glyphCells` signatures for the display glyphs. (The DOM form,
|
|
@@ -404,13 +518,24 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
|
|
|
404
518
|
|
|
405
519
|
## Rules an agent should respect
|
|
406
520
|
|
|
407
|
-
- Never invent `ui-*` class names. Every valid class is a member of
|
|
408
|
-
`cls` in `classes/index.d.ts
|
|
521
|
+
- Never invent `ui-*` class names. Every valid `ui-*` class is a member of
|
|
522
|
+
`cls` in `classes/index.d.ts` (and `classes/classes.json`); if a `ui-*`
|
|
523
|
+
name is not there, it does not exist. The `is-*` state hooks
|
|
524
|
+
(`is-num`/`is-pos`/`is-neg`/`is-key` on `.ui-table` cells and `.ui-stat`
|
|
525
|
+
deltas, `is-open`/`is-active`/`is-inactive` on stateful components) are the
|
|
526
|
+
one exception — they are real, documented in `docs/reference.md`
|
|
527
|
+
(§"Table-local state classes" / §"Composition & state") and emitted by the
|
|
528
|
+
`ui.*()` recipes, but deliberately NOT in `cls`. Do not strip them.
|
|
409
529
|
- Prefer the `ui.*()` recipes over hand-concatenating modifier strings.
|
|
410
530
|
Report/layout classes added in 0.4.1 are the exception: use `cls.report*`,
|
|
411
531
|
`cls.chart*`, `cls.printOnly`, or literal documented class names because
|
|
412
532
|
there are no `ui.report()` / `ui.chart()` recipes yet. Annotations do have a
|
|
413
533
|
`ui.annotation()` recipe for variant/tone selection.
|
|
534
|
+
- For a standalone HTML report, never `<link>` a `@ponchia/ui/css/*.css`
|
|
535
|
+
package specifier (it does not resolve in a browser) and never assume
|
|
536
|
+
`dist/bronto.css` carries the report/chart/legend/annotation layers — it
|
|
537
|
+
does not. Link each opt-in leaf from `dist/css/` via a real URL
|
|
538
|
+
(`./node_modules/…` or a pinned CDN). See the loading note above.
|
|
414
539
|
- Override framework styles by writing your own rules outside
|
|
415
540
|
`@layer bronto` — not with higher specificity or `!important`.
|
|
416
541
|
- Color is tiered (ADR-0001): neutral canvas · one rationed accent · locked
|