@ponchia/ui 0.4.0 → 0.5.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +352 -12
  2. package/MIGRATIONS.json +92 -0
  3. package/README.md +27 -17
  4. package/annotations/index.d.ts +280 -0
  5. package/annotations/index.js +522 -0
  6. package/behaviors/carousel.js +197 -0
  7. package/behaviors/combobox.js +195 -0
  8. package/behaviors/command.js +187 -0
  9. package/behaviors/connectors.js +96 -0
  10. package/behaviors/crosshair.js +58 -0
  11. package/behaviors/dialog.js +73 -0
  12. package/behaviors/disclosure.js +25 -0
  13. package/behaviors/dismissible.js +24 -0
  14. package/behaviors/forms.js +158 -0
  15. package/behaviors/glyph.js +109 -0
  16. package/behaviors/index.d.ts +82 -1
  17. package/behaviors/index.js +18 -1336
  18. package/behaviors/internal.js +50 -0
  19. package/behaviors/legend.js +46 -0
  20. package/behaviors/menu.js +46 -0
  21. package/behaviors/popover.js +108 -0
  22. package/behaviors/spotlight.js +53 -0
  23. package/behaviors/table.js +109 -0
  24. package/behaviors/tabs.js +103 -0
  25. package/behaviors/theme.js +82 -0
  26. package/behaviors/toast.js +152 -0
  27. package/classes/index.d.ts +318 -0
  28. package/classes/index.js +352 -0
  29. package/classes/vscode.css-custom-data.json +18 -14
  30. package/connectors/index.d.ts +71 -0
  31. package/connectors/index.js +179 -0
  32. package/css/analytical.css +21 -0
  33. package/css/annotations.css +292 -0
  34. package/css/command.css +97 -0
  35. package/css/connectors.css +93 -0
  36. package/css/crosshair.css +100 -0
  37. package/css/disclosure.css +29 -0
  38. package/css/dots.css +2 -0
  39. package/css/feedback.css +104 -0
  40. package/css/fonts.css +11 -7
  41. package/css/generated.css +117 -0
  42. package/css/legend.css +268 -0
  43. package/css/marks.css +144 -0
  44. package/css/motion.css +88 -0
  45. package/css/overlay.css +52 -1
  46. package/css/primitives.css +18 -0
  47. package/css/report.css +363 -0
  48. package/css/selection.css +46 -0
  49. package/css/sources.css +179 -0
  50. package/css/spotlight.css +104 -0
  51. package/css/state.css +121 -0
  52. package/css/tokens.css +78 -60
  53. package/css/workbench.css +83 -0
  54. package/dist/bronto.css +1 -1
  55. package/dist/css/analytical.css +1 -0
  56. package/dist/css/annotations.css +1 -0
  57. package/dist/css/command.css +1 -0
  58. package/dist/css/connectors.css +1 -0
  59. package/dist/css/crosshair.css +1 -0
  60. package/dist/css/disclosure.css +1 -1
  61. package/dist/css/dots.css +1 -1
  62. package/dist/css/feedback.css +1 -1
  63. package/dist/css/fonts.css +1 -1
  64. package/dist/css/generated.css +1 -0
  65. package/dist/css/legend.css +1 -0
  66. package/dist/css/marks.css +1 -0
  67. package/dist/css/motion.css +1 -1
  68. package/dist/css/overlay.css +1 -1
  69. package/dist/css/primitives.css +1 -1
  70. package/dist/css/report.css +1 -0
  71. package/dist/css/selection.css +1 -0
  72. package/dist/css/sources.css +1 -0
  73. package/dist/css/spotlight.css +1 -0
  74. package/dist/css/state.css +1 -0
  75. package/dist/css/tokens.css +1 -1
  76. package/dist/css/workbench.css +1 -0
  77. package/docs/adr/0001-color-system.md +26 -27
  78. package/docs/adr/0002-scope-and-2026-baseline.md +104 -0
  79. package/docs/adr/0003-theme-model.md +97 -0
  80. package/docs/annotations.md +345 -0
  81. package/docs/architecture.md +202 -0
  82. package/docs/command.md +95 -0
  83. package/docs/connectors.md +91 -0
  84. package/docs/contrast.md +42 -42
  85. package/docs/crosshair.md +63 -0
  86. package/docs/generated.md +91 -0
  87. package/docs/legends.md +168 -0
  88. package/docs/marks.md +86 -0
  89. package/docs/reference.md +418 -15
  90. package/docs/reporting.md +305 -0
  91. package/docs/selection.md +40 -0
  92. package/docs/sources.md +110 -0
  93. package/docs/spotlight.md +78 -0
  94. package/docs/stability.md +52 -0
  95. package/docs/state.md +85 -0
  96. package/docs/theming.md +18 -6
  97. package/docs/usage.md +43 -3
  98. package/docs/workbench.md +72 -0
  99. package/fonts/doto-400.woff2 +0 -0
  100. package/fonts/doto-500.woff2 +0 -0
  101. package/fonts/doto-600.woff2 +0 -0
  102. package/fonts/doto-700.woff2 +0 -0
  103. package/fonts/doto-800.woff2 +0 -0
  104. package/fonts/doto-900.woff2 +0 -0
  105. package/llms.txt +288 -8
  106. package/package.json +95 -5
  107. package/qwik/index.d.ts +60 -0
  108. package/qwik/index.js +149 -0
  109. package/react/index.d.ts +40 -14
  110. package/react/index.js +32 -5
  111. package/solid/index.d.ts +40 -14
  112. package/solid/index.js +31 -3
  113. package/tokens/index.d.ts +3 -3
  114. package/tokens/index.js +25 -19
  115. package/tokens/index.json +32 -28
  116. package/tokens/resolved.json +34 -32
  117. package/tokens/tokens.dtcg.json +22 -14
  118. package/fonts/doto-400.ttf +0 -0
  119. package/fonts/doto-500.ttf +0 -0
  120. package/fonts/doto-600.ttf +0 -0
  121. package/fonts/doto-700.ttf +0 -0
  122. package/fonts/doto-800.ttf +0 -0
  123. package/fonts/doto-900.ttf +0 -0
package/CHANGELOG.md CHANGED
@@ -1,12 +1,353 @@
1
1
  # Changelog
2
2
 
3
- > **Versioning:** pre-1.0, breaking changes ship in the _minor_. Pin
4
- > `~0.x`; `^0.x` does **not** protect you. See README → Versioning, and
3
+ > **Versioning:** pre-1.0, breaking changes ship in the _minor_. Pin to the
4
+ > minor — `~0.4.0` (equivalently `^0.4.0`) resolves to `>=0.4.0 <0.5.0`; a bare
5
+ > `^0` / `*` wildcard does **not** protect you. See README → Versioning, and
5
6
  > the deprecation policy in CONTRIBUTING.md.
6
7
 
8
+ ## 0.5.0 — 2026-06-02
9
+
10
+ A **minor** that builds out the "analytical & generated-report UI" identity: a
11
+ full suite of opt-in **communication primitives** — SVG annotations, legends,
12
+ text/evidence marks, leader-line connectors, a guided-focus spotlight, a
13
+ crosshair/readout, a selection-state vocabulary, label declutter + direct labels
14
+ (`declutterLabels`/`directLabels`), and a source/citation/provenance **trust
15
+ layer** — plus a consolidation pass over them. Each owns its visual grammar and
16
+ pure geometry and refuses to own scales/state/hit-testing (no chart engine).
17
+
18
+ Per the project's versioning policy, breaking changes ship in the minor. This
19
+ release carries three: the opt-in report kit's chart data key moved into the new
20
+ legend layer (`.ui-chart__legend`/`__swatch` removed — see Changed and
21
+ [`MIGRATIONS.json`](MIGRATIONS.json)), annotation arrowheads now render via
22
+ the shared connectors geometry kernel (a small path-shape change), and the
23
+ opt-in marks' rationed-accent tone was renamed `evidence`→`accent` to match the
24
+ rest of the analytical tone vocabulary. Everything else is additive and opt-in,
25
+ save for the tiny `.ui-shortcut` keyboard-hint primitive that joins the core
26
+ layer; the rest of the default `dist/bronto.css` is unchanged. Also folds in the
27
+ 0.4.x maintenance hardening that had not yet been released.
28
+
29
+ ### Added
30
+
31
+ - **SVG annotations** (`@ponchia/ui/css/annotations.css`,
32
+ `@ponchia/ui/annotations`, `.ui-annotation*`, `ui.annotation()`): an opt-in
33
+ annotation layer for charts, reports, and analytical figures, following the
34
+ d3-annotation grammar (a **subject** marks the thing, a **connector** points
35
+ away, a **note** carries the text). Ships a class grammar (variants for
36
+ label/callout/elbow/curve/circle/rect/threshold/badge/bracket/band/slope/
37
+ compare/cluster/axis/timeline/evidence, six tones, and opt-in
38
+ `draw`/`reveal`/`pulse`/`focus` motion that respects `prefers-reduced-motion`)
39
+ plus tiny geometry helpers that return SVG strings only — they own no chart
40
+ scales, mutate no DOM, and provide no edit mode. Documented in
41
+ [`docs/annotations.md`](docs/annotations.md) and gated by `check:report`.
42
+ - **Legends / data keys** (`@ponchia/ui/css/legend.css`, `.ui-legend*`,
43
+ `ui.legend()`/`ui.legendItem()`/`ui.legendSwatch()`, `initLegend`): an opt-in,
44
+ standalone data-key layer that reads the `--chart-*` palette tokens.
45
+ Categorical, continuous gradient (sequential + `--diverging`), threshold, and
46
+ pattern keys; swatch colour set inline (`--chart-color`) or via
47
+ `.ui-legend__swatch--1..8` index helpers; vertical/compact/with-values
48
+ layouts. WCAG 1.4.1 by construction (the text label is the non-colour
49
+ channel), with `forced-colors` and print care. Optional interactive
50
+ (series-toggling) entries are `<button aria-pressed>` controls: `initLegend`
51
+ flips `aria-pressed`/`.is-inactive` and emits `bronto:legend:toggle`
52
+ (`{ series, active }`) — the host owns hiding the series and any `aria-live`
53
+ announcement (it is never a chart engine). Optional `useLegend` hook in the
54
+ React/Solid/Qwik bindings. New `check:legend` gate proves swatch colours are a
55
+ subset of `tokens/charts.js` and never a raw hex. Documented in
56
+ [`docs/legends.md`](docs/legends.md).
57
+ - **Text marks / evidence** (`@ponchia/ui/css/marks.css`, `.ui-mark*`,
58
+ `.ui-bracket-note*`, `ui.mark()`/`ui.bracketNote()`): an opt-in layer of
59
+ sober, report-grade emphasis for running prose — the counterpart to SVG
60
+ annotations (annotations call out a figure, marks call out a sentence). Inline
61
+ `.ui-mark` (highlight/underline/box/strike; `--accent` + status
62
+ tones; `--draw` reduced-motion-safe sweep) for use on `<mark>`, and
63
+ `.ui-bracket-note` for bracketing a whole passage. Pure CSS on semantic
64
+ tokens, monochrome by default, with `forced-colors` care. Documented in
65
+ [`docs/marks.md`](docs/marks.md).
66
+ - **Connectors / leader lines** (`@ponchia/ui/css/connectors.css`,
67
+ `@ponchia/ui/connectors`, `.ui-connector*`, `initConnectors`, `ui.connector()`):
68
+ an opt-in layer that draws a line between two DOM elements (the
69
+ page-coordinate cousin of annotations). Pure geometry helpers
70
+ (`connectRects`/`connectorPath`/`arrowHead`/…) that return SVG strings and own
71
+ no DOM, an `.ui-connector` overlay grammar (straight/elbow/curve, arrow/dot
72
+ ends, tones, dashed, `--draw`), and an optional `initConnectors` behavior that
73
+ draws + tracks on resize/scroll. `useConnectors` in the bindings. Documented in
74
+ [`docs/connectors.md`](docs/connectors.md).
75
+ - **Spotlight / guided focus** (`@ponchia/ui/css/spotlight.css`, `.ui-spotlight*`,
76
+ `.ui-tour-note*`, `initSpotlight`, `ui.spotlight()`): an opt-in guided-focus
77
+ overlay — a box-shadow cutout over a target element, optional ring, and a
78
+ callout note. `initSpotlight` positions the cutout (`--spot-x/y/w/h`) and
79
+ re-places on resize/scroll and when `data-target` changes. Deliberately **not**
80
+ a tour engine — the host owns step order/advancing/visibility. `useSpotlight`
81
+ in the bindings. Documented in [`docs/spotlight.md`](docs/spotlight.md).
82
+ - **Crosshair / readout** (`@ponchia/ui/css/crosshair.css`, `.ui-crosshair*`,
83
+ `.ui-readout`, `initCrosshair`, `ui.crosshair()`): an opt-in plot ruler +
84
+ pinned readout. `initCrosshair` tracks the pointer over a
85
+ `[data-bronto-crosshair]` plot, sets `--crosshair-x/y`, and dispatches
86
+ `bronto:crosshair:move` with px + 0–1 fractions — it reports position only and
87
+ never maps pixels to data (that needs the host's scales). `useCrosshair` in the
88
+ bindings. Documented in [`docs/crosshair.md`](docs/crosshair.md).
89
+ - **Selection states** (`@ponchia/ui/css/selection.css`, `.ui-sel*`,
90
+ `ui.sel()`): a tiny cross-cutting selection-emphasis vocabulary
91
+ (`--on`/`--off`/`--maybe`) reusable on chart marks, table rows, list items, or
92
+ map regions. The carve-out from brush/lasso — Bronto styles the states; the
93
+ host owns the selection/hit-test logic. Documented in
94
+ [`docs/selection.md`](docs/selection.md).
95
+ - **Sources, citations & provenance** (`@ponchia/ui/css/sources.css`,
96
+ `.ui-citation`/`.ui-source-card`/`.ui-source-list`/`.ui-provenance`,
97
+ `ui.citation()`/`ui.source()`/`ui.provenance()`): an opt-in, CSS-only **trust
98
+ layer** for generated reports and AI output — the grammar for "where did this
99
+ come from?". A cross-cutting `.ui-src--*` state (verified/reviewed/generated/
100
+ unverified/stale/conflict) sets a rationed tone, always paired with an
101
+ author-written label (never colour alone). Bronto owns the grammar + states;
102
+ the host owns fetching, citation numbering, and trust. The first
103
+ frontier-primitive beyond the analytical suite. Documented in
104
+ [`docs/sources.md`](docs/sources.md).
105
+ - **Keyboard-shortcut hint** (`.ui-shortcut` + `.ui-shortcut__sep`, core): a tiny
106
+ universal-chrome primitive that lays out one or more `.ui-kbd` keys as a chord
107
+ (`⌘`+`K`) or sequence (`G` then `I`) with a dim connective. The command tier's
108
+ smallest piece, broadly useful outside a palette (menu items, buttons,
109
+ tooltips). Class-only, like `.ui-kbd`.
110
+ - **Lifecycle / system state** (`@ponchia/ui/css/state.css`, `.ui-state`
111
+ (+`__label`/`__detail`/`--busy`) with canonical state modifiers
112
+ (saving/saved/queued/offline/stale/conflict/error/locked/reviewed/
113
+ needs-review), `.ui-syncbar`, `ui.state()`): an opt-in, CSS-only vocabulary for
114
+ the states apps actually live in — a labelled state object with a rationed tone
115
+ and a page/document sync bar. The label is the state (never colour alone);
116
+ `--busy` pulses the indicator (reduced-motion-safe). Bronto ships the visual
117
+ states + canonical wording; the host owns the state machine, retry, and
118
+ persistence. Frontier candidate #2. Documented in [`docs/state.md`](docs/state.md).
119
+ - **Generated content & AI trust** (`@ponchia/ui/css/generated.css`,
120
+ `.ui-generated`/`.ui-origin-label`/`.ui-reasoning`/`.ui-tool-log`/`.ui-tool-call`,
121
+ `ui.originLabel()`): an opt-in, CSS-only set of **trust surfaces** for AI /
122
+ system-generated content — a marked region, an origin label, and quiet
123
+ native-`<details>` reasoning + tool-call logs. Not a chat kit; no
124
+ fabricated-confidence widget. Bronto styles disclosure/origin/trace, the host
125
+ owns model metadata, redaction, and safety. Pairs with the source layer.
126
+ Documented in [`docs/generated.md`](docs/generated.md).
127
+ - **Workbench** (`@ponchia/ui/css/workbench.css`, `.ui-inspector`/`.ui-property`/
128
+ `.ui-selectionbar`): an opt-in, CSS-only core for tool UIs — a selected-object
129
+ inspector panel, denser property rows, and a raised selection action bar.
130
+ Layout + affordances only; resizable split panes and drag handles are
131
+ deferred. Documented in [`docs/workbench.md`](docs/workbench.md).
132
+ - **Command palette** (`@ponchia/ui/css/command.css`, `.ui-command` (+
133
+ `__input`/`__list`/`__group`/`__item`/`__shortcut`/`__meta`/`__empty`),
134
+ `initCommand`, `useCommand`): an opt-in CSS shell + behavior — filter +
135
+ keyboard-navigate a DOM-authored command list (roving focus, group hiding,
136
+ full keyboard), emitting `bronto:command:select` ({ value, label }) and
137
+ `bronto:command:close`. Bronto navigates; the host owns the action registry,
138
+ routing, and execution. No global Cmd/Ctrl+K. Completes the command tier
139
+ (frontier #3) atop the shipped `ui-shortcut`. Documented in
140
+ [`docs/command.md`](docs/command.md).
141
+ - **Label declutter** (`@ponchia/ui/annotations` `declutterLabels`): a
142
+ deterministic, order-preserving **1-D** label de-overlap helper (sort, push
143
+ apart by `size + gap`, slide to fit `max`) — pure, no DOM/scales. Not a 2-D
144
+ collision solver. Documented in [`docs/annotations.md`](docs/annotations.md).
145
+ - **Direct labels** (`@ponchia/ui/annotations` `directLabels`): the
146
+ direct-labeling companion to `declutterLabels` — it declutters labels along an
147
+ axis **and** draws the leader from each anchor to its placed label, reusing the
148
+ connectors geometry kernel. Returns `[{ x, y, anchor, key, d }]` (the `d` feeds
149
+ a `ui-annotation__connector`). Deterministic and pure: no scales, no DOM, no
150
+ 2-D placement (the 1-D core of Labella, completed with leaders). Documented in
151
+ [`docs/annotations.md`](docs/annotations.md).
152
+ - **Connectors** (`@ponchia/ui/connectors`, `@ponchia/ui/css/connectors.css`,
153
+ `initConnectors`, `useConnectors`, `ui.connector()`) and **Spotlight**
154
+ (`css/spotlight.css`, `initSpotlight`, `ui.spotlight()`) — leader lines between
155
+ DOM elements and a guided-focus overlay; both opt-in, geometry/visual only
156
+ (the host owns layout/tour state).
157
+ - **Crosshair / readout** (`css/crosshair.css`, `initCrosshair`,
158
+ `ui.crosshair()`) and **selection states** (`css/selection.css`, `ui.sel()`) —
159
+ a plot ruler that reports pointer position (not data), and a cross-cutting
160
+ `.ui-sel--on/off/maybe` emphasis vocabulary (the host owns brush/hit-test).
161
+ - **`@ponchia/ui/css/analytical.css`** — a convenience roll-up that bundles the
162
+ seven analytical leaves (annotations, legend, marks, connectors, spotlight,
163
+ crosshair, selection) into one import. Add `dataviz.css`/`report.css`
164
+ separately as needed.
165
+
166
+ ### Fixed
167
+
168
+ - The optional Qwik binding (`@ponchia/ui/qwik`) is now built from the packed
169
+ tarball in CI **and** release, alongside React/Solid — closing a coverage gap
170
+ (it was documented as optimizer-proven but no job actually built it). Also
171
+ covered by `check:pack`, the size report, and the dead-code config.
172
+
173
+ ### Changed
174
+
175
+ - **Breaking (opt-in report kit):** the chart data key moved out of
176
+ `css/report.css` into the standalone `css/legend.css`. `.ui-chart__legend` →
177
+ `.ui-legend` (now with `.ui-legend__item`/`.ui-legend__label` rows) and
178
+ `.ui-chart__swatch` → `.ui-legend__swatch`. Import `@ponchia/ui/css/legend.css`
179
+ beside the report kit; see [`MIGRATIONS.json`](MIGRATIONS.json) and
180
+ [`docs/legends.md`](docs/legends.md). The `--chart-color`/`--chart-pattern`
181
+ swatch contract is unchanged, so the rename is mechanical.
182
+ - **Breaking (opt-in marks):** the rationed-accent **tone** on `.ui-mark` and
183
+ `.ui-bracket-note` was renamed `evidence` → `accent` (`ui-mark--evidence` →
184
+ `ui-mark--accent`, `ui-bracket-note--evidence` → `ui-bracket-note--accent`;
185
+ `ui.mark({ tone: 'accent' })` / `ui.bracketNote({ tone: 'accent' })`) so the
186
+ accent tone reads the same across every analytical primitive (it already was
187
+ `accent` on `ui.connector`/`ui.annotation`). `.ui-annotation--evidence` is
188
+ **unchanged** — it is a marker _variant_ (a proof/source shape), not a tone.
189
+ Mechanical whole-token rename; see [`MIGRATIONS.json`](MIGRATIONS.json).
190
+ - **Consolidation:** the SVG geometry is single-sourced in the `connectors`
191
+ kernel — `@ponchia/ui/annotations` now builds its connectors on it, so a
192
+ line/curve/arrow/dot is drawn one way across both. `connectorLine`/`Curve`/
193
+ `EndDot` output is byte-identical; **`connectorEndArrow` is the one
194
+ (minor-breaking) shape change** — the arrowhead now matches the connectors
195
+ arrowhead. New `check:helpers-dts` gate keeps the hand-maintained
196
+ `annotations`/`connectors` `.d.ts` in parity with their runtime exports.
197
+ - The Doto webfont now ships as **woff2 only** (Brotli) instead of uncompressed
198
+ TTF: ~5.7 kB per weight vs ~137 kB, cutting the six-weight payload from ~823 kB
199
+ to ~35 kB (the dot-matrix glyphs compress ~96%) and shrinking the unpacked
200
+ tarball by roughly the same. No TTF fallback is carried — woff2 is supported by
201
+ the entire browser floor (ADR-0002: Chrome 125 / Safari 18 / Firefox 129).
202
+ `@font-face` is internal, so this is transparent to consumers; only self-hosts
203
+ that referenced `fonts/doto-*.ttf` directly need to point at `*.woff2`.
204
+ - `docs/architecture.md` now ships in the package, so the offline rationale the
205
+ shipped ADRs link to resolves inside the tarball.
206
+ - `docs/stability.md` clarifies that `data-surface`/`data-density`/
207
+ `data-contrast` are **convenience presets**, not part of the stability
208
+ contract; `data-theme` (light/dark) remains the contractual base.
209
+
210
+ ### Internal
211
+
212
+ - Token values are single-sourced in `tokens/index.js` (`cssVars`); the
213
+ `css/tokens.css` palette is generated from it, so the dark palette is authored
214
+ once instead of in three places (the shipped CSS is byte-identical).
215
+ - `behaviors/index.js` is split into per-behavior modules behind the same public
216
+ barrel (no surface change).
217
+ - Drift-gate consolidation (`assertFresh`), a Qwik type smoke + stronger
218
+ class-recipe wiring test, the APCA advisory widened to the accent text across
219
+ the core palette and every colorway (still advisory; WCAG 2.1 AA stays the
220
+ hard gate), an OLED computed-style smoke test, and several doc reconciliations.
221
+ - New `demos.spec` e2e sweep runs the console-error / uncaught-exception /
222
+ failed-response guards **and** an axe scan over every per-feature demo page
223
+ (annotations, legends, marks, connectors, spotlight, crosshair, selection,
224
+ report) in both themes and cross-browser — previously only `/demo/` was
225
+ guarded, so a throw or 404 on those SVG-heavy pages could not fail CI.
226
+ - The `check:dist` payload ceiling was raised to 80 kB raw / 14.5 kB gzip (from
227
+ 78 kB / 13.5 kB). The default bundle was sitting ~21 bytes under the old gzip
228
+ gate — the analytical primitives are opt-in leaves and stay out of it, so this
229
+ is residual prior growth; the bump restores a real ~3% raw / ~7% gzip margin
230
+ so an ordinary token addition no longer trips an unrelated PR.
231
+
232
+ ## 0.4.1 — 2026-06-01
233
+
234
+ Patch hardening for the public framework surface, plus the first step of the
235
+ modern-platform motion direction (see [ADR-0002](docs/adr/0002-scope-and-2026-baseline.md)).
236
+
237
+ ### Added
238
+
239
+ - **Static report kit — `@ponchia/ui/css/report.css` + `docs/reporting.md`.**
240
+ An opt-in, PDF-first report layer for LLM-authored and hand-authored HTML:
241
+ report covers, headers, section numbering, summaries, findings, evidence
242
+ blocks, source/appendix/footnote blocks, chart wrappers/legends/fallback
243
+ tables, and print utilities (`ui-print-only`, `ui-screen-only`,
244
+ `ui-break-before`, `ui-break-after`, `ui-keep`, `ui-print-exact`). It stays
245
+ out of the default bundle, ships with the offline LLM docs, and is covered by
246
+ a report fixture, package/export checks, and class-contract validation.
247
+ The layer also includes compact covers, unnumbered report sections, simple
248
+ static chart-bar primitives, and evidence-table framing rules so generated
249
+ reports need less private CSS.
250
+ - **Zero-JS enter _and_ exit motion for native-`<dialog>` overlays.** Modal and
251
+ drawer (and their backdrop) now fade/scale **both ways** via `@starting-style`
252
+ + `transition-behavior: allow-discrete` — previously they only animated in and
253
+ vanished on close. Pure CSS, reduced-motion-aware (snaps with no flash), scoped
254
+ to `dialog.ui-modal` so the controlled `.is-open` path is unchanged.
255
+ - **Enter/exit motion extended to popover, toast, and accordion** (ADR-0002
256
+ "next, same approach"):
257
+ - **Popover** (`.ui-popover`) fades + slides both ways via the same
258
+ `@starting-style` + `allow-discrete` recipe, covering both the native
259
+ `[popover]` top-layer path and the `.is-open` fallback. Zero JS,
260
+ reduced-motion-aware.
261
+ - **Toast** (`.ui-toast`) now plays a CSS fade-out on dismiss instead of being
262
+ yanked from the DOM. The `toast()` behavior adds `.is-leaving` and removes
263
+ the node on `transitionend` (with a timeout fallback); it falls back to
264
+ instant removal under reduced-motion or where no transition is computed, so
265
+ the persistent `aria-live` region is undisturbed.
266
+ - **Accordion** (`.ui-accordion`, native `<details>`) animates auto-height
267
+ open/close via `::details-content` + `interpolate-size: allow-keywords` +
268
+ `content-visibility … allow-discrete`. Strict progressive enhancement —
269
+ gated on `@supports selector(::details-content)`; engines without it (today,
270
+ Firefox/Safari) simply snap, exactly as before.
271
+ - **Scroll-driven motion (progressive enhancement).** `.ui-scroll-progress` (a
272
+ reading-progress bar on a `scroll(root block)` timeline, RTL-aware) and
273
+ `.ui-scroll-reveal` (a JS-free, IntersectionObserver-free reveal on a `view()`
274
+ timeline). Both are gated on `@supports (animation-timeline: …)` and
275
+ `prefers-reduced-motion: no-preference`, so engines without scroll timelines
276
+ (today, Firefox/Safari) keep a static end-state and reduced-motion users get
277
+ no movement.
278
+ - **View Transitions (progressive enhancement).** A `.ui-vt` helper
279
+ (`view-transition-name: var(--ui-vt-name)`) to morph an element across a
280
+ same-document `startViewTransition()` or a cross-document navigation, an
281
+ on-brand default for the `::view-transition-*(root)` cross-fade, and a
282
+ **reduced-motion kill-switch** for the `::view-transition-*` pseudo-tree
283
+ (which the platform does *not* quiet automatically). Cross-document nav stays
284
+ a documented one-liner you add yourself (`@view-transition { navigation: auto }`
285
+ is document-global, so it can't be layered or scoped by the framework).
286
+ - **Optional Qwik bindings — `@ponchia/ui/qwik`.** Same thin-adapter shape as
287
+ the React/Solid bindings (`useDialog`, `useToast`, … `useBrontoBehavior`, plus
288
+ the `cls`/`ui`/`cx` + `applyStoredTheme` re-exports), wrapping the SSR-safe
289
+ behaviors in Qwik's `useVisibleTask$` (run on visible, cleanup on dispose) so a
290
+ resumable page stays zero-JS until interaction. Scope a behavior with a Qwik
291
+ signal: `useDialog({ root: useSignal() })`. `@builder.io/qwik` is an **optional**
292
+ peer dependency, so the core stays zero-dependency. New `examples/qwik-vite`
293
+ builds it through the real Qwik optimizer.
294
+ - **OLED true-black surface variant — `data-surface="oled"`.** The dark base is
295
+ now a readable elevated near-black (see Changed); this opt-in root attribute
296
+ restores pure black for OLED power-saving and the original "Nothing" look.
297
+ CSS-only preset (like `data-density`/`data-contrast`), scoped to the dark
298
+ theme. Documented in `docs/theming.md`.
299
+ - **APCA advisory for dark text.** `check:contrast` now emits a non-failing
300
+ warning when a dark text pairing falls below its perceptual APCA target (WCAG
301
+ stays the hard gate) — the early-warning that would have caught the illegible
302
+ dim text. The kitchen-sink demo gains a unified theme picker (theme × colorway
303
+ × surface, all persisted).
304
+ - **[ADR-0003](docs/adr/0003-theme-model.md)** records the theme model: a binary
305
+ light/dark base × one-knob derivation × orthogonal axes (colorway, surface,
306
+ contrast, density), and why a flat named-theme catalog is rejected.
307
+ - React and Solid Vite examples, CI/release matrix coverage for those examples,
308
+ runtime binding tests, public API stability docs, a release runbook, and
309
+ `npm run size:report`.
310
+
311
+ ### Changed
312
+
313
+ - **Dark theme re-tuned for readability.** The dark base moved off pure `#000`
314
+ to an elevated near-black (`--bg #121212`, panels `#1c1c1c`/`#222`/`#242424`,
315
+ lines `#383838`/`#555`); body text eased `#f2f2f2 → #e6e6e6` (APCA Lc 99 → ~91,
316
+ removing halation) and **dim/meta text raised `#858585 → #a0a0a0`** (APCA
317
+ Lc ~36 → ~49 — the actual "hard to read" fix). WCAG 2.x over-rates contrast on
318
+ pure black, so pairings "passed" while reading poorly; the re-tune clears WCAG
319
+ AA on every pairing and lifts perceptual (APCA) contrast. Accent and status
320
+ colours are unchanged; true black stays available via `data-surface="oled"`.
321
+ - **Browser floor raised to Chrome/Edge 125+, Safari 18+, Firefox 129+**
322
+ (early–mid 2025). A deliberate greenfield stance (ADR-0002) so the framework
323
+ can build natively on `@starting-style`, `transition-behavior: allow-discrete`,
324
+ `oklch()`/relative color, and `light-dark()`. No fallbacks ship below the
325
+ floor; not-yet-cross-engine features (View Transitions, scroll-driven
326
+ animations) are enhancement-only and degrade to a static end-state.
327
+ - Bundle budget nudged for the new motion: gzip 13.0 → 13.5 kB (for the dialog
328
+ enter/exit work) and raw 76 → 77 kB (for the popover/toast/accordion motion
329
+ plus the scroll-driven + view-transition CSS). Gzip held at ~13.1 kB — it
330
+ compresses well — so the compressed payload still has headroom.
331
+
332
+ ### Fixed
333
+
334
+ - React and Solid bindings now resolve scoped roots on mount, so `{ root: ref }`
335
+ and resolver callbacks work after framework refs are assigned. Nullish resolver
336
+ results normalize to default behavior instead of crashing destructuring
337
+ behavior initializers.
338
+ - Scoped behavior roots now resolve controlled ids root-first, then
339
+ document-wide. This keeps existing body/portal-mounted dialogs, popovers, and
340
+ disclosure panels working while preventing earlier duplicate ids outside an
341
+ island from shadowing the in-root target.
342
+ - `data-bronto-dismiss="<selector>"` ignores malformed selectors instead of
343
+ throwing during event handling.
344
+ - The one-node glyph mask path now includes a WebKit-prefixed mask declaration,
345
+ and the OKLCH accent ramp uses an explicit white/black neutral endpoint for
346
+ cross-engine browser parity.
347
+
7
348
  ## 0.4.0 — 2026-05-31
8
349
 
9
- The color-system release — [ADR-0001](docs/adr/0001-color-system.md) steps 1–7.
350
+ The color-system release — [ADR-0001](docs/adr/0001-color-system.md) steps 1–8.
10
351
  A governed evolution beyond pure monochrome: the tier model is written down and
11
352
  **enforced** (`check:color-policy`), and the "Nothing" look is proven to be a
12
353
  _skin, not the architecture_ — opt-in **colorways** (amber CRT · phosphor green ·
@@ -34,11 +375,11 @@ categorical color lands later it ships as a governed, opt-in data-viz module
34
375
  ### Added
35
376
 
36
377
  - **The `--accent-1..6` ramp is now perceptually even (OKLCH).** Steps 1–4 mix
37
- the accent toward the background `in oklch` instead of `in srgb` (ADR-0001
38
- step 8), so the ramp reads as evenly-spaced better for charts / multi-state
39
- surfaces. `scripts/gen-resolved.mjs` learned to resolve `color-mix(in oklch,…)`
40
- hex (bit-for-bit matching browser `color-mix`), so `tokens/resolved.json`,
41
- the DTCG export, and `docs/reference.md` all carry the new values. These are
378
+ the accent `in oklch` instead of using the old sRGB ramp (ADR-0001 step 8), so
379
+ the ramp reads as evenly-spaced. `scripts/gen-resolved.mjs` learned to resolve
380
+ `color-mix(in oklch,…)` → hex with the same one-channel tolerance browsers
381
+ show, so `tokens/resolved.json`, the DTCG export, and `docs/reference.md` all
382
+ carry the new values. These are
42
383
  token **values** (non-contractual under the 0.x policy) and the ramp is not
43
384
  consumed by any shipped component, so there is **no change to any component's
44
385
  rendering** — only consumers using `var(--accent-1..4)` directly see the
@@ -102,10 +443,9 @@ categorical color lands later it ships as a governed, opt-in data-viz module
102
443
  - **`check:skins` gate** — `css/skins.css` can't drift from `tokens/skins.js`,
103
444
  every skin defines `--accent`, and colorways stay out of the default bundle.
104
445
  - **[ADR-0001 — Color system](docs/adr/0001-color-system.md)** — the five-tier
105
- color constitution and the backward-compatible roadmap. Steps 1–6 are
106
- implemented in this release (gate + colorways + Tier-3 tokens + OKLCH for new
107
- work + APCA advisory); the data-viz categorical module and any core-ramp
108
- OKLCH migration are deliberately deferred.
446
+ color constitution and the backward-compatible roadmap. Steps 1–8 are
447
+ implemented in this release: gate + colorways + Tier-3 tokens + OKLCH for new
448
+ work + APCA advisory + data-viz + OKLCH core accent ramp.
109
449
 
110
450
  ## 0.3.6 — 2026-05-31
111
451
 
@@ -0,0 +1,92 @@
1
+ {
2
+ "$comment": "Machine-readable rename/removal map for @ponchia/ui upgrades (classes, attributes, and tokens). Generated-by-hand from CHANGELOG BREAKING sections; consumed by docs/migrations/*.md and any codemod/sed recipe. 'safe' rules are mechanically rewritable (whole-token, no semantic change); 'manual' rules need human judgement (concept moved or removed, not a 1:1 rename).",
3
+ "migrations": [
4
+ {
5
+ "from": "0.2",
6
+ "to": "0.3",
7
+ "summary": "Entire non-ui-* legacy vocabulary removed; everything is now under the .ui-* contract and the check-classes drift gate.",
8
+ "safe": [
9
+ { "old": "skip-link", "new": "ui-skiplink" },
10
+ { "old": "site-nav", "new": "ui-sitenav" },
11
+ { "old": "site-menu", "new": "ui-sitemenu" },
12
+ { "old": "theme-toggle", "new": "ui-themetoggle", "prefix": true },
13
+ { "old": "app-shell", "new": "ui-app-shell", "prefix": true },
14
+ { "old": "app-rail", "new": "ui-app-rail", "prefix": true },
15
+ { "old": "app-topbar", "new": "ui-app-topbar", "prefix": true },
16
+ { "old": "app-toolbar", "new": "ui-app-toolbar", "prefix": true },
17
+ { "old": "app-nav", "new": "ui-app-nav", "prefix": true },
18
+ { "old": "app-panel", "new": "ui-app-panel", "prefix": true },
19
+ { "old": "app-content", "new": "ui-app-content", "prefix": true },
20
+ { "old": "app-main", "new": "ui-app-main", "prefix": true },
21
+ { "old": "app-metrics", "new": "ui-app-metrics", "prefix": true },
22
+ { "old": "app-metric", "new": "ui-app-metric", "prefix": true },
23
+ { "old": "app-empty-state", "new": "ui-app-empty-state", "prefix": true }
24
+ ],
25
+ "manual": [
26
+ {
27
+ "old": "hero / project-* / post-card / essay-* / page-* / home-* / signal-panel / worklog-summary",
28
+ "new": "the ui-* content layer",
29
+ "note": "Long-form content: .ui-prose / .ui-quote. Cards: .ui-card. Layout: .ui-grid / .ui-stack. Site chrome: the ui-site* shell. No 1:1 mapping — re-compose with the content primitives."
30
+ },
31
+ {
32
+ "old": "callout",
33
+ "new": "ui-alert",
34
+ "note": "Tone modifiers differ (.ui-alert--info/-success/-warning/-danger); re-pick the tone."
35
+ },
36
+ {
37
+ "old": "metric-tile",
38
+ "new": "ui-app-metric",
39
+ "note": "Now scoped to the admin shell vocabulary; standalone stat usage should wrap in .ui-app-metrics."
40
+ },
41
+ {
42
+ "old": "tag-list / tag",
43
+ "new": "ui-tags / ui-tag",
44
+ "note": "Compact variant .tag-list--compact → .ui-tags--compact; verify accent-on-accent contrast (see CHANGELOG 0.3.0 a11y fix)."
45
+ }
46
+ ],
47
+ "codemod": "See docs/migrations/0.2-to-0.3.md for a ready-to-run ripgrep+sed recipe covering the 'safe' rules."
48
+ },
49
+ {
50
+ "from": "0.3",
51
+ "to": "0.4",
52
+ "summary": "Additive colour-system release (ADR-0001); the default dist/bronto.css renders identically. No class or attribute renames. One orphan token pair removed.",
53
+ "safe": [],
54
+ "manual": [
55
+ {
56
+ "old": "--orange / --orange-soft",
57
+ "new": "(removed — re-declare in a consumer :root override if referenced)",
58
+ "note": "Orphan token pair: defined in the token mirrors but referenced by no shipped component and documented nowhere, and untiered under the new colour model. Removed under the CONTRIBUTING 'provably-unreferenced surface' exception. If you used it: :root { --orange: #a85f32; --orange-soft: rgb(168 95 50 / 0.13); }"
59
+ }
60
+ ],
61
+ "codemod": "No class codemod needed (no renames). See docs/migrations/0.3-to-0.4.md; audit usage with: rg -- '--orange' ."
62
+ },
63
+ {
64
+ "from": "0.4",
65
+ "to": "0.5",
66
+ "summary": "Adds the analytical-primitives suite (annotations, legend, marks, connectors, spotlight, crosshair, selection + the analytical.css roll-up); all additive/opt-in. Three breaking changes: the chart data key moved out of the report kit into the standalone Legends layer (`.ui-chart__legend`/`.ui-chart__swatch` removed); annotation arrowheads now render via the shared connectors geometry kernel (a small visual path change, no API change); and the marks/bracket-note rationed-accent tone was renamed `evidence`→`accent` to match the annotation/connector tone vocabulary (`.ui-annotation--evidence` stays — it's a marker variant, not a tone).",
67
+ "safe": [
68
+ { "old": "ui-chart__swatch", "new": "ui-legend__swatch" },
69
+ { "old": "ui-mark--evidence", "new": "ui-mark--accent" },
70
+ { "old": "ui-bracket-note--evidence", "new": "ui-bracket-note--accent" }
71
+ ],
72
+ "manual": [
73
+ {
74
+ "old": "ui.mark({ tone: 'evidence' }) / ui.bracketNote({ tone: 'evidence' })",
75
+ "new": "tone: 'accent'",
76
+ "note": "The rationed-accent tone option on the mark/bracket-note recipes is now 'accent' (was 'evidence'), matching ui.connector/ui.annotation. Do NOT rewrite ui.annotation({ variant: 'evidence' }) or the 'evidence' subject marker — those are a marker shape, not a tone, and are unchanged."
77
+ },
78
+ {
79
+ "old": "ui-chart__legend",
80
+ "new": "ui-legend",
81
+ "note": "Also import '@ponchia/ui/css/legend.css' beside report.css, and wrap each entry's content as <li class=\"ui-legend__item\"> … <span class=\"ui-legend__label\">…</span>. The swatch's --chart-color/--chart-pattern inline contract is unchanged; the categorical --chart-N colour is also available via .ui-legend__swatch--N. See docs/legends.md."
82
+ },
83
+ {
84
+ "old": "connectorEndArrow (annotations)",
85
+ "new": "connectorEndArrow (unchanged API)",
86
+ "note": "No code change needed. The function signature is identical; only the rendered arrowhead path differs slightly now that it shares the connectors geometry kernel. Re-baseline any exact-path SVG snapshot tests of annotation arrowheads."
87
+ }
88
+ ],
89
+ "codemod": "rg -l 'ui-chart__legend|ui-chart__swatch' then s/ui-chart__swatch/ui-legend__swatch/g and rework the ul.ui-chart__legend wrapper into ul.ui-legend with li.ui-legend__item rows. See docs/legends.md."
90
+ }
91
+ ]
92
+ }