@ponchia/ui 0.8.0 → 0.9.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.
@@ -0,0 +1,216 @@
1
+ # Migrating 0.7 to 0.8
2
+
3
+ Machine-readable migration graph: [`MIGRATIONS.json`](../../MIGRATIONS.json) —
4
+ it has no entry for this pair, because nothing was renamed or removed. Every
5
+ class, token, attribute, and export valid in 0.7 is still valid.
6
+
7
+ 0.8.0 comes from auditing one real consumer's stylesheet in full. It repairs an
8
+ accessibility floor, adds three surfaces that consumer had to hand-write, and
9
+ changes what a colorway does. Only the last of those needs a decision from you.
10
+
11
+ ## 1. Decide what your skins should look like — the one breaking change
12
+
13
+ **Only affects you if you set `data-bronto-skin`.** If you don't, skip to §2.
14
+
15
+ Until 0.7, a colorway moved `--accent` and nothing else; the neutral canvas
16
+ stayed grey, and ADR-0001 step 4 said so. From 0.8 a colorway also re-points ten
17
+ canvas tokens per theme:
18
+
19
+ ```
20
+ --bg --bg-elevated --panel --panel-strong --panel-soft
21
+ --line --line-strong --text --text-soft --text-dim
22
+ ```
23
+
24
+ So "Amber CRT" now actually renders amber. Nothing in your source changes and no
25
+ checker will flag anything — the break is purely visual, which is why it is
26
+ worth reading rather than discovering.
27
+
28
+ **Contrast is not a regression risk.** Each neutral keeps the core token's OKLCH
29
+ *lightness* exactly and moves only hue plus a small chroma, and `check-contrast`
30
+ re-measures all 21 gated pairings per skin per theme. Status colours
31
+ (`--success` / `--warning` / `--danger` / `--info`) are untouched by design: a
32
+ warning must look like a warning in every skin.
33
+
34
+ ### If you already hand-wrote a canvas for a skin
35
+
36
+ Delete it. That workaround is what motivated this change, and a hand-rolled
37
+ version is almost certainly not contrast-gated, probably covers one theme, and
38
+ probably misses whichever skin nobody opened.
39
+
40
+ ### If you want the 0.7 look back
41
+
42
+ Re-declare the ten tokens after the skin import. They are ordinary custom
43
+ properties on a `:root[data-bronto-skin=…]` selector inside `@layer bronto`, so
44
+ un-layered app CSS wins without a specificity fight:
45
+
46
+ ```css
47
+ @import '@ponchia/ui';
48
+ @import '@ponchia/ui/css/skins.css';
49
+
50
+ /* Keep the neutral canvas grey under every colorway. */
51
+ :root[data-bronto-skin] {
52
+ --bg: #f4f4f2;
53
+ --bg-elevated: #fbfbfa;
54
+ --panel: #ffffff;
55
+ --panel-strong: #ffffff;
56
+ --panel-soft: #ececea;
57
+ --line: #d8d8d4;
58
+ --line-strong: #a8a8a2;
59
+ --text: #0a0a0a;
60
+ --text-soft: #353533;
61
+ --text-dim: #686863;
62
+ }
63
+ ```
64
+
65
+ (Those are the 0.7 light values; take the dark set from `tokens/resolved.json`
66
+ and repeat under `:root[data-theme='dark'][data-bronto-skin]`.)
67
+
68
+ ## 2. Delete your tap-target workaround
69
+
70
+ The coarse-pointer floor was written as a bare `2.9rem`, and `css/base.css` sets
71
+ `html { font-size: 0.9375rem }` — so it resolved to **43.5px**, half a pixel
72
+ under the 44 that WCAG 2.5.5 and both platform HIGs require, and less than that
73
+ under any host with a smaller root. If you noticed and declared your own 44px
74
+ floor, you can now drop it:
75
+
76
+ ```diff
77
+ -:root { --touch-target: 44px; }
78
+ -
79
+ -@media (pointer: coarse) {
80
+ - .my-control { min-block-size: var(--touch-target); }
81
+ -}
82
+ ```
83
+
84
+ Bronto's controls float to `var(--tap-target)` — `max(44px, 2.9rem)` — on their
85
+ own. For your *own* controls, consume the token rather than a literal:
86
+
87
+ ```css
88
+ @media (pointer: coarse) {
89
+ .my-control {
90
+ min-block-size: var(--tap-target); /* 44px floor, WCAG 2.5.5 */
91
+ }
92
+ }
93
+ ```
94
+
95
+ `--tap-target-min` is the WCAG 2.5.8 AA 24px floor, for controls that only have
96
+ to clear the smaller bar. Both clamp in px on purpose: **keep the clamp if you
97
+ override them.** A bare rem is how a 44px floor quietly becomes 43.5px.
98
+
99
+ ## 3. Delete your safe-area declarations
100
+
101
+ 0.7 had no `env()` awareness at all. If you declared your own insets, drop them —
102
+ the same four names now ship:
103
+
104
+ ```diff
105
+ -:root {
106
+ - --safe-area-top: env(safe-area-inset-top, 0px);
107
+ - --safe-area-bottom: env(safe-area-inset-bottom, 0px);
108
+ -}
109
+ ```
110
+
111
+ Eight viewport-anchored surfaces now read them: the app rail and topbar, a
112
+ sticky site header, the skip link, both toast stacks, the drawer modal, and the
113
+ lightbox. Every rule uses `max(<authored>, var(--safe-area-*))`, so **desktop
114
+ rendering is unchanged**.
115
+
116
+ They are indirected through custom properties rather than calling `env()` at the
117
+ point of use, which matters twice: a desktop test runner cannot emulate `env()`
118
+ but can override a property, and a host running inside its own chrome (an
119
+ embedded webview, a kiosk frame) can declare the real insets. Follow the same
120
+ convention for your own floating chrome:
121
+
122
+ ```css
123
+ .my-floating-bar {
124
+ inset-block-end: max(1rem, var(--safe-area-bottom));
125
+ }
126
+ ```
127
+
128
+ ## 4. Two new opt-in ergonomics
129
+
130
+ Neither is required; both replace a common workaround.
131
+
132
+ **`ui-button__label`** — an icon button can keep its words for the accessible
133
+ name and for text-based test selectors while giving back the pixels. One markup
134
+ shape serves both forms, and no `aria-label` can drift out of sync with the
135
+ visible wording:
136
+
137
+ ```html
138
+ <button class="ui-button ui-button--icon">
139
+ <span class="ui-icon" style="--icon-mask: …"></span>
140
+ <span class="ui-button__label">Delete</span>
141
+ </button>
142
+ ```
143
+
144
+ Drop `--icon` and the same markup renders glyph + word. The slot ellipsises
145
+ rather than wrapping, so a labelled button in a tight bar shrinks instead of
146
+ pushing its neighbours out.
147
+
148
+ **`ui-button--dense`** — for bars whose *height* is the constraint: a pane title
149
+ bar, a packed toolbar, a table row's actions. It lowers only the visual floor,
150
+ to `--tap-target-min`. The coarse-pointer block still floats it to the full
151
+ `--tap-target`, so a control you shrink for a mouse is never shrunk for a
152
+ finger. `ui.button({ size: 'dense' })` in the recipe API.
153
+
154
+ ## 5. Retire your own severity vocabulary
155
+
156
+ Nothing forces this, but it is the reason most likely to have produced
157
+ divergent code. Bronto shipped the tones without the **scale**, so consumers
158
+ invented tier names — and inside one app they drift, because each surface was
159
+ written on a different day. If you have more than one, `css/state.css` now
160
+ publishes the canonical ladder:
161
+
162
+ ```
163
+ critical › error › warning › notice › ok (+ unknown, outside the order)
164
+ ```
165
+
166
+ ```js
167
+ import { severity, SEVERITY_LEVELS } from '@ponchia/ui/classes';
168
+
169
+ severity('critical'); // { class: 'ui-severity', 'data-level': 'critical' }
170
+ severity('warning', { part: 'row' }); // { class: 'ui-severity-row', … }
171
+ SEVERITY_LEVELS; // sort and filter from this, not a local copy
172
+ ```
173
+
174
+ The level travels on `data-level` — one attribute name — so a chip, a row, a
175
+ dot, and your own element all read the same selector, and your own element can
176
+ take `var(--severity-tone)` without copying a colour table.
177
+
178
+ Map your existing tiers onto it rather than keeping both. `unknown` is the
179
+ landing spot for anything unmeasured or stale; do **not** map it to `ok`, which
180
+ is an assertion of health and is how a dead collector reads as a healthy system.
181
+
182
+ ## 6. Other surfaces you may be hand-rolling
183
+
184
+ Each of these replaced something a real consumer had built locally. None is
185
+ required.
186
+
187
+ - **`.ui-pane`** — a grab header, an in-place rename input, and an actions slot
188
+ that scrolls rather than pushing its last control past the clipped edge. If
189
+ you have a node/window/panel with a draggable title bar, this is it.
190
+ `.ui-panel` is still just a padded card.
191
+ - **`.ui-toolstrip--pane`** — a control bar belonging to one pane rather than to
192
+ the app: no frame of its own, and it refuses to wrap so a second row cannot
193
+ resize live content underneath. Mark the shrinking element with
194
+ `.ui-toolstrip__fill`.
195
+ - **`.ui-selectionbar--anchored`** (and the same on `.ui-toolstrip`) — viewport
196
+ anchoring for a floating bar, safe-area aware. Use
197
+ `--anchor-block-start` for the bar that must *not* sit under the thumb.
198
+ - **`.ui-empty-state__glyph/__lead/__hint`** and **`--invite`** — the three
199
+ parts every empty surface re-invents, plus the distinction between reporting
200
+ absence and offering the next action.
201
+
202
+ ## 7. If you read `tokens.dtcg.json`
203
+
204
+ Six new scale tokens are **deliberately absent** from it, listed in the root
205
+ extension's `omittedCssVariables`: the two tap-target floors are `max()`
206
+ comparisons and the four safe-area insets are `env()` reads, and neither has a
207
+ conforming DTCG shape. Emitting one arm of a clamp, or the 0px fallback of an
208
+ `env()`, would publish a value that is wrong everywhere it matters. Read
209
+ `tokens.json` for the authored CSS. This is the same treatment `--shadow` and
210
+ the em trackings already get.
211
+
212
+ ## Nothing else changed
213
+
214
+ No class was renamed or removed. No export moved. `bronto-ui-check` will not
215
+ report anything new for a 0.7-clean consumer — which is worth stating plainly,
216
+ because the one breaking change in this release is invisible to it.
@@ -0,0 +1,66 @@
1
+ # Migrating 0.8 to 0.9
2
+
3
+ Machine-readable migration graph: [`MIGRATIONS.json`](../../MIGRATIONS.json).
4
+
5
+ One required change, and it is a one-word addition.
6
+
7
+ ## 1. Add `ui-menu--dropdown` to your menus
8
+
9
+ `.ui-menu` used to weld its placement into the surface: `position: absolute`
10
+ plus an offset relative to its trigger. That made the class unusable for a menu
11
+ opened at a POINT — a canvas context menu, a long-press sheet — so a consumer
12
+ with one re-declared the panel, border, radius and shadow just to get a surface.
13
+
14
+ Placement is now opted into:
15
+
16
+ ```diff
17
+ <details class="ui-menu-host" data-bronto-menu>
18
+ <summary class="ui-button ui-button--subtle">Menu</summary>
19
+ - <div class="ui-menu">
20
+ + <div class="ui-menu ui-menu--dropdown">
21
+ ```
22
+
23
+ Without the modifier the surface renders in normal flow. Nothing else changed:
24
+ `--dropdown` carries exactly the declarations that used to be unconditional.
25
+
26
+ For a menu you position yourself, use `ui-menu--at-pointer` and set `left`/`top`
27
+ (or the logical equivalents) from the host — Bronto only takes it out of flow
28
+ and gives it the popover layer.
29
+
30
+ ## 2. Optional: adopt `ui-row`
31
+
32
+ New in the default bundle, so it costs nothing to try. If you have a list of
33
+ selectable lines that is not a table and not a menu — search results, an
34
+ explorer, an outline, backlinks, commits — that is `ui-row`:
35
+
36
+ ```html
37
+ <button class="ui-row ui-row--ruled" type="button" aria-selected="true">
38
+ <span class="ui-row__mark" aria-hidden="true">◆</span>
39
+ <span class="ui-row__title">apps/server/src/collab/room.ts</span>
40
+ <span class="ui-row__meta">4m</span>
41
+ </button>
42
+ ```
43
+
44
+ `__title` truncates; `__meta` does not. Selection reads `aria-selected` or
45
+ `aria-current`, so the visual state cannot disagree with what a screen reader
46
+ announces. Rows carrying a severity want `ui-severity-row` instead.
47
+
48
+ `ui-menu__item` composes it, so menu items and rows cannot drift apart.
49
+
50
+ ## 3. Know what `data-density` actually does
51
+
52
+ No change in behaviour — a correction to what the docs claimed. The preset
53
+ re-points the `--space-*` scale, so it moves the ~40 components whose padding is
54
+ expressed in that scale and **none** of the rest. `ui-alert` and
55
+ `ui-menu__item` are the two most likely to surprise you.
56
+
57
+ The others carry tuned pairs like `0.5rem 0.55rem` that a seven-step scale
58
+ cannot express; flattening them would change the default rendering everyone
59
+ uses. If you need a denser variant of a component that does not respond,
60
+ override its padding — and if you do that repeatedly for the same component,
61
+ report it, because that is evidence for a real `--dense` modifier.
62
+
63
+ ## Nothing else changed
64
+
65
+ No class was removed or renamed. `bronto-ui-check` will not report anything new
66
+ for a 0.8-clean consumer.
@@ -49,6 +49,7 @@ semantic versioning contract for the surfaces listed here.
49
49
  | `./css/skins.css` | `./dist/css/skins.css` | Opt-in layered CSS leaf | Stable additive | Generated layered direct-import leaf. Opt-in and not included in dist/bronto.css. |
50
50
  | `./css/dataviz.css` | `./dist/css/dataviz.css` | Opt-in layered CSS leaf | Stable additive | Generated layered direct-import leaf. Opt-in and not included in dist/bronto.css. |
51
51
  | `./css/report.css` | `./dist/css/report.css` | Opt-in layered CSS leaf | Stable additive | Generated layered direct-import leaf. Opt-in and not included in dist/bronto.css. |
52
+ | `./css/row.css` | `./dist/css/row.css` | Bundled layered CSS leaf | Stable additive | Generated layered direct-import leaf. Also included in dist/bronto.css. |
52
53
  | `./css/figure.css` | `./dist/css/figure.css` | Opt-in layered CSS leaf | Stable additive | Generated layered direct-import leaf. Opt-in and not included in dist/bronto.css. |
53
54
  | `./css/annotations.css` | `./dist/css/annotations.css` | Opt-in layered CSS leaf | Stable additive | Generated layered direct-import leaf. Opt-in and not included in dist/bronto.css. |
54
55
  | `./css/legend.css` | `./dist/css/legend.css` | Opt-in layered CSS leaf | Stable additive | Generated layered direct-import leaf. Opt-in and not included in dist/bronto.css. |
@@ -94,6 +95,7 @@ semantic versioning contract for the surfaces listed here.
94
95
  | `./css/unlayered/skins.css` | `./css/skins.css` | Unlayered CSS leaf | Stable path | Raw authored CSS leaf for consumers that deliberately opt out of @layer bronto on that leaf. |
95
96
  | `./css/unlayered/dataviz.css` | `./css/dataviz.css` | Unlayered CSS leaf | Stable path | Raw authored CSS leaf for consumers that deliberately opt out of @layer bronto on that leaf. |
96
97
  | `./css/unlayered/report.css` | `./css/report.css` | Unlayered CSS leaf | Stable path | Raw authored CSS leaf for consumers that deliberately opt out of @layer bronto on that leaf. |
98
+ | `./css/unlayered/row.css` | `./css/row.css` | Unlayered CSS leaf | Stable path | Raw authored CSS leaf for consumers that deliberately opt out of @layer bronto on that leaf. |
97
99
  | `./css/unlayered/figure.css` | `./css/figure.css` | Unlayered CSS leaf | Stable path | Raw authored CSS leaf for consumers that deliberately opt out of @layer bronto on that leaf. |
98
100
  | `./css/unlayered/annotations.css` | `./css/annotations.css` | Unlayered CSS leaf | Stable path | Raw authored CSS leaf for consumers that deliberately opt out of @layer bronto on that leaf. |
99
101
  | `./css/unlayered/legend.css` | `./css/legend.css` | Unlayered CSS leaf | Stable path | Raw authored CSS leaf for consumers that deliberately opt out of @layer bronto on that leaf. |
@@ -299,6 +301,8 @@ always includes `package.json`, `README.md`, `LICENSE`, and
299
301
  | `docs/migrations/0.4-to-0.5.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
300
302
  | `docs/migrations/0.5-to-0.6.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
301
303
  | `docs/migrations/0.6-to-0.7.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
304
+ | `docs/migrations/0.7-to-0.8.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
305
+ | `docs/migrations/0.8-to-0.9.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
302
306
  | `docs/adr/0001-color-system.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
303
307
  | `docs/adr/0002-scope-and-2026-baseline.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
304
308
  | `docs/adr/0003-theme-model.md` | Shipped documentation | Curated Markdown reading asset shipped in the npm tarball. |
@@ -315,7 +319,7 @@ result. The listed gates are part of `npm run check`.
315
319
  | Package manifest | `package.json` | docs/package-contract.md | `npm run package-contract:build` | check:fresh; check:exports; check:pack; check:consumer-surface; check:consumer-types; check:publint; check:attw | The complete export/file matrix in this document is generated from the manifest; packed tarball imports, concrete file resolution, and package-level type resolution are smoke-tested in clean consumers. |
316
320
  | Token model | `tokens/index.js` | css/tokens.css; tokens/index.json; tokens/tokens.dtcg.json; tokens/resolved.json; tokens/figma.variables.json; tokens/index.d.ts | `npm run tokens:css:build; tokens:build; dtcg:build; resolved:build; figma:variables:build; dts:build` | check:fresh; check:contrast | Token names/roles are public. Resolved and Figma handoff values are visual tuning before 1.0. |
317
321
  | Class registry | `classes/index.js plus css/*.css selectors` | classes/classes.json; classes/index.d.ts; classes/vscode.css-custom-data.json; docs/reference.md | `npm run classes:json:build; dts:build; vscode:build; reference:build` | check:fresh; check:classes; check:contract | The typed registry, JSON vocabulary, and generated reference stay aligned with real selectors. |
318
- | Authored CSS graph | `css/core.css plus css/*.css leaves` | dist/bronto.css; dist/css/*.css (46 layered outputs) | `npm run dist:build` | check:dist; check:exports; check:component-matrix | Default bundle and direct layered leaf imports are generated from authored CSS, size-gated, and coverage-owned as foundation or component leaves. |
322
+ | Authored CSS graph | `css/core.css plus css/*.css leaves` | dist/bronto.css; dist/css/*.css (47 layered outputs) | `npm run dist:build` | check:dist; check:exports; check:component-matrix | Default bundle and direct layered leaf imports are generated from authored CSS, size-gated, and coverage-owned as foundation or component leaves. |
319
323
  | JSDoc-authored public JS | `behaviors/; annotations/; connectors/; react/; solid/; qwik/; svelte/; vue/` | adjacent *.d.ts and *.d.ts.map files | `npm run dts:emit` | check:dts-emit; check:types; check:consumer-surface; check:consumer-types; check:behavior-matrix; check:attw; check:publint | Declarations are emitted from the shipped JS, package subpath imports are compiled from a packed clean consumer, and public behavior exports are docs/unit/browser owned. |
320
324
  | Glyph registry | `glyphs/glyphs.js` | glyphs/glyphs.d.ts | `npm run glyphs:build` | check:glyphs; check:unit | Glyph names and render options are public. The registry stays sorted and type-covered. |
321
325
  | Display colorways | `tokens/skins.js` | css/skins.css; tokens/skins.d.ts | `npm run skins:build` | check:skins; check:contrast | Skins are opt-in root-level choices and never part of dist/bronto.css. |
package/docs/reference.md CHANGED
@@ -9,7 +9,7 @@ rendering of every class is the kitchen-sink demo:
9
9
  **<https://ponchia.github.io/bronto-ui/>**. Theming knobs and the token
10
10
  contract: [docs/theming.md](theming.md).
11
11
 
12
- - 669 classes across 183 component groups
12
+ - 677 classes across 184 component groups
13
13
  - Import the typed registry: `import { cls, ui, cx } from '@ponchia/ui/classes'`
14
14
  - Validate markup as data (no JS/TS): `@ponchia/ui/classes.json` — the same
15
15
  vocabulary as language-neutral JSON (`groups`, `classes`, `states`,
@@ -874,6 +874,8 @@ each one matches a real selector in the stylesheet.
874
874
  | `cls.menuItem` | `ui-menu__item` | part |
875
875
  | `cls.menuLabel` | `ui-menu__label` | part |
876
876
  | `cls.menuSep` | `ui-menu__sep` | part |
877
+ | `cls.menuAtPointer` | `ui-menu--at-pointer` | modifier |
878
+ | `cls.menuDropdown` | `ui-menu--dropdown` | modifier |
877
879
 
878
880
  ### `.ui-menu-host`
879
881
 
@@ -1117,6 +1119,17 @@ each one matches a real selector in the stylesheet.
1117
1119
  | --- | --- | --- |
1118
1120
  | `cls.reveal` | `ui-reveal` | base |
1119
1121
 
1122
+ ### `.ui-row`
1123
+
1124
+ | Registry key | Class | Kind |
1125
+ | --- | --- | --- |
1126
+ | `cls.row` | `ui-row` | base |
1127
+ | `cls.rowMark` | `ui-row__mark` | part |
1128
+ | `cls.rowMeta` | `ui-row__meta` | part |
1129
+ | `cls.rowTitle` | `ui-row__title` | part |
1130
+ | `cls.rowRuled` | `ui-row--ruled` | modifier |
1131
+ | `cls.rowStacked` | `ui-row--stacked` | modifier |
1132
+
1120
1133
  ### `.ui-screen-only`
1121
1134
 
1122
1135
  | Registry key | Class | Kind |
package/docs/reporting.md CHANGED
@@ -54,18 +54,18 @@ No install? Link the same files from a CDN. Pin the version — pre-1.0, breakin
54
54
  changes ship in the minor (see [stability.md](./stability.md)):
55
55
 
56
56
  ```html
57
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/bronto.css" />
58
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/css/report-kit.css" />
57
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/bronto.css" />
58
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/css/report-kit.css" />
59
59
  ```
60
60
 
61
61
  Leaf-by-leaf CDN imports use the same `dist/css/` paths:
62
62
 
63
63
  ```html
64
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/bronto.css" />
65
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/css/report.css" />
66
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/css/dataviz.css" />
67
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/css/annotations.css" />
68
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/css/legend.css" />
64
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/bronto.css" />
65
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/css/report.css" />
66
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/css/dataviz.css" />
67
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/css/annotations.css" />
68
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/css/legend.css" />
69
69
  ```
70
70
 
71
71
  The CDN serves the package's own `fonts/` next to the CSS, so font URLs resolve
@@ -879,7 +879,7 @@ or validation runtime.
879
879
 
880
880
  ```json
881
881
  {
882
- "$schema": "https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/schemas/report-claims.v1.schema.json",
882
+ "$schema": "https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/schemas/report-claims.v1.schema.json",
883
883
  "schemaVersion": "bronto-report-claims.v1",
884
884
  "report": { "title": "Decision readiness", "type": "decision" },
885
885
  "claims": [
package/docs/stability.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Public API stability
2
2
 
3
3
  `@ponchia/ui` is pre-1.0. Breaking changes ship in the minor (`0.x.0`), and
4
- patches are non-breaking. In practical terms: **PATCH releases (`0.8.x`) are
4
+ patches are non-breaking. In practical terms: **PATCH releases (`0.9.x`) are
5
5
  non-breaking bug-fixes and additive changes — safe to upgrade without review;
6
6
  MINOR releases (`0.x.0`) may include breaking changes and consumers should
7
7
  review the CHANGELOG before upgrading.** Pin `~0.x` (tilde) to accept only
@@ -140,6 +140,7 @@ current public-surface matrix and the release policy above still applies.
140
140
  | Connectors (`@ponchia/ui/connectors`, `css/connectors.css`, `.ui-connector*`, `initConnectors`) | Stable additive | Connector class names, the `data-bronto-connector` attribute contract, geometry helper function names, and recipe options are public. Helper internals/heuristics may tune before 1.0. Opt-in, not in the default bundle. |
141
141
  | Spotlight (`css/spotlight.css`, `.ui-spotlight*`, `.ui-tour-note*`, `initSpotlight`) | Stable additive | Spotlight/tour-note class names, the `--spot-*` custom-property contract, and the `data-bronto-spotlight`/`data-target` attributes are public. Opt-in, not in the default bundle. Not a tour engine. |
142
142
  | Crosshair (`css/crosshair.css`, `.ui-crosshair*`, `.ui-readout`, `initCrosshair`) | Stable additive | Crosshair/readout class names, the `--crosshair-x/y` properties, the `data-bronto-crosshair` attribute, and the `bronto:crosshair:move`/`:leave` event contract are public. Opt-in. Reports pointer position only — no data mapping. |
143
+ | Rows (`css/row.css`, `.ui-row*`) | Stable additive | Class names, the `__title` / `__meta` / `__mark` parts, the `--stacked` / `--ruled` modifiers, and the selection contract are public: `aria-selected`, `aria-current` and `.is-selected` all paint the selected state, so the visual state cannot disagree with the announced one. `__title` is the part that truncates and `__meta` is the part that does not — that asymmetry is the contract, not a detail. **In the default bundle**, unusually for a new surface: `.ui-menu__item` composes it, so a core component depends on it. Also exported standalone, which is why it appears here, but it is NOT opt-in. |
143
144
  | Selection states (`css/selection.css`, `.ui-sel*`) | Stable additive | The `.ui-sel`/`--on`/`--off`/`--maybe` emphasis classes and recipe options are public. Opt-in, cross-cutting. The host owns selection logic; Bronto only styles the states. |
144
145
  | Analytical roll-up (`css/analytical.css`) | Stable additive | A convenience `@import` of the nine analytical leaves (figure, annotations, legend, marks, connectors, spotlight, crosshair, selection, highlights). The set of leaves it bundles may grow additively; each leaf also stays individually exported. Opt-in, not in the default bundle. |
145
146
  | Sources / provenance (`css/sources.css`, `.ui-citation*`, `.ui-source-card*`, `.ui-source-list*`, `.ui-provenance*`, `.ui-src--*`, `initSources`) | Stable additive | Citation/source/provenance class names, the cross-cutting `.ui-src--*` trust-state modifiers (always paired with an author label), the optional `data-bronto-sources` / `data-bronto-source-ref` behavior contract, `bronto:source:focus`, and the `ui.citation`/`ui.source`/`ui.provenance` recipes + `cls.sourceList` are public. Opt-in, not in the default bundle. |
package/docs/theming.md CHANGED
@@ -130,6 +130,22 @@ you change CSS `--accent` later.
130
130
  - **Spacing** — override the `--space-2xs … --space-2xl` scale, or use a
131
131
  preset: `data-density="compact"` / `data-density="comfortable"` on any
132
132
  element (defaults to the middle scale).
133
+
134
+ **Read this before relying on the preset.** It re-points the `--space-*`
135
+ scale, and only components whose padding is *expressed in that scale* move
136
+ with it — around 40 of them, including `ui-panel`, `ui-modal__body`,
137
+ `ui-evidence-item`, `ui-claim`, `ui-job`, `ui-code__body` and the report
138
+ surfaces. The rest carry tuned padding pairs like `0.5rem 0.55rem`, which the
139
+ seven-step scale cannot express, so **they do not respond at all** —
140
+ `ui-alert` and `ui-menu__item` are the two most likely to surprise you.
141
+
142
+ That is a real limit, not an oversight to work around: flattening a tuned pair
143
+ onto the nearest scale step would change how those components look at the
144
+ default density, which is the one nearly everyone uses. If you need a denser
145
+ variant of a component that does not respond, override its padding directly —
146
+ and if you find yourself doing that repeatedly for the same component, that is
147
+ worth reporting, because it is evidence for a real `--dense` modifier rather
148
+ than a preset that half-works.
133
149
  - **Dark surface** — the dark theme's base is a deliberately *elevated*
134
150
  near-black (`--bg: #121212`) for readability: pure black + bright text
135
151
  causes halation, and near-black-on-black surface steps are imperceptible.
package/docs/usage.md CHANGED
@@ -186,6 +186,48 @@ a `.ui-legend` key, and fallback data. Full LLM/static report cookbook:
186
186
  spinner is CSS. This is the ARIA-driven contract — see reference.md
187
187
  → "Composition & state".
188
188
 
189
+ ## Rows: `ui-row` vs table vs menu item
190
+
191
+ Three shapes look alike and are not interchangeable:
192
+
193
+ - **`ui-table`** when the data has columns and a header. A table promises that
194
+ the third cell means the same thing on every line.
195
+ - **`ui-menu__item`** when the list is a menu: it dismisses on choice, and it is
196
+ reached through `ui-menu-host`.
197
+ - **`ui-row`** for everything else — a search result, a file in an explorer, an
198
+ outline entry, a backlink, a commit. A full-width clickable line that
199
+ *persists*.
200
+
201
+ ```html
202
+ <button class="ui-row ui-row--ruled" type="button" aria-current="true">
203
+ <span class="ui-row__mark" aria-hidden="true">◆</span>
204
+ <span class="ui-row__title">apps/server/src/collab/room.ts</span>
205
+ <span class="ui-row__meta">4m</span>
206
+ </button>
207
+ ```
208
+
209
+ The one rule worth knowing: **`__title` is what truncates.** It takes the slack
210
+ and gives it back first; `__meta` never shrinks, because a half-rendered number
211
+ is worse than no number.
212
+
213
+ **Pick the right attribute, and it is probably not `aria-selected`.** That one
214
+ is only valid on a row whose role accepts it — `option` inside a `listbox`, or
215
+ `row` / `tab` / `gridcell` / `treeitem`. On a bare `<button>` it is invalid ARIA
216
+ and axe rates it *critical*; this project shipped that mistake in its own demo
217
+ and the a11y gate caught it before release.
218
+
219
+ - `aria-current="true"` — the row is the current one. The common case, and valid
220
+ on any element.
221
+ - `aria-selected="true"` — only when the row really is an `option` in a
222
+ `listbox`, or another role that accepts it.
223
+ - `.is-selected` — when neither fits.
224
+
225
+ All three paint the same, so the visual state cannot disagree with the announced
226
+ one. Rows carrying a severity should use `ui-severity-row` (`css/state.css`)
227
+ instead, which adds the tone gutter.
228
+
229
+ `ui-menu__item` composes `ui-row`, which is why they cannot drift.
230
+
189
231
  ## Empty state vs invite
190
232
 
191
233
  Both use `ui-empty-state`, and the slots are the same three parts — a quiet
package/llms.txt CHANGED
@@ -45,7 +45,7 @@ the path changes from source `css/` to built `dist/css/`:
45
45
  <!-- installed locally -->
46
46
  <link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/<leaf>.css" />
47
47
  <!-- or from a CDN; pin the version (pre-1.0, breaking changes ship in the minor) -->
48
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/css/<leaf>.css" />
48
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.9.0/dist/css/<leaf>.css" />
49
49
  ```
50
50
 
51
51
  The flattened default bundle is `dist/bronto.css` (bundler shorthand
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@ponchia/ui",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
- "description": "CSS-first identity and UI layer for services, tools, sites, and reports works in HTML, every framework, and PDF, no component runtime. Shared app shell, forms, tables, workflow chrome, plus opt-in analytical/report primitives. Monochrome with one rationed accent. Zero runtime dependencies.",
5
+ "description": "CSS-first identity and UI layer for services, tools, sites, and reports \u2014 works in HTML, every framework, and PDF, no component runtime. Shared app shell, forms, tables, workflow chrome, plus opt-in analytical/report primitives. Monochrome with one rationed accent. Zero runtime dependencies.",
6
6
  "keywords": [
7
7
  "css",
8
8
  "ui",
@@ -113,6 +113,8 @@
113
113
  "docs/migrations/0.4-to-0.5.md",
114
114
  "docs/migrations/0.5-to-0.6.md",
115
115
  "docs/migrations/0.6-to-0.7.md",
116
+ "docs/migrations/0.7-to-0.8.md",
117
+ "docs/migrations/0.8-to-0.9.md",
116
118
  "docs/adr/0001-color-system.md",
117
119
  "docs/adr/0002-scope-and-2026-baseline.md",
118
120
  "docs/adr/0003-theme-model.md",
@@ -213,24 +215,24 @@
213
215
  "prepublishOnly": "npm run build:artifacts && npm run check"
214
216
  },
215
217
  "devDependencies": {
216
- "@arethetypeswrong/cli": "^0.18.4",
218
+ "@arethetypeswrong/cli": "^0.18.5",
217
219
  "@axe-core/playwright": "^4.11.3",
218
220
  "@builder.io/qwik": "^1.20.0",
219
221
  "@playwright/test": "1.60.0",
220
222
  "github-actionlint": "^1.7.12",
221
- "jsdom": "^29.1.1",
222
- "knip": "^6.23.0",
223
- "pdfjs-dist": "^6.1.200",
224
- "prettier": "^3.9.1",
225
- "publint": "^0.3.21",
226
- "react": "^19.2.7",
227
- "react-dom": "^19.2.7",
228
- "solid-js": "^1.9.13",
229
- "stylelint": "^17.14.0",
223
+ "jsdom": "^30.0.1",
224
+ "knip": "^6.32.1",
225
+ "pdfjs-dist": "^6.2.108",
226
+ "prettier": "^3.9.6",
227
+ "publint": "^0.3.23",
228
+ "react": "^19.2.8",
229
+ "react-dom": "^19.2.8",
230
+ "solid-js": "^1.9.14",
231
+ "stylelint": "^17.14.1",
230
232
  "stylelint-config-standard": "^40.0.0",
231
233
  "stylelint-use-logical": "^2.1.3",
232
234
  "typescript": "^6.0.3",
233
- "vega": "^6.2.0",
235
+ "vega": "^6.3.1",
234
236
  "vega-lite": "^6.4.3"
235
237
  },
236
238
  "peerDependencies": {
@@ -278,6 +280,7 @@
278
280
  "./css/skins.css": "./dist/css/skins.css",
279
281
  "./css/dataviz.css": "./dist/css/dataviz.css",
280
282
  "./css/report.css": "./dist/css/report.css",
283
+ "./css/row.css": "./dist/css/row.css",
281
284
  "./css/figure.css": "./dist/css/figure.css",
282
285
  "./css/annotations.css": "./dist/css/annotations.css",
283
286
  "./css/legend.css": "./dist/css/legend.css",
@@ -323,6 +326,7 @@
323
326
  "./css/unlayered/skins.css": "./css/skins.css",
324
327
  "./css/unlayered/dataviz.css": "./css/dataviz.css",
325
328
  "./css/unlayered/report.css": "./css/report.css",
329
+ "./css/unlayered/row.css": "./css/row.css",
326
330
  "./css/unlayered/figure.css": "./css/figure.css",
327
331
  "./css/unlayered/annotations.css": "./css/annotations.css",
328
332
  "./css/unlayered/legend.css": "./css/legend.css",