@ponchia/ui 0.3.6 → 0.4.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 +945 -0
- package/README.md +16 -6
- package/classes/index.d.ts +1 -0
- package/classes/index.js +1 -0
- package/classes/vscode.css-custom-data.json +4 -12
- package/css/dataviz.css +96 -0
- package/css/dots.css +30 -2
- package/css/skins.css +54 -0
- package/css/tokens.css +4 -10
- package/dist/bronto.css +1 -1
- package/dist/css/dataviz.css +1 -0
- package/dist/css/dots.css +1 -1
- package/dist/css/skins.css +1 -0
- package/dist/css/tokens.css +1 -1
- package/docs/adr/0001-color-system.md +272 -0
- package/docs/contrast.md +170 -51
- package/docs/reference.md +11 -9
- package/docs/theming.md +66 -1
- package/docs/usage.md +46 -5
- package/glyphs/glyphs.d.ts +14 -1
- package/glyphs/glyphs.js +143 -2
- package/llms.txt +43 -4
- package/package.json +54 -5
- package/react/index.d.ts +36 -0
- package/react/index.js +67 -0
- package/solid/index.d.ts +36 -0
- package/solid/index.js +67 -0
- package/tokens/charts.d.ts +37 -0
- package/tokens/charts.js +96 -0
- package/tokens/charts.json +61 -0
- package/tokens/index.d.ts +3 -3
- package/tokens/index.js +4 -8
- package/tokens/index.json +8 -16
- package/tokens/resolved.json +9 -13
- package/tokens/skins.d.ts +27 -0
- package/tokens/skins.js +62 -0
- package/tokens/tokens.dtcg.json +4 -24
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,945 @@
|
|
|
1
|
+
# Changelog
|
|
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
|
|
5
|
+
> the deprecation policy in CONTRIBUTING.md.
|
|
6
|
+
|
|
7
|
+
## 0.4.0 — 2026-05-31
|
|
8
|
+
|
|
9
|
+
The color-system release — [ADR-0001](docs/adr/0001-color-system.md) steps 1–7.
|
|
10
|
+
A governed evolution beyond pure monochrome: the tier model is written down and
|
|
11
|
+
**enforced** (`check:color-policy`), and the "Nothing" look is proven to be a
|
|
12
|
+
_skin, not the architecture_ — opt-in **colorways** (amber CRT · phosphor green ·
|
|
13
|
+
e-ink), a **data-viz palette** for dashboards (colourblind-safe, gated under
|
|
14
|
+
simulated protan/deutan/tritan vision), Tier-3 dot-matrix display tokens, OKLCH
|
|
15
|
+
authoring, and an APCA advisory contrast track all ship. Plus a reframed README
|
|
16
|
+
+ a rendered docs site, and the curated CHANGELOG is now the GitHub Release body.
|
|
17
|
+
|
|
18
|
+
**The default build is unchanged** — the red accent, every retained token name,
|
|
19
|
+
and both theme palettes render identically; colorways and data-viz are opt-in
|
|
20
|
+
entrypoints, never in the default bundle. The only breaking change is the
|
|
21
|
+
removal of the orphan `--orange` token (undocumented, unused) — see below.
|
|
22
|
+
|
|
23
|
+
**BREAKING (orphan token removed)** — **`--orange` / `--orange-soft`** are
|
|
24
|
+
removed. They were defined in every token mirror (`css/tokens.css`,
|
|
25
|
+
`tokens/index.js`, `tokens.dtcg.json`, `resolved.json`, `index.d.ts`,
|
|
26
|
+
`reference.md`) but **referenced by no component and documented nowhere**, and
|
|
27
|
+
untiered under the new color model. As a provably-unreferenced token this is
|
|
28
|
+
removed in a single minor under the CONTRIBUTING.md deprecation-policy
|
|
29
|
+
exception (no working call-site to wind down). Removed rather than adopted; if
|
|
30
|
+
categorical color lands later it ships as a governed, opt-in data-viz module
|
|
31
|
+
(ADR-0001 tier 4), not a stray top-level token. _Migration:_ if you referenced
|
|
32
|
+
`--orange`/`--orange-soft`, define it yourself in a consumer override.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- **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
|
|
42
|
+
token **values** (non-contractual under the 0.x policy) and the ramp is not
|
|
43
|
+
consumed by any shipped component, so there is **no change to any component's
|
|
44
|
+
rendering** — only consumers using `var(--accent-1..4)` directly see the
|
|
45
|
+
(intended) shift.
|
|
46
|
+
- **Framework bindings — `@ponchia/ui/react` + `@ponchia/ui/solid`.** Optional,
|
|
47
|
+
thin hooks over the SSR-safe `init*` behaviors (run on mount, clean up on
|
|
48
|
+
unmount/dispose): `useDialog`, `useTabs`, `useMenu`, `useCombobox`,
|
|
49
|
+
`usePopover`, `useDisclosure`, `useFormValidation`, `useTableSort`,
|
|
50
|
+
`useCarousel`, `useDismissible`, `useThemeToggle`, `useDotGlyph`,
|
|
51
|
+
`useToast()`, and the generic `useBrontoBehavior(init, opts)`; `cls`/`ui`/`cx`
|
|
52
|
+
re-exported for one-import DX. `react` / `solid-js` are **optional peer
|
|
53
|
+
dependencies** — the core stays zero-runtime-dependency. Thin adapters over
|
|
54
|
+
the canonical CSS/behaviors layer, not a component library (architecture ADR).
|
|
55
|
+
- **Glyphs: a one-node icon-at-scale render path + a `.ui-icon` wrapper + 5
|
|
56
|
+
circle-family glyphs.** `renderGlyph(name, { render: 'mask', size })` now
|
|
57
|
+
returns a **single** `.ui-icon` element masked by the glyph bitmap (one DOM
|
|
58
|
+
node instead of 256 cells) — for an icon in every table row. It scales with
|
|
59
|
+
the text (`--icon-size`, default `1em`) and inherits `currentColor`. New
|
|
60
|
+
`.ui-icon` CSS primitive (`cls.icon`) drives it. Vocabulary grows to 48 with
|
|
61
|
+
`circle`, `check-circle`, `x-circle`, `plus-circle`, `minus-circle`.
|
|
62
|
+
- **Data-viz colour module — `@ponchia/ui/css/dataviz.css` + `@ponchia/ui/charts.json`.**
|
|
63
|
+
An opt-in Tier-4 chart palette for dashboards (ADR-0001 step 7). **Hybrid
|
|
64
|
+
accent-led**: series 1 is the live `var(--accent)` (the brand stays series 1);
|
|
65
|
+
series 2–8 are the Okabe-Ito colourblind-safe set; plus a sequential ramp
|
|
66
|
+
(heatmaps) and a diverging ramp (gains/losses). **Colour is never the sole
|
|
67
|
+
signal** — each series ships a matching `--chart-pattern-*` dot-matrix fill
|
|
68
|
+
(WCAG 1.4.1). The categorical palette is **gated for distinguishability under
|
|
69
|
+
normal + simulated protan/deutan/tritan vision** (`check:charts`, OKLab ΔE),
|
|
70
|
+
not just eyeballed. Resolved hex per theme in `tokens/charts.json` for
|
|
71
|
+
canvas/SVG/charting libs; typed `ChartTokenName` (`./charts`). **Charts-only,
|
|
72
|
+
never UI chrome** (`check:color-policy` fails on `var(--chart-*)` in core CSS)
|
|
73
|
+
and **never in the default bundle** (separate entrypoint). Sourced from
|
|
74
|
+
`tokens/charts.js` (generated → drift-checked by `check:charts`).
|
|
75
|
+
- **Display colorways — `@ponchia/ui/css/skins.css`.** Opt-in
|
|
76
|
+
`data-bronto-skin="amber-crt | phosphor-green | e-ink"`, a **root-level**
|
|
77
|
+
choice like `data-theme` (apply on `<html>`). Each re-points the one accent
|
|
78
|
+
to a different single hue — the derived accent family, focus ring, dot-matrix
|
|
79
|
+
and glyphs follow automatically; status colours and the neutral canvas are
|
|
80
|
+
untouched. Authored in **OKLCH**, per-theme (a dark + light accent, like the
|
|
81
|
+
core red), and **every skin accent is contrast-gated** to the same WCAG AA /
|
|
82
|
+
3:1 floors as the core (see `docs/contrast.md`). Shipped as a **separate
|
|
83
|
+
entrypoint, never in the default `dist/bronto.css`** — zero cost unless you
|
|
84
|
+
import it. Sourced from `tokens/skins.js` (generated → drift-checked by
|
|
85
|
+
`check:skins`).
|
|
86
|
+
- **Tier-3 dot-matrix "display expression" tokens** (`css/dots.css`):
|
|
87
|
+
`--dotmatrix-glow` (phosphor bloom on lit cells), `--dotmatrix-pulse-min`
|
|
88
|
+
(the `--pulse` floor), documented `--dotmatrix-reveal-step` (scan cadence).
|
|
89
|
+
All default to a **no-op**, so the default render is unchanged; the phosphor
|
|
90
|
+
colorways use the glow in dark.
|
|
91
|
+
- **APCA advisory contrast** in `docs/contrast.md`. Every pairing (core **and**
|
|
92
|
+
every colorway) now shows an APCA-W3 `Lc` column beside the WCAG ratio — a
|
|
93
|
+
perceptual cross-check. **Advisory only**: WCAG 2.1 AA stays the hard gate
|
|
94
|
+
(`check:contrast`). Implemented dependency-free, alongside an OKLCH→sRGB
|
|
95
|
+
converter so OKLCH-authored values can be measured.
|
|
96
|
+
- **`check:color-policy` gate** (`scripts/check-color-policy.mjs`, wired into
|
|
97
|
+
`npm run check`). Enforces the color constitution: every color-defining token
|
|
98
|
+
(across `global`/`light`/`dark`) must be classified into a tier (this is what
|
|
99
|
+
would have caught `--orange`); the `--chart-*` / `--cat-*` / `--data-*`
|
|
100
|
+
data-viz namespace is reserved; and component CSS may not use raw chromatic
|
|
101
|
+
color (only tiered tokens, with neutral grays / `color-mix()` endpoints).
|
|
102
|
+
- **`check:skins` gate** — `css/skins.css` can't drift from `tokens/skins.js`,
|
|
103
|
+
every skin defines `--accent`, and colorways stay out of the default bundle.
|
|
104
|
+
- **[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.
|
|
109
|
+
|
|
110
|
+
## 0.3.6 — 2026-05-31
|
|
111
|
+
|
|
112
|
+
Display glyphs: a small `@ponchia/ui/glyphs` subpath of dot-matrix bitmaps
|
|
113
|
+
rendered on the existing `.ui-dotmatrix` primitive — no SVG, no icon font,
|
|
114
|
+
re-skinned by the same `--field-dot*` tokens. All additive — a new optional
|
|
115
|
+
JS subpath plus one backward-compatible CSS var → a patch under the 0.x
|
|
116
|
+
policy.
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
|
|
120
|
+
- **`@ponchia/ui/glyphs` — a 43-glyph dot-matrix display-icon set.** A frozen
|
|
121
|
+
16×16 bitmap registry (`GLYPHS`, `GLYPH_NAMES`, `GLYPH_SIZE`) with `glyph()`,
|
|
122
|
+
`glyphCells()`, and `renderGlyph(name, { label, grid, solid, anim, dot, gap })`
|
|
123
|
+
— an SSR-safe HTML string, decorative (`aria-hidden`) by default and
|
|
124
|
+
`role="img"` when labelled. Covers navigation (`arrow-*`, `chevron-*`),
|
|
125
|
+
actions (`check`, `close`, `plus`, `minus`, `search`, `menu`, `gear`,
|
|
126
|
+
`edit`, `trash`, `download`, `upload`, `link`, `refresh`), media (`play`,
|
|
127
|
+
`pause`), state (`eye`, `eye-off`), theming (`sun`, `moon`), objects
|
|
128
|
+
(`mail`, `file`, `folder`, `clock`, `home`, `user`, `heart`, `star`,
|
|
129
|
+
`bell`, `lock`, `info`, `warning`), layout (`grid`, `more-vertical`,
|
|
130
|
+
`more-horizontal`) and `spark` (the two-tone accent demo). Three knobs from
|
|
131
|
+
one source: the default dot look for **display** sizes; **`solid: true`**
|
|
132
|
+
(or `data-bronto-glyph-solid`) which fuses the cells into a square, gapless
|
|
133
|
+
pixel glyph legible as an **inline icon down to ~16px**; and opt-in
|
|
134
|
+
**`anim`** (`reveal` powers the cells on in a scan, `pulse` makes the glyph
|
|
135
|
+
breathe) — decorative only, disabled under `prefers-reduced-motion`, with
|
|
136
|
+
the meaning kept in the static frame + label. `renderGlyph` returns a
|
|
137
|
+
`<span>` (valid inline / inside a `<button>`) and accepts any string for
|
|
138
|
+
dynamic dispatch (`GlyphNameInput = GlyphName | (string & {})`) — unknown
|
|
139
|
+
names hit the documented `''`/`[]`/`undefined` fallback — while the
|
|
140
|
+
`GlyphName` union itself stays strict (typos in annotations are errors). The
|
|
141
|
+
union is generated and CI-drift-checked from the runtime, like the
|
|
142
|
+
`cls`/token maps.
|
|
143
|
+
- **`initDotGlyph()` behavior.** Expands `[data-bronto-glyph]` placeholders
|
|
144
|
+
into a `.ui-dotmatrix` grid in place (optional `data-bronto-glyph-label`),
|
|
145
|
+
idempotent, with a cleanup that fully reverts — the DOM counterpart to
|
|
146
|
+
`renderGlyph`.
|
|
147
|
+
|
|
148
|
+
### Changed
|
|
149
|
+
|
|
150
|
+
- **`.ui-dotmatrix` gains `--dotmatrix-dot` and `--dotmatrix-dot-radius`
|
|
151
|
+
knobs** — the former for intrinsic dot sizing (`grid-template-columns`
|
|
152
|
+
falls back to the previous `minmax(0, 1fr)` when unset), the latter to
|
|
153
|
+
square off the cells (`--dotmatrix-dot-radius: 0`) for the solid pixel-glyph
|
|
154
|
+
look. Both default to the prior behaviour, so existing matrices are
|
|
155
|
+
unchanged. Adds opt-in `ui-dotmatrix--reveal` / `ui-dotmatrix--pulse`
|
|
156
|
+
animation modifiers (`cls.dotmatrixReveal` / `cls.dotmatrixPulse`), both
|
|
157
|
+
reduced-motion-aware; `--dotmatrix-reveal-step` tunes the reveal scan speed
|
|
158
|
+
(per-cell delay, default `3ms`).
|
|
159
|
+
|
|
160
|
+
## 0.3.5 — 2026-05-29
|
|
161
|
+
|
|
162
|
+
A consumer-evidence pass: six small primitives that adopters were
|
|
163
|
+
repeatedly hand-rolling, added as pure CSS in
|
|
164
|
+
`@layer bronto` reusing existing tokens. All additive — no new token, no
|
|
165
|
+
new gated contrast pairing, no breaking change → a patch under the 0.x
|
|
166
|
+
policy.
|
|
167
|
+
|
|
168
|
+
### Added
|
|
169
|
+
|
|
170
|
+
- **`ui-pagehead` — the in-page title bar.** `ui-pagehead` +
|
|
171
|
+
`__title` + `__actions`: eyebrow/breadcrumb + title on the start,
|
|
172
|
+
an actions cluster on the end, one hairline beneath. Composes the
|
|
173
|
+
existing `ui-eyebrow` / `ui-breadcrumb` rather than duplicating them.
|
|
174
|
+
Parts-only (no recipe), like `ui-panel`.
|
|
175
|
+
- **`ui-steps` — a stepper for multi-step flows.** `ui-steps` (an `<ol>`)
|
|
176
|
+
+ `__item` + `__item--done`, auto-numbered by CSS counter with hairline
|
|
177
|
+
connectors. State is ARIA-driven: the active step is `aria-current="step"`
|
|
178
|
+
(no class); completed steps take `--done`.
|
|
179
|
+
- **`ui-timeline` — a vertical event list.** `ui-timeline` (an `<ol>`) +
|
|
180
|
+
`__item` + `__time`, on a hairline spine with a per-item marker dot;
|
|
181
|
+
`aria-current` marks the live event (accent marker).
|
|
182
|
+
- **`ui-meter` — a labelled proportion / threshold bar.** `ui-meter` +
|
|
183
|
+
`__fill` + tone modifiers `--accent` / `--success` / `--warning` /
|
|
184
|
+
`--danger`, with a `ui.meter({ tone })` recipe + `MeterOpts`. Distinct
|
|
185
|
+
from `ui-progress` (task progress, can be indeterminate): a meter shows
|
|
186
|
+
a measured static value (coverage, capacity, a KPI). Width is the same
|
|
187
|
+
shared `--value` knob progress uses; author `role="meter"` +
|
|
188
|
+
`aria-valuenow/min/max`.
|
|
189
|
+
- **`ui-kbd` — an inline keyboard-key glyph.** Wrap a `<kbd>`; one per key
|
|
190
|
+
for a shortcut.
|
|
191
|
+
- **`ui-input-icon` — a leading/trailing icon *inside* a control.**
|
|
192
|
+
`ui-input-icon` + `__icon` + `--end`, with a `ui.inputIcon({ end })`
|
|
193
|
+
recipe + `InputIconOpts`. Distinct from `ui-input-group` (an *adjacent*
|
|
194
|
+
affix): the icon overlays inside one `.ui-input`, which keeps full width
|
|
195
|
+
and gains padding on the icon side. Closes the "no framework primitive"
|
|
196
|
+
gap consumers were filling with a bespoke absolute overlay.
|
|
197
|
+
- **`ui-carousel` + `initCarousel` — an image gallery / carousel, and a
|
|
198
|
+
lightbox built on it.** `ui-carousel` (`__stage` / `__viewport` /
|
|
199
|
+
`__slide` / `__prev` / `__next` / `__thumbs` / `__thumb` / `__status`)
|
|
200
|
+
is a **scroll-snap** track, so touch + trackpad swipe (with momentum)
|
|
201
|
+
are the browser's, not hand-rolled. `initCarousel` adds prev/next,
|
|
202
|
+
keyboard (Arrow/Home/End), a thumbnail strip with `aria-current` sync,
|
|
203
|
+
the position counter, and carousel ARIA, keeping a JS index in sync with
|
|
204
|
+
the scroll position both ways (`IntersectionObserver` where available);
|
|
205
|
+
`data-bronto-carousel-loop` wraps; it emits `bronto:change`
|
|
206
|
+
(`{ index }`). A **full-screen lightbox** is the same markup inside a
|
|
207
|
+
native `<dialog class="ui-lightbox">` (+ `ui-lightbox__close`) opened by
|
|
208
|
+
the existing `initDialog` — so the top layer, focus-trap, Escape and
|
|
209
|
+
focus-return come from `<dialog>` with zero new focus code. Closes the
|
|
210
|
+
gallery/lightbox/carousel gap consumers were filling by hand (one
|
|
211
|
+
adopter had shipped three overlapping hand-rolled versions). SSR-safe,
|
|
212
|
+
idempotent, returns a cleanup; declared in `behaviors/index.d.ts` and
|
|
213
|
+
demoed.
|
|
214
|
+
- Demo gains a **"0.3.5 additions"** kitchen-sink section; `docs/usage.md`
|
|
215
|
+
gains meter-vs-progress and steps/timeline/kbd/input-icon guidance; the
|
|
216
|
+
generated `docs/reference.md`, `classes/index.d.ts`,
|
|
217
|
+
`classes/vscode.css-custom-data.json` and `dist/*` pick the new surface
|
|
218
|
+
up automatically.
|
|
219
|
+
|
|
220
|
+
### Changed
|
|
221
|
+
|
|
222
|
+
- **Bundle gzip budget 12 kB → 13 kB** (raw cap unchanged at 76 kB). The
|
|
223
|
+
six new primitives plus the carousel/lightbox grew `dist/bronto.css` to
|
|
224
|
+
~73 kB raw / ~12.7 kB gzip (against the 76 kB / 13 kB caps); the gzip cap
|
|
225
|
+
is recalibrated per the bump-deliberately rule in
|
|
226
|
+
`scripts/build-dist.mjs`.
|
|
227
|
+
|
|
228
|
+
### Packaging & docs
|
|
229
|
+
|
|
230
|
+
- **`fonts/OFL.txt`** — the bundled Doto font is now shipped with its SIL
|
|
231
|
+
Open Font License 1.1 text and attribution (© 2024 The Doto Project
|
|
232
|
+
Authors), as required to redistribute it; README gained a font-license
|
|
233
|
+
note. No code change.
|
|
234
|
+
- **README rewritten** for the npm package page (de-duplicated, accurate
|
|
235
|
+
install/quick-start/theming, absolute links); `package.json` gained a
|
|
236
|
+
compelling `description` + `keywords`; `ROADMAP.md` reconciled to 0.3.5.
|
|
237
|
+
- **Visual regression reworked** to component-scoped per-section snapshots
|
|
238
|
+
(`data-shot` slugs, auto-discovered) so adding a primitive no longer
|
|
239
|
+
drifts every baseline; the `visual-baselines` workflow's change-gate now
|
|
240
|
+
detects brand-new (untracked) baselines.
|
|
241
|
+
|
|
242
|
+
## 0.3.4 — 2026-05-17
|
|
243
|
+
|
|
244
|
+
A review-driven accessibility + adoption pass (three external reviews →
|
|
245
|
+
independent Opus review → AgentMix deep multi-POV review). All additive:
|
|
246
|
+
new gated artifact, two new shipped docs, one new token. No breaking
|
|
247
|
+
change → a patch under the 0.x policy.
|
|
248
|
+
|
|
249
|
+
### Added
|
|
250
|
+
|
|
251
|
+
- **`docs/contrast.md` — a published, CI-gated WCAG 2.1 contrast
|
|
252
|
+
matrix.** Every contractual token pairing, the conformance level it is
|
|
253
|
+
*held to*, and its measured sRGB ratio per theme. Generated from the
|
|
254
|
+
resolved token model (`scripts/gen-contrast.mjs`) so it cannot drift
|
|
255
|
+
from the palette, and **gated**: the new `check:contrast` fails
|
|
256
|
+
`npm run check` (and so release) if any gated pairing drops below its
|
|
257
|
+
floor. Text pairings are held to AA 4.5:1; non-text UI to 3:1;
|
|
258
|
+
decorative hairlines are reported but WCAG-1.4.11-exempt by design
|
|
259
|
+
(the low ratio is published, not hidden). New `exports`/`files`
|
|
260
|
+
entry; indexed in `llms.txt` + README.
|
|
261
|
+
- **`docs/usage.md` — the decision guide.** When to use which primitive
|
|
262
|
+
(badge vs chip vs status dot), the unset density default and its two
|
|
263
|
+
presets, prose-in-card, when to reach for a behavior. Hand-written and
|
|
264
|
+
stable (contract, like `theming.md`); ships in the tarball for offline
|
|
265
|
+
agents/consumers.
|
|
266
|
+
- **`info` status tone — token wired through the full status family.**
|
|
267
|
+
New `--info` / `--info-soft` tokens (+ `--bronto-color-info` semantic
|
|
268
|
+
alias), dual-theme, **and** the consumers that make it real:
|
|
269
|
+
`ui-badge--info`, `ui-alert--info`, `ui-toast--info`, `ui-dot--info`,
|
|
270
|
+
with `ui.badge`/`ui.alert`/`ui.dot` recipes, `BadgeOpts`/`DotOpts`/
|
|
271
|
+
`Tone` types, the toast `ToastOpts` tone, the generated reference and
|
|
272
|
+
the demo. This deliberately reverses the 0.3.2 `ui-badge--info`
|
|
273
|
+
deferral: shipping a token no component consumes would be the exact
|
|
274
|
+
dead-token defect this release exists to remove. Its gated contrast
|
|
275
|
+
row is now a real indicator (measured ≥3:1 on surface — light 5.77:1,
|
|
276
|
+
dark 8.41:1). Status hues (`success`/`warning`/`danger`/`info`) are
|
|
277
|
+
outside the rationed-accent rule by design.
|
|
278
|
+
- **`docs/theming.md` — a full re-skin recipe.** Demonstrates that the
|
|
279
|
+
"Nothing" identity is a token skin, not the architecture: a per-theme
|
|
280
|
+
override block (measured AA-passing accents) restyles the whole system
|
|
281
|
+
with no fork.
|
|
282
|
+
|
|
283
|
+
### Changed
|
|
284
|
+
|
|
285
|
+
- `.ui-dotbar i` radius `1px` → `var(--radius-sm)` (byte-identical
|
|
286
|
+
render — `--radius-sm` *is* `1px` — but now responds to a radius
|
|
287
|
+
re-skin; no visual-baseline drift).
|
|
288
|
+
- **`--dot-font` is now a live knob.** It and `--display` were defined
|
|
289
|
+
identically and nothing consumed `--dot-font`, yet README / Astro
|
|
290
|
+
guide / `fonts.css` all advertised it as a self-host/re-skin override
|
|
291
|
+
(a documented dead token — the exact defect this release exists to
|
|
292
|
+
remove). `--display` now derives from `--dot-font`
|
|
293
|
+
(`--display: var(--dot-font)`): byte-identical render today, but
|
|
294
|
+
overriding `--dot-font` as documented finally works. Removing the
|
|
295
|
+
token instead would have been breaking (names are contractual), so
|
|
296
|
+
the patch-safe fix is to make the advertised knob real.
|
|
297
|
+
- Contrast gate now also covers text on `--surface-muted`
|
|
298
|
+
(`--text-soft`, `--text-dim`) — that surface is rendered as a fill by
|
|
299
|
+
forms/disclosure and `--text-dim` there is the tightest real margin
|
|
300
|
+
(~4.7:1). Passing today; now gated so a future palette nudge can't
|
|
301
|
+
silently regress it. (Found by the full-codebase audit.)
|
|
302
|
+
- ROADMAP reconciled against shipped reality: the entire original 0.3.1
|
|
303
|
+
checklist has been delivered for several releases. CHANGELOG is now
|
|
304
|
+
the stated source of truth.
|
|
305
|
+
|
|
306
|
+
### Fixed
|
|
307
|
+
|
|
308
|
+
- `scripts/gen-contrast.mjs` colour parser now rejects non-finite
|
|
309
|
+
channels and handles percent alpha, so a `NaN` ratio can no longer
|
|
310
|
+
silently pass the gate (`check:contrast` also fails explicitly on a
|
|
311
|
+
non-finite ratio). Found by the AgentMix review.
|
|
312
|
+
- `demo/theme-playground.html` WCAG linearisation threshold aligned to
|
|
313
|
+
the canonical `0.04045` (was `0.03928`); points at the gated
|
|
314
|
+
implementation as the source of truth.
|
|
315
|
+
- `check-classes` now strips CSS comments before scraping selectors. It
|
|
316
|
+
is the one contract check that scrapes CSS rather than diffing a
|
|
317
|
+
generator, so a `.ui-*` named only inside a comment could previously
|
|
318
|
+
satisfy the `cls`⇄selector contract — a real (if currently
|
|
319
|
+
unexercised) drift hole. Closed by the full-codebase audit.
|
|
320
|
+
- **`ToastOpts` was runtime-public but type-private.** `toast()` has
|
|
321
|
+
always accepted (and tested) `assertive` / `closable`, but the typed
|
|
322
|
+
`ToastOpts` stopped at `tone`/`title`/`duration`, so a TypeScript
|
|
323
|
+
consumer couldn't pass documented options. Added both (+ a type
|
|
324
|
+
test). `check:dts` covers only the *generated* classes/tokens `.d.ts`,
|
|
325
|
+
not the hand-written behaviors one — this drift was invisible to the
|
|
326
|
+
gate.
|
|
327
|
+
- **`initFormValidation` suppressed native bubbles too late.**
|
|
328
|
+
`form.noValidate` was set inside the submit/blur handlers, so the
|
|
329
|
+
*first* invalid real-browser submit of a pre-existing form showed the
|
|
330
|
+
UA bubble instead of the Bronto error summary (the demo masked it
|
|
331
|
+
with authored `novalidate`). It is now set at init for matched forms
|
|
332
|
+
and restored on cleanup; dynamically-added forms stay covered by the
|
|
333
|
+
in-handler set.
|
|
334
|
+
- **Combobox could select a filtered-out option.** Typing a query that
|
|
335
|
+
hid the active option left `aria-activedescendant` stale; Enter then
|
|
336
|
+
selected the hidden option. `filter()` now clears stale active state
|
|
337
|
+
and Enter is visibility-guarded (WAI-ARIA APG correctness).
|
|
338
|
+
- `check-dist` now also asserts the on-disk `dist/**/*.css` set exactly
|
|
339
|
+
matches the generated bundles — since the whole `dist/` ships, a
|
|
340
|
+
stale/renamed leaf would otherwise reach npm undetected.
|
|
341
|
+
- README bundle-size figures refreshed (~64 kB raw / ~11 kB gzip; the
|
|
342
|
+
enforced ceiling remains `check-dist`'s budget). Prior `~54/~10`
|
|
343
|
+
prose had drifted since 0.3.2.
|
|
344
|
+
|
|
345
|
+
## 0.3.3 — 2026-05-16
|
|
346
|
+
|
|
347
|
+
A second consumer-evidence pass ("felt it twice") plus
|
|
348
|
+
agent-discoverability. All additive — new classes/recipes, a new
|
|
349
|
+
generated artifact, a widened input type, a freed primitive with a
|
|
350
|
+
permanent alias. No breaking change → a patch under the 0.x policy.
|
|
351
|
+
|
|
352
|
+
### Added
|
|
353
|
+
|
|
354
|
+
- **`@ponchia/ui/tokens/resolved.json`** — every colour token resolved
|
|
355
|
+
to a static `#rrggbb` / `rgba(...)` per theme, with `var()` and sRGB
|
|
356
|
+
`color-mix()` evaluated at build time. For render targets that cannot
|
|
357
|
+
read CSS custom properties: MapLibre GPU paint, `<canvas>`, WebGL,
|
|
358
|
+
SVG, server-side image gen. Generated + drift-checked (new
|
|
359
|
+
`check:resolved` gate); no new colours introduced (`check:shiki`
|
|
360
|
+
unaffected). Resolves the deferred charts-palette gap now that a 2nd,
|
|
361
|
+
non-charting consumer has hit it.
|
|
362
|
+
- **`ui-button--sm` / `ui-button--lg`** — token-driven size scale for
|
|
363
|
+
dense tooling (toolbars, pagination, table actions) and hero CTAs.
|
|
364
|
+
`ui.button({ size: 'sm' | 'lg' })`. Default size unchanged.
|
|
365
|
+
- **`ui-empty-state`** — the empty-state primitive is now
|
|
366
|
+
shell-agnostic; `ui-app-empty-state` remains a permanent grouped alias
|
|
367
|
+
(byte-identical render, no baseline drift). Same playbook as 0.3.2
|
|
368
|
+
`ui-stat`.
|
|
369
|
+
- **`ui-app-rail__account`** — a framework-blessed identity / sign-out
|
|
370
|
+
slot, so admin shells stop hand-rolling it; stays visible when the
|
|
371
|
+
rail collapses on mobile.
|
|
372
|
+
- **`ui-modal` controlled (`is-open`) path** — a portal/React modal that
|
|
373
|
+
can't be a native `<dialog>` wears the same skin + open layout via
|
|
374
|
+
`is-open` (`ui.modal({ open: true })`). Backdrop and focus-trap remain
|
|
375
|
+
the consumer's responsibility (the `<dialog>` path still gets them
|
|
376
|
+
free).
|
|
377
|
+
- **`llms.txt`** at the package root — a self-contained agent entrypoint
|
|
378
|
+
(typed contract, the `@layer bronto` override rule, import surface,
|
|
379
|
+
shipped offline references).
|
|
380
|
+
- **`docs/reference.md` and `docs/theming.md` now ship in the npm
|
|
381
|
+
tarball** — an offline coding agent gets the full class catalog and
|
|
382
|
+
token contract from `node_modules/@ponchia/ui/`. The reference also
|
|
383
|
+
now documents the table-local `is-num`/`is-pos`/`is-neg` state classes
|
|
384
|
+
and the ARIA-driven composition/state model. New `exports` subpaths:
|
|
385
|
+
`./llms.txt`, `./docs/reference.md`, `./docs/theming.md`,
|
|
386
|
+
`./tokens/resolved.json`.
|
|
387
|
+
|
|
388
|
+
### Changed
|
|
389
|
+
|
|
390
|
+
- **`ClassValue` widened to clsx parity** (`string | number | boolean |
|
|
391
|
+
null | undefined | …`). The idiomatic React `reactNode && 'cls'` guard
|
|
392
|
+
(where the node may be `0` / `''`) now type-checks; the runtime `cx`
|
|
393
|
+
already skipped every falsy value, so this is a non-breaking type
|
|
394
|
+
relaxation.
|
|
395
|
+
- `check-pack.mjs` relaxed from a blanket `docs/` ship-block to a
|
|
396
|
+
**curated allowlist** (`docs/reference.md`, `docs/theming.md` only); a
|
|
397
|
+
consistency assertion fails if that set drifts from `package.json`
|
|
398
|
+
`files`. The rest of `docs/` stays dev-only by design — a deliberate,
|
|
399
|
+
documented narrowing of the earlier runtime-only stance.
|
|
400
|
+
|
|
401
|
+
### Deferred (deliberately not shipped)
|
|
402
|
+
|
|
403
|
+
- **React/Solid binding layer.** The duplicated form/badge "glue" two
|
|
404
|
+
consumers feel is ARIA-driven by design (`aria-invalid`, `aria-busy`,
|
|
405
|
+
`aria-describedby`), so the agnostic surface is already complete; the
|
|
406
|
+
remaining duplication is the framework-binding layer, still deferred.
|
|
407
|
+
The reference now documents the composition model explicitly.
|
|
408
|
+
- **`ui-app-rail__foot` mobile `display:none`.** Whether the foot should
|
|
409
|
+
survive the mobile breakpoint is a visual/possibly-breaking call; the
|
|
410
|
+
new `__account` slot (which does survive) covers the actual need
|
|
411
|
+
without changing existing behaviour.
|
|
412
|
+
|
|
413
|
+
## 0.3.2 — 2026-05-16
|
|
414
|
+
|
|
415
|
+
Re-skin-proven adoption pass: a real content-site consumer rebuilt
|
|
416
|
+
several idioms bespoke because a primitive was missing or shell-locked.
|
|
417
|
+
This promotes the genuinely generic, token-only ones upstream. **All
|
|
418
|
+
additions are non-breaking** (additive classes/recipes; the metric tile
|
|
419
|
+
keeps its admin-shell name as a permanent alias) — a patch per the 0.x
|
|
420
|
+
policy.
|
|
421
|
+
|
|
422
|
+
### Added
|
|
423
|
+
|
|
424
|
+
- **`ui-stat` / `ui-statgrid`** — the metric tile is now shell-agnostic
|
|
425
|
+
(label + display value + signed delta). The admin-shell
|
|
426
|
+
`ui-app-metric*` / `ui-app-metrics` names remain as permanent aliases
|
|
427
|
+
grouped on the same rules (byte-identical output, no baseline drift).
|
|
428
|
+
- **`ui-link--cta`** — the eyebrow-faced action link (accent · display ·
|
|
429
|
+
uppercase + arrow glyph), composed from the same tokens as
|
|
430
|
+
`ui-eyebrow`. `ui.link({ cta: true })`.
|
|
431
|
+
- **`ui-badge--dot`** — leading state dot; composes with any badge tone
|
|
432
|
+
(`is`-tone tints the dot). `ui.badge({ tone, dot: true })`.
|
|
433
|
+
- **`ui-eyebrow--sm`** — restores the dense size step (was
|
|
434
|
+
`eyebrow--tight` in 0.2.2). `ui.eyebrow({ sm: true })`.
|
|
435
|
+
- **`ui-container--wide`** — documented wide preset (`--container-wide`,
|
|
436
|
+
default 82rem) for app/marketing shells. `ui.container({ wide: true })`.
|
|
437
|
+
- **`ui-siteheader--sticky`** — structural sticky only (the floating-card
|
|
438
|
+
skin stays consumer identity, deliberately not shipped).
|
|
439
|
+
- **`ui-dotmatrix`** (+`__cell`, `--hot`, `--accent`) — data-bound dot
|
|
440
|
+
grid, the on-brand counterpart to the decorative `ui-dotgrid`; the
|
|
441
|
+
data→cell mapping stays the consumer's.
|
|
442
|
+
- **`ui-num`** (+`--pos`, `--neg`, `--muted`) — the tabular / end-aligned
|
|
443
|
+
/ P&L-tone numeric vocabulary the table has shipped since 0.1.0, freed
|
|
444
|
+
from `.ui-table` so cards, stats and inline figures share one
|
|
445
|
+
contract. `ui.num({ tone })`. (Two independent admin consumers were
|
|
446
|
+
reinventing `.text-green`/right-align outside a table.)
|
|
447
|
+
- **`ui-badge--muted`** — the idle / unknown / "no signal yet" status
|
|
448
|
+
tone, distinct from the default tinted badge. `ui.badge({ tone:
|
|
449
|
+
'muted' })`. Token-safe, no new hue.
|
|
450
|
+
|
|
451
|
+
### Fixed
|
|
452
|
+
|
|
453
|
+
- **`ui-card--interactive`** had no keyboard cue (cards typically wrap a
|
|
454
|
+
single link): added `:focus-within` border + a `--shadow-raised` ring
|
|
455
|
+
on hover. a11y completeness fix.
|
|
456
|
+
|
|
457
|
+
### Changed
|
|
458
|
+
|
|
459
|
+
- dist raw size budget recalibrated 64 kB → 76 kB (post-0.3.2 bundle is
|
|
460
|
+
~64.5 kB raw / ~11.1 kB gzip; ~18% raw headroom restored). The gzip
|
|
461
|
+
cap (12 kB) is unchanged — the wire-size contract still holds.
|
|
462
|
+
|
|
463
|
+
## 0.3.1 — 2026-05-16
|
|
464
|
+
|
|
465
|
+
Adoption + gap-closing pass driven by a 12-perspective review (two Opus
|
|
466
|
+
analyses + two five-model AgentMix deep runs). **All additions are
|
|
467
|
+
non-breaking** (additive classes/tokens/behaviors; short token names
|
|
468
|
+
kept as permanent aliases) — so this is a patch, per the 0.x policy
|
|
469
|
+
(only breaking changes bump the minor); the 0.3.0 legacy removal
|
|
470
|
+
stands. Tracked scope: ROADMAP.md.
|
|
471
|
+
|
|
472
|
+
### Added
|
|
473
|
+
|
|
474
|
+
- **Components/behaviors** (all SSR-safe, idempotent, cleanup-returning,
|
|
475
|
+
dependency-free): `ui-combobox` + `initCombobox` (WAI-ARIA APG
|
|
476
|
+
combobox); `ui-popover` + `initPopover` (collision-aware, native
|
|
477
|
+
top-layer when available); `initFormValidation` (Constraint
|
|
478
|
+
Validation → `aria-invalid`/`aria-describedby` + error summary);
|
|
479
|
+
`initTableSort` (sortable `aria-sort` headers + row selection,
|
|
480
|
+
`bronto:selectionchange`); `.ui-button[aria-busy]` loading state;
|
|
481
|
+
toast dismiss button + separate assertive region for `danger`.
|
|
482
|
+
- **Forms:** `ui-input-group`(+`__addon`), `ui-file`, `ui-range`,
|
|
483
|
+
`ui-error-summary`.
|
|
484
|
+
- **Layout:** `ui-sidebar`, `ui-switcher`, `ui-center`, `ui-ratio`;
|
|
485
|
+
opt-in `ui-cq` container queries for `ui-grid` / `ui-app-metrics`.
|
|
486
|
+
- **Tokens:** semantic `--bronto-color-*` tier, `--accent-1..6` /
|
|
487
|
+
`--surface-1..6` ramps, `--z-*` stacking scale (every framework
|
|
488
|
+
`z-index` now resolves through it; values unchanged).
|
|
489
|
+
- **DX:** generated drift-checked `docs/reference.md`; VS Code
|
|
490
|
+
`classes/vscode.css-custom-data.json` (token IntelliSense, exported
|
|
491
|
+
as `./vscode.css-custom-data.json`); per-framework integration guides
|
|
492
|
+
+ Tailwind interop recipe; `examples/{vanilla-vite,astro,sveltekit}`
|
|
493
|
+
+ consumer-smoke CI matrix; README badges; `ROADMAP.md`;
|
|
494
|
+
`MIGRATIONS.json` + `docs/migrations/0.2-to-0.3.md`;
|
|
495
|
+
`demo/theme-playground.html` (live contrast checker).
|
|
496
|
+
- **a11y:** `role="switch"` contract + forced-colors switch cues;
|
|
497
|
+
`@supports(anchor-name)` tooltip un-clipping.
|
|
498
|
+
|
|
499
|
+
### Fixed
|
|
500
|
+
|
|
501
|
+
- **Release hygiene:** the `0.3.0` section was still labelled
|
|
502
|
+
`unreleased` after `v0.3.0` shipped to npm `latest`. Dated it
|
|
503
|
+
correctly and added a `check:release` gate (in `npm run check`) that
|
|
504
|
+
fails when `package.json`'s version maps to an `unreleased` changelog
|
|
505
|
+
heading, so a published version can never again be marked unreleased.
|
|
506
|
+
|
|
507
|
+
### Changed
|
|
508
|
+
|
|
509
|
+
- `npm run check` is now 14 gates (+`check:release`, `check:reference`,
|
|
510
|
+
`check:vscode`); `prepack` regenerates the reference + VS Code data.
|
|
511
|
+
- CONTRIBUTING.md documents a deprecate-one-minor policy so
|
|
512
|
+
"minor may break" is predictable.
|
|
513
|
+
|
|
514
|
+
## 0.3.0 — 2026-05-16
|
|
515
|
+
|
|
516
|
+
### Multi-POV review hardening
|
|
517
|
+
|
|
518
|
+
A six-perspective review (DX/contract, CSS architecture, a11y,
|
|
519
|
+
release/supply-chain, plus AgentMix) drove this pass.
|
|
520
|
+
|
|
521
|
+
**BREAKING (token / contract level)**
|
|
522
|
+
|
|
523
|
+
- **New `--accent-text` token** (= `var(--accent-strong)`). Everywhere
|
|
524
|
+
the accent was used as _foreground text_ (links on hover, active
|
|
525
|
+
nav/tab/accordion, prose markers, eyebrows, chips, breadcrumb,
|
|
526
|
+
pagination) now resolves through `--accent-text`, not raw `--accent`,
|
|
527
|
+
so a pale re-brand no longer silently fails text contrast.
|
|
528
|
+
_Migration:_ none for default themes (visually identical). If you
|
|
529
|
+
re-brand `--accent` to a light hue, also set `--accent-text` to a
|
|
530
|
+
dark-enough value (see docs/theming.md).
|
|
531
|
+
- **`--focus-ring` is now solid `var(--accent)`** (was an unused
|
|
532
|
+
50%/55% transparent mix) and every focus outline is wired to it.
|
|
533
|
+
Default focus appearance is unchanged; the `[data-contrast=high]` /
|
|
534
|
+
`prefers-contrast` promotion and per-theme `--focus-ring` overrides
|
|
535
|
+
now actually take effect. _Migration:_ none unless you relied on the
|
|
536
|
+
(previously dead) token value.
|
|
537
|
+
- **`classes/index.d.ts` / `tokens/index.d.ts` are now generated
|
|
538
|
+
literal types.** `cls` exposes literal keys+values; token views use
|
|
539
|
+
`ColorKey`/`ScaleKey`/`*TokenName` unions; `themeColor` takes
|
|
540
|
+
`ThemeName`. Mistyped keys are now compile errors. _Migration:_ fix
|
|
541
|
+
any code that relied on the old `Record<string,string>` (e.g. reading
|
|
542
|
+
a non-existent key and getting `string` instead of an error). JS
|
|
543
|
+
token keys are kebab-case — `themeColor('dark')['accent-soft']`.
|
|
544
|
+
|
|
545
|
+
**Fixed**
|
|
546
|
+
|
|
547
|
+
- **a11y (WCAG AA):** `.ui-chip--accent`, legacy `.eyebrow` group and
|
|
548
|
+
`.tag-list--compact` first child no longer use raw `--accent` as
|
|
549
|
+
small text (was ~3.9:1 in light).
|
|
550
|
+
- **a11y:** native `<dialog>` returns focus to its trigger on _every_
|
|
551
|
+
close path (Esc, close button, backdrop light-dismiss, programmatic).
|
|
552
|
+
- **a11y:** the toast `aria-live` stack is a persistent region — no
|
|
553
|
+
longer created-then-destroyed per drain, fixing dropped first /
|
|
554
|
+
post-drain screen-reader announcements.
|
|
555
|
+
- **a11y:** `.ui-tab:focus-visible` is now visually distinct from the
|
|
556
|
+
active-tab underline (inset ring).
|
|
557
|
+
- **DX:** the `.` export is conditional (`style`/`default`) instead of a
|
|
558
|
+
bare `.css` string, so type-aware tooling no longer mis-resolves the
|
|
559
|
+
package root. The root is CSS-only (documented).
|
|
560
|
+
|
|
561
|
+
**Changed (non-breaking)**
|
|
562
|
+
|
|
563
|
+
- Behavior initializers (`initThemeToggle`, `dismissible`, `initDialog`,
|
|
564
|
+
`initDisclosure`, `initTabs`) are now idempotent — re-init (HMR,
|
|
565
|
+
framework remount, repeat calls) replaces rather than stacking
|
|
566
|
+
duplicate listeners. Tab ids use a module-global counter so separate
|
|
567
|
+
islands never collide on `bronto-tab-1`.
|
|
568
|
+
- New drift gate `check:dts` (generated `.d.ts` ⇄ JS runtime), wired
|
|
569
|
+
into `npm run check` and `prepack`. `docs/architecture.md` drift table
|
|
570
|
+
and release-gating section corrected to the real four-job DAG
|
|
571
|
+
(`validate` + `e2e` → `publish-npm` → `release-notes`).
|
|
572
|
+
- README: explicit "do not mix a bundle with a raw leaf import" hazard
|
|
573
|
+
warning; a Versioning section; size/`@import`-depth prose de-drifted.
|
|
574
|
+
- Tests: +3 unit tests (dialog focus-return, initializer idempotency,
|
|
575
|
+
global-unique tab ids); +5 e2e a11y tests (RTL axe pass, dialog
|
|
576
|
+
focus-return on Escape, persistent toast live region, disclosure
|
|
577
|
+
toggle, modal computed-contrast instead of a blanket rule disable);
|
|
578
|
+
demo gained a `[data-bronto-disclosure]` instance (was untested).
|
|
579
|
+
_Release note:_ the visual-snapshot baselines (`test/e2e/__screenshots__`)
|
|
580
|
+
are intentionally stale after the contrast / focus-ring / legacy-removal
|
|
581
|
+
changes (cross-OS rasterisation means they can only be authored in the
|
|
582
|
+
pinned container, not on a dev machine). Regenerate them with one click:
|
|
583
|
+
run the **“Update visual baselines”** workflow (`workflow_dispatch`,
|
|
584
|
+
`.github/workflows/visual-baselines.yml`) from this branch — it rebuilds
|
|
585
|
+
them in `mcr.microsoft.com/playwright:v1.60.0-jammy` and commits them
|
|
586
|
+
back, after which the `e2e` gate goes green on its own. Red by design
|
|
587
|
+
until that runs.
|
|
588
|
+
|
|
589
|
+
**BREAKING (legacy vocabulary removed / migrated)**
|
|
590
|
+
|
|
591
|
+
The whole non-`ui-*` surface is gone; everything shipped is now under the
|
|
592
|
+
`.ui-*` contract and the `check-classes` drift gate.
|
|
593
|
+
|
|
594
|
+
- **Deleted (had `ui-*` equivalents):** `css/layout.css`, `css/cards.css`,
|
|
595
|
+
`css/typography.css` and their entire vocabulary — `.hero`,
|
|
596
|
+
`.project-*`, `.post-card`, `.essay-*`, `.metric-tile`, `.callout`,
|
|
597
|
+
`.eyebrow`, bare `.button`, `.section-head`, `.tag-list`,
|
|
598
|
+
`.profile-link-list`, `.page-*`, `.home-*`, `.signal-panel`,
|
|
599
|
+
`.worklog-summary`, … _Migration:_ use the `ui-*` content layer —
|
|
600
|
+
`.ui-prose`/`.ui-quote` (long-form), `.ui-card`, `.ui-eyebrow`,
|
|
601
|
+
`.ui-button`, `.ui-tag`/`.ui-tags`, `.ui-grid`/`.ui-stack`, the
|
|
602
|
+
`ui-site*` shell. `.skip-link` → `.ui-skiplink`; `.site-nav` →
|
|
603
|
+
`.ui-sitenav`; `.site-menu` → `.ui-sitemenu` (responsive nav) or the
|
|
604
|
+
new `.ui-menu-host` (a `<details>` + `.ui-menu` dropdown wrapper).
|
|
605
|
+
- **Renamed → first-class:** the admin shell `.app-*` → **`.ui-app-*`**
|
|
606
|
+
(`ui-app-shell`/`-rail`/`-topbar`/`-toolbar`/`-nav`/`-panel`/
|
|
607
|
+
`-content`/`-main`/`-metrics`/`-metric`/`-empty-state`, with the same
|
|
608
|
+
`__part` / `--mod` suffixes). The theme toggle `.theme-toggle__*` →
|
|
609
|
+
**`.ui-themetoggle__*`**. _Migration:_ rename these class strings in
|
|
610
|
+
consumer markup (or use the new `cls.app*` / `cls.themetoggle*` /
|
|
611
|
+
`cls.menuHost` entries). They are now typed and drift-checked.
|
|
612
|
+
- **Bundle collapsed:** `css/responsive.css` and `css/index.css` removed.
|
|
613
|
+
`ui-*` components own their breakpoints, so there is no core/full
|
|
614
|
+
split: `@ponchia/ui/css` now resolves to `css/core.css` (one bundle),
|
|
615
|
+
`@ponchia/ui` → the single `dist/bronto.css` (~54 kB / ~10 kB gzip,
|
|
616
|
+
was ~70/12). _Removed exports:_ `./css/index.css`,
|
|
617
|
+
`./css/responsive.css`, `./dist/bronto-core.css`, and the deleted
|
|
618
|
+
leaves' `./css/{layout,typography,cards}.css`. _Migration:_ import
|
|
619
|
+
`@ponchia/ui` or `@ponchia/ui/css`.
|
|
620
|
+
|
|
621
|
+
**BREAKING (per-leaf imports are now layer-safe)**
|
|
622
|
+
|
|
623
|
+
- Every `@ponchia/ui/css/<leaf>.css` export now resolves to a
|
|
624
|
+
self-`@layer bronto`-wrapped build (`dist/css/<leaf>.css`), so a
|
|
625
|
+
direct leaf import is layered by default and safe to mix with the
|
|
626
|
+
bundle — the silent cascade-inversion footgun is gone. The raw,
|
|
627
|
+
full-specificity source is still available as a deliberate escape
|
|
628
|
+
hatch at the explicit **`@ponchia/ui/css/unlayered/<leaf>.css`**
|
|
629
|
+
path. _Migration:_ none if you import the bundle. If you imported a
|
|
630
|
+
raw leaf *expecting* unlayered/full-specificity behaviour, switch
|
|
631
|
+
that import to the `css/unlayered/*` path; otherwise the now-layered
|
|
632
|
+
leaf is the correct (safe) default. Drift-checked by `check-dist`.
|
|
633
|
+
|
|
634
|
+
### Tooling (external-review triage)
|
|
635
|
+
|
|
636
|
+
Adopted what fits the CSS-first / zero-runtime-dep / curated-artifact
|
|
637
|
+
ADR; declined what doesn't (recorded so the decision isn't re-litigated).
|
|
638
|
+
|
|
639
|
+
**Added**
|
|
640
|
+
|
|
641
|
+
- **TypeScript type gate** — `tsconfig.json` + `test/types.test-d.ts`
|
|
642
|
+
+ `check:types` (in `npm run check`). Compiles the published `.d.ts`
|
|
643
|
+
and asserts, via `@ts-expect-error`, that the generated literal
|
|
644
|
+
`cls`/token types reject typos and `themeColor` rejects non-`ThemeName`.
|
|
645
|
+
Completes the review's "auto-generate .d.ts, kill drift" item
|
|
646
|
+
(generation + `check-dts` landed earlier this minor; this proves the
|
|
647
|
+
result). `typescript` is devDep-only — no runtime/types-export change.
|
|
648
|
+
- **Prettier** — `.prettierrc` + `check:format`/`format`, in
|
|
649
|
+
`npm run check`. Scoped to hand-authored non-CSS source; CSS stays
|
|
650
|
+
Stylelint-owned, generated artifacts and the curated Markdown/`demo`
|
|
651
|
+
are `.prettierignore`d so formatters never fight generators.
|
|
652
|
+
- **GitHub issue/PR templates** — collect `@ponchia/ui` version,
|
|
653
|
+
consuming framework, and surface; PR template carries the
|
|
654
|
+
contract/SemVer/a11y checklist.
|
|
655
|
+
- **Bundle-size budget tightened** — `check-dist` `BUDGET` recalibrated
|
|
656
|
+
90 kB→64 kB raw / 16 kB→12 kB gzip (bundle is ~54/~10 post-cleanup),
|
|
657
|
+
so regrowth is gated, not just catastrophic blowouts. (Dependabot was
|
|
658
|
+
already added earlier this minor.)
|
|
659
|
+
|
|
660
|
+
**Declined (rationale)** — Storybook (heavy React/Vite toolchain vs the
|
|
661
|
+
framework-agnostic zero-dep ADR; `demo/index.html` is the self-driving
|
|
662
|
+
surface); Style Dictionary as a dependency (the shipped
|
|
663
|
+
`tokens.dtcg.json` *is* the deliberate bring-your-own platform interop;
|
|
664
|
+
no native consumers exist — consumers run SD themselves);
|
|
665
|
+
standard-version/auto-changelog (the curated narrative CHANGELOG is an
|
|
666
|
+
asset; commits are already conventional); Renovate (Dependabot chosen);
|
|
667
|
+
Lighthouse CI (the axe a11y gate + size budget already cover the
|
|
668
|
+
regression vectors).
|
|
669
|
+
|
|
670
|
+
### Post-review fixes (independent Opus + AgentMix pass on this branch)
|
|
671
|
+
|
|
672
|
+
- **Fixed (HIGH, regression introduced here):** the persistent-toast
|
|
673
|
+
rAF deferral could resurrect an already-dismissed first toast into the
|
|
674
|
+
`aria-live` region (dismiss within the first frame). Now guarded by a
|
|
675
|
+
`dismissed` flag; `dismiss()` is idempotent. +2 unit tests polyfilling
|
|
676
|
+
rAF (the jsdom env had no `requestAnimationFrame`, so the path was
|
|
677
|
+
previously untested).
|
|
678
|
+
- **Fixed (HIGH, regression introduced here):** the layered per-leaf
|
|
679
|
+
`@ponchia/ui/css/fonts.css` (now `dist/css/fonts.css`) referenced
|
|
680
|
+
`url(../fonts/*)`, which from `dist/css/` resolves to the unshipped
|
|
681
|
+
`dist/fonts/`. `build-dist` now rewrites `../fonts/` → `../../fonts/`
|
|
682
|
+
for the deeper per-leaf files (the flattened bundle at `dist/` is
|
|
683
|
+
unaffected and unchanged). `check-dist` now also resolves every
|
|
684
|
+
`url(...)` in each generated file against its own location, so this
|
|
685
|
+
class of depth bug can't recur.
|
|
686
|
+
- **Fixed (docs):** README SemVer guidance was wrong — at `0.x` npm
|
|
687
|
+
resolves `^0.3.0` and `~0.3.0` identically (`>=0.3.0 <0.4.0`); both
|
|
688
|
+
hold back the breaking `0.4.0`. Corrected. Removed the stale
|
|
689
|
+
"legacy `site-*`/`.tag-list` kept as back-compat" line (they were
|
|
690
|
+
deleted this release). De-duplicated the `check-dist` paragraph in
|
|
691
|
+
architecture.md.
|
|
692
|
+
- **Hardened:** the release `publish-npm` step uses
|
|
693
|
+
`npm publish --ignore-scripts`, so `NODE_AUTH_TOKEN` is never exposed
|
|
694
|
+
to the prepack/prepublishOnly lifecycle; it ships the artifacts already
|
|
695
|
+
byte-verified by `validate` on the same commit.
|
|
696
|
+
|
|
697
|
+
### Further discovered-issue cleanup
|
|
698
|
+
|
|
699
|
+
Bounded, sensible items surfaced by the reviews, now closed:
|
|
700
|
+
|
|
701
|
+
- **a11y:** new `initMenu` behavior — Escape / outside-click /
|
|
702
|
+
close-on-activate (with focus return to `<summary>`) for a native
|
|
703
|
+
`<details data-bronto-menu>` `.ui-menu` dropdown. Deliberately a
|
|
704
|
+
disclosure of buttons, not an over-claimed ARIA menu (review M3).
|
|
705
|
+
Wired in the demo; unit-tested.
|
|
706
|
+
- **a11y:** the active tab's selected state is re-asserted under
|
|
707
|
+
`forced-colors: active` (`border/colour: Highlight`) — it was
|
|
708
|
+
invisible in Windows High Contrast (review L3).
|
|
709
|
+
- **a11y (demo):** the pagination "previous" control is now a real
|
|
710
|
+
`disabled` button (was a focusable/clickable `aria-disabled`,
|
|
711
|
+
misleading on the axe-gated integration surface); arrow controls
|
|
712
|
+
gained accessible names; active page uses `aria-current="page"`
|
|
713
|
+
(review M1).
|
|
714
|
+
- **CI:** GitHub Pages now deploys only after the `CI` workflow
|
|
715
|
+
concludes **successfully** on `main` (`workflow_run` trigger, not a
|
|
716
|
+
bare push) — a red-e2e/broken demo can no longer be published
|
|
717
|
+
independently of the gates.
|
|
718
|
+
- **docs:** theming.md documents the one accent surface the framework
|
|
719
|
+
can't tune — native control `accent-color` under a pale re-brand
|
|
720
|
+
(review css M2).
|
|
721
|
+
|
|
722
|
+
### Content-site layer
|
|
723
|
+
|
|
724
|
+
Promotes the proven, hand-rolled site shell into the first-class typed
|
|
725
|
+
contract so consumers stop reimplementing it. (The legacy `site-*` /
|
|
726
|
+
`.tag-list` back-compat classes referenced here were **removed** in the
|
|
727
|
+
same release — see the "legacy vocabulary removed / migrated" BREAKING
|
|
728
|
+
section above; they are not shipped.)
|
|
729
|
+
|
|
730
|
+
- **`site.css`**: `ui-container` (+`--narrow`), `ui-siteheader`
|
|
731
|
+
(`__brand`/`__actions`), `ui-sitenav` (active via `aria-current`, dot
|
|
732
|
+
cue, responsive collapse into `ui-sitemenu` — native `<details>`, no
|
|
733
|
+
JS), `ui-sitefooter` (`__links`), `ui-skiplink`, `ui-tags`/`ui-tag`
|
|
734
|
+
(`--accent`; neutral content labels, distinct from interactive
|
|
735
|
+
`ui-chip`), `ui-meta` (dot-separated meta row).
|
|
736
|
+
- **`ui-quote`** (+ `__cite`) in `content.css`: a pull-quote companion
|
|
737
|
+
to `.ui-prose` — emphasis by scale + a short accent rule, not a box.
|
|
738
|
+
- **Shiki**: `@ponchia/ui/shiki/nothing.json` — a documented optional
|
|
739
|
+
VS Code/TextMate theme (rationed: brand accent + greyscale),
|
|
740
|
+
drift-checked (`check:shiki` keeps it on-palette and in sync with the
|
|
741
|
+
dark `--accent`). Bring-your-own-highlighter, like `tokens.dtcg.json`.
|
|
742
|
+
- Full contract treatment: 18 classes + `ui.container`/`ui.tag` recipes
|
|
743
|
+
+ `.d.ts` (guarded), cascade/exports/dist wired, demo + docs. The
|
|
744
|
+
`not-a-gap` items from the source review (theme-toggle CSS already
|
|
745
|
+
exists in `navigation.css`; `ui-timeline` too consumer-specific) were
|
|
746
|
+
deliberately excluded.
|
|
747
|
+
|
|
748
|
+
## 0.2.2 — 2026-05-15
|
|
749
|
+
|
|
750
|
+
Component + mobile expansion, then a framework-grade hardening pass
|
|
751
|
+
(RTL, a11y, theming contract, Markdown content layer). Additive — no
|
|
752
|
+
existing token/selector values changed except documented WCAG fixes.
|
|
753
|
+
|
|
754
|
+
### Framework hardening
|
|
755
|
+
|
|
756
|
+
- **RTL / logical properties**: every `css/*` physical property is now
|
|
757
|
+
logical (`*-inline/-block-*`), enforced by `stylelint-use-logical`
|
|
758
|
+
(`csstools/use-logical: always`). Render-neutral in LTR; RTL mirrors
|
|
759
|
+
cleanly (verified, incl. the drawer).
|
|
760
|
+
- **A11y**: `initTabs` behavior (WAI-ARIA Tabs keyboard pattern);
|
|
761
|
+
`forced-colors` (Windows High Contrast) support in `base.css`; WCAG
|
|
762
|
+
contrast fixes — light `--text-dim`/`--warning`, dark `--text-dim`
|
|
763
|
+
now ≥ 4.5:1. Badge variants drop tone-on-tinted-tone text (failed AA
|
|
764
|
+
at small bold) — tone now rides the border + tint, text inherits the
|
|
765
|
+
high-contrast neutral. `.ui-eyebrow` uses `--accent-strong` so it
|
|
766
|
+
clears 4.5:1 on soft surfaces too. (All surfaced by the new axe gate.)
|
|
767
|
+
- **Theming contract**: `--accent` is one knob — the whole accent family
|
|
768
|
+
is `color-mix`-derived (ratios tuned to the prior hex, ≈ zero default
|
|
769
|
+
drift). `data-density` (compact/comfortable) and `data-contrast=high`
|
|
770
|
+
+ `@media (prefers-contrast: more)` presets. See `docs/theming.md`.
|
|
771
|
+
- **content.css**: `.ui-prose` (+ `--compact`) styles raw
|
|
772
|
+
Markdown-renderer HTML — headings, lists, quote, code, tables, media,
|
|
773
|
+
figures — with **zero per-element classes**, keeping documents
|
|
774
|
+
semantic and machine-readable.
|
|
775
|
+
- **CI regression safety**: Playwright visual snapshots of the demo
|
|
776
|
+
(dark / light / RTL / modal) + `@axe-core/playwright` WCAG 2.1 A/AA
|
|
777
|
+
gates (both themes, modal, tab keyboard pattern), as a new `visual`
|
|
778
|
+
CI job pinned to the Playwright container the baselines were authored
|
|
779
|
+
in (byte-stable, no cross-OS font flake). Catches CSS/markup
|
|
780
|
+
regressions structure-checks can't.
|
|
781
|
+
- **Prebuilt bundles**: `dist/bronto.css` + `dist/bronto-core.css` —
|
|
782
|
+
the `@import` graph flattened + conservatively minified into one
|
|
783
|
+
`@layer bronto` file (~62 kB / ~11 kB gzip), no load waterfall.
|
|
784
|
+
Exposed as `@ponchia/ui` (`.`) and `./dist/*`; `check:dist` keeps it
|
|
785
|
+
byte-fresh and in a size budget; built in `prepack`. README documents
|
|
786
|
+
the evergreen support floor (Chrome 111+/Safari 16.4+/Firefox 121+).
|
|
787
|
+
|
|
788
|
+
### Multi-agent review response
|
|
789
|
+
|
|
790
|
+
Acted on a deep read-only review (AgentMix `deep`), verifying each
|
|
791
|
+
finding against the code first:
|
|
792
|
+
|
|
793
|
+
- **Public TS contract**: `classes/index.d.ts` was stale — added the 9
|
|
794
|
+
missing `ui.*` recipes (`alert`, `toast`, `progress`, `dotspinner`,
|
|
795
|
+
`dotbar`, `modal`, `tab`, `avatar`, `prose`) + option types, and a new
|
|
796
|
+
drift guard in `check-classes` so a recipe without a declaration now
|
|
797
|
+
fails `npm run check`.
|
|
798
|
+
- **RTL completeness**: `[dir='rtl']` mirrors for the cases the lint
|
|
799
|
+
plugin can't convert — switch thumb, theme-toggle thumb, `<select>`
|
|
800
|
+
marker (`background-position`), arrow-link hover nudge.
|
|
801
|
+
- **Bug**: `.ui-progress__bar` transitioned the (now non-existent)
|
|
802
|
+
physical `width`; animate `inline-size`.
|
|
803
|
+
- **Release gating**: `release.yml` now runs the containerised
|
|
804
|
+
visual/a11y suite and `publish-npm`/`release-notes` depend on it — a
|
|
805
|
+
tagged release can't skip what every branch push runs.
|
|
806
|
+
- **Hardening**: `initTabs` scopes to its own group (nested-safe);
|
|
807
|
+
`initDialog` root semantics documented (dialogs are document-global
|
|
808
|
+
by design); `scripts/serve.mjs` binds loopback + strict path
|
|
809
|
+
containment; fixed an invalid selector in `docs/theming.md`.
|
|
810
|
+
|
|
811
|
+
### Second review pass (PR #3)
|
|
812
|
+
|
|
813
|
+
Independent Opus review said SHIP; the AgentMix `deep` mix flagged
|
|
814
|
+
more — verified each, fixed the real ones:
|
|
815
|
+
|
|
816
|
+
- **Release hygiene**: `package-lock.json` synced to `0.2.2`;
|
|
817
|
+
`release.yml` `release-notes` now `needs: publish-npm` (no GitHub
|
|
818
|
+
Release for a version that failed to publish — no split-brain).
|
|
819
|
+
- **RTL**: `.ui-toast-stack` used physical `inset` → logical
|
|
820
|
+
`inset-block`/`inset-inline` so the stack mirrors in RTL.
|
|
821
|
+
- **`initTabs`**: a `root` that *is* the `[data-bronto-tabs]` element is
|
|
822
|
+
now initialised (querySelectorAll only sees descendants); tabs are
|
|
823
|
+
cross-linked to panels via `aria-controls`/`aria-labelledby`
|
|
824
|
+
(APG-complete), ids minted only where absent.
|
|
825
|
+
- **Toast**: dropped the per-item `role="status"` nested inside the
|
|
826
|
+
`aria-live` stack (double-announcement risk).
|
|
827
|
+
- **DTCG**: `--shadow: none` was typed `color` (name matched the colour
|
|
828
|
+
regex, value failed the shadow test) — shadows are now classified by
|
|
829
|
+
name first → `$type: "shadow"`.
|
|
830
|
+
- **Tests**: new `ui.*` recipe-output coverage + a `.d.ts`-declaration
|
|
831
|
+
assertion; `initTabs` root-self/APG test; `tokens.dtcg.json` shape
|
|
832
|
+
test (shadow typing + the null-+-extension invariant); `serve.mjs`
|
|
833
|
+
`safePath` traversal unit test. The RTL e2e now waits for the
|
|
834
|
+
mirrored end-state instead of racing a fixed sleep (the CSS was
|
|
835
|
+
correct; the old test read mid-transition).
|
|
836
|
+
|
|
837
|
+
### Discovered follow-ups
|
|
838
|
+
|
|
839
|
+
Closed the remaining items surfaced across the review/verification:
|
|
840
|
+
|
|
841
|
+
- **Regression tests for the review fixes**: `serve.mjs` refactored to a
|
|
842
|
+
pure exported `safePath()` with a traversal/sibling-prefix unit test;
|
|
843
|
+
`initTabs` nested-isolation test — which **caught a real bug in the
|
|
844
|
+
first nested fix** (the outer group's delegated click still fired for
|
|
845
|
+
nested tabs); now gated on owned membership, not DOM containment. New
|
|
846
|
+
e2e assertion that RTL truly mirrors the switch transform + select
|
|
847
|
+
marker (not just box model).
|
|
848
|
+
- **Print** (`@media print` in `base.css`): ink-on-white, chrome hidden,
|
|
849
|
+
`break-inside` guards, prose link URLs surfaced, `@page` margin.
|
|
850
|
+
- **prefers-reduced-data**: points `--display`/`--dot-font` at the mono
|
|
851
|
+
stack so the Doto webfont is never fetched for data-saver users.
|
|
852
|
+
- **DTCG export**: `@ponchia/ui/tokens.dtcg.json` (W3C Design Tokens
|
|
853
|
+
format) generated from the model, drift-checked (`check:dtcg`), built
|
|
854
|
+
in `prepack`. Runtime-derived tokens are spec-shaped with
|
|
855
|
+
`$value:null` + `$extensions` rather than fabricated numbers.
|
|
856
|
+
|
|
857
|
+
### Earlier in this cycle
|
|
858
|
+
|
|
859
|
+
Component + mobile expansion. No token/selector changes to existing
|
|
860
|
+
classes — purely additive; existing consumers are unaffected.
|
|
861
|
+
|
|
862
|
+
- **Dot loaders**: new orbital `ui-dotspinner` (the Nothing-signature
|
|
863
|
+
ring loader, `--sm`/`--lg`), `ui-dotbar--indeterminate` sweep, and a
|
|
864
|
+
linear `ui-progress` (determinate via `--value`, plus
|
|
865
|
+
`ui-progress--indeterminate`).
|
|
866
|
+
- **feedback.css**: `ui-alert` / callout (tones + dismissible), `ui-toast`
|
|
867
|
+
+ `ui-toast-stack`, CSS-only `ui-tooltip`.
|
|
868
|
+
- **overlay.css**: `ui-modal` + `ui-modal--drawer` on native `<dialog>`
|
|
869
|
+
(bottom-sheet on mobile), `ui-menu` dropdown.
|
|
870
|
+
- **disclosure.css**: `ui-tabs` (ARIA + `.is-active` contract, scrollable
|
|
871
|
+
on mobile), `ui-accordion` (styled `<details>`), `:has()`-driven
|
|
872
|
+
`ui-segmented`, `ui-breadcrumb`, `ui-pagination`, `ui-avatar` /
|
|
873
|
+
`ui-avatar-group`.
|
|
874
|
+
- **Behaviors**: `initDialog` (native `<dialog>` open/close + backdrop
|
|
875
|
+
light-dismiss) and `toast()`. SSR-safe; covered by the test suite.
|
|
876
|
+
- **Mobile**: 44px touch targets for buttons/inputs/checkboxes on coarse
|
|
877
|
+
pointers; component-level breakpoints for modal/drawer/menu/tabs.
|
|
878
|
+
- **Contract**: 53 new classes added to the typed `cls` registry + recipes
|
|
879
|
+
(`ui.alert`, `ui.toast`, `ui.progress`, `ui.dotspinner`, `ui.modal`,
|
|
880
|
+
`ui.tab`, `ui.avatar`); `npm run check` and the 20-test suite stay green.
|
|
881
|
+
- **Docs**: removed the stale "not published yet" install note (the
|
|
882
|
+
package is live on npm); documented the new layers and behaviors.
|
|
883
|
+
|
|
884
|
+
## 0.2.1 — 2026-05-15
|
|
885
|
+
|
|
886
|
+
- Remove private project names and personal paths from docs and CSS
|
|
887
|
+
comments (no code/selector/token changes). Supersedes 0.2.0, which
|
|
888
|
+
carried those references in shipped CSS comments.
|
|
889
|
+
|
|
890
|
+
## 0.2.0 — 2026-05-15
|
|
891
|
+
|
|
892
|
+
Architecture: keep plain CSS as the universal substrate, add thin optional
|
|
893
|
+
layers on top (see `docs/architecture.md`). No `css/*` selector/token values
|
|
894
|
+
changed — existing consumers are visually unaffected.
|
|
895
|
+
|
|
896
|
+
- **Cascade**: the whole framework now ships inside `@layer bronto`, so
|
|
897
|
+
un-layered consumer CSS overrides it without specificity fights. Applied
|
|
898
|
+
only at the bundle entrypoints (`core.css`, `index.css`); source files
|
|
899
|
+
unchanged. _Behavioural change for consumers that override via specificity._
|
|
900
|
+
- **Fonts**: `@font-face` moved from `tokens.css` to `css/fonts.css` with
|
|
901
|
+
package-relative URLs (`../fonts/*`) — no more absolute `/fonts`
|
|
902
|
+
assumption. Bundled into `core.css`/`index.css`; exported standalone.
|
|
903
|
+
- **`@ponchia/ui/tokens`**: design tokens as data (`index.js` canonical,
|
|
904
|
+
`index.json` generated, `themeColor()` helper, typed).
|
|
905
|
+
- **`@ponchia/ui/classes`**: typed class-name contract — `cls` registry,
|
|
906
|
+
`ui.*` recipe builders, `cx()`. Framework-agnostic, returns strings.
|
|
907
|
+
- **`@ponchia/ui/behaviors`**: vanilla, SSR-safe, dependency-free helpers —
|
|
908
|
+
`applyStoredTheme`, `initThemeToggle`, `dismissible`, `initDisclosure`.
|
|
909
|
+
- **Drift control**: `npm run check` adds `check-tokens` and
|
|
910
|
+
`check-classes`; the demo now drives itself via the shipped modules.
|
|
911
|
+
- **Packaging**: `exports` for the new entrypoints (with `types`),
|
|
912
|
+
`sideEffects` for tree-shaking, `files` widened.
|
|
913
|
+
- **Distribution decided**: published to npm as **`@ponchia/ui`** (the
|
|
914
|
+
`@bronto` scope isn't ownable; the `@layer bronto` / `data-bronto-*`
|
|
915
|
+
namespace is unchanged). `private` removed, `publishConfig`
|
|
916
|
+
(`access: public`, `provenance: true`), `repository`/`homepage`/`bugs`
|
|
917
|
+
added. `release.yml` now gates on a real `npm publish` job
|
|
918
|
+
(`validate` → `publish-npm`). Rationale + pre-publish blockers
|
|
919
|
+
(LICENSE, `NPM_TOKEN`, version bump) in `docs/architecture.md`.
|
|
920
|
+
|
|
921
|
+
## 0.1.0 — 2026-05-15
|
|
922
|
+
|
|
923
|
+
First standalone release. Extracted into its own standalone package.
|
|
924
|
+
|
|
925
|
+
- Re-skinned to a Nothing-inspired design language: monochrome dual
|
|
926
|
+
light/dark palette, single red accent, Doto dot-matrix display type, flat
|
|
927
|
+
hairline surfaces, sharp radii, no soft shadows.
|
|
928
|
+
- New `motion.css` — keyframes (migrated from the old responsive layer so
|
|
929
|
+
core-only consumers keep their animations) plus reveal / stagger /
|
|
930
|
+
skeleton / spinner / caret utilities and full reduced-motion handling.
|
|
931
|
+
- New `dots.css` — dot-grid surfaces, dotted rule, status dot (with live
|
|
932
|
+
pulse), dot loader, dot progress bar, matrix-reveal.
|
|
933
|
+
- New `forms.css` — input, select, textarea, search, switch, checkbox.
|
|
934
|
+
- New `table.css` — `ui-table` with dense / comfortable / lined variants and
|
|
935
|
+
numeric helpers for admin dashboards.
|
|
936
|
+
- Expanded `app.css` into a full admin shell: sidebar rail with dot nav,
|
|
937
|
+
sticky blurred topbar, toolbar, panel, metric tiles, empty state, mobile
|
|
938
|
+
rail collapse.
|
|
939
|
+
- Re-skinned primitives, navigation (dot active indicator), and the
|
|
940
|
+
semantic typography/eyebrows.
|
|
941
|
+
- Renamed `theme.css` → `tokens.css`; dropped the `components.css`
|
|
942
|
+
indirection; `core.css` now bundles the full set; `index.css` =
|
|
943
|
+
core + responsive. `package.json` exports updated accordingly.
|
|
944
|
+
- Doto fonts vendored into `fonts/` as the canonical home.
|
|
945
|
+
- Added `demo/index.html` kitchen sink.
|