@adia-ai/web-components 0.5.11 → 0.5.13
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 +2270 -0
- package/color/index.d.ts +137 -0
- package/color/index.js +305 -0
- package/components/color-input/class.js +221 -0
- package/components/color-input/color-input.a2ui.json +218 -0
- package/components/color-input/color-input.css +47 -0
- package/components/color-input/color-input.d.ts +87 -0
- package/components/color-input/color-input.js +26 -0
- package/components/color-input/color-input.yaml +188 -0
- package/components/index.js +1 -0
- package/components/stat/stat-ui.d.ts +38 -0
- package/components/swatch/class.js +28 -0
- package/components/swatch/swatch.a2ui.json +14 -2
- package/components/swatch/swatch.css +32 -0
- package/components/swatch/swatch.d.ts +13 -3
- package/components/swatch/swatch.yaml +35 -4
- package/package.json +17 -2
- package/styles/components.css +1 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,2270 @@
|
|
|
1
|
+
# Changelog — @adia-ai/web-components
|
|
2
|
+
|
|
3
|
+
Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
4
|
+
[Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
Scope: custom elements, core (`AdiaElement` + reactivity + templates),
|
|
7
|
+
trait system, style tokens, patterns (composite elements). The A2UI
|
|
8
|
+
runtime ships in the sibling `@adia-ai/a2ui-runtime` package
|
|
9
|
+
(renamed from `@adia-ai/a2ui-utils` in v0.3.0) as of `0.0.4`.
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
_No pending changes._
|
|
13
|
+
|
|
14
|
+
## [0.5.13] - 2026-05-15
|
|
15
|
+
|
|
16
|
+
### v0.5.13 §310 — `apcaContrast` soft-clamp constant fix (FEEDBACK-35; P2 correctness)
|
|
17
|
+
|
|
18
|
+
`@adia-ai/web-components/color`'s `apcaContrast()` was using `APCA_LO_CLAMP = 0.06` for the soft-clamp threshold where the canonical APCA spec (`apca-w3@0.1.9`'s `SAPC_BLACK_THRESHOLD`) calls for `0.022`. The cubic-root soft-clamp `Math.pow(threshold - Y, 1.414)` operating on the wrong threshold lifted near-black luminance too aggressively. Pre-fix `apcaContrast('#000','#fff')` returned 99.49; post-fix returns 106.04 — matches canonical reference within ±0.01 Lc across all 8 reference pairs. Consumers using `<swatch-ui auto-contrast>` (which transitively calls `pickContrastingFg → apcaContrast`) silently got wrong contrast verdicts for any swatch with `Y < 0.06`.
|
|
19
|
+
|
|
20
|
+
#### Fixed — `color/`
|
|
21
|
+
|
|
22
|
+
- `color/index.js` `apcaContrast()` soft-clamp now uses `APCA_LO_FG`/`APCA_LO_BG = 0.022` (declared correctly since v0.5.12 but never read). Dead constants (`APCA_NORM_L`, `APCA_REVERSE_FACTOR`, `APCA_NORM_FACTOR`, `APCA_LO_CLAMP`, `APCA_RESCALE`) removed; new `APCA_BLACK_CLAMP = 1.414` factored out for readability.
|
|
23
|
+
|
|
24
|
+
### v0.5.13 §311 — `@adia-ai/web-components/color` P3 helpers (FEEDBACK-31)
|
|
25
|
+
|
|
26
|
+
`@adia-ai/web-components/color` (v0.5.12 §301) shipped sRGB-only gamut helpers; the v0.6.0 §301 plan-doc spec lines 121-126 committed both sRGB AND Display-P3. v0.5.13 §311 closes the gap.
|
|
27
|
+
|
|
28
|
+
#### Added — `color/`
|
|
29
|
+
|
|
30
|
+
- `inP3Gamut(L, C, H): boolean` — returns true if the OKLCH triple is inside Display-P3 gamut (tolerance `0.001`).
|
|
31
|
+
- `gamutMapChromaP3(L, C, H): number` — 8-iteration chroma bisection in P3 (matches `gamutMapChroma`'s shape).
|
|
32
|
+
- Internal `linearSrgbToLinearP3()` matrix sourced from CSS Color 4 § 12.3 (D65 → D65; no Bradford chromatic adaptation needed).
|
|
33
|
+
- `color/index.d.ts` ships matching declarations.
|
|
34
|
+
|
|
35
|
+
### v0.5.13 §312 — `<stat-ui>` explicit exports map entries (FEEDBACK-32)
|
|
36
|
+
|
|
37
|
+
v0.5.12 §253a hand-authored `stat-ui.d.ts` on disk but the package.json wildcard `./components/*` expanded `./components/stat` → `./components/stat/stat.js` (non-existent; actual file is `stat-ui.js`). Consumer TS imports failed at the package-export layer with `TS2882` even though the file exists + Vite resolved at runtime.
|
|
38
|
+
|
|
39
|
+
#### Changed — `package.json`
|
|
40
|
+
|
|
41
|
+
- `exports` map adds 2 explicit entries: `./components/stat` + `./components/stat/stat-ui.js` both pointing at `stat-ui.{d.ts,js}`.
|
|
42
|
+
- **Drops at v0.6.0 §303** when the `git mv stat-ui.{js,css,d.ts} → stat.{js,css,d.ts}` rename normalizes the filename + the wildcard naturally covers `stat.{js,d.ts}`.
|
|
43
|
+
|
|
44
|
+
### v0.5.13 §313 — `<color-input-ui>` constraint pass-through + parsed-detail forwarding (FEEDBACK-33)
|
|
45
|
+
|
|
46
|
+
`<color-input-ui>` (v0.5.12 §302) composed `<color-picker-ui>` but dropped 5 generation-constraint props (`maxChroma` / `maxL` / `minL` / `hueDriftMax` / `baseHue`) and 3 parsed-OKLCH-channel-scalars (`{l, c, h}`) from the re-emitted event detail. Consumers using L-range constraints or OKLCH-native logic (Tokens Studio's `defaults.Lmin`/`Lmax`) couldn't migrate to `<color-input-ui>` without a UX regression.
|
|
47
|
+
|
|
48
|
+
#### Added — `components/color-input/`
|
|
49
|
+
|
|
50
|
+
- `class.js` adds 5 generation-constraint props to `static properties` + sets them on inner picker at `#mount()` + diff-detect re-set on `render()` (Object.is handles NaN-equality for `baseHue`/`hueDriftMax`).
|
|
51
|
+
- `#commit()` re-emits with all 6 detail fields including parsed scalars `l: detail.l, c: detail.c, h: detail.h`.
|
|
52
|
+
- `color-input.yaml` declares the 5 props + 3 new detail fields per `change`/`input` events.
|
|
53
|
+
- `color-input.d.ts` `ColorInputChangeEventDetail` interface gains `l: number; c: number; h: number;` fields; class gains 5 typed prop declarations.
|
|
54
|
+
|
|
55
|
+
### v0.5.13 §314 — `<swatch-ui>` `[slot="chrome"]` named slot (FEEDBACK-34)
|
|
56
|
+
|
|
57
|
+
`<swatch-ui>`'s `#stamp()` lifecycle wiped `innerHTML` then funneled surviving children into `#labelEl`. Consumer chrome positioned absolutely against the swatch tile (gamut badges + override/tracked dots per C1.3 dogfood) landed inside the label's text bbox where `position: absolute; top/right/bottom/left` anchored to the small label geometry instead of the tile. v0.5.13 §314 adds a `[slot="chrome"]` named slot whose children survive stamping as direct host siblings of `#tileEl`.
|
|
58
|
+
|
|
59
|
+
#### Added — `components/swatch/`
|
|
60
|
+
|
|
61
|
+
- `class.js` `#stamp()` extracts `[slot="chrome"]` children BEFORE the wipe; re-attaches them as direct host siblings IMMEDIATELY after `#tileEl`. The host's `position: relative` anchor (when `shape="block"`) lets consumer absolute-positioning anchor to the tile's geometry.
|
|
62
|
+
- `swatch.yaml` `slots:` block declares the `chrome` named slot + clarifies `default` slot's funnel-into-label behavior.
|
|
63
|
+
|
|
64
|
+
#### Migration
|
|
65
|
+
|
|
66
|
+
```diff
|
|
67
|
+
<swatch-ui shape="block" label-position="overlay" selectable>
|
|
68
|
+
- <badge-ui class="dts-gamut-badge" ...>P3</badge-ui>
|
|
69
|
+
- <span class="dts-override-dot"></span>
|
|
70
|
+
+ <badge-ui slot="chrome" class="dts-gamut-badge" ...>P3</badge-ui>
|
|
71
|
+
+ <span slot="chrome" class="dts-override-dot"></span>
|
|
72
|
+
</swatch-ui>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Single `slot="chrome"` attribute on each chrome element. Existing absolute-positioning CSS unchanged.
|
|
76
|
+
|
|
77
|
+
## [0.5.12] - 2026-05-15
|
|
78
|
+
|
|
79
|
+
### v0.5.12 §252 — `package.json` `files` array completion (FB-28 close-out)
|
|
80
|
+
|
|
81
|
+
Closes FB-28 (CHANGELOG.md tarball asymmetry). `packages/web-components/package.json` `files` array gains `README.md` + `CHANGELOG.md` entries (both files already existed at source; previously absent from publish whitelist). 4-cycle lag (v0.5.8 → v0.5.11) since the original FB-22 §1 P3 adjacent ask went silently un-responded in RESPONSE-22.
|
|
82
|
+
|
|
83
|
+
Sibling-package sweep verified — all 9 published packages (`@adia-ai/web-components` + `@adia-ai/web-modules` + 7 `a2ui-*` + `@adia-ai/llm`) now have symmetric `files` arrays containing `README.md` + `CHANGELOG.md`. No drift.
|
|
84
|
+
|
|
85
|
+
### v0.5.12 §253 — `stat-ui.d.ts` hand-author + slot 26 widening (FB-30 close-out)
|
|
86
|
+
|
|
87
|
+
Closes FB-30 (display-primitive .d.ts drift). Drift surface #1 (`.d.ts` axis) post-§253: 6 sub-axes mechanically protected, slot 26 now scoped for BOTH form-bearing AND display sub-axes. v0.5.10's "100% structural protection" milestone holds; v0.5.12 §253b extends slot 26 scope without changing the slot count.
|
|
88
|
+
|
|
89
|
+
#### Added — `components/stat/stat-ui.d.ts`
|
|
90
|
+
|
|
91
|
+
`packages/web-components/components/stat/stat-ui.d.ts` NEW hand-authored matching `stat.yaml` props (5: `label` / `value` / `change` / `trend` / `icon`). Filename mirrors `stat-ui.js` (not `stat.js`) for TS side-effect import resolution. Post-v0.6.0 §303 rename, files normalize to `stat.{js,d.ts}` + codegen takes over.
|
|
92
|
+
|
|
93
|
+
Root cause deeper than FB-30 framing: `dts-codegen.mjs:189` `isCssOnly()` looks for `${name}.js` — for `stat/`, that's `stat.js`, but the actual file is `stat-ui.js` (irregular filename). False-positives stat as CSS-only; codegen never writes `.d.ts`. v0.6.0 §303 rename fixes this; v0.5.12 §253a is the bridge.
|
|
94
|
+
|
|
95
|
+
#### Changed — `scripts/release/check-yaml-vs-dts-coverage.mjs` slot 26 widened
|
|
96
|
+
|
|
97
|
+
- `hasShippedJs(dir, comp)` — looks for `<comp>.js` OR `<comp>-ui.js` (handles irregular-filename case)
|
|
98
|
+
- `findDtsPath(dir, comp)` — looks for `<comp>.d.ts` OR `<comp>-ui.d.ts` (mirrors JS filename)
|
|
99
|
+
- NEW `CSS_ONLY_PRIMITIVES` exclusion set (`aside` / `footer` / `header` / `section`) — intentionally yaml-only stubs
|
|
100
|
+
- NEW finding kind: `missing-dts-file` (display-primitive sub-axis catch)
|
|
101
|
+
- Scope: FORM_BEARING-only → all primitives with shipped JS + yaml
|
|
102
|
+
|
|
103
|
+
Validated by smoke test: removing `stat-ui.d.ts` fires `missing-dts-file: stat`; restoring closes clean.
|
|
104
|
+
|
|
105
|
+
### v0.5.12 §301 — NEW `@adia-ai/web-components/color` subpath (FEEDBACK-29 re-bucket)
|
|
106
|
+
|
|
107
|
+
NEW subpath bundling OKLCH ↔ sRGB conversion, hex ↔ OKLCH, sRGB gamut-mapping, APCA contrast, and OKLab-distance helpers as pure functions. Consumer-side `src/lib/color-engine.ts` ~250 LOC of duplicated helpers can retire.
|
|
108
|
+
|
|
109
|
+
#### Added — `color/`
|
|
110
|
+
|
|
111
|
+
- `color/index.js` — `oklchToOklab`, `oklabToOklch`, `oklabToLinearSrgb`, `linearToSrgb`, `srgbToLinear`, `oklchToRgb`, `rgbToHex`, `oklchToHex`, `hexToOklch`, `isInGamut`, `isOklchInGamut`, `gamutMapChroma`, `apcaContrast`, `pickContrastingFg`, `oklchDistance`, plus `MAX_CHROMA` + `GAMUT_EPSILON` constants. Pure functions; no DOM / runtime side-effects.
|
|
112
|
+
- `color/index.d.ts` — full TS surface, `OKLab` + `OKLCH` interfaces, comprehensive JSDoc with APCA threshold guidance.
|
|
113
|
+
|
|
114
|
+
#### Changed — `package.json`
|
|
115
|
+
|
|
116
|
+
- `exports["./color"]` added pointing at `color/index.{js,d.ts}`.
|
|
117
|
+
- `files: ["color/", …]` added so the subpath ships in the tarball.
|
|
118
|
+
|
|
119
|
+
### v0.5.12 §302 — NEW `<color-input-ui>` compact form-bearing primitive (FEEDBACK-29 re-bucket)
|
|
120
|
+
|
|
121
|
+
Canonicalizes the USAGE.md §221f recipe (popover + button + color-picker) into a single form-associated tag for inline form contexts (settings drawer "source color" field, swatch-row inline-edit). Light-DOM composition; the inner picker fires `change` + `input` which the host re-emits with a flattened detail payload that always carries both hex + oklch string forms regardless of `[format]`.
|
|
122
|
+
|
|
123
|
+
#### Added — `components/color-input/`
|
|
124
|
+
|
|
125
|
+
- `color-input.yaml` — schema declares 6 props (`name`, `value`, `format`, `disabled`, `placement`, `open`) + 2 events with flattened parallel-views detail.
|
|
126
|
+
- `class.js` — `UIColorInput extends UIFormElement`. Builds its inner DOM (`<popover-ui>` + `<button-ui>` + `<color-picker-ui>`) as light-DOM children in `connected()`; wires picker → host event re-emission + popover `open` mirror via MutationObserver.
|
|
127
|
+
- `color-input.css` — compact swatch chip + tabular-num value label; honors `--color-input-swatch-size` token.
|
|
128
|
+
- `color-input.d.ts` — hand-authored (FORM_BEARING in dts-codegen); declares `ColorInputChangeEventDetail` with parallel `hex` + `oklch` views.
|
|
129
|
+
- `color-input.js` — auto-register shim.
|
|
130
|
+
- `color-input.a2ui.json` — codegen sidecar.
|
|
131
|
+
|
|
132
|
+
#### Changed
|
|
133
|
+
|
|
134
|
+
- `components/index.js` — re-exports `UIColorInput`.
|
|
135
|
+
- `styles/components.css` — `@import` for `color-input/color-input.css`.
|
|
136
|
+
- `scripts/build/dts-codegen.mjs` — `FORM_BEARING` set adds `color-input` so codegen preserves hand-authored event types.
|
|
137
|
+
- `scripts/release/check-enum-vs-css-selector.mjs` — parser now honors yaml `attribute:` overrides when matching CSS selectors (closes the swatch `labelPosition`/`label-position` false-positive class). Baselines added for color-input's behavioral enums (`format`, `placement`) which are JS-routed not CSS-routed; stale baselines for `heatmap:colorScheme:success/warning` + `page:maxWidth:*` (closed by the attribute-override fix) swept from the expected-findings set.
|
|
138
|
+
|
|
139
|
+
### v0.5.12 R23 §1 — `<swatch-ui label-position="overlay">` (FB-23 §1)
|
|
140
|
+
|
|
141
|
+
NEW enum value on `<swatch-ui>` — `[label-position]` (default `below`) accepts `overlay` to render the label inside the tile via absolute positioning. Pair with `[auto-contrast]` for OKLab-L-driven legibility. Unblocks Tokens Studio's C1.3 dogfood migration (blocked 3 cycles on this design call).
|
|
142
|
+
|
|
143
|
+
#### Added — `components/swatch/`
|
|
144
|
+
|
|
145
|
+
- `swatch.yaml` — `labelPosition` prop (kebab attribute `label-position`) with `below|overlay` enum.
|
|
146
|
+
- `swatch.css` — `:scope[shape="block"][label-position="overlay"]` rules positioning the label absolutely over the tile.
|
|
147
|
+
- `swatch/class.js` — static property declaration; reflected.
|
|
148
|
+
|
|
149
|
+
## [0.5.11] - 2026-05-15
|
|
150
|
+
|
|
151
|
+
### v0.5.11 §250 — `?attr=${bool}` silent-failure trap closed (FEEDBACK-27)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
Closes the fourth template-parser-contract trap in the R6-R27 series. v0.5.3 §155 closed HTML-comment quote-state edge cases; v0.5.3 §152 closed partial-attribute interpolation with a load-time `console.warn`. §250 graduates the Lit-style `?attr=${bool}` boolean-attribute shape to the same warn + degrade contract.
|
|
155
|
+
|
|
156
|
+
#### Fixed — §250a (v0.5.11) — `core/template.js` `scan()` rejects `?`-prefixed attribute names with a console.warn
|
|
157
|
+
|
|
158
|
+
`packages/web-components/core/template.js` — `scan()` attribute-walk adds a 4th branch alongside `@event=` / `.prop=` / canonical `attr=`. When `name[0] === '?'`:
|
|
159
|
+
|
|
160
|
+
1. Strip the bogus `?attr` attribute from the DOM (prevents the literal `?disabled="true"` poison-pill that consumers saw pre-§250).
|
|
161
|
+
2. Fire `console.warn` naming the offending attribute + the corrected migration path (`use .${prop}=${'${value}'}` — property binding).
|
|
162
|
+
3. Degrade the part slot to a no-op text-node binding (`parts[i] = { t: 'n', n: document.createTextNode(''), ... }`) so the failure mode is "no attribute, with a warn" rather than "inert attribute, no warn".
|
|
163
|
+
|
|
164
|
+
Pre-§250 (silent inert binding):
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
// Pre-§250 — silently registered `?disabled="true"` on the DOM; consumer's
|
|
168
|
+
// `<color-picker-ui>` ignored it; picker stayed interactive.
|
|
169
|
+
html`<color-picker-ui ?disabled=${isTracked}>`;
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Post-§250 (warn + safe-degrade):
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
console.warn: [template] Lit-style boolean attribute "?disabled=" is not supported.
|
|
176
|
+
Element: <color-picker-ui>
|
|
177
|
+
Use .disabled=${value} (property binding) instead — the primitive reflects
|
|
178
|
+
the property to the DOM attribute for you.
|
|
179
|
+
See USAGE.md § Template parser — invariants + unsupported syntaxes.
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Why NOT actually implement Lit's `?attr=` semantics: AdiaUI primitives declare reflective property/attribute mapping via `static properties = { disabled: { type: Boolean, reflect: true } }`. The runtime handles property-to-attribute reflection automatically. Adding `?attr=` would create two valid syntaxes for the same effect — discoverability tax with no behavioral benefit.
|
|
183
|
+
|
|
184
|
+
7 new vitest cases in `packages/web-components/core/template.test.js` lock in the §250 contract:
|
|
185
|
+
|
|
186
|
+
- `?attr=` fires warn (truthy + falsy)
|
|
187
|
+
- Does NOT register literal `?attr` attribute on the DOM
|
|
188
|
+
- Does NOT set the matching attribute either (no Lit-attr semantics)
|
|
189
|
+
- No false positives on canonical `attr=` / `.prop=` / `@event=`
|
|
190
|
+
|
|
191
|
+
#### Changed — §250b (v0.5.11) — USAGE.md adds "Template parser — invariants + unsupported syntaxes" section
|
|
192
|
+
|
|
193
|
+
`packages/web-components/USAGE.md` § Template parser — NEW section enumerates all 4 documented parser contracts:
|
|
194
|
+
|
|
195
|
+
| Syntax | Status | Migration |
|
|
196
|
+
|---|---|---|
|
|
197
|
+
| `attr=${val}` (full interpolation) | ✅ Supported | n/a |
|
|
198
|
+
| `.prop=${val}` (property binding) | ✅ Supported | canonical for boolean state |
|
|
199
|
+
| `@event=${handler}` (event listener) | ✅ Supported | n/a |
|
|
200
|
+
| `?attr=${bool}` (Lit-style boolean) | ❌ NOT supported — `console.warn` v0.5.11 §250 | Use `.attr=${bool}` |
|
|
201
|
+
|
|
202
|
+
Also enumerates the 3 historical parser-bug fixes (apostrophes in HTML comments + quoted attributes in HTML comments + backticks-in-comments) so the parser's tacit contract is now a fully-enumerated invariants list.
|
|
203
|
+
|
|
204
|
+
Pattern matures: every documented-but-easy-to-miss template-parser failure now emits a `console.warn` at scan time. Consumer onboarding from Lit / native lit-html no longer hits the silent-failure class.
|
|
205
|
+
|
|
206
|
+
## [0.5.10] - 2026-05-15
|
|
207
|
+
|
|
208
|
+
### v0.5.10 §248 — `check-static-methods-vs-dts.mjs` slot 20 base-class spread-walk extension (FB-25 audit-extension)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
Closes the FB-25 base-class blindspot mechanically. The audit grows a 5th declaration-axis on the `.d.ts` surface:
|
|
212
|
+
|
|
213
|
+
- For each registered base class (currently `{ UIFormElement }`), walk its `static get properties()` return-object body + cross-reference against base `.d.ts` instance-field declarations.
|
|
214
|
+
- New finding kind: `base-property-undeclared`. Hard-fails strict mode when a base class's runtime property set has no matching field declaration in the base's `.d.ts`.
|
|
215
|
+
|
|
216
|
+
Closes the recurrence path for FB-25: any future addition to `UIFormElement.properties` without a matching `core/form.d.ts` field declaration fails the audit at release time. Subclasses using `...UIFormElement.properties` inherit the property at runtime; without the base-class `.d.ts` declaration, consumers using TS `extends` get TS2339 on `el.<prop> = ...`.
|
|
217
|
+
|
|
218
|
+
Caveat in the audit: the base's `.d.ts` typically declares the metadata-type shape `static properties: { ... };` whose keys overlap the instance-field names. The audit strips the `static properties: { ... };` braced block before scanning for `DTS_FIELD` matches to avoid false-positive coverage.
|
|
219
|
+
|
|
220
|
+
Validated by deliberate-removal test: removing `throttle: number;` from `core/form.d.ts` fires `base-property-undeclared: throttle`; restoring closes clean.
|
|
221
|
+
|
|
222
|
+
### v0.5.10 §249 (slot 26 NEW) — `check-yaml-vs-dts-coverage.mjs` (FB-26 audit-extension)
|
|
223
|
+
|
|
224
|
+
NEW audit slot 26. Closes the FB-26 hand-authored `.d.ts` drift class mechanically. Walks every form-bearing primitive (`FORM_BEARING` set per `dts-codegen.mjs` — 17 primitives that skip codegen because they hand-author their `.d.ts` for rich event-detail typing) and verifies yaml `props:` reflection:
|
|
225
|
+
|
|
226
|
+
- For each form-bearing primitive: parse `<name>.yaml` `props:` block → set of declared prop names
|
|
227
|
+
- Parse `<name>.d.ts` class body → set of instance-field declarations (including getters)
|
|
228
|
+
- Subtract `UIFormElement`-inherited fields (via `core/form.d.ts` walk; 16 fields including the §247d `throttle` addition)
|
|
229
|
+
- Set-diff yaml-only → flag as `yaml-vs-dts-missing` (hard finding)
|
|
230
|
+
|
|
231
|
+
Slot 26's purpose is parallel to slot 19's: slot 19 catches yaml → class.js drift (schema vs implementation); slot 26 catches yaml → hand-authored .d.ts drift (schema vs typed-API surface). Together they bound the "yaml is the SoT, but the SoT can drift from the type" gap that v0.5.9 §220 + v0.5.6 §192 surfaced from different directions.
|
|
232
|
+
|
|
233
|
+
`EXPECTED_FINDINGS = new Set([])` — post-§247 closures, the audit runs clean across all 17 form-bearing primitives. Any subsequent yaml-prop addition without the matching `.d.ts` hand-author fires strict-mode hard-fail.
|
|
234
|
+
|
|
235
|
+
Validated by deliberate-removal test: removing `inputmode: string;` from `input.d.ts` fires `yaml-vs-dts-missing: input:inputmode`; restoring closes clean.
|
|
236
|
+
|
|
237
|
+
### v0.5.10 §247 — post-v0.5.9 `.d.ts` drift close-out (FB-23 / FB-24 / FB-25 / FB-26)
|
|
238
|
+
|
|
239
|
+
Six items address consumer-reported drift between v0.5.9 runtime + yaml + `.d.ts` overlay. All PATCH-class additive (no breaking changes; types narrow what was previously `any` or undeclared). Single commit lands all six.
|
|
240
|
+
|
|
241
|
+
#### Added — §247 `HAND_AUTHORED_DTS` skip-list extension (`text` + `feed`)
|
|
242
|
+
|
|
243
|
+
`scripts/build/dts-codegen.mjs` `HAND_AUTHORED_DTS` set grows `{ 'toast' }` → `{ 'toast', 'text', 'feed' }`. Pattern source: v0.5.9 §246. Two new entries:
|
|
244
|
+
|
|
245
|
+
- **`text`** — preserves per-`UITextVariant`-member JSDoc that the yaml `enum:` schema can't carry (one description per enum value, not just the property). Closes FB-23 §3 (§221k Part A — the JSDoc-per-variant deferred mid-cycle in v0.5.9).
|
|
246
|
+
- **`feed`** — preserves the `UIFeed` static-API class + `UIFeedPostOptions` + `FeedHandle` interfaces that the v0.5.9 §228 sibling-yaml walk can't generate (UIFeed has no tag-registered yaml). Closes FB-24 §1.
|
|
247
|
+
|
|
248
|
+
#### Fixed — §247 `text.d.ts` per-variant JSDoc + ARIA-role disclaimer (FB-23 §2 + §3)
|
|
249
|
+
|
|
250
|
+
`packages/web-components/components/text/text.d.ts` hand-authored. Two surfaces:
|
|
251
|
+
|
|
252
|
+
1. **`UITextVariant` named type** with per-member JSDoc (12 variants × 1-line description). IDE hover on `<text-ui variant="?">` surfaces the picker heuristic inline; complements the §221k chooser guide in USAGE.md (which only the consumer who reads docs sees).
|
|
253
|
+
2. **Property-level JSDoc** on `variant: UITextVariant` carries the **presentational-only** disclaimer: `<text-ui variant="heading">` does NOT set `role="heading"` + `aria-level`. For semantic headings, wrap with native `<h1>`-`<h6>` OR add `role` + `aria-level` to the host. Closes the FB-23 §2 ARIA-role discoverability gap; the actual API addition (`level=` / `as=`) is deferred to v0.6.0.
|
|
254
|
+
|
|
255
|
+
#### Fixed — §247 `feed.d.ts` UIFeed static-API surface (FB-24 §1)
|
|
256
|
+
|
|
257
|
+
`packages/web-components/components/feed/feed.d.ts` hand-authored. Adds:
|
|
258
|
+
|
|
259
|
+
- `UIFeed` class with `static get(position?)` / `static post(opts)` / `static clear(position?)` / `static purge()` / `static releaseContainerIfEmpty(container)` — the imperative one-shot API consumers use without instantiating `<feed-ui>` declaratively.
|
|
260
|
+
- `UIFeedPostOptions` interface mirroring `UIFeedItem`'s reflected props + `position` + the phase-2 `action?` field.
|
|
261
|
+
- `FeedHandle` interface (id + dismiss + update) — the return type of `UIFeed.post()`. Parallels `UIToastFeedHandle` from `toast.d.ts` (post-v0.5.6 §197 + v0.5.9 §246).
|
|
262
|
+
- `FeedPosition` named type for the 7 lane anchors (6 corners + inline).
|
|
263
|
+
|
|
264
|
+
#### Fixed — §247 `core/form.d.ts` adds `throttle: number` (FB-25 §1)
|
|
265
|
+
|
|
266
|
+
`packages/web-components/core/form.d.ts` adds `throttle: number` field declaration + 3 method signatures (`scheduleThrottledInput` + `flushPendingInput` + `dropPendingInput`) on `UIFormElement`. Closes FB-25's drift: v0.5.9 §220 added `throttle` to the runtime base class's `static get properties()` but never propagated the type declaration. All 17 form-bearing primitives (input / select / slider / range / textarea / switch / check / radio / segmented / search / otp-input / option-card / color-picker / rating / code / calendar-picker / upload) inherit the field via TS `extends`. Single 1-LOC fix covers all 17 instead of 17 per-component edits.
|
|
267
|
+
|
|
268
|
+
**Pre-existing slider.d.ts `throttle: number;` declaration** becomes redundant (now inherited). Cleanup deferred to v0.6.0 hand-author de-dup pass; no functional impact.
|
|
269
|
+
|
|
270
|
+
#### Fixed — §247 5 missing prop declarations on form-bearing `.d.ts` (FB-26 §1)
|
|
271
|
+
|
|
272
|
+
Per FB-26's wider-scope audit beyond FB-25's `throttle`-only scope:
|
|
273
|
+
|
|
274
|
+
- `input.d.ts` adds `inputmode: string` + `autocomplete: string` (HTML5 attribute forwards to contenteditable surface)
|
|
275
|
+
- `select.d.ts` adds `variant: 'default' | 'outline' | 'ghost' | 'soft'` + `size: 'xs' | 'sm' | 'md' | 'lg' | 'xl'` (universal `[size]` family + variant chrome)
|
|
276
|
+
- `rating.d.ts` adds `variant: 'star' | 'heart' | 'thumbs'` (icon-set treatment)
|
|
277
|
+
|
|
278
|
+
5 props × ~3 LOC each. All yaml-declared + runtime-functional pre-v0.5.10; only TS type surface was missing.
|
|
279
|
+
|
|
280
|
+
#### Changed — §247 USAGE.md adds two clarification sections (FB-23 §1 + §2)
|
|
281
|
+
|
|
282
|
+
`packages/web-components/USAGE.md` grows two notes inside the v0.5.9 §221 sweep section:
|
|
283
|
+
|
|
284
|
+
1. **`<text-ui>` ARIA-role clarification** — three authoring patterns (native `<hN>` wrap / ARIA-only on host / presentational-only) with the picker heuristic. Cross-references the `text.d.ts` property-level disclaimer.
|
|
285
|
+
2. **`<swatch-ui shape="block">` label-position** — confirms label renders BELOW the tile (flex-column); label-on-tile use case (Tokens Studio C1.3 pattern) is NOT supported in v0.5.x; the auto-contrast classes (`data-on-light` / `data-on-dark`) are designed for a future overlay mode. v0.6.0 candidate: `<swatch-ui label-position="overlay">` (or `shape="block-overlay"`, or sibling `<swatch-tile-ui>` slot composition).
|
|
286
|
+
|
|
287
|
+
### v0.6.0 candidates surfaced by FB-23/24/25/26
|
|
288
|
+
|
|
289
|
+
- Codegen yaml-schema extension to carry per-`enum:`-member descriptions (retires `text.d.ts` from `HAND_AUTHORED_DTS`)
|
|
290
|
+
- Audit slot 20 spread-walk: when encountering `...Base.properties` in a static-properties literal, recursively walk the base's keys (closes the FB-25 base-class blindspot mechanically)
|
|
291
|
+
- NEW audit slot 26 `check-yaml-vs-dts-coverage.mjs` for form-bearing primitives (closes the FB-26 hand-authored `.d.ts` drift class mechanically)
|
|
292
|
+
- Audit-extension to walk all `export class` (not just `extends UIElement`) — closes the FB-24 ambient static-API class drift
|
|
293
|
+
- `<text-ui level="N">` or `<text-ui as="hN">` semantic-heading attribute (API design call — closes FB-23 §2 with runtime ARIA-role setting, not just docs)
|
|
294
|
+
- `<swatch-ui label-position="overlay">` (or equivalent) — API for label-on-tile use case (FB-23 §1 feature)
|
|
295
|
+
|
|
296
|
+
## [0.5.9] - 2026-05-15
|
|
297
|
+
|
|
298
|
+
### Added — §246 (v0.5.9) — `dts-codegen.mjs` `HAND_AUTHORED_DTS` skip-list + restore `toast.d.ts` static-method surface
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
Post-§228 codegen regenerated all `.d.ts` files including `toast.d.ts`, which lost its `static show(opts): UIToastFeedHandle` declaration (yaml's `props:`/`events:` shape can't express imperative static methods). The runtime API was missing from the TS surface.
|
|
302
|
+
|
|
303
|
+
Fix:
|
|
304
|
+
|
|
305
|
+
- `scripts/build/dts-codegen.mjs` — new `HAND_AUTHORED_DTS = new Set(['toast'])` checked in `generateForComponent()` before regen; status returns `'skip-hand-authored'`. Pattern matches the existing `FORM_BEARING` skip mechanism.
|
|
306
|
+
- `packages/web-components/components/toast/toast.d.ts` — restored full hand-authored shape: `UIToastShowOptions` interface + `UIToastFeedHandle` interface + `static show(opts?): UIToastFeedHandle` declaration. Header doc flags HAND-AUTHORED status + references §246 + cross-links the skip list.
|
|
307
|
+
|
|
308
|
+
Verified: `node scripts/build/components.mjs` runs codegen with `--force` flag; toast.d.ts is preserved across builds.
|
|
309
|
+
|
|
310
|
+
v0.6.0 follow-up candidate: yaml `methods:` schema + codegen support for static-method emission would retire this skip-list entry by making toast's surface fully codegen'd. Filed mentally; not yet on plan-doc.
|
|
311
|
+
|
|
312
|
+
### Added — §246 (v0.5.9) — regression tests for §220 throttle + §223 empty-state minimal
|
|
313
|
+
|
|
314
|
+
`packages/web-components/components/input/input.test.js` — 5 new tests for the §220 throttle wiring on `<input-ui>`: inheritance from UIFormElement, attribute reflection, synchronous dispatch when throttle=0, trailing-debounce when throttle>0, flushPendingInput() + dropPendingInput() semantics. Passes 13/13.
|
|
315
|
+
|
|
316
|
+
`packages/web-components/components/empty-state/empty-state.test.js` — NEW test file (component had no tests). 6 tests for the §223 minimal mode: default non-minimal state, `[minimal]` attribute reflection, icon-size opt-out (no `size="lg"` when minimal), no-regression for canvas-style stamping, heading + description slots in both modes, consumer-provided `[slot="action"]` preserved. Passes 6/6.
|
|
317
|
+
|
|
318
|
+
Authoring pitfall captured in the input.test.js diff: when testing trailing-debounce, surface-event bubbling pollutes host-event count — `<input-ui>` listens for native `InputEvent` on its contenteditable surface, which bubbles to the host alongside the host's own repackaged `CustomEvent('input', {detail:{value}})`. Filter assertions by `e.detail?.value !== undefined` to count only host-emitted events. Generalizes to any primitive testing repackaged-event semantics.
|
|
319
|
+
|
|
320
|
+
### Fixed — §230-bundle wave 2 (v0.5.9) — close remaining 9 of 16 baselined orphan-token references
|
|
321
|
+
|
|
322
|
+
The remaining 9 architect-decision entries in `check-component-css-vs-styles-tokens.mjs` (audit slot 25, shipped v0.5.8 §231) resolved. After this commit, the baseline shrinks 9 → 0; `EXPECTED_FINDINGS = new Set([])`. All 16 v0.5.8 orphans closed across the two waves:
|
|
323
|
+
|
|
324
|
+
**Wave 2 architect decisions:**
|
|
325
|
+
|
|
326
|
+
- **NEW token** `--a-radius-xs` (parametric: `--a-radius-xs-k: 0.166`) in `styles/tokens.css`. Resolves heatmap + swatch callsites.
|
|
327
|
+
- **NEW tokens** `--a-chrome-fg` (= `--a-chrome-light` — white text) + `--a-chrome-bg` (= `oklch(0 0 0 / 0.4)` — dark scrim) in `styles/colors/semantics.css`. Canonical badge-on-chrome family. Resolves swatch badge callsites; documents the pattern for video-controls / color-readout / overlay use cases.
|
|
328
|
+
- **NEW token** `--a-ui-line-height` (= `var(--a-body-leading)` = 1.5) in `styles/typography.css`. Resolves alert callsite.
|
|
329
|
+
- `components/nav/nav.css` `var(--a-duration-base, 200ms)` → `var(--a-duration)` (canonical mid-tier, 250ms).
|
|
330
|
+
- `components/code/code.css` `var(--a-surface-floating)` → `var(--a-bg-strong)` (elevated panel surface).
|
|
331
|
+
- `components/feed/feed.css` `var(--a-feed-max-width, 22rem)` → component-local literal `22rem`. Hoisted per RESPONSE-21 guidance.
|
|
332
|
+
- `components/swatch/swatch.css` `var(--a-bg-2)` → `var(--a-bg-muted)` (canonical canvas-2 alias).
|
|
333
|
+
|
|
334
|
+
Closes drift surface #7 (token-reference vs definition) fully. `check-component-css-vs-styles-tokens --strict` exits 0 with zero baseline entries.
|
|
335
|
+
|
|
336
|
+
### Fixed — §230-bundle wave 1 (v0.5.9) — close 7 of 16 baselined orphan-token references + new `--a-ui-xs: 12px`
|
|
337
|
+
|
|
338
|
+
Wave 1 (kimba prep batch at `73d06956c`):
|
|
339
|
+
|
|
340
|
+
- **NEW token** `--a-ui-xs: 12px` defined in `styles/typography.css` (one notch below `--a-ui-sm: 13px`).
|
|
341
|
+
- `components/tooltip/tooltip.css` (×2) — `var(--a-weight-regular)` → `var(--a-weight-normal)`.
|
|
342
|
+
- `components/range/range.css` — `var(--a-ui-fg)` → `var(--a-fg)`.
|
|
343
|
+
- `components/{select,slider,switch,tree}/*.css` (×4) — `var(--a-fine-size)` fallback → `var(--a-ui-xs)`.
|
|
344
|
+
- `components/swatch/swatch.css` `--a-ui-xs` references (×2) now resolve cleanly via the new definition.
|
|
345
|
+
|
|
346
|
+
### Added — §232 (v0.5.9) — NEW audit slot 24 `check-enum-vs-css-selector.mjs` (drift surface #6 closed)
|
|
347
|
+
|
|
348
|
+
`scripts/release/check-enum-vs-css-selector.mjs` (~330 LOC). Walks each `<name>.yaml` for `enum:` blocks, cross-references against `:scope[<prop>="<value>"]` selectors in the component's `.css`. Flags enum values declared in yaml but with no matching CSS rule — silent fall-through to default variant (FEEDBACK-17 §1 bug class).
|
|
349
|
+
|
|
350
|
+
Baseline: 119 findings across multiple components (chart type / popover placement / tooltip placement etc. — many JS-routed via Floating UI or chart libraries, false-positive for CSS-cascade routing). Strict mode hard-fails on NEW drift beyond baseline; architect-triage cycle-by-cycle as primitives migrate to true CSS-cascade routing.
|
|
351
|
+
|
|
352
|
+
Closes the 6th drift surface in the 7-surface lockdown taxonomy.
|
|
353
|
+
|
|
354
|
+
### Added — §222 (v0.5.9) — NEW audit slot 21 `check-connected-reads-attr.mjs` (drift surface #5 closed)
|
|
355
|
+
|
|
356
|
+
`scripts/release/check-connected-reads-attr.mjs` (~300 LOC). Walks each `class.js` for `connected()` / `connectedCallback()` bodies that synchronously read a declared `static properties.X` value, without an `attributeChangedCallback` to re-sync when the attribute applies after connection.
|
|
357
|
+
|
|
358
|
+
Bug class: FEEDBACK-10 §1 `<toggle-scheme-ui scheme="${reactiveValue}">` race — `#initState()` reads `this.scheme` before the framework's attribute-application phase, so declarative-rebinds lose to AUTO fallbacks. v0.5.7 §200 closed for `<toggle-scheme-ui>` specifically; §222 catches the next instance mechanically.
|
|
359
|
+
|
|
360
|
+
Baseline: 67 findings across components. Heuristic intentionally narrow (one-hop method chase, narrow gate), but accepts false positives are expected on first ship. Architect-triage cycle-by-cycle. Strict mode hard-fails on NEW drift beyond baseline.
|
|
361
|
+
|
|
362
|
+
Closes the 5th drift surface in the 7-surface lockdown taxonomy.
|
|
363
|
+
|
|
364
|
+
### Added — §220 (v0.5.9) — `throttle` parity on form-bearing primitives via shared `UIFormElement` helper
|
|
365
|
+
|
|
366
|
+
`packages/web-components/core/form.js` graduates the v0.5.5 §184 slider trailing-debounce pattern to the shared `UIFormElement` base class:
|
|
367
|
+
|
|
368
|
+
- `throttle` static property (default 0) — declarative ms window for the `input` event
|
|
369
|
+
- `scheduleThrottledInput()` — call from input-event sites; trailing-debounces dispatch when `throttle > 0`
|
|
370
|
+
- `flushPendingInput()` — call from change / blur / commit paths; ensures trailing `input` fires before `change`
|
|
371
|
+
- `dropPendingInput()` — called automatically by `disconnected()` to prevent late dispatches
|
|
372
|
+
|
|
373
|
+
Callsite migrations:
|
|
374
|
+
|
|
375
|
+
- `components/slider/class.js` — drops local `#inputTimer` + `#flushInput()`; delegates via the shared helpers (semantics preserved)
|
|
376
|
+
- `components/input/class.js` `#onInput` — now calls `scheduleThrottledInput()` (was unconditional dispatch)
|
|
377
|
+
- `components/textarea/class.js` `#onInput` — same migration; `#onBlur` + `#onKeydown` call `flushPendingInput()` before commit
|
|
378
|
+
|
|
379
|
+
`input.yaml` + `textarea.yaml` document the new `throttle` prop. Use for expensive `input`-driven computation (server-side autocomplete, large list filter, palette regen) where consumers want trailing-debounce semantics without authoring their own timer.
|
|
380
|
+
|
|
381
|
+
Closes FEEDBACK-14 §3.
|
|
382
|
+
|
|
383
|
+
### Added — §223 (v0.5.9) — `<empty-state-ui minimal>` single-line muted layout
|
|
384
|
+
|
|
385
|
+
`empty-state.yaml` + `class.js` + `empty-state.css` — new `minimal: boolean` prop drops the centered-column placeholder chrome (no canvas-style padding, no icon-size lg, no max-width on description). Renders as `[icon] heading [description]` inline in muted-fg, with `[slot="action"]` margin-collapsed to trailing edge. Use for inline empty-table-row / empty-list / placeholder cells where the canvas placeholder is too loud.
|
|
386
|
+
|
|
387
|
+
Closes FEEDBACK-13 §4.
|
|
388
|
+
|
|
389
|
+
### Added — §228 (v0.5.9) — `dts-codegen.mjs` sibling-yaml walk + 5 NEW sibling yamls + 2 parent yaml `name:` fixes
|
|
390
|
+
|
|
391
|
+
`scripts/build/dts-codegen.mjs` (~40 LOC change) — walks ALL `*.a2ui.json` sidecars in each component dir + emits ONE `<dir>.d.ts` with one `export class UI<Name>` declaration per sidecar. Uses `x-adiaui.name` (canonical class name) instead of `UI${title}` (fragile — yaml `name:` and `component:` can drift, e.g. `feed.yaml` `name: UIFeedContainer` + `component: Feed` → old codegen wrote `UIFeed` extending `UIElement` which is wrong since `UIFeed` is the imperative host class, not a custom element).
|
|
392
|
+
|
|
393
|
+
5 NEW sibling yamls authored:
|
|
394
|
+
|
|
395
|
+
- `feed/feed-container.yaml` (later retired in favor of `feed.yaml` canonical-class) — actually `feed-container` redundant since `feed.yaml` already declares `UIFeedContainer`
|
|
396
|
+
- `menu/menu-item.yaml` (`UIMenuItem`)
|
|
397
|
+
- `menu/menu-divider.yaml` (`UIMenuDivider`)
|
|
398
|
+
- `stepper/stepper-item.yaml` (`UIStepperItem`)
|
|
399
|
+
- `toggle-group/toggle-option.yaml` (`UIToggleOption`)
|
|
400
|
+
- `toolbar/toolbar-group.yaml` (`UIToolbarGroup`)
|
|
401
|
+
|
|
402
|
+
2 parent yaml `name:` fixes (yaml was wrong; class.js was right):
|
|
403
|
+
|
|
404
|
+
- `col/col.yaml`: `name: UIColumn` → `UICol` (class.js exports `UICol`)
|
|
405
|
+
- `richtext/richtext.yaml`: `name: UIRichtext` → `UIRichText` (class.js exports `UIRichText`)
|
|
406
|
+
|
|
407
|
+
`index.d.ts` tag-map: `UIColumn` → `UICol` (`col-ui`) + `UIRichtext` → `UIRichText` (`richtext-ui`).
|
|
408
|
+
|
|
409
|
+
13 component `.d.ts` files regenerated by codegen with both parent + sibling classes declared cleanly. After this commit + §229 baseline shrink, `check-static-methods-vs-dts --strict` runs clean across all 4 sub-axes.
|
|
410
|
+
|
|
411
|
+
Closes FEEDBACK-18 §2 (child-class drift) and the 8 audit-driven additions on top of the 7-instance enumeration.
|
|
412
|
+
|
|
413
|
+
### Fixed — §229 (v0.5.9) — class-export walk baseline shrinks 15 → 0
|
|
414
|
+
|
|
415
|
+
`scripts/release/check-static-methods-vs-dts.mjs` `EXPECTED_CLASS_EXPORT_FINDINGS` shrunk to empty Set after §228 codegen ships. All 15 sibling-class drift entries close mechanically.
|
|
416
|
+
|
|
417
|
+
Drift surface #1 (`.d.ts` axis) now fully strict-mode-protected across all 4 sub-axes (method + event + property + class-export).
|
|
418
|
+
|
|
419
|
+
### Added — §227 (v0.5.9) — `check-styles-barrel-completeness.mjs` `--package=web-modules` flag
|
|
420
|
+
|
|
421
|
+
`scripts/release/check-styles-barrel-completeness.mjs` — `runWebModulesAudit()` walks all 6 web-modules clusters (shell / chat / editor / simple / runtime / theme) and verifies each `*.css` file is reachable via one of the three `package.json` export-map patterns (`./<cluster>/*.css`, `./<cluster>/*/*.css`, `./<cluster>/*/css/*.css`).
|
|
422
|
+
|
|
423
|
+
Companion audit to §226 (v0.5.9 prep batch's web-modules `package.json` exports map fix). Together they close the second half of drift surface #3 (CSS-barrel — web-modules side).
|
|
424
|
+
|
|
425
|
+
### Added — §225 (v0.5.9) — `<select-ui>` `#parseOptions()` once-per-element console.warn
|
|
426
|
+
|
|
427
|
+
`packages/web-components/components/select/class.js` — class-level `static #warnedNonOption = new WeakSet()` + `#parseOptions()` collects unknown-child tags + emits a single `console.warn` per element when consumer-authored children aren't native `<option>`/`<optgroup>`. Pattern mirrors v0.5.5 §184 §8 + v0.5.7 §201. `select.yaml` gains `usage:` block documenting native `<option>` children + programmatic `.options = [...]` paths. Closes FEEDBACK-10 §3.
|
|
428
|
+
|
|
429
|
+
### Added — §224 (v0.5.9) — `<feed-ui>` `data-spawned-by="toast"` marker on toast-spawned containers
|
|
430
|
+
|
|
431
|
+
`packages/web-components/components/toast/class.js` — `UIToast.show()` stamps `data-spawned-by="toast"` on the spawned `<feed-ui>` container at creation. Idempotent (once per container). Lets DOM-query consumers distinguish toast-spawned containers from user-authored ones. `toast.yaml` gains `usage:` block documenting the marker + query example. Closes FEEDBACK-10 §2.
|
|
432
|
+
|
|
433
|
+
### Changed — §221a-k (v0.5.9) — 11-item docs sweep
|
|
434
|
+
|
|
435
|
+
`packages/web-components/USAGE.md` grows a new section "v0.5.9 — Consumer-feedback discoverability sweep" (~218 lines) covering 11 items surfaced across consumer-feedback rounds R9, R10, R13, R15, R16, R20:
|
|
436
|
+
|
|
437
|
+
- **§221a** Universal `[size]` prop family — token wiring + size-cascade authoring patterns
|
|
438
|
+
- **§221b** `<input-ui>` migration guide from native `<input>` — common gotchas + payload-shape table
|
|
439
|
+
- **§221c** `<switch-ui>` vs `<check-ui>` vs `<segmented-ui>` — the "named binary state" trap
|
|
440
|
+
- **§221d** `<select-ui>` native `<option>` children — declarative + programmatic paths
|
|
441
|
+
- **§221e** `<accordion-item-ui>` action buttons in custom headers — `[slot="action"]` exclusion list
|
|
442
|
+
- **§221f** `<color-picker-ui>` `<popover-ui trigger=click>` inline pattern
|
|
443
|
+
- **§221g** `[data-scheme]` ancestor opt-in for color scheme — patterns + edge cases
|
|
444
|
+
- **§221h** Effect-dispatch timing — `queueMicrotask` batching + the double-microtask test-flush idiom (also added to `signals.d.ts` JSDoc on `effect()`)
|
|
445
|
+
- **§221i** Backticks inside HTML comments inside `html\`…\`` templates — JS-spec footgun
|
|
446
|
+
- **§221j** Typography token cheatsheet — L0/L1 token families + common misreads (`--a-font-semibold` doesn't exist; use `--a-weight-semibold`)
|
|
447
|
+
- **§221k** `<text-ui variant>` chooser guide — 12 canonical variants with picker heuristics
|
|
448
|
+
|
|
449
|
+
`packages/web-components/core/signals.d.ts` — JSDoc on `effect()` documents the queueMicrotask batching semantics + the double-microtask test-flush idiom (the canonical fix for "my effect didn't run yet" in tests).
|
|
450
|
+
|
|
451
|
+
### Added — §225 (v0.5.9) — `<select-ui>` `#parseOptions()` once-per-element console.warn
|
|
452
|
+
|
|
453
|
+
`packages/web-components/components/select/class.js` — class-level `static #warnedNonOption = new WeakSet()` + `#parseOptions()` collects unknown-child tags + emits a single `console.warn` per element when consumer-authored children aren't native `<option>`/`<optgroup>`. Pattern mirrors v0.5.5 §184 §8 + v0.5.7 §201. `select.yaml` gains `usage:` block documenting native `<option>` children + programmatic `.options = [...]` paths. Closes FEEDBACK-10 §3.
|
|
454
|
+
|
|
455
|
+
### Added — §224 (v0.5.9) — `<feed-ui>` `data-spawned-by="toast"` marker on toast-spawned containers
|
|
456
|
+
|
|
457
|
+
`packages/web-components/components/toast/class.js` — `UIToast.show()` stamps `data-spawned-by="toast"` on the spawned `<feed-ui>` container at creation. Idempotent (once per container). Lets DOM-query consumers distinguish toast-spawned containers from user-authored ones. `toast.yaml` gains `usage:` block documenting the marker + query example. Closes FEEDBACK-10 §2.
|
|
458
|
+
|
|
459
|
+
### Fixed — §229 (v0.5.9) — `check-static-methods-vs-dts.mjs` (slot 20) class-export walk extension
|
|
460
|
+
|
|
461
|
+
`scripts/release/check-static-methods-vs-dts.mjs` gains the **4th declaration-axis** on the `.d.ts` surface: walks `export class UI<Name> extends UI<Base>` declarations in `class.js` against `export class` in every `.d.ts` in the component dir. Codegen'd `.d.ts` files NOW INCLUDED for the class-export axis (codegen emits primary; sibling-class drift is §228's gap). Static-method / event / property axes continue to skip codegen'd files (yaml-vs-runtime via slot 19).
|
|
462
|
+
|
|
463
|
+
Audit-driven discovery surfaced **15 class-export-undeclared findings across 13 components** — 8 more than FEEDBACK-18 §2's original enumeration. All 15 baselined as `EXPECTED_CLASS_EXPORT_FINDINGS`; strict mode hard-fails on NEW class-export drift beyond the baseline. After §228 codegen sibling-yaml walk ships, the baseline shrinks 15 → 0; `.d.ts` axis fully strict-mode-protected across all 4 sub-axes.
|
|
464
|
+
|
|
465
|
+
## [0.5.8] - 2026-05-15
|
|
466
|
+
|
|
467
|
+
### Changed — `patterns/` demo-page refresh (v0.5.8)
|
|
468
|
+
|
|
469
|
+
- `patterns/component-tokens/component-tokens.examples.html` + `patterns/responsive-shell-sidebar/responsive-shell-sidebar.examples.html` — demo refresh consuming v0.5.7 canonical fixes (`<text-ui>` retired-variant cleanup landed in v0.5.7 §210; component-tokens demo updated to reference real tokens; responsive-shell-sidebar demo aligned with v0.5.3 §157 pattern). Companion to §230 token-reference cleanup.
|
|
470
|
+
|
|
471
|
+
### Fixed — §230 (v0.5.8) — `--a-font-weight-*` orphaned references closed in 3 components
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
3 component CSS files referenced `var(--a-font-weight-*)` tokens that had been removed from the canonical token namespace in v0.5.0 (typography.css's "to be removed" comment was acted on but 3 consumers weren't updated). The references resolved to empty → CSS-keyword default (inherited 400 happened to match intent for nav-item / nav-group; feed.css had an inline `, 600` fallback masking the breakage). Consumer-override path was silently broken.
|
|
475
|
+
|
|
476
|
+
- `components/nav-item/nav-item.css:42` — `var(--a-font-weight-normal)` → `var(--a-weight-normal)`
|
|
477
|
+
- `components/nav-group/nav-group.css:12` — `var(--a-font-weight-normal)` → `var(--a-weight-normal)`
|
|
478
|
+
- `components/feed/feed.css:136` — `var(--a-font-weight-strong, 600)` → `var(--a-weight-semibold)` (preserves rendering weight; drops inline fallback)
|
|
479
|
+
- `styles/typography.css` comment block updated to reflect actual state (REMOVED in v0.5.0; was "to be removed" before).
|
|
480
|
+
|
|
481
|
+
Closes FEEDBACK-20 §1.
|
|
482
|
+
|
|
483
|
+
### Added — §231 (v0.5.8) — audit slot 25 `check-component-css-vs-styles-tokens.mjs`
|
|
484
|
+
|
|
485
|
+
NEW: `scripts/release/check-component-css-vs-styles-tokens.mjs` — closes the **7th drift surface** in the v0.5.x drift-class lockdown taxonomy: **token-reference vs token-definition axis**. Walks every `components/<dir>/*.css` for `var(--a-<name>)` references, walks `styles/**/*.css` (recursive — includes `styles/colors/semantics.css` + the 18-file color tree) for `--a-<name>:` definitions, reports orphaned references.
|
|
486
|
+
|
|
487
|
+
Audit-driven discovery cadence (per memory `feedback_audit_driven_discovery_cadence`): running the audit against `main` post-authoring surfaced **19 orphaned references across 12 components** — 16 more than FEEDBACK-20 §1's original 3-reference filing. The 16 additional findings are baselined as `EXPECTED_FINDINGS` (matching the v0.5.6 §192 schema-vs-impl-coverage baseline pattern) and filed for v0.5.8+ peer-architect triage. Strict mode hard-fails on NEW orphans beyond the baseline; stale-baseline detection reports entries that no longer fire.
|
|
488
|
+
|
|
489
|
+
Drift-class lockdown taxonomy now covers all 7 surfaces (v0.5.7 closed 4; v0.5.8 closes the remaining 3 via §222 + §232 + §231).
|
|
490
|
+
|
|
491
|
+
**Audit-script family graduation**: v0.5.4 → v0.5.8: 13 → 22+ trip-wires.
|
|
492
|
+
|
|
493
|
+
## [0.5.7] - 2026-05-15
|
|
494
|
+
|
|
495
|
+
### Changed — `traits/catalog.examples.js` consumer sweep (§210 follow-on, v0.5.7)
|
|
496
|
+
|
|
497
|
+
`traits/catalog.examples.js` swept for the §210 retired `<text-ui variant="subheading">` — replaced with the canonical `subsection` token at 2 call sites (catalog header rendering). Companion mechanical cleanup for the §210 phantom-variant removal.
|
|
498
|
+
|
|
499
|
+
### Fixed — §210 (v0.5.7) — `<text-ui>` variant enum drift (token-vs-rule + phantom entries)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
Close FEEDBACK-17 §1. `text.yaml` + `text.d.ts` + `text.a2ui.json` documented 18 `variant` enum values; `text.css` shipped `:scope[variant=…]` rules for only 9. The 9 stranded values fell through to `body` defaults silently — no console warning, no visual cue. Sixth instance of the recurring "static-declaration lies about runtime" drift class (R5/R7/R8/R9/R14/R17). Two distinct sub-fixes in one arc:
|
|
503
|
+
|
|
504
|
+
**Token-backed variants restored to rendering (3 values):**
|
|
505
|
+
- `subsection`, `deck`, `metric` — each has a full `--a-<role>-{family,weight,size,leading,tracking,case,color}` token family already shipping in `styles/typography.css`, but no matching `:scope` rule consumed the tokens. Added 3 `:scope[variant=…]` rules to `text.css` matching the existing 9-rule pattern. Verified via the new `text.test.js` suite that each rule references `var(--a-<role>-family|weight|size)` (not `var(--a-body-*)` defaults).
|
|
506
|
+
|
|
507
|
+
**Phantom enum entries retired (6 values):**
|
|
508
|
+
- `subheading`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6` — these had no `--a-<role>-*` tokens shipped anywhere (verified across `styles/typography.css` + `styles/prose.css` + `styles/tokens.css`). The yaml + d.ts + a2ui.json advertised them; the project shipped no implementation surface to render them. Removed from all three documentation surfaces. SemVer-minor compatibility note: any consumer who authored `<text-ui variant="subheading">` or `variant="h<N>">` was already getting body-default rendering — the behavior change is from "silent body-default" to "type-error-at-compile-time + clearer authoring contract."
|
|
509
|
+
|
|
510
|
+
42 new tests in `text.test.js` cover (1) mount smoke for all 12 surviving enum values, (2) every documented variant has a matching CSS rule, (3) the 3 restored variants reference role tokens (not body defaults), (4) the 6 phantom entries do NOT appear in `.d.ts` union OR `.a2ui.json` enum, (5) `.a2ui.json` enum + `.d.ts` union + CSS rules are mutually consistent 1:1. Plus a section-level demo in `text.examples.html` showcasing the 3 restored variants (subsection/deck/metric) inline with kicker/display/heading/body so the demo page visually surfaces the new contract.
|
|
511
|
+
|
|
512
|
+
Audit-slot extension queued for v0.5.8: extend slot 19 (`check-yaml-impl-coverage.mjs`) one step further — for each `enum` value on a prop, assert a matching `:scope[<name>="<value>"]` rule exists in the component's `.css`. Catches both halves of this drift class (token-vs-rule + phantom enum) mechanically. Reference: FEEDBACK-17 §1 audit-slot suggestion.
|
|
513
|
+
|
|
514
|
+
### Fixed — §200 (v0.5.7) — `<toggle-scheme-ui>` post-connect reactive-scheme race
|
|
515
|
+
|
|
516
|
+
`packages/web-components/components/toggle-scheme/class.js` — overrides `attributeChangedCallback` to re-run `#initState()` when the `scheme` attribute changes AFTER `connectedCallback` AND before first user interaction.
|
|
517
|
+
|
|
518
|
+
The bug class: `template.js scan()` strips placeholder attributes pre-insertion; `replaceChildren()` upgrades the element + fires `connectedCallback`; the old `#initState()` synchronously reads `this.scheme` and locks to AUTO fallback because the attribute is still stripped; then `template.js update()` re-applies `setAttribute('scheme', '<reactive>')` but the AUTO state is already cached. Consumers using `<toggle-scheme-ui scheme="${reactiveValue}">` saw incorrect scheme on every page load.
|
|
519
|
+
|
|
520
|
+
Fix introduces a `#userTouched` flag set by three paths: (1) the internal button-press handler, (2) `setScheme()` programmatic, (3) `toggle()` programmatic. Until `#userTouched` flips true, post-connect `scheme` attribute changes re-run `#initState()` so the reactive value wins. Once user picks explicitly, the flag locks the choice across subsequent reactive re-renders.
|
|
521
|
+
|
|
522
|
+
6 new tests in `toggle-scheme.test.js` cover the race repro, initial-attr passthrough, all 3 user-touch paths locking the choice, and pre-touch attribute removal back to auto. Closes FEEDBACK-10 §1.
|
|
523
|
+
|
|
524
|
+
### Fixed — §201 (v0.5.7) — `<color-picker-ui>` `#parseValue()` accepts `NaN` / `none` / `%`
|
|
525
|
+
|
|
526
|
+
`packages/web-components/components/color-picker/class.js` — `#parseValue()` regex extended to accept three CSS Color L4 / culori-convention channel shapes that the v0.5.6 baseline silently discarded:
|
|
527
|
+
|
|
528
|
+
- **`NaN`** — culori chromaless-hue convention; coerced to `0`.
|
|
529
|
+
- **`none`** — CSS Color L4 powerless-component syntax; coerced to `0` (matches the L4 powerless-cascade spec).
|
|
530
|
+
- **`%`** on L — `oklch(53% 0.05 240)` → divides by 100.
|
|
531
|
+
|
|
532
|
+
Plus: when input doesn't match any documented shape, a `console.warn` fires **once per element** (deduped via class-level `static #warnedBadParse = new WeakSet()`). Matches the v0.5.5 §184 §8 `<button-ui>` icon-only safety-net pattern + v0.5.7 §215 (queued) `<select-ui>` `#parseOptions` pattern.
|
|
533
|
+
|
|
534
|
+
7 new tests in `color-picker.test.js` cover all 4 input shapes (numeric, NaN, none, %), hex passthrough, warn-once dedup, and per-instance warn budget. Closes FEEDBACK-13 §1 + FEEDBACK-14 §2 (co-credited per the 2026-05-15 slot-dance reconciliation).
|
|
535
|
+
|
|
536
|
+
### Added — §207 (v0.5.7) — audit slot 20 `check-static-methods-vs-dts.mjs`
|
|
537
|
+
|
|
538
|
+
NEW: `scripts/release/check-static-methods-vs-dts.mjs` cross-checks three runtime surfaces in `class.js` against the sibling hand-authored `.d.ts`:
|
|
539
|
+
|
|
540
|
+
1. **Static methods** — `static <name>(...)` declarations should appear as static signatures in `.d.ts`. Caught FEEDBACK-09 §9 (`<toast-ui>.show()`).
|
|
541
|
+
2. **Dispatched events** — `dispatchEvent(new CustomEvent('<name>', ...))` literals should appear as `addEventListener(type: '<name>', ...)` overloads in `.d.ts`. Caught FEEDBACK-07's event-type drift class + R9 §10.
|
|
542
|
+
3. **Static-properties keys** — `static properties = { <key>: ... }` keys should appear as public field declarations in `.d.ts`. NEW per FEEDBACK-14 §1 (`<slider-ui>` `throttle` + `hint` missing) — 5th instance of the runtime-vs-`.d.ts` drift class family.
|
|
543
|
+
|
|
544
|
+
Codegen'd `.d.ts` files (73 of 90; identified via the "Type declarations generated by scripts/build/dts-codegen.mjs" marker) are skipped — yaml is their SoT, and slot 19 (`check-yaml-impl-coverage.mjs`, v0.5.6 §192) covers the yaml-vs-runtime drift surface.
|
|
545
|
+
|
|
546
|
+
Heuristics: balanced-brace walker to extract `static properties = { ... }` body; depth-tracked key extraction for top-level prop names only; regex extraction for event literals + static method signatures + `.d.ts` field/method declarations.
|
|
547
|
+
|
|
548
|
+
### Changed — §207-bundled — close 15 `.d.ts` drift findings surfaced by audit slot 20
|
|
549
|
+
|
|
550
|
+
Running the new slot 20 against `main` surfaced 15 hard findings across 6 hand-authored form-bearing primitives — all closed in this same cycle to complete the drift-class lockdown narrative. Like §205 (`requiredIcons` 2 → 5 primitives), the audit-driven discovery materially expanded scope:
|
|
551
|
+
|
|
552
|
+
- `calendar-picker.d.ts` — adds `label`, `placeholder`, `format`, `min: string | null`, `max: string | null` fields.
|
|
553
|
+
- `code.d.ts` — adds `name`, `required`, `disabled`, `readonly` fields.
|
|
554
|
+
- `input.d.ts` — adds `addEventListener(type: 'submit', ...)` overload (the runtime dispatches `Event('submit')` on Enter-key + form-submit at `class.js:717+725`).
|
|
555
|
+
- `select.d.ts` — adds `hint` field.
|
|
556
|
+
- `switch.d.ts` — adds `hint` field.
|
|
557
|
+
- `upload.d.ts` — adds `label`, `accept`, `multiple` fields.
|
|
558
|
+
|
|
559
|
+
All declarations carry `§207 (v0.5.7)` JSDoc cross-refs. Post-fix audit reports clean across all 95 primitives.
|
|
560
|
+
|
|
561
|
+
### Added — §208 (v0.5.7) — audit slot 22 `check-styles-barrel-completeness.mjs`
|
|
562
|
+
|
|
563
|
+
NEW: `scripts/release/check-styles-barrel-completeness.mjs` cross-checks `packages/web-components/styles/components.css` `@import` lines against the per-component CSS files on disk. Catches the "primitive ships CSS but barrel forgot to @import it" drift class surfaced by FEEDBACK-11 §1.
|
|
564
|
+
|
|
565
|
+
Three drift classes caught:
|
|
566
|
+
1. `file-exists-not-imported` (hard) — CSS file exists at `components/<X>/<X>.css` (or irregular `<X>-ui.css`) but barrel doesn't @import it.
|
|
567
|
+
2. `imported-not-existing` (hard) — barrel @imports a file that doesn't exist on disk.
|
|
568
|
+
3. `duplicate-import` (warn) — same file @imported twice.
|
|
569
|
+
|
|
570
|
+
Filename handling: supports both `<name>.css` (canonical) AND `<name>-ui.css` (irregular — stat-ui-only as of v0.5.7; planned rename in v0.6.0 §303 per R11 §2). CSS-only components (`header`, `footer`, `section`) are skipped via `CSS_ONLY_COMPONENTS` allowlist.
|
|
571
|
+
|
|
572
|
+
Post-§203 audit reports clean across all 95 primitives + 92 @import lines.
|
|
573
|
+
|
|
574
|
+
### Added — §202 (v0.5.7) — `<slider-ui>` `.d.ts` declares `throttle` + `hint`
|
|
575
|
+
|
|
576
|
+
`packages/web-components/components/slider/slider.d.ts` — adds `throttle: number` + `hint: string` to the `UISlider` class declaration. Closes FEEDBACK-14 §1 — runtime + yaml + a2ui.json all shipped these props since v0.5.5 §184; the `.d.ts` lagged behind. 5th recurrence of the runtime-vs-`.d.ts` drift class (R5 / R7 / R8 / R9 / R14). Consumers using `<slider-ui throttle="50" hint="…">` no longer need `as any` casts or augment shims.
|
|
577
|
+
|
|
578
|
+
### Changed — §206 (v0.5.7) — `<accordion-item-ui>` action-slot opt-out
|
|
579
|
+
|
|
580
|
+
`packages/web-components/components/accordion/class.js` — `#onClick` now skips toggle when the click originates inside `[slot="action"]`, `[slot="actions"]`, or `[data-no-toggle]`. Lets consumers author rich custom headers with action buttons (Copy / Download / settings) inside `[slot="header"]` without bubbling-toggle UX. Slot vocabulary matches the canonical `drawer-ui` + `pane-ui` naming. Additive — existing consumers see no behavior change. Closes FEEDBACK-16 §2.
|
|
581
|
+
|
|
582
|
+
`packages/web-components/components/accordion/accordion-item.yaml` — gains `slots:` block documenting `header` + `action` slots; `events:` block formalizing the `toggle` event detail; sidecar regenerated.
|
|
583
|
+
|
|
584
|
+
`packages/web-components/components/accordion/accordion.yaml` — `slots.default.description` corrected from `pane-ui children` to `accordion-item-ui children`. Closes FEEDBACK-13 §2 (folded into §206 since adjacent yaml).
|
|
585
|
+
|
|
586
|
+
### Changed — §205 (v0.5.7) — `requiredIcons` completeness on 5 primitives (2 from FEEDBACK-16, 3 from §209 audit-extension discovery)
|
|
587
|
+
|
|
588
|
+
Five primitives' `static requiredIcons` declarations updated to mirror their runtime dynamic-icon stamps:
|
|
589
|
+
|
|
590
|
+
**Filed by FEEDBACK-16 §1:**
|
|
591
|
+
- `packages/web-components/components/color-picker/class.js:130` — `['copy']` → `['copy', 'check', 'warning']`. Copy-button dynamic-swaps to `check` (success) / `warning` (failure) at line 496.
|
|
592
|
+
- `packages/web-components/components/table/class.js:98` — `['caret-right', 'caret-up-down', 'table']` → adds `'arrow-up'`, `'arrow-down'`, `'funnel-simple'`, `'funnel-simple-fill'`. Dynamic sort-direction + filter-state stamps at lines 679 + 707.
|
|
593
|
+
|
|
594
|
+
**Surfaced by §209 audit-regex extension (see below):**
|
|
595
|
+
- `packages/web-components/components/agent-artifact/class.js` — NEW `static requiredIcons = ['caret-right', 'caret-down']`. Chevron stamps on collapse/expand state at lines 119 + 188.
|
|
596
|
+
- `packages/web-components/components/table-toolbar/class.js` — NEW `static requiredIcons = ['arrow-up', 'arrow-down', 'caret-up-down']`. Nested-ternary sort-indicator stamp at line 576.
|
|
597
|
+
- `packages/web-components/components/timeline/class.js` — NEW `static requiredIcons = ['caret-down', 'caret-right']`. Expanded-state chevron at line 167.
|
|
598
|
+
|
|
599
|
+
(In all 3 newly-surfaced primitives, `this.icon` reads are consumer-supplied — not declared in `requiredIcons` per the established convention.)
|
|
600
|
+
|
|
601
|
+
Yaml `requiredIcons:` blocks mirror the class.js change for all 5; sidecars regenerated. Closes FEEDBACK-16 §1 + 3 additional drift instances that the pre-§209 audit didn't catch.
|
|
602
|
+
|
|
603
|
+
### Fixed — §209 (v0.5.7) — `check-required-icons.mjs` (audit slot 11) extended to catch ternary-style icon stamps
|
|
604
|
+
|
|
605
|
+
`scripts/release/check-required-icons.mjs` — regex extended to extract icon-name literals from `.setAttribute('name', <expr>)` where `<expr>` is a ternary (or nested-ternary) rather than a singleton string literal. Uses a balanced-paren walker to capture the 2nd-argument expression (handles inner calls like `this.#filters.has(col.key) ? 'A' : 'B'`), then matches literals that appear in ternary-branch position (preceded by `?` or `:`). Avoids false-positives on comparator literals (e.g. `dir === 'asc'`).
|
|
606
|
+
|
|
607
|
+
Closes the audit-blind-spot bug class that allowed FEEDBACK-16 §1's drift to slip past CI: pre-§209 the slot reported "all primitives clean"; post-§209 + §205 the audit reports clean while §205 closes the actual drift. The audit now reliably catches the runtime-vs-`static requiredIcons` drift class on both singleton-literal AND ternary-expression stamp sites.
|
|
608
|
+
|
|
609
|
+
Discovery surface: running the post-§209 audit against `main` surfaced 3 additional primitives with the same drift class (`agent-artifact`, `table-toolbar`, `timeline`) — all 3 fixed under §205 above.
|
|
610
|
+
|
|
611
|
+
### Added — §204 (v0.5.7) — `package.json` `exports` accepts nested-CSS specifier shapes
|
|
612
|
+
|
|
613
|
+
`packages/web-components/package.json` `exports` map gains two entries:
|
|
614
|
+
|
|
615
|
+
```json
|
|
616
|
+
"./components/*/*.css": "./components/*/*.css",
|
|
617
|
+
"./components/*/css/*.css": "./components/*/css/*.css"
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
Consumers can now import component CSS with the path-mirroring shape that matches every JS subpath import:
|
|
621
|
+
|
|
622
|
+
```js
|
|
623
|
+
// Both shapes now resolve:
|
|
624
|
+
import '@adia-ai/web-components/components/toggle-scheme.css';
|
|
625
|
+
import '@adia-ai/web-components/components/toggle-scheme/toggle-scheme.css';
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
The second new entry handles `editor-shell`'s nested sub-stylesheets (`components/editor-shell/css/{layout,tokens,bespoke}.css`). Closes FEEDBACK-15 §1.
|
|
629
|
+
|
|
630
|
+
### Fixed — §203 (v0.5.7) — `styles/components.css` barrel completeness
|
|
631
|
+
|
|
632
|
+
`packages/web-components/styles/components.css` — adds 2 `@import` lines for `<link-ui>` + `<toggle-scheme-ui>`. Both primitives ship per-component CSS files (`components/link/link.css`, `components/toggle-scheme/toggle-scheme.css`) that previously weren't `@import`-ed into the canonical barrel. Consumers using `<link href="@adia-ai/web-components/styles/components.css">` previously rendered both elements unstyled. Closes FEEDBACK-11 §1 (the 2 genuinely-missing instances; `stat-ui` was already imported at its irregular filename per R11 §2, deferred to v0.6.0 §303).
|
|
633
|
+
|
|
634
|
+
## [0.5.6] - 2026-05-14
|
|
635
|
+
|
|
636
|
+
### Added — §191 (v0.5.6) — close §178 baseline-missing 7 `.d.ts` siblings
|
|
637
|
+
|
|
638
|
+
`core/anchor.d.ts`, `core/controller.d.ts`, `core/markdown.d.ts`, `core/polyfills.d.ts`, `core/provider.d.ts`, `core/streams-bridge.d.ts`, `core/transport.d.ts` — all 7 public-API JS modules now have hand-authored TypeScript declarations mirroring the runtime exports. Pattern follows §154 `icons.d.ts` (v0.5.4 `cf7c14aaa` hotfix): types live alongside the runtime SoT, documented inline, regenerated only if the runtime changes shape.
|
|
639
|
+
|
|
640
|
+
**Type surfaces now exposed to TS consumers**:
|
|
641
|
+
|
|
642
|
+
- `anchor.d.ts` — `Placement` type (12-value union), `AnchorOptions` interface, `supportsAnchorCSS: boolean`, `anchorPopover(anchor, popover, options?): () => void`.
|
|
643
|
+
- `controller.d.ts` — `BaseController` class (public surface — `host`, `connect`, `disconnect`, `subscribe`, `notify`, lifecycle hooks, `getState`), `RouteController extends BaseController`, plus supporting `ControllerSchema`/`Route`/`RouteState`/`RouteCommands`/`RouteControllerOptions` interfaces.
|
|
644
|
+
- `markdown.d.ts` — `renderMarkdown(src: string): string`.
|
|
645
|
+
- `polyfills.d.ts` — side-effect-only module declaration (`export {}`). Documents the runtime feature checks + the two opt-in polyfill packages.
|
|
646
|
+
- `provider.d.ts` — `RouteController` re-declaration (matches `controller.d.ts` for historical compatibility), `UIRouter extends UIElement`, `TemplateResolver` type, `HTMLElementTagNameMap['router-ui']` declaration so `document.querySelector('router-ui')` returns `UIRouter`.
|
|
647
|
+
- `streams-bridge.d.ts` — `BridgeRenderer` interface (duck-typed renderer contract), `BridgeOptions` interface, `bridgeStream` / `bridgeStreamAsync` signatures.
|
|
648
|
+
- `transport.d.ts` — `TransportErrorKind` discriminator (4-value union), `TransportOptions` interface, `request` / `json` signatures (`json` is generic over response body type), `TransportError` class with `kind`/`status`/`body` fields.
|
|
649
|
+
|
|
650
|
+
**Audit-script closure**: `scripts/release/check-dts-sibling-presence.mjs` (audit slot 17) `EXPECTED_MISSING` allowlist emptied — baseline 7 → 0. Strict mode now hard-fails on any future regression (audit reports 14/14 public-API entries with sibling `.d.ts`, 0 missing). Defensive stale-baseline detection retained — every future entry treated as policy gap requiring justification.
|
|
651
|
+
|
|
652
|
+
**Verification**: `node scripts/release/check-dts-sibling-presence.mjs --strict` → exit 0. `node scripts/build/components.mjs --verify` → clean (135 files). `npm run check` → mcp:smoke OK.
|
|
653
|
+
|
|
654
|
+
### Changed — §197 (v0.5.6) — FEEDBACK-09 §9 + §10 typing fixes
|
|
655
|
+
|
|
656
|
+
**§9 — `<toast-ui>` `.d.ts` adds the static `show()` declaration**
|
|
657
|
+
|
|
658
|
+
`UIToast.show()` was authored in `class.js` since the imperative path
|
|
659
|
+
shipped but absent from `toast.d.ts`. TS consumers calling
|
|
660
|
+
`UIToast.show({ text: 'Saved' })` got `Property 'show' does not exist on typeof UIToast`. §197 adds two interfaces (`UIToastShowOptions`,
|
|
661
|
+
`UIToastFeedHandle`) and the static method declaration. Same drift class as the v0.5.3 §154 `core/icons.d.ts` hotfix.
|
|
662
|
+
|
|
663
|
+
**§10 — Generic `<V extends string = string>` on Select / Segmented / Switch ChangeEventDetail**
|
|
664
|
+
|
|
665
|
+
`SelectChangeEventDetail`, `SegmentedChangeEventDetail`, and `SwitchChangeEventDetail` previously hard-coded `value: string`, forcing Tokens Studio's 11 consumer call-sites to widen via `as` casts. Adding a generic parameter `<V extends string = string>` defaulting to `string` is backwards-compatible (existing consumers see no change) and lets type-aware call-sites pin the literal value type:
|
|
666
|
+
|
|
667
|
+
```ts
|
|
668
|
+
type Size = 'sm' | 'md' | 'lg';
|
|
669
|
+
select.addEventListener('change', (e: SelectChangeEvent<Size>) => {
|
|
670
|
+
e.detail.value; // typed as Size, not string
|
|
671
|
+
});
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Applies to `SelectChangeEvent`, `SegmentedChangeEvent`, `SwitchChangeEvent` aliases as well. `SwitchChangeEventDetail.checked` stays `boolean` (only `value` is generified).
|
|
675
|
+
|
|
676
|
+
### Changed — §197 (v0.5.6) — audit slot 11 regex tolerates generic params
|
|
677
|
+
|
|
678
|
+
`scripts/release/check-form-bearing-dts.mjs` (slot 11) was rejecting the new generic-parameterized `EventDetail` interfaces because the old regex required `<X>EventDetail\s*\{`. §197 widens both the interface-parse regex AND the `Event = CustomEvent<...>` alias regex to accept an optional `<...>` generic-params block. Audit stays at 0 errors / 0 warnings against the updated .d.ts files.
|
|
679
|
+
## [0.5.5] - 2026-05-14
|
|
680
|
+
|
|
681
|
+
### Added — §176 (v0.5.5) — six new sibling sub-component yamls
|
|
682
|
+
|
|
683
|
+
Six sibling yamls authored per the v0.5.4 §172 scanner pattern (sibling-yaml discovery in the build pipeline). Each describes a co-located sub-component class that previously existed as a registered custom element without its own catalog entry — surfaced as the §175 baseline-orphan class.
|
|
684
|
+
|
|
685
|
+
- `list/list-item.yaml` — `UIListItem` (3 props: icon, text, description)
|
|
686
|
+
- `avatar/avatar-group.yaml` — `UIAvatarGroup` (2 props: max, size)
|
|
687
|
+
- `accordion/accordion-item.yaml` — `UIAccordionItem` (2 props: text, open)
|
|
688
|
+
- `timeline/timeline-item.yaml` — `UITimelineItem` (8 props: text, description, time, duration, icon, variant, status, spinner)
|
|
689
|
+
- `action-list/action-item.yaml` — `UIActionItem` (5 props: icon, text, value, variant, disabled)
|
|
690
|
+
- `tabs/tab.yaml` — `UITab` (4 props: text, value, icon, disabled)
|
|
691
|
+
|
|
692
|
+
After §184's `tree-item.yaml` addition, sibling-yaml pattern is now at **7 components**. Catalog: 125 → 132 components (+7 across §176 + §184).
|
|
693
|
+
|
|
694
|
+
Commit `443365913`. See root CHANGELOG and journal §176 for full context.
|
|
695
|
+
|
|
696
|
+
### Added — §184 (v0.5.5, FEEDBACK-08 response cycle) — 6 new APIs + 1 build-time audit
|
|
697
|
+
|
|
698
|
+
FEEDBACK-08 (2026-05-14) reported 9 items post-v0.5.3 dogfooding. Items 3 (`<segment-ui>` `aria-label` auto-wire) + 9 (`<segment-ui disabled>` schema docs) were already resolved in v0.5.5 in-flight work; 7 remaining items land here as a single arc:
|
|
699
|
+
|
|
700
|
+
- **`<tree-item-ui>` `badge` attribute (FEEDBACK-08 §1, P1).** Mirrors the `<nav-item-ui>` `badge` API — trailing muted small text alongside the row, right-aligned. Use for counts/labels (e.g. `<tree-item-ui text="Colors" badge="7">`). Empty span auto-hides. Plus a sibling `tree-item.yaml` (per the v0.5.5 §176 sibling-yaml authoring pattern) so the previously-orphan `UITreeItem` component now has its own catalog entry, `.d.ts`, and `.a2ui.json` sidecar. New CSS tokens: `--tree-badge-{bg,fg,px,radius,size}`.
|
|
701
|
+
- **`<tree-ui>` programmatic expand/collapse API (FEEDBACK-08 §2, P1).** Five new methods on `UITree`: `.expand(itemOrValue)`, `.collapse(itemOrValue)`, `.expandAll()`, `.collapseAll()`, `.expandTo(itemOrValue)` (expands ancestors + scrolls into view). All accept either an `HTMLElement` (must match `tree-item-ui`) OR a string (matched against `[value]` first, then `[text]` for ergonomics). Removes the `_expanded[]` + `tree-select`-listener boilerplate consumers were maintaining locally.
|
|
702
|
+
- **`<slider-ui>` `throttle` attribute (FEEDBACK-08 §4, P1).** Declarative debounce for the `input` event when driving expensive computation (palette regen, shader compile, large list reflow). When `throttle > 0`, value updates + visual feedback remain immediate but `input` event emission is debounced — only the FINAL value in the throttle window dispatches. `change` fires unthrottled on pointerup / track click / keyboard; any pending `input` flushes BEFORE `change` so consumers always see `input → input → … → input → change` ordering. `throttle="0"` (default) preserves the pre-§184 every-pointer-move-fires-input behavior. Common values: 50–100ms.
|
|
703
|
+
- **`<slider-ui>` / `<select-ui>` / `<switch-ui>` `hint` attribute (FEEDBACK-08 §7, P2).** Caption rendered beneath the control + wired to `aria-describedby` on the host. Distinct from the in-component `label` (which becomes `aria-label`). `<switch-ui>` had `hint` declared in yaml since §170 but the template never rendered it — this arc closes the schema-vs-implementation gap on switch in addition to adding the new declarations on slider + select. New CSS tokens per primitive: `--{slider,select,switch}-hint-{mt,size,fg,lh}`.
|
|
704
|
+
- **`<button-ui>` icon-only a11y safety net (FEEDBACK-08 §8, P2).** When `<button-ui icon="X">` is used WITHOUT `text`, `aria-label`, `aria-labelledby`, OR `title`, `console.warn()` once per element (deduped via `WeakSet`) so the bug class is diagnosable in dev. When `title="Undo"` IS set, mirror it to `aria-label` automatically — matches the common icon-only-button-with-tooltip pattern (zero-author-cost a11y). Consumers can still set `aria-label` explicitly; the auto-mirror only fires when no other accessible name exists. Per FEEDBACK-08's two options A + B chosen together (warn + auto-derive).
|
|
705
|
+
- **`core/template.js` partial-attribute error message (FEEDBACK-08 §5, P2).** The §152 (v0.5.3) runtime warn previously suggested `.${attr.name}=${expression}` as a generic property-assignment recipe. For `class` specifically, `.class=${expr}` sets a JS expando (`element.class = "foo"`) instead of the `className` property — CSS classes never apply. Updated the warning to special-case `class` (suggests `.className=${expression}` first, then `class="${expression}"` for the whole-attribute path) and `style` (suggests `.style.cssText=${expression}`); other attributes keep the generic recipe.
|
|
706
|
+
|
|
707
|
+
### Added — §184 audit slot 18 (build-time partial-attribute interpolation scanner)
|
|
708
|
+
|
|
709
|
+
NEW `scripts/release/check-template-interp.mjs` (~220 LOC) closes FEEDBACK-08 §6. Walks every `*.js` / `*.mjs` / `*.ts` / `*.tsx` file under `packages/web-components/`, `packages/web-modules/`, `apps/`, `playgrounds/`, `catalog/` (excludes `node_modules/`, `dist/`, `.test.*`, `.spec.*`), strips comments, finds every `` html` `` tagged template literal via brace-balanced walker (matching the runtime template parser's contract), inspects attribute values for partial-attribute interpolation (`attr="prefix ${var}"` patterns where the value mixes literal + placeholder content). Whole-attribute forms (`attr="${expression}"`) and prop/event forms (`.prop=`, `@event=`) are NOT flagged.
|
|
710
|
+
|
|
711
|
+
The runtime guard at `core/template.js` (§152) warns at mount time; this static scanner catches the bug class before it ships, even in conditional branches that never run during dev testing (the case FEEDBACK-08 §6 highlights). Wired as `npm run check:template-interp` (advisory exit 0) + `:strict` (exit 1 on findings) + added to `npm run check` aggregate alongside the existing 17 audit-script-family trip-wires. Initial run across all 5 scan roots: zero findings. Audit-script family now spans **18 trip-wires** at v0.5.5.
|
|
712
|
+
## [0.5.4] - 2026-05-14
|
|
713
|
+
|
|
714
|
+
### Added — `core/icons.d.ts` authored (+148 LOC, NEW; pre-cycle FEEDBACK-08-ish gap closure)
|
|
715
|
+
|
|
716
|
+
NEW `packages/web-components/core/icons.d.ts` (commit `cf7c14aaa`).
|
|
717
|
+
Mirrors all 10 runtime exports the `core/icons.js` SoT declares,
|
|
718
|
+
including the v0.5.3 §154 helpers (`installIconLoadersForRegistered`,
|
|
719
|
+
`discoverRequiredIcons`).
|
|
720
|
+
|
|
721
|
+
**Why this slipped past v0.5.3's gates**: the audit-script family
|
|
722
|
+
had 11 trip-wires at v0.5.3 including §102 `check-core-barrel-dts`
|
|
723
|
+
which catches **drift when a `.d.ts` exists** (every exported runtime
|
|
724
|
+
symbol has a matching type), but does NOT catch the **totally-missing
|
|
725
|
+
`.d.ts` case** for a `core/*.js` file. Result: a new `core/<name>.js`
|
|
726
|
+
file shipping without `<name>.d.ts` was silently consumer-broken on
|
|
727
|
+
TS-strict surfaces (TypeScript consumers importing from
|
|
728
|
+
`@adia-ai/web-components/core/icons` resolved to a missing `.d.ts`
|
|
729
|
+
and got `Cannot find module`) but JS-green elsewhere.
|
|
730
|
+
|
|
731
|
+
In-the-wild detection: `/Users/kimba/Projects/adia/color-app/src/main.ts:48`
|
|
732
|
+
(TypeScript strict mode) carried a stale comment noting the workaround
|
|
733
|
+
needed because `installIconLoadersForRegistered.d.ts` was missing. The
|
|
734
|
+
user wanted to upgrade to the recommended auto-discovering helper but
|
|
735
|
+
was blocked.
|
|
736
|
+
|
|
737
|
+
Filed slot 14 candidate for v0.5.5+ (`check-dts-sibling-presence`):
|
|
738
|
+
detect totally-missing `.d.ts` files for `core/*.js`, not just symbol-level
|
|
739
|
+
drift within existing `.d.ts` files.
|
|
740
|
+
|
|
741
|
+
### Fixed — §170 `static labelDeprecated = false` opt-out for 7 form-bearing primitives (v0.5.4)
|
|
742
|
+
|
|
743
|
+
Closes the `<select-ui label="...">` false-positive deprecation
|
|
744
|
+
class observed 2026-05-14 console:
|
|
745
|
+
|
|
746
|
+
```
|
|
747
|
+
form.js:205 [AdiaUI] <select-ui label="…"> is deprecated — wrap in
|
|
748
|
+
<field-ui label="…"> for proper label association.
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
`UIFormElement.#warnDeprecatedLabel()` (`core/form.js:197`) fires for
|
|
752
|
+
any form-bearing element where `properties.label` exists AND `static
|
|
753
|
+
labelDeprecated !== false` AND `hasAttribute('label')`. Pre-§170,
|
|
754
|
+
only `Input`, `Slider`, `Range` opted out. The 7 other form-bearing
|
|
755
|
+
primitives that declare `label:` in yaml as a first-class prop
|
|
756
|
+
spammed false-positive warnings on every gen-ui render.
|
|
757
|
+
|
|
758
|
+
Added `static labelDeprecated = false` to:
|
|
759
|
+
|
|
760
|
+
- `calendar-picker/class.js`
|
|
761
|
+
- `check/class.js`
|
|
762
|
+
- `radio/class.js`
|
|
763
|
+
- `select/class.js`
|
|
764
|
+
- `switch/class.js`
|
|
765
|
+
- `textarea/class.js`
|
|
766
|
+
- `upload/class.js`
|
|
767
|
+
|
|
768
|
+
Audit method: cross-reference yaml `props.label:` declarations
|
|
769
|
+
against `class.js` `static labelDeprecated` opt-out. Found 11
|
|
770
|
+
form-bearing primitives with `label:` prop; 3 already opted out
|
|
771
|
+
(Input/Slider/Range); 7 missing (this commit); 1 false positive
|
|
772
|
+
in audit (field-ui — extends UIElement not UIFormElement; only
|
|
773
|
+
mentions UIFormElement in a comment).
|
|
774
|
+
|
|
775
|
+
v0.5.5 §171 will add audit-script trip-wire to catch this drift
|
|
776
|
+
class mechanically going forward.
|
|
777
|
+
|
|
778
|
+
### Added — §172 NEW `chat-input.yaml` catalog entry; `<chat-input-ui>` no longer orphan (v0.5.4)
|
|
779
|
+
|
|
780
|
+
NEW `packages/web-components/components/chat-thread/chat-input.yaml`
|
|
781
|
+
(+251 LOC). Closes the v0.5.4 ticket
|
|
782
|
+
`20260514045025-chatinput-training-data-unclea`: `<chat-input-ui>`
|
|
783
|
+
was an orphan component (lived as a sibling file inside
|
|
784
|
+
`chat-thread/` rather than its own folder); the build scanner only
|
|
785
|
+
looked for canonical `<name>/<name>.yaml`, so the catalog had NO
|
|
786
|
+
`ChatInput` entry. Runtime registry mapped `ChatInput → chat-input-ui`
|
|
787
|
+
but the LLM had no schema describing what the element stamps. Result:
|
|
788
|
+
generator added redundant Button(primary) siblings next to ChatInput
|
|
789
|
+
for "send" because the built-in send button was invisible to it.
|
|
790
|
+
|
|
791
|
+
The yaml encodes:
|
|
792
|
+
- 5 props (disabled, loading, placeholder, model, models)
|
|
793
|
+
- `submit` event with `{text, model}` detail
|
|
794
|
+
- 3 slots (toolbar, send, model — each marked "most authors should
|
|
795
|
+
NOT override")
|
|
796
|
+
- 3 a2ui rules explicitly stating "DO NOT add a separate Button
|
|
797
|
+
sibling for send"
|
|
798
|
+
- 3 anti-patterns
|
|
799
|
+
- 4 examples
|
|
800
|
+
|
|
801
|
+
Sibling yaml in `feed/` (`feed-item.yaml`, pre-existing orphan)
|
|
802
|
+
also unblocked by the build-scanner fix in `@adia-ai/a2ui-compose`
|
|
803
|
+
§172.
|
|
804
|
+
|
|
805
|
+
### Maintenance — audit-script companion §174 ships in v0.5.4 (no source change to web-components)
|
|
806
|
+
|
|
807
|
+
Repo-level audit script targeting web-components drift:
|
|
808
|
+
|
|
809
|
+
- **§174 `check-form-element-label-opt-out.mjs`** (slot 15) — codifies the
|
|
810
|
+
§170 audit recipe. For every form-bearing primitive (extends
|
|
811
|
+
UIFormElement): if yaml declares `label:` as first-class, class.js MUST
|
|
812
|
+
opt out via `static labelDeprecated = false;`. Catches future drift if a
|
|
813
|
+
new form-bearing primitive is added without the opt-out.
|
|
814
|
+
|
|
815
|
+
No web-components source change in §174 — detects future drift in the
|
|
816
|
+
yaml-vs-class.js invariant established by §170.
|
|
817
|
+
|
|
818
|
+
### Changed — `version`: `0.5.3` → `0.5.4`.
|
|
819
|
+
## [0.5.3] - 2026-05-14
|
|
820
|
+
|
|
821
|
+
### Added — `requiredIcons` static export on 12 primitives + `installIconLoadersForRegistered()` helper + audit slot 11 (§154, FEEDBACK-06 §4 + FEEDBACK-07 §4 P1, v0.5.3)
|
|
822
|
+
|
|
823
|
+
FEEDBACK-06 §4 + FEEDBACK-07 §4 (duplicate ask per author's cross-reference) reported consumers trial-and-error-discovering which Phosphor icons AdiaUI primitives auto-stamp (e.g. `<select-ui>` stamps `caret-up-down`; `<tag-ui>` dismissable stamps `x`; `<tree-ui>` stamps `caret-right`). Without a discoverable contract, consumers built the icon list by refresh-and-look.
|
|
824
|
+
|
|
825
|
+
**Three surfaces**:
|
|
826
|
+
|
|
827
|
+
**(a) `static requiredIcons` field** added to 12 auto-stamping primitives — `accordion`, `agent-questions`, `agent-reasoning`, `agent-trace`, `calendar-picker`, `color-picker`, `command`, `pane`, `select`, `table`, `tag`, `tree`. Each declares the Phosphor names it stamps without consumer markup:
|
|
828
|
+
|
|
829
|
+
```js
|
|
830
|
+
export class UISelect extends UIFormElement {
|
|
831
|
+
static requiredIcons = ['caret-up-down'];
|
|
832
|
+
// ...
|
|
833
|
+
}
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
**(b) `requiredIcons:` yaml field** on the same 12 yamls; mirrors the class.js declaration. `scripts/schemas/component.yaml.schema.json` updated to accept the field (string array, kebab-case pattern). `npm run components` validates the yaml against the schema + propagates the field into `.a2ui.json` sidecars.
|
|
837
|
+
|
|
838
|
+
**(c) `installIconLoadersForRegistered(modules)` helper** in `core/icons.js`. Walks `customElements.get()` for the 12 known auto-stamping tag names + collects the union of `static requiredIcons` + installs loaders. Also exposes `.discover()` for consumers who want the icon list without installing:
|
|
839
|
+
|
|
840
|
+
```js
|
|
841
|
+
import { installIconLoadersForRegistered } from '@adia-ai/web-components/core/icons';
|
|
842
|
+
|
|
843
|
+
const modules = import.meta.glob('/node_modules/@phosphor-icons/core/assets/regular/*.svg', { query: '?raw' });
|
|
844
|
+
const discovered = installIconLoadersForRegistered(modules);
|
|
845
|
+
// discovered: ['caret-up-down', 'x', 'caret-right', 'check-circle', ...]
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
**(d) Audit-script slot 11** at `scripts/release/check-required-icons.mjs` (~190 LOC). Cross-checks `static requiredIcons` (class.js SoT) vs `requiredIcons:` yaml + runtime `<icon-ui name="X">` literal + `setAttribute('name', 'X')` calls. Catches:
|
|
849
|
+
|
|
850
|
+
1. **declared-not-stamped** — yaml/class.js says `X` but no runtime stamp site
|
|
851
|
+
2. **stamped-not-declared** — runtime stamps `X` but declaration omits it (consumer-failure risk)
|
|
852
|
+
3. **missing-declaration** — runtime stamps icons but no class.js `static requiredIcons` field
|
|
853
|
+
4. **yaml-class-mismatch** — yaml and class.js disagree on the set
|
|
854
|
+
5. **yaml-missing-block** / **class-missing-declaration** — one side has the declaration, the other doesn't
|
|
855
|
+
|
|
856
|
+
Wired as `npm run check:required-icons` + added to the `npm run check` aggregate after `check:substitutable-set-drift` (slot 10). Audit-script family now spans **11 trip-wires**:
|
|
857
|
+
|
|
858
|
+
| Slot | Script |
|
|
859
|
+
|---|---|
|
|
860
|
+
| 1 | check-no-live-readers |
|
|
861
|
+
| 2 | check-changelog-coverage |
|
|
862
|
+
| 3 | check-browser-safe |
|
|
863
|
+
| 4 | smoke:genui-composition-retrieval |
|
|
864
|
+
| 5 | check-form-bearing-dts |
|
|
865
|
+
| 6 | check-core-barrel-dts |
|
|
866
|
+
| 7 | check-yaml-events-vs-runtime |
|
|
867
|
+
| 8 | check-free-form-eval-regression |
|
|
868
|
+
| 9 | check-standalone-html-phosphor |
|
|
869
|
+
| 10 | check-substitutable-set-drift |
|
|
870
|
+
| **11** | **check-required-icons — NEW v0.5.3** |
|
|
871
|
+
|
|
872
|
+
Verification: 95 components scanned; 0 drift. The 12 auto-stamping primitives all match yaml ↔ class.js ↔ runtime.
|
|
873
|
+
|
|
874
|
+
Heuristic limitations (documented in script header): computed icon names (`setAttribute('name', this.icon)`), trait-emitted icons, and JSDoc/comment example references are filtered or reported as "unresolvable" — manual audit applies.
|
|
875
|
+
|
|
876
|
+
### Added — `responsive-shell-sidebar` pattern (§157, FEEDBACK-06 §3 P1, v0.5.3)
|
|
877
|
+
|
|
878
|
+
New pattern at `packages/web-components/patterns/responsive-shell-sidebar/` documents the dual-mount editor-shell sidebar recipe: inline panels at `>900px` viewports, drawer twins below. FEEDBACK-06 §3 reported color-app hand-rolling ~40 LOC of CSS + state plumbing for exactly this pattern in Tokens Studio.
|
|
879
|
+
|
|
880
|
+
**The pattern** ships:
|
|
881
|
+
|
|
882
|
+
- `.wide-only` / `.narrow-only` CSS convention (display: contents / display: none with breakpoint media query)
|
|
883
|
+
- Dual-mount inline sidebars (wrapped in `.wide-only`) + drawer twins outside shell slots
|
|
884
|
+
- Toolbar trigger buttons (inside `.narrow-only`) opening the drawer twins
|
|
885
|
+
- **MediaQueryList listener** that auto-closes drawers on viewport widening (the gap FEEDBACK-06 §3 flagged for the peer agent)
|
|
886
|
+
- Signal-based state sharing recipe (single signal source, parent reads `.value` once, passes to both mount points)
|
|
887
|
+
- Dual-mount caveat documented (signal-bound = safe; local-DOM-state = lost on resize)
|
|
888
|
+
- v0.6.0 graduation path noted: Option A `<editor-sidebar responsive-breakpoint="900">` built-in attribute deferred pending editor-shell + pane-ui semantics audit + paired `<show-when breakpoint>` trait
|
|
889
|
+
|
|
890
|
+
Per FEEDBACK-06 §3's "Option B is cheaper landing and matches the existing pattern catalog" framing. Option A graduation lives in v0.6.0 RFC.
|
|
891
|
+
|
|
892
|
+
Files added: `responsive-shell-sidebar.html` (shell + iframed examples), `responsive-shell-sidebar.examples.html` (working dual-mount + auto-close MQL + `data-chunk` annotations for corpus harvest), `responsive-shell-sidebar.css` (breakpoint grid + visibility rules), `README.md`.
|
|
893
|
+
|
|
894
|
+
### Fixed — yaml-events drift cleanup on 5 components + audit-script false-positive fix (§144 + §162, v0.5.3)
|
|
895
|
+
|
|
896
|
+
`npm run check:yaml-events` (audit slot 7, v0.5.1 §100a) reported 6 components with yaml/runtime drift after v0.5.2 §130's toast.close fix. §144 closed 4 of the 6 with hard-finding fixes; §162 (folded into the same v0.5.3 cycle) closes the remaining 2 via audit-script fixes that surfaced a real `<table-ui>` drift previously masked by false positives.
|
|
897
|
+
|
|
898
|
+
**§144 — Phantom events dropped** (yaml declared but runtime never dispatched):
|
|
899
|
+
|
|
900
|
+
- **`accordion`** — phantom `change` → dropped. Runtime dispatches `toggle { open: boolean }` (single-pane) which was undeclared in yaml. Replaced `change` block with proper `toggle` declaration + detail typing. Codegen regenerates `AccordionToggleEvent` with `{ open: boolean }` in `.d.ts`.
|
|
901
|
+
- **`canvas`** — 3 phantoms (`change`, `click`, `input`) → all dropped. Runtime dispatches only `canvas-interaction` (at canvas.js:50 + :167); the other three events were never bound.
|
|
902
|
+
- **`card`** — phantom `drag-end` → dropped. No runtime drag-end dispatch in card class. (`<row-ui>` had the same yaml drag-end but also no dispatch — fixed in same arc.)
|
|
903
|
+
- **`row`** — phantom `drag-end` → dropped. Same as card; trait-emitted events may dispatch from droppable trait but not card/row directly.
|
|
904
|
+
|
|
905
|
+
**§162 — Audit-script false-positive fix + table `row-collapse` declared**:
|
|
906
|
+
|
|
907
|
+
The audit's runtime-event extractor used a single regex with `[\s\S]*?detail\s*:\s*(\{[^{}]*\}|...)` between event name and detail. Two bugs: (a) `[^{}]*` couldn't parse `detail: { filters: {} }` (nested braces); the lazy `[\s\S]*?` then greedy-expanded across multiple `dispatchEvent` calls, falsely cross-attributing the NEXT sibling's `detail:` to the current event. (b) `detail: { ...conn }` was parsed as field-named `conn` rather than treating the spread as opaque. Rewritten as a brace-balanced walker with explicit spread detection.
|
|
908
|
+
|
|
909
|
+
- **`noodles`** — false positive cleared. `noodle-connect`/`noodle-disconnect` correctly emit `detail: { ...conn }` (spread); audit now treats spread as opaque and skips comparison (matches the script's "variable detail" handling).
|
|
910
|
+
- **`table`** — false positive cleared AND real drift surfaced + fixed. Pre-§162 the audit reported `filter-change → runtime emits {index, row}` (over-matched from row-expand). Post-§162 the audit honestly found a NEW real drift: `<table-ui>.dispatchEvent(new CustomEvent('row-collapse', { detail: { index, row } }))` at table/class.js:235 was undeclared in yaml (only `row-expand` was declared). Added `row-collapse` declaration mirroring `row-expand`'s shape. Codegen regenerates `TableRowCollapseEvent` + `{ index: number, row: object }` in `.d.ts`.
|
|
911
|
+
|
|
912
|
+
`check:yaml-events` now reports **0 findings of any kind** — first fully-clean run since the audit's v0.4.9 §99g + v0.5.0 §100a graduation. **All 6 components from the §130 drift report are now resolved**; v0.5.4 follow-up dropped (no remaining cleanup arc).
|
|
913
|
+
|
|
914
|
+
### Added — `<slider-ui>` function-typed `.value` dev-mode guard (§153, FEEDBACK-07 §3 P1, v0.5.3)
|
|
915
|
+
|
|
916
|
+
FEEDBACK-07 §3 reported that `slider-ui .value=${() => Math.round(gen.lightness * 100)}` silently stored the arrow function as the property value — thumb stayed at 0% with no error or console output. Root cause: `slider-ui` reads `this.value` synchronously in `render()`; the framework's `isFn` branch normally wraps functions in `effect()` and calls them, but the wrap is bypassed when consumers assign imperatively (`sliderEl.value = fn`) or when a non-AdiaUI binding system doesn't recognize the function-as-value convention.
|
|
917
|
+
|
|
918
|
+
**Fix**: `slider-ui` `render()` checks `typeof this.value === 'function'` and emits a descriptive `console.warn` naming the two correct patterns:
|
|
919
|
+
|
|
920
|
+
```
|
|
921
|
+
[slider-ui] .value received a function. Did you mean:
|
|
922
|
+
.value=${fn()} ← call the function to get the current value
|
|
923
|
+
.value=${signal.value} ← read the signal's current value
|
|
924
|
+
Functions are not auto-invoked at render time; the slider reads
|
|
925
|
+
.value synchronously. See USAGE.md "Reactive binding" for the
|
|
926
|
+
parent-template-re-read pattern that works across frameworks.
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
Plus: `return` early from render so the slider doesn't NaN-math the function ref into a 0% position. Subsequent property assignments (with a numeric value) trigger re-render normally.
|
|
930
|
+
|
|
931
|
+
**Docs**: USAGE.md "Derived reactive bindings" subsection updated with a note about the dev-mode guard + the two fix patterns. The pre-existing `() => signal.value * 100` reactive pattern docs are unchanged — they correctly described Pattern A; the guard catches Pattern B (imperative-set with function ref).
|
|
932
|
+
|
|
933
|
+
§153c (deferred to v0.5.4+): generic `UIFormElement`-level guard at the framework's `installProps()` site that warns for ANY Number/Boolean-typed property assigned a function. Larger change requires audit of edge cases (e.g. computed signals that look function-ish); deferred.
|
|
934
|
+
|
|
935
|
+
### Added — `<drawer-ui>` `close` event detail carries `reason` (§156, FEEDBACK-06 §2 P2, v0.5.3)
|
|
936
|
+
|
|
937
|
+
`<drawer-ui>` previously dispatched a plain `Event('close', { bubbles: true })` with no detail — and the `.d.ts` lied (declared `CustomEvent<unknown>` while the runtime was actually `Event`). FEEDBACK-06 §2 asked for typed `detail.reason` so consumers can distinguish dismiss-intent (escape / backdrop) from explicit (close-button) from programmatic.
|
|
938
|
+
|
|
939
|
+
**New type** in `drawer.d.ts`:
|
|
940
|
+
|
|
941
|
+
```ts
|
|
942
|
+
export type DrawerCloseReason = 'escape' | 'backdrop' | 'close-button' | 'programmatic';
|
|
943
|
+
export interface DrawerCloseEventDetail { reason: DrawerCloseReason; }
|
|
944
|
+
export type DrawerCloseEvent = CustomEvent<DrawerCloseEventDetail>;
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
Runtime captures the reason at each entry point (`#closeReason` private field set in `#onPress` / `#onDialogCancel` / `#onDialogClick`); `#onDialogClose` reads + resets the field, then dispatches `new CustomEvent('close', { detail: { reason }, bubbles: true })`. After dispatch the field resets to `'programmatic'` so a subsequent `.open = false` from consumer code doesn't inherit a stale event-driven reason.
|
|
948
|
+
|
|
949
|
+
`drawer.yaml` `events.close.detail.reason` declares the 4-value enum so codegen produces the typed literal union in `.d.ts`. `check:yaml-events` audit (slot 7) confirms yaml ↔ runtime alignment.
|
|
950
|
+
|
|
951
|
+
**Migration**: existing consumers reading `e.detail` from the `close` event got `undefined` (and TypeScript said `unknown`). Now they get `{ reason: DrawerCloseReason }` (and TS narrows to the literal union). Existing code that ignored `detail` continues to work unchanged. Same shape becomes a template for any future `modal-ui` / `popover-ui` close events.
|
|
952
|
+
|
|
953
|
+
### Fixed — Template `inTag()` HTML-comment handling (§155, FEEDBACK-06 §1 P0, v0.5.3)
|
|
954
|
+
|
|
955
|
+
`packages/web-components/core/template.js` `inTag()` previously tracked `<`, `>`, `'`, `"` to decide whether each `${…}` placeholder was in tag-position (substitute `{{p:N}}`) or content-position (substitute `<!--p:N-->`). The walker had no HTML-comment awareness — an apostrophe inside `<!-- foo's bar -->` put `q=1` (single-quoted-string state), masked the `-->` closer, and silently mis-classified every subsequent placeholder.
|
|
956
|
+
|
|
957
|
+
FEEDBACK-06 §1 reproduced the bug end-to-end: an explanatory comment containing `<editor-shell>'s named slots` produced post-classification garbage `<segmented-ui .value=<!--p:10--> …>`; the DOM parser ate the trailing `>` of the substituted comment; `scan()` found no part registered at index 10; `update()` fell through the `isFn` branch and invoked the consumer's arrow handler with no arguments → `Cannot read properties of undefined (reading 'detail')` crash at mount, with a stack trace pointing at user code (not framework code).
|
|
958
|
+
|
|
959
|
+
**Fix**: skip HTML comments wholesale before the quote/tag walker runs. Comments cannot open a tag and cannot contain real string delimiters as far as the live HTML parser is concerned. Unterminated comments fall through to `last = 0` (content-position; safe default). ~15 LOC inside `inTag()`. Adopted FEEDBACK-06 §1's proposed patch verbatim.
|
|
960
|
+
|
|
961
|
+
Symptom class closed: any template literal with an HTML comment containing an apostrophe (or any unmatched quote char) no longer mis-classifies subsequent placeholders. The "handler called with `e === undefined`" crash class is gone.
|
|
962
|
+
|
|
963
|
+
**Companion (deferred)**: the same heuristic also doesn't model `<![CDATA[ … ]]>` blocks or `<script>`/`<style>` raw-text content (FEEDBACK-06 §1 closing note). Deferred to v0.5.4 unless a confirmed bug class surfaces. Comment-skip handles the observed FEEDBACK-06 case.
|
|
964
|
+
|
|
965
|
+
### Added — Template partial-attribute interpolation runtime guard (§152, FEEDBACK-07 §2 P0, v0.5.3)
|
|
966
|
+
|
|
967
|
+
`packages/web-components/core/template.js` `scan()` previously skipped attributes whose value didn't match the full-attr regex `^\{\{p:(\d+)\}\}$`. Partial interpolation like `style="background:${a}; color:${b}"` (post-concat: `"background:{{p:0}}; color:{{p:1}}"`) silently failed — no part registered, the literal `{{p:N}}` text reached the DOM as the attribute's static value. FEEDBACK-07 §2 reported color swatches rendering as empty black squares from exactly this pattern.
|
|
968
|
+
|
|
969
|
+
**Fix**: scan() now detects `{{p:` substrings inside non-matching attribute values + emits a descriptive `console.warn` naming the element + attribute + first 80 chars of the value + the three supported binding modes. Warn (not throw) because hot template paths fire many times — a thrown error would crash render; the warn surfaces the bug class loudly without breaking the page.
|
|
970
|
+
|
|
971
|
+
**Docs**: USAGE.md "Property binding patterns" section grows a "Template attribute bindings" subsection documenting the three modes (`attr="${value}"` full-replacement, `.prop=${value}` property assignment, partial-interpolation not supported) with the `style="background:${a}; color:${b}"` example reproduced from FEEDBACK-07.
|
|
972
|
+
|
|
973
|
+
No behavior change for templates that were already correct (full-attr placeholders). Behavior change only for previously-silent-failing partial-attr templates: now they warn loudly + still render the garbage `{{p:N}}` text (so the symptom is recoverable). Consumers should fix their templates to use one of the three documented modes.
|
|
974
|
+
|
|
975
|
+
### Fixed — CodeMirror transitive dep declarations (§151, FEEDBACK-07 §1 P0, v0.5.3)
|
|
976
|
+
|
|
977
|
+
`packages/web-components/package.json` previously declared only `@adia-ai/a2ui-runtime` in `dependencies`. The `components/code/code-editor.js` source static-imports 6 packages (`@codemirror/state`, `@codemirror/view`, `@codemirror/commands`, `@codemirror/language`, `@codemirror/lint`, `@lezer/highlight`) and dynamic-imports 6 more (`@codemirror/lang-{javascript,json,css,html,markdown,yaml}`). None were declared. Consumer builds (Vite/Rolldown/esbuild) failed with cascading `Failed to resolve import` errors on `@adia-ai/web-components` install, requiring 12 manual `npm install` commands per FEEDBACK-07 §1.
|
|
978
|
+
|
|
979
|
+
**Fix**: hybrid declaration — 6 always-loaded packages as `dependencies`; 6 `@codemirror/lang-*` packages as `optionalDependencies` (lazy-imported only when the `language` prop is set). `optionalDependencies` is the right shape because `npm install` doesn't error on missing optionals, but the consumer who passes `language="json"` (etc.) gets a clear missing-optional-dep message at runtime instead of a silent dynamic-import failure.
|
|
980
|
+
|
|
981
|
+
Consumers affected: anyone importing `@adia-ai/web-components` whose bundler resolves the `code-editor.js` chunk (side-effect-imported via the barrel). Pre-fix workaround: 12 manual `npm install @codemirror/* @lezer/highlight` commands. Post-fix: `npm install @adia-ai/web-components` resolves all 6 core deps automatically + the lang-* on first use of the `language` prop.
|
|
982
|
+
|
|
983
|
+
No runtime behavior change.
|
|
984
|
+
|
|
985
|
+
### Fixed — `installIconLoaders` tolerates non-canonical loader-map key paths (§140, v0.5.3-staged)
|
|
986
|
+
|
|
987
|
+
FEEDBACK-06 from color-app reported `installIconLoaders` → `warnMissingIcon` firing for `caret-right` / `x` / `caret-up-down` even though the consumer had installed a loader map. Root cause: `resolveLoader()` only looked up loaders by the canonical `/node_modules/@phosphor-icons/core/assets/<weight>/<filename>` path. When the consumer's Vite root, package manager (pnpm hoist), or manually-built loader map produced keys with a different prefix — e.g. `/node_modules/.pnpm/@phosphor-icons+core@.../node_modules/.../assets/regular/caret-right.svg` — the lookup missed silently + the warn fired at install time.
|
|
988
|
+
|
|
989
|
+
**Fix**: `resolveLoader()` adds a filename-suffix fallback. The fast path still tries the canonical phosphor path first (O(1), preserves chat-ui dev convention); on miss, scans the weight's module map for any key ending with `/<filename>` (O(N), but only on miss). Same two-step shape for the `-fill` back-compat name suffix. Public API unchanged; only internal lookup logic.
|
|
990
|
+
|
|
991
|
+
Consumers affected: any project that calls `installIconLoaders()` with a loader map whose keys aren't prefixed with `/node_modules/@phosphor-icons/core/assets/`. Examples: pnpm projects, projects with custom Vite roots, projects with manually-built loader maps using brace-list globs over absolute paths.
|
|
992
|
+
|
|
993
|
+
New tests: `packages/web-components/core/icons.test.js` (12 cases) — covers canonical fast path, pnpm-style prefix, custom Vite root, manually-built map, `-fill` back-compat (both paths), non-regular weights, alias resolution via suffix, DOM re-stamp end-to-end, and miss-on-both-paths. Full vitest suite 787/787 (+12 new). No public-API change; soft-internal change only.
|
|
994
|
+
## [0.5.2] - 2026-05-13
|
|
995
|
+
|
|
996
|
+
### Changed — `toast.yaml` drops phantom `events.close` declaration (§130, v0.5.2)
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
`packages/web-components/components/toast/toast.yaml` previously declared `events: { close: { description: "Fired when the toast is dismissed via click or auto-timeout", ... } }` — but the 92-line runtime is a thin facade over `<feed-ui>` (since v0.4.7 §82) and never dispatched the `close` event. Codegen pipeline (yaml → `.a2ui.json` x-adiaui.events → `.d.ts` `ToastCloseEvent` + `ToastCloseEventDetail` types) was emitting type surfaces for an event that never fired. Same drift class as v0.4.8 §90 (color-picker phantom `format-change`).
|
|
1000
|
+
|
|
1001
|
+
**Migration**: zero consumer impact — `<toast-ui>.addEventListener('close', handler)` already silently never fired; consumers wanting close-event semantics wire it on the host `<feed-ui>` where the lifecycle actually lives.
|
|
1002
|
+
|
|
1003
|
+
Companion regen via `npm run components --force`:
|
|
1004
|
+
- `toast.a2ui.json` — `x-adiaui.events` block scrubbed
|
|
1005
|
+
- `toast.d.ts` — `ToastCloseEvent` + `ToastCloseEventDetail` types stripped
|
|
1006
|
+
- Catalog `catalog-a2ui_0_9.json` — Toast component events block synced (regen ride-along)
|
|
1007
|
+
|
|
1008
|
+
Type API change technically MAJOR-shaped under strict SemVer (consumer types narrow), but runtime behavior is identical → PATCH appropriate.
|
|
1009
|
+
## [0.5.1] - 2026-05-13
|
|
1010
|
+
|
|
1011
|
+
_Lockstep ride-along (no source change)._
|
|
1012
|
+
## [0.5.0] - 2026-05-13
|
|
1013
|
+
|
|
1014
|
+
**v0.5.0-staged** — staged for the next minor cut.
|
|
1015
|
+
|
|
1016
|
+
### Fixed — `core/element.d.ts` missing runtime re-exports (§102, FEEDBACK-05 P1)
|
|
1017
|
+
|
|
1018
|
+
`core/element.js` re-exports the reactive + template helpers from sibling modules:
|
|
1019
|
+
|
|
1020
|
+
```js
|
|
1021
|
+
export { signal, computed, effect, batch, untracked, isSignal } from './signals.js';
|
|
1022
|
+
export { html, css, repeat } from './template.js';
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
`core/element.d.ts` only declared the `UIElement` class + a few interface types. The canonical USAGE.md import pattern:
|
|
1026
|
+
|
|
1027
|
+
```ts
|
|
1028
|
+
import { UIElement, html, signal, computed, effect } from '@adia-ai/web-components/core/element';
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
works at runtime but fails `tsc` with `TS2305: Module '"@adia-ai/web-components/core/element"' has no exported member 'html'` (etc.). Tokens Studio surfaced this in FEEDBACK-05 post-v0.4.9 upgrade — the only shim they still carried.
|
|
1032
|
+
|
|
1033
|
+
**Fix:** `core/element.d.ts` now mirrors the runtime re-exports:
|
|
1034
|
+
|
|
1035
|
+
```ts
|
|
1036
|
+
export { signal, computed, effect, batch, untracked, isSignal } from './signals.js';
|
|
1037
|
+
export type { ReadonlySignal, Signal, ComputedSignal, EffectOptions, EffectDisposer } from './signals.js';
|
|
1038
|
+
export { html, css, repeat } from './template.js';
|
|
1039
|
+
export type { TemplateResult } from './template.js';
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
Consumers can delete their `declare module` shim after upgrading.
|
|
1043
|
+
|
|
1044
|
+
Same drift class as v0.4.8 §90 (color-picker.d.ts) and v0.4.9 §91b / §98 (form-bearing `.d.ts` audit) — but in a `core/*` barrel, not a `components/*/<name>.d.ts`. The §98 audit covered the 17 form-bearing primitives' types; this surface was orthogonal and slipped past both sweeps.
|
|
1045
|
+
|
|
1046
|
+
### Added — `core/data-stream.d.ts` (NEW, §102 sibling-fix)
|
|
1047
|
+
|
|
1048
|
+
`core/index.js` explicitly re-exports `streams` + `whenStream` from `./data-stream.js` (the public surface of the attribute-driven data ingestion module). `core/data-stream.d.ts` didn't exist, so neither symbol was reachable via TypeScript through the core barrel. Authored `data-stream.d.ts` declaring `StreamEntry`, `streams` (`{ get, has, keys, size }`), and `whenStream(id): Promise<StreamEntry>`.
|
|
1049
|
+
|
|
1050
|
+
`core/index.d.ts` adds the matching `export { streams, whenStream } from './data-stream.js'` + `export type { StreamEntry }` so the core barrel's TypeScript surface matches the runtime exactly.
|
|
1051
|
+
|
|
1052
|
+
### Added — `scripts/release/check-core-barrel-dts.mjs` audit (§102)
|
|
1053
|
+
|
|
1054
|
+
New trip-wire to catch the FEEDBACK-05 drift class going forward. Walks every `packages/web-components/core/*.js` barrel, extracts explicit `export { … } from '…'` re-exports, compares against the sibling `.d.ts`. Flags runtime re-exports missing from the type barrel.
|
|
1055
|
+
|
|
1056
|
+
Heuristic limits documented in the script header:
|
|
1057
|
+
- Only matches `export { X, Y } from '…'` form. Misses `export * from '…'` re-bundles (covered by `tsc --strict` round-trips).
|
|
1058
|
+
- Type-only re-exports (`export type { X } from '…'`) match either form in the `.d.ts` — the audit only cares that the name is reachable.
|
|
1059
|
+
- Files without a sibling `.d.ts` are skipped (codegen'd elsewhere or genuinely typeless).
|
|
1060
|
+
|
|
1061
|
+
Wired as `npm run check:core-barrel-dts`. The audit-script family now spans **7 trip-wires** (§72 check-no-live-readers + §81 check-changelog-coverage + §83 check-browser-safe + §84 behavioral composition-retrieval + §98 check-form-bearing-dts + §100a check-yaml-events-vs-runtime + §102 check-core-barrel-dts).
|
|
1062
|
+
## [0.4.9] - 2026-05-13
|
|
1063
|
+
|
|
1064
|
+
### Added — `<swatch-ui>` multi-badge + auto-contrast label (§99a + §99b)
|
|
1065
|
+
|
|
1066
|
+
Two follow-on enhancements to the v0.4.9 §91a swatch extension. **§99a multi-badge** — `[badge]` now parses comma- or space-separated variant lists; multiple pips render side-by-side in the upper-right (each with its own semantic color + `aria-label`). Each pip stamps as `<span data-badge-variant="X">` so per-variant CSS targets a stable selector. Diff-on-change re-render — no tear-down on no-op renders. **§99b auto-contrast** — new `[auto-contrast]` boolean reflected prop. When set on `shape="block"`, JS computes the swatch color's OKLab lightness via a 1px canvas probe + stamps `[data-on-light]` or `[data-on-dark]` on the label element. CSS swaps `--swatch-label-fg` accordingly (threshold 0.62, WCAG-aligned for sRGB). Detail line follows the label's choice via sibling combinator. Only applies to `shape="block"` where the label sits ON the tile. Handles every CSS color form the browser parses (oklch / hex / hsl / named / var() refs). Backwards compat preserved — both default off.
|
|
1067
|
+
|
|
1068
|
+
### Added — `<color-picker-ui>` generation constraints (§100b, FEEDBACK-02 #7)
|
|
1069
|
+
|
|
1070
|
+
Closes consumer-friction item #7 from `FEEDBACK-02--adia-packages--2026-05-12.md`. Six new props let consumers constrain the picker to a generation context:
|
|
1071
|
+
|
|
1072
|
+
- `[max-chroma]` (number, default `Infinity`) — clamp OKLCH chroma channel to at most this value.
|
|
1073
|
+
- `[max-l]` (number, default `1`) — clamp OKLCH lightness to at most this value.
|
|
1074
|
+
- `[min-l]` (number, default `0`) — clamp OKLCH lightness to at least this value (symmetric companion to `[max-l]`).
|
|
1075
|
+
- `[hue-drift-max]` (number, default `NaN`) — max signed-shortest-path hue deviation in degrees from `[base-hue]`. Wrap-aware — a drift of 350° resolves as -10°.
|
|
1076
|
+
- `[base-hue]` (number, default `NaN`) — reference hue for `[hue-drift-max]`; falls back to the picker's hue at first commit so consumers can pre-seed `[value]` and constrain drift from that initial value.
|
|
1077
|
+
|
|
1078
|
+
Clamps run BEFORE the gamut-mapping pass in `#commit()` so consumer-declared bounds win even when the user's drag would otherwise be in-gamut.
|
|
1079
|
+
|
|
1080
|
+
**One new event** — `constraint-clamp` — fires immediately before `change` / `input` when one or more axes were clamped. `detail.clamps` is a non-empty array of `{ axis, requested, clamped, reason }` records. `axis` is `"l" | "c" | "h"`; `reason` names the triggering prop (`max-l` / `min-l` / `max-chroma` / `hue-drift-max`). Consumers can surface UX feedback (toast, validity warning, scope-drift indicator) without polling.
|
|
1081
|
+
|
|
1082
|
+
Types: `ColorPickerClampRecord`, `ColorPickerConstraintClampEventDetail`, `ColorPickerConstraintClampEvent` added to `color-picker.d.ts` + re-exported from the package barrel.
|
|
1083
|
+
|
|
1084
|
+
### Added — yaml event-detail blocks across 26 non-form-bearing primitives (§100c)
|
|
1085
|
+
|
|
1086
|
+
Closes the v0.5.x captured item "x-adiaui.events detail-type sidecar → typed `CustomEvent<DetailShape>`". The §80 codegen reads `events.<name>.detail` from each yaml; pre-§100c, ~77% of non-form events had only a `description:` and codegen emitted `CustomEvent<unknown>`. The sweep authored structured `detail:` blocks for 30 events across 26 yamls:
|
|
1087
|
+
|
|
1088
|
+
action-list, agent-artifact, agent-feedback-bar, agent-questions, agent-reasoning (×3), agent-suggestions, agent-trace, chart-legend, command, demo-toggle, list, menu, nav, nav-group, nav-item, pagination, swiper (×2), tabs, tag, toggle-group, toggle-scheme, tree, chat-thread, link, stream, noodles (×2). Plus manual fixes for: timeline (yaml said `{ id, open }` but runtime emits `{ expanded }` — drift fix); table (added `filter-change` + `row-expand`); chart (added `legend-update`); heatmap (added chart-hover/leave/select signal-only re-emissions).
|
|
1089
|
+
|
|
1090
|
+
After regen, codegen now produces `CustomEvent<<NamedDetail>>` types for 30+ additional events. TypeScript consumers reading event details get typed access instead of `unknown`.
|
|
1091
|
+
|
|
1092
|
+
### Added — `cross_package_composes:` yaml block + check-composes-coverage extension (§99d)
|
|
1093
|
+
|
|
1094
|
+
Graduates the hardcoded `CROSS_PACKAGE_ALLOWLIST` from `check-composes-coverage.mjs` to a yaml-driven block. Each component yaml gains an optional `cross_package_composes:` block naming primitives in other `@adia-ai/*` packages it composes:
|
|
1095
|
+
|
|
1096
|
+
```yaml
|
|
1097
|
+
# canvas.yaml
|
|
1098
|
+
composes: [] # same-package siblings (none)
|
|
1099
|
+
cross_package_composes:
|
|
1100
|
+
- tag: a2ui-root
|
|
1101
|
+
from: '@adia-ai/web-modules/runtime'
|
|
1102
|
+
note: Hosts A2UI rendering. Required when canvas mounts content.
|
|
1103
|
+
- tag: theme-ui
|
|
1104
|
+
from: '@adia-ai/web-modules/theme'
|
|
1105
|
+
note: Optional — only read when [theme-wrapper] is set.
|
|
1106
|
+
```
|
|
1107
|
+
|
|
1108
|
+
The audit script reads the block at scan time + drops matching tags from the "undeclared composition" finding set. Future cross-package compositions need only their tag declared in yaml — no script change required.
|
|
1109
|
+
|
|
1110
|
+
### Changed — `<editor-sidebar>` `[name]` → `[persist]` template sweep (§99c)
|
|
1111
|
+
|
|
1112
|
+
Two occurrences in `apps/genui/app/a2ui-editor/a2ui-editor.contents.html` migrated to model the preferred shape. `[name]` continues to work via the v0.4.9 §91c back-compat alias path. Surveyed via background Explore agent; no other `[name]` occurrences across `apps/`, `playgrounds/`, `catalog/`, or `site/`.
|
|
1113
|
+
|
|
1114
|
+
### Audit summary — non-form primitives' yaml events vs runtime (§100a)
|
|
1115
|
+
|
|
1116
|
+
New `scripts/release/check-yaml-events-vs-runtime.mjs` companion to peer's §98 `check-form-bearing-dts.mjs`. Walks every non-form-bearing component, greps `class.js` for dispatch literals, parses yaml `events:` blocks + detail sub-blocks, reports phantom yaml events / undeclared runtime events / detail drift. Wired as `npm run check:yaml-events`. Heuristic limits accepted + documented in the script header (trait-emitted events, computed event names, variable-detail helpers).
|
|
1117
|
+
|
|
1118
|
+
### Fixed — `color-picker.d.ts` event detail shape mismatch (§90, FEEDBACK-04 P0)
|
|
1119
|
+
|
|
1120
|
+
Closes FEEDBACK-04 claim #2 — a consumer's 70-line `renderSwatch()` helper composing background color, key label, gamut/contrast badge, copy-to-clipboard, and keyboard-select collapses to a single declarative tag:
|
|
1121
|
+
|
|
1122
|
+
```html
|
|
1123
|
+
<swatch-ui
|
|
1124
|
+
shape="block" size="lg"
|
|
1125
|
+
color="oklch(0.53 0.18 240)"
|
|
1126
|
+
label="500"
|
|
1127
|
+
detail="oklch(0.53 0.18 240)"
|
|
1128
|
+
badge="apca-pass"
|
|
1129
|
+
copyable
|
|
1130
|
+
selectable
|
|
1131
|
+
></swatch-ui>
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
**Six new props** (all additive — existing consumers unchanged):
|
|
1135
|
+
|
|
1136
|
+
- `badge` — enum `"" | "out-of-gamut" | "p3-only" | "apca-pass" | "apca-fail"`. Renders △ / ✦ / ✓ / ✗ in the upper-right of the tile with semantic color + `aria-label` for screen readers (e.g. "Outside sRGB gamut", "Contrast passes APCA").
|
|
1137
|
+
- `detail` — secondary line of text below the label. Typically the raw token value (e.g. `oklch(0.53 0.18 240)`) when the swatch represents a design-token step.
|
|
1138
|
+
- `copyable` — boolean. Renders an inline copy-to-clipboard button (⧉ → ✓ on success, ⚠ on failure; auto-resets after 1.2s). Uses `navigator.clipboard.writeText`.
|
|
1139
|
+
- `copy-value` — string. Override what gets copied; defaults to `[color]`.
|
|
1140
|
+
- `selectable` — boolean. Makes the host keyboard-focusable + clickable. Sets `role="button"` + `tabindex="0"`; wires Enter / Space activation.
|
|
1141
|
+
- `selected` — boolean reflected. Visual selected state with focus ring; sets `aria-pressed`.
|
|
1142
|
+
|
|
1143
|
+
**One new event:**
|
|
1144
|
+
|
|
1145
|
+
- `select` — fires when a selectable swatch is activated (click / Enter / Space). `detail: { value, color, label }` where `value` is `[color]` (or `[label]` as fallback).
|
|
1146
|
+
|
|
1147
|
+
**CSS variants added** under the existing `@scope (swatch-ui)` block: badge tokens (`--swatch-badge-*`), copy-button tokens (`--swatch-copy-*`), select-ring tokens (`--swatch-select-ring*`). Per-badge color uses semantic tones — out-of-gamut maps to `--a-warning`, apca-pass to `--a-success`, etc.
|
|
1148
|
+
|
|
1149
|
+
**Backwards compat:** every new prop defaults off / empty. Existing usage (`<swatch-ui shape="dot" color="..." label="...">`) is byte-equivalent in stamping and behavior.
|
|
1150
|
+
|
|
1151
|
+
**Migration for the Tokens Studio FEEDBACK-04 #2 helper:**
|
|
1152
|
+
|
|
1153
|
+
```diff
|
|
1154
|
+
- const swatch = renderSwatch({ color, label, badge, copyValue, selected })
|
|
1155
|
+
- // ...70 LOC of manual stamping + badge SVG + copy state + a11y
|
|
1156
|
+
+ html`<swatch-ui
|
|
1157
|
+
+ shape="block" size="lg"
|
|
1158
|
+
+ color=${color} label=${label} detail=${detail}
|
|
1159
|
+
+ badge=${gamutBadge} copyable selectable
|
|
1160
|
+
+ ?selected=${selected.value}
|
|
1161
|
+
+ @select=${(e) => onSelect(e.detail.color)}
|
|
1162
|
+
+ ></swatch-ui>`
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
### Added — `complete` event declaration on `<otp-input-ui>` (§91b, audit sweep)
|
|
1166
|
+
|
|
1167
|
+
§90 audit recipe applied to all 17 form-bearing primitives. `otp-input.d.ts` was missing the `complete` event declaration even though the runtime has emitted it at `class.js:156` since the primitive shipped — fires once when the user fills the last digit slot with `detail: { value: combined }`. Added `OtpInputCompleteEvent` + `OtpInputCompleteEventDetail` types + the `addEventListener('complete', ...)` overload. Also fixed `otp-input.yaml` `events.complete.description` — said "Detail contains { code }" but actual emission is `{ value }`; updated description + added `detail:` block matching the runtime.
|
|
1168
|
+
|
|
1169
|
+
### Added — `save` + `language-load-error` event declarations on `<code-ui>` (§91b, audit sweep)
|
|
1170
|
+
|
|
1171
|
+
Same audit. `code.d.ts` was missing two events the runtime has emitted since the primitive shipped:
|
|
1172
|
+
|
|
1173
|
+
- `save` (at `class.js:435`) — fires on Mod+S keybind; `cancelable: true`; `detail: { value }`.
|
|
1174
|
+
- `language-load-error` (at `class.js:226` and `:237`) — fires when CodeMirror's dynamic language-mode or core bundle fails to load; `detail: { phase: 'core' | 'language', language?: string, error: unknown }`.
|
|
1175
|
+
|
|
1176
|
+
Added `CodeSaveEvent` + `CodeSaveEventDetail` + `CodeLanguageLoadErrorEvent` + `CodeLanguageLoadErrorEventDetail` types + both `addEventListener` overloads. Re-exported from `packages/web-components/index.d.ts` barrel.
|
|
1177
|
+
|
|
1178
|
+
Also fixed `code.yaml`: removed a phantom `copy` event declaration (no runtime emission); added `detail:` blocks for the four real events (`input`, `change`, `save`, `language-load-error`).
|
|
1179
|
+
|
|
1180
|
+
### Audit summary — hand-authored `.d.ts` cleanliness as of v0.4.9
|
|
1181
|
+
|
|
1182
|
+
After §90 + §91b sweeps, **all 17 form-bearing primitives' hand-authored `.d.ts` files are runtime-matched.** Audit recipe captured in `docs/plans/0.4.9-release-plan.md` §91b for future cycles — automatable as `scripts/release/check-form-bearing-dts.mjs` in a later cycle if drift returns.
|
|
1183
|
+
|
|
1184
|
+
### Documentation — USAGE.md "Derived reactive bindings" subsection (§91d, FEEDBACK-04 #3)
|
|
1185
|
+
|
|
1186
|
+
Closes the last open FEEDBACK-04 item (claim #3, P2 — derived-reactive binding discoverability). The consumer narrative was explicit: *"This pattern is correct but discoverable only by reading the template engine source."* Pre-§91d, USAGE.md mentioned the eager-evaluation trap briefly but didn't ship the worked example with ✅/❌ markers that the consumer asked for.
|
|
1187
|
+
|
|
1188
|
+
New subsection at `USAGE.md § Property binding patterns › Derived reactive bindings` shows four patterns (two correct, two broken) with explicit annotations:
|
|
1189
|
+
|
|
1190
|
+
```js
|
|
1191
|
+
// ✅ Derived reactive — re-evaluates whenever minL changes
|
|
1192
|
+
html`<slider-ui .value=${() => minL.value * 100} min="0" max="100" />`
|
|
1193
|
+
// ✅ Direct signal — re-evaluates whenever minL changes
|
|
1194
|
+
html`<slider-ui .value=${minL} min="0" max="1" step="0.01" />`
|
|
1195
|
+
// ❌ Static snapshot — reads minL.value ONCE at render time; thumb never moves
|
|
1196
|
+
html`<slider-ui .value=${minL.value * 100} />`
|
|
1197
|
+
// ❌ Function as the value — slider receives the function object, not its result
|
|
1198
|
+
html`<slider-ui .value=${(v) => v * 100} />`
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
Plus a follow-on showing `computed()` as the documented alternative for complex derived values (memoized, stable handle, works in both `.prop=` bindings and `${…}` text bindings). Cross-links back to the existing "eager-evaluation trap" subsection.
|
|
1202
|
+
|
|
1203
|
+
**FEEDBACK-04 closure status:** 7/7 items addressed (P0 #1 §90 + P1 #2 §91a + P2 #3 §91d + P2 #4 §91b + P2 #5 §90 + P2 #6 §91c + P3 #7 deferred to v0.5.x as wishlist).
|
|
1204
|
+
|
|
1205
|
+
### Fixed — `color-picker.d.ts` event detail shape mismatch (§90, FEEDBACK-04 P0)
|
|
1206
|
+
|
|
1207
|
+
`FEEDBACK-04--adia-ui--2026-05-13.md` reported the consumer's listener typed as `{ hex, l, c, h }` but mistakenly believed the actual detail was `{ value, format }`. **Both were wrong** — the runtime (`class.js:414`) has always emitted `{ value, l, c, h, hex, oklch }`. The hand-authored `color-picker.d.ts` was the source of the consumer's `{ value, format }` belief — it had been stale since the runtime detail shape was extended.
|
|
1208
|
+
|
|
1209
|
+
**Fix:** updated `ColorPickerChangeEventDetail` to match the runtime:
|
|
1210
|
+
|
|
1211
|
+
```ts
|
|
1212
|
+
export interface ColorPickerChangeEventDetail {
|
|
1213
|
+
value: string; // format-respecting (hex when [format="hex"], oklch when [format="oklch"])
|
|
1214
|
+
l: number; // OKLCH lightness (0–1)
|
|
1215
|
+
c: number; // OKLCH chroma (0–~0.4)
|
|
1216
|
+
h: number; // OKLCH hue (0–360°)
|
|
1217
|
+
hex: string; // hex string (always present)
|
|
1218
|
+
oklch: string; // oklch string (always present)
|
|
1219
|
+
}
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
Also removed `ColorPickerFormatChangeEvent` + `ColorPickerFormatChangeEventDetail` from the exports — there is no `format-change` event in the runtime (`#commit()` only dispatches `'input'` and `'change'`). The dead type names are dropped from `index.d.ts` barrel; soft-breaking only for consumers that imported those type names (no runtime listener was firing anyway).
|
|
1223
|
+
|
|
1224
|
+
`ColorFormat` simplified from `'hex' | 'rgb' | 'hsl' | 'oklch'` to `'hex' | 'oklch'` to match the yaml + runtime (the two formats actually supported).
|
|
1225
|
+
|
|
1226
|
+
### Changed — color-picker.d.ts JSDoc surfaces the dual-form invariant
|
|
1227
|
+
|
|
1228
|
+
JSDoc on `ColorPickerChangeEventDetail` now explicitly states that `hex` and `oklch` are always populated regardless of the `[format]` setting — consumers reading the `.d.ts` see the invariant without needing to consult RESPONSE-02.
|
|
1229
|
+
## [0.4.8] - 2026-05-12
|
|
1230
|
+
|
|
1231
|
+
### Changed — `core/icons.js` split into pluggable registry + opt-in Phosphor side-effect (§89, v0.4.8)
|
|
1232
|
+
|
|
1233
|
+
Closes the `FEEDBACK-adia-packages-03.md` ask: every `<icon-ui name="X">` in a consumer app was pulling the entire Phosphor set (~1,500 icons × 6 weights = ~9,000 SVGs) through Vite's build pipeline, emitting **9,074 chunk files** and a **38 MB `dist/assets/`** even for apps rendering 2 icons. Root cause: `core/icons.js` ran six lazy `import.meta.glob('.../<weight>/*.svg')` calls at module load — Vite emits one code-split chunk per matched file regardless of usage.
|
|
1234
|
+
|
|
1235
|
+
**Split shape:**
|
|
1236
|
+
|
|
1237
|
+
- `core/icons.js` — registry surface only. Exports `registerIcon`, `registerIcons`, `getIcon`, `hasIcon`, `isIconName`, `listIcons`, `whenIconRegistryReady`, `installIconLoaders` (NEW), `ICON_WEIGHTS`. No top-level globs, no top-level side effects. Cheap to import.
|
|
1238
|
+
- `core/icons-phosphor.js` (NEW) — side-effect module that runs the six globs (Vite path) or the `icons-manifest.js` fetch (static-serving path) and installs the resulting loader map via `installIconLoaders()`.
|
|
1239
|
+
|
|
1240
|
+
**Three barrels side-effect-import `icons-phosphor.js` to preserve zero-config:**
|
|
1241
|
+
|
|
1242
|
+
- `index.js` — main barrel
|
|
1243
|
+
- `core/index.js` — core barrel
|
|
1244
|
+
- `components/index.js` — components barrel (used by site/docs)
|
|
1245
|
+
|
|
1246
|
+
**Consumer-facing impact:**
|
|
1247
|
+
|
|
1248
|
+
| Import path | Phosphor auto-loaded? | Bundle |
|
|
1249
|
+
|---|---|---|
|
|
1250
|
+
| `import '@adia-ai/web-components'` | ✅ Yes (unchanged) | full set |
|
|
1251
|
+
| `import '@adia-ai/web-components/core'` | ✅ Yes (unchanged) | full set |
|
|
1252
|
+
| `import '@adia-ai/web-components/components'` | ✅ Yes (unchanged) | full set |
|
|
1253
|
+
| `import '@adia-ai/web-components/components/button'` | ❌ **CHANGED** — was full set, now registry-only | scoped |
|
|
1254
|
+
|
|
1255
|
+
**Migration for piecemeal consumers** with bundle-size SLOs:
|
|
1256
|
+
|
|
1257
|
+
```js
|
|
1258
|
+
// Either: side-effect-import the full set explicitly
|
|
1259
|
+
import '@adia-ai/web-components/components/button';
|
|
1260
|
+
import '@adia-ai/web-components/core/icons-phosphor';
|
|
1261
|
+
|
|
1262
|
+
// Or: register only the icons you use (brace-list glob = static-analyzed → N chunks)
|
|
1263
|
+
import '@adia-ai/web-components/components/button';
|
|
1264
|
+
import { installIconLoaders } from '@adia-ai/web-components/core/icons';
|
|
1265
|
+
installIconLoaders({
|
|
1266
|
+
regular: import.meta.glob(
|
|
1267
|
+
'/node_modules/@phosphor-icons/core/assets/regular/{caret-right,caret-up-down,moon,sun}.svg',
|
|
1268
|
+
{ query: '?raw', import: 'default', eager: true }
|
|
1269
|
+
),
|
|
1270
|
+
});
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
`installIconLoaders` accepts the `import.meta.glob` output shape (`{ '/path/to/star.svg': loader }`) and supports both eager (loader = SVG string) and lazy (loader = `() => Promise<string>`) globs. Calling it re-stamps any `<icon-ui>` elements that asked for an icon before loaders arrived.
|
|
1274
|
+
|
|
1275
|
+
**Measured impact** (Tokens Studio consumer, 4-icon app, post-fix):
|
|
1276
|
+
|
|
1277
|
+
| Metric | Pre-fix | Post-fix (scoped) |
|
|
1278
|
+
|---|---|---|
|
|
1279
|
+
| Files emitted under `dist/assets/` | ~9,074 | ~10 (target — verified consumer-side) |
|
|
1280
|
+
| Total `dist/assets/` on disk | ~38 MB | ~30 KB (target) |
|
|
1281
|
+
| Main `index-*.js` post-tree-shake | 1.48 MB | ~50-100 KB (target) |
|
|
1282
|
+
|
|
1283
|
+
`sideEffects` array in `package.json` extends to include `./core/icons-phosphor.js` so the registration side effect survives tree-shaking under the documented zero-config paths.
|
|
1284
|
+
|
|
1285
|
+
### Added — `test/refactor-class-subpath.test.js` (§85b, v0.4.8)
|
|
1286
|
+
|
|
1287
|
+
Unit test pinning the v0.4.7 §77 class-subpath refactor's parser invariants. 158 LOC across 6 cases; synthetic feed-shaped input with one `extends` class + one no-`extends` utility class + module-level listener trailer; asserts the shim re-exports the listener trailer (post-§85a fix) AND that `class.js` does NOT (side-effect-free invariant). The bug class this pins: the §85a fix loosened `classRe` regex + made `generateShimFile` emit `parsed.trailer`; this test prevents future regressions on either path. Refactor script lives at `scripts/refactor/class-subpath.mjs`; the test lives here under `packages/web-components/test/` per project convention (the script's inputs are web-components-shaped).
|
|
1288
|
+
|
|
1289
|
+
### Added — event-types codegen for 38 non-form primitives (§80, v0.4.8)
|
|
1290
|
+
|
|
1291
|
+
Closes the v0.4.7 deferral from root CHANGELOG "Out of scope": typed event surfaces for non-form primitives. v0.4.6 §68 hand-authored event types for the 17 form-bearing primitives. v0.4.7 §74 added codegen'd property types for 73 non-form primitives but left events as base `CustomEvent` (untyped detail). v0.4.8 §80 fills the gap.
|
|
1292
|
+
|
|
1293
|
+
**What consumers see after upgrading:**
|
|
1294
|
+
|
|
1295
|
+
```ts
|
|
1296
|
+
import type { UIModal, UITimeline, TimelineToggleEvent } from '@adia-ai/web-components';
|
|
1297
|
+
|
|
1298
|
+
const modal = document.querySelector('modal-ui')!;
|
|
1299
|
+
modal.addEventListener('close', (e) => { /* e: CustomEvent<unknown> — name typed */ });
|
|
1300
|
+
|
|
1301
|
+
const timeline = document.querySelector('timeline-ui')!;
|
|
1302
|
+
timeline.addEventListener('timeline-toggle', (e: TimelineToggleEvent) => {
|
|
1303
|
+
const id: string = e.detail.id; // typed
|
|
1304
|
+
const open: boolean = e.detail.open; // typed
|
|
1305
|
+
});
|
|
1306
|
+
```
|
|
1307
|
+
|
|
1308
|
+
**Codegen extension:** `scripts/build/dts-codegen.mjs` (+89 LOC) reads `x-adiaui.events` from each component's `.a2ui.json` sidecar and emits:
|
|
1309
|
+
- `<Title><EventPascal>EventDetail` interface (when yaml `detail:` block is populated)
|
|
1310
|
+
- `<Title><EventPascal>Event = CustomEvent<<Detail>>` type alias (`unknown` detail if no `detail:` block)
|
|
1311
|
+
- Per-class `addEventListener` overloads (one generic `HTMLElementEventMap` overload + one specific per typed event)
|
|
1312
|
+
|
|
1313
|
+
Naming convention dedups doubled prefixes — `timeline-toggle` on `UITimeline` → `TimelineToggleEvent`, not `TimelineTimelineToggleEvent`.
|
|
1314
|
+
|
|
1315
|
+
**Yaml authoring scope was small.** 35 of the 38 non-form event-emitters already had yaml `events:` blocks. Only `feed`, `pane`, `timeline` had empty `events: {}` blocks needing population. Sidecar regen via `npm run build:components`.
|
|
1316
|
+
|
|
1317
|
+
**Tally:** 91 typed event aliases + 21 detail interfaces emitted across the 73 codegen'd `.d.ts` files. ~23% of events carry detail typing.
|
|
1318
|
+
|
|
1319
|
+
**Barrel surface — `export type {}` → `export *` per component.** `packages/web-components/index.d.ts` non-form section now re-exports via `export *`, so event type aliases + detail interfaces (e.g. `ModalCloseEvent`, `TimelineToggleEventDetail`) are reachable from the package root.
|
|
1320
|
+
|
|
1321
|
+
### Coverage closure — 90 of 95 primitives typed
|
|
1322
|
+
|
|
1323
|
+
| Primitive class | Property types | Event types |
|
|
1324
|
+
|---|---|---|
|
|
1325
|
+
| 17 form-bearing | ✅ v0.4.6 §68 (hand-authored) | ✅ v0.4.6 §68 (rich event detail types) |
|
|
1326
|
+
| 38 non-form event-emitters | ✅ v0.4.7 §74 (codegen) | ✅ **v0.4.8 §80 (this release — codegen)** |
|
|
1327
|
+
| 35 non-form non-emitters | ✅ v0.4.7 §74 (codegen) | n/a (no events to type) |
|
|
1328
|
+
| 5 CSS-only elements | n/a (no class) | n/a (no class) |
|
|
1329
|
+
|
|
1330
|
+
The codegen pipeline is now feature-complete for the typed-API surface. Future event additions: author yaml `events:` block → run `npm run build:components` + `npm run codegen:dts` → ship.
|
|
1331
|
+
## [0.4.7] - 2026-05-12
|
|
1332
|
+
|
|
1333
|
+
### Refactored — class.js helper extractions in agent + toolbar primitives (post-§77 follow-up)
|
|
1334
|
+
|
|
1335
|
+
Riding along on the §77 `<name>.js` → `class.js` split. Each affected primitive's class.js now hoists previously-inlined imperative DOM helpers to module scope for readability + reuse:
|
|
1336
|
+
|
|
1337
|
+
- **`agent-feedback-bar/class.js`** + **`agent-questions/class.js`** + **`agent-reasoning/class.js`** — `makeButton({ icon, text })` helper (small `<button-ui>` stamper with `variant="ghost" size="sm"` defaults). Replaces ~6 lines of inline `document.createElement` + `setAttribute` per stamp site.
|
|
1338
|
+
- **`toolbar/class.js`** — six new module-scope helpers + one constant: `SPILLOVER_LABEL_FLAG` attr, `isDivider(el)`, `humanizeIcon(name)` (kebab→Title Case fallback), `applySpilloverLabels(root)` + `stripSpilloverLabels(root)` (auto-label buttons when they spill into the overflow menu so menu items aren't icon-only), `outerWidth(el)` (rect + margins). Spillover now stamps `text` from `aria-label` || humanized `icon` so menu items carry readable labels.
|
|
1339
|
+
- **`table-toolbar/class.js`** — four new helpers + two thresholds: `emptyHint(text)` + `popoverHead(text)` (popover header/empty-state stampers), `getCellValue(row, col)` (accessor-or-key path resolver), `looksLikeIdKey(key)` (heuristic skip for `id`/`uuid`/`*Id` columns in filter generators), `SELECT_THRESHOLD = 50`, `SAMPLE_LIMIT = 500`.
|
|
1340
|
+
|
|
1341
|
+
No behavior change for default consumers (the helpers are pure factorings of existing inline logic). Pairs cleanly with §77 because the new class.js files were the natural home for these extractions.
|
|
1342
|
+
|
|
1343
|
+
### Added — `.d.ts` codegen for 73 non-form primitives (v0.4.7, §74)
|
|
1344
|
+
|
|
1345
|
+
Closes the v0.4.7 deferral from v0.4.6 §68 (`.d.ts` shipment was 17 of 95 primitives). After this release, **90 of 95** primitives that ship a JS class are now typed (the remaining 5 are CSS-only "elements" — `header`, `footer`, `section`, etc. — that have no class). TypeScript consumers now get:
|
|
1346
|
+
|
|
1347
|
+
- `document.querySelector('button-ui')` returns `UIButton` (not `Element`)
|
|
1348
|
+
- `createElement('card-ui')` returns `UICard`
|
|
1349
|
+
- Typed properties on every non-form primitive: `<button-ui>.size` is `'xs' | 'sm' | 'md' | 'lg' | 'xl'`, not `string`; `<card-ui>.variant` is the actual union; etc.
|
|
1350
|
+
- JSDoc descriptions surface in IDE tooltips
|
|
1351
|
+
|
|
1352
|
+
**Codegen script:** `scripts/build/dts-codegen.mjs` (~225 LOC; npm `codegen:dts` / `codegen:dts:dry`) reads each component's `.a2ui.json` sidecar (the v0.9 JSON Schema regenerated from `<name>.yaml` by `npm run components`) and emits a typed `<name>.d.ts` alongside `<name>.js` / `class.js`. Property types derive from JSON Schema: `enum` → string-literal union, `type: "string|number|boolean|object|array"` → primitive / `Record<string, unknown>` / array. The 17 form-bearing primitives (input, select, slider, range, textarea, switch, check, radio, segmented, search, otp-input, option-card, color-picker, rating, code, calendar-picker, upload) stay **hand-authored** because they carry rich event types (`CustomEvent<InputChangeEventDetail>` etc.) not representable in the sidecar; codegen explicitly skips them so re-runs don't overwrite the rich types.
|
|
1353
|
+
|
|
1354
|
+
**Barrel + tag-map:** `packages/web-components/index.d.ts` gets 73 new `export type { UI<X> }` re-exports + 73 new `HTMLElementTagNameMap` entries. The hand-authored "Note: only the typed primitives are listed here…" caveat is removed — every primitive that ships a class is now typed.
|
|
1355
|
+
|
|
1356
|
+
**Coordination with class subpath (§77):** `package.json`'s `./components/*/class` types entry maps to `./components/*/*.d.ts` (the per-component `.d.ts`) — so the class subpath gets typed automatically; no separate `class.d.ts` files needed.
|
|
1357
|
+
|
|
1358
|
+
### Added — non-side-effect `class` subpath per component (v0.4.7)
|
|
1359
|
+
|
|
1360
|
+
Closes the last roadmap item from the §61/§68 consumer-feedback arc (FEEDBACK-adia-packages.md, claim #7). Every component with an `<x-ui>` tag now ships a sibling `class.js` exporting the class **without** calling `customElements.define`. New subpath:
|
|
1361
|
+
|
|
1362
|
+
```js
|
|
1363
|
+
// Auto-register (default; tag registered immediately):
|
|
1364
|
+
import '@adia-ai/web-components/components/slider';
|
|
1365
|
+
|
|
1366
|
+
// Class import (no auto-register; consumer decides when to define):
|
|
1367
|
+
import { UISlider } from '@adia-ai/web-components/components/slider/class';
|
|
1368
|
+
```
|
|
1369
|
+
|
|
1370
|
+
**Use cases enabled:**
|
|
1371
|
+
- **Test isolation** — subclass + register under a unique per-test tag without clobbering the global `slider-ui` registration
|
|
1372
|
+
- **Tag-name override** — register `<my-slider>` for a subclass while `<slider-ui>` remains the canonical
|
|
1373
|
+
- **Selective composition** — import the class for inheritance without forcing tag registration on the host page
|
|
1374
|
+
|
|
1375
|
+
### Refactored — `packages/web-components/components/` (87 single-class + multi-class)
|
|
1376
|
+
|
|
1377
|
+
Mechanical refactor across all components with `customElements.define`:
|
|
1378
|
+
|
|
1379
|
+
**Before** — `<name>.js` had imports + class definition(s) + `customElements.define` calls + export.
|
|
1380
|
+
|
|
1381
|
+
**After** — split into two files:
|
|
1382
|
+
- **`class.js`** (NEW) — imports + class definition(s) with `export` keyword. No `customElements.define` call. Importing this file gives you the class without auto-registering. ~95% of the original LOC moves here verbatim.
|
|
1383
|
+
- **`<name>.js`** (REWRITTEN, ~17 LOC) — imports the class(es) from `./class.js` + imports `defineIfFree` from `../../core/register.js` + calls `defineIfFree('<tag>', UI<Name>)` per registered tag + re-exports the class(es). Preserves the auto-register subpath unchanged for existing consumers.
|
|
1384
|
+
|
|
1385
|
+
**Why `defineIfFree` not `customElements.define`?** Two reasons: (1) the file may be imported transitively from multiple paths after the refactor — `defineIfFree` (shipped in v0.4.6) is the conflict-safe variant that no-ops on duplicate registration. (2) Documented consumer-side pattern: when two packages register the same tag, `customElements.define` throws `NotSupportedError`; `defineIfFree` returns `false` gracefully.
|
|
1386
|
+
|
|
1387
|
+
**Skipped (5 files)** — `button.js` (refactored manually as the proof), `index.js` (barrel re-export), `code/code-editor.js` + `table/cell-types.js` (helpers, not components), plus 6 CSS-only directories (`section`, `stat`, etc.) that have no `.js` file. Components with multiple co-located `customElements.define` calls (menu/tree/timeline/avatar/etc., 11 total) have their multiple classes all moved to a single `class.js` with multiple `defineIfFree` calls in the shim.
|
|
1388
|
+
|
|
1389
|
+
**Script:** `scripts/refactor/class-subpath.mjs` — re-runnable parser that finds class boundaries via brace-counting, identifies `customElements.define` calls, and rewrites both files. Encoded for future similar refactors (per the §69 multi-`*` substitution memory).
|
|
1390
|
+
|
|
1391
|
+
### Changed — `package.json` exports
|
|
1392
|
+
|
|
1393
|
+
Added `./components/*/class` subpath with TypeScript types mapped to the existing per-primitive `.d.ts` files (no separate `.d.ts` per subpath needed — same class, same types):
|
|
1394
|
+
|
|
1395
|
+
```json
|
|
1396
|
+
"./components/*/class": {
|
|
1397
|
+
"types": "./components/*/*.d.ts",
|
|
1398
|
+
"default": "./components/*/class.js"
|
|
1399
|
+
}
|
|
1400
|
+
```
|
|
1401
|
+
|
|
1402
|
+
The 17 form-bearing primitives that received `.d.ts` files in v0.4.6 automatically get typed class imports under the new subpath. The ~80 non-form primitives (button, card, table, chart, popover, etc.) get codegen'd `.d.ts` via §74 in this same v0.4.7 release — typed class imports work for both subpaths from day one.
|
|
1403
|
+
|
|
1404
|
+
### Changed — `USAGE.md § Registration` updated
|
|
1405
|
+
|
|
1406
|
+
Removed the "FUTURE — not available yet (v0.4.7+)" caveat; documented the class subpath as shipped + added a test-isolation example showing how to register under a unique per-test tag via `defineIfFree`.
|
|
1407
|
+
|
|
1408
|
+
### Verification
|
|
1409
|
+
|
|
1410
|
+
| Gate | Result |
|
|
1411
|
+
|---|---|
|
|
1412
|
+
| `vitest packages/web-components` | 483 passed / 0 failed (byte-equivalent to pre-refactor — every existing test consumes the auto-register path, which still works) |
|
|
1413
|
+
| `node -e \"require.resolve(...)\"` for new subpaths | 4/4 representative paths resolve correctly (button/class, slider/class, menu/class multi-class, input/class) |
|
|
1414
|
+
| `customElements.define('tag', class)` not called when `./class` subpath imported alone | Verified — `class.js` files have zero side effects |
|
|
1415
|
+
| Component count post-refactor | 87 processed + 11 skipped (CSS-only / helpers / button-as-proof) = 98 component dirs; 87 paired with `class.js` |
|
|
1416
|
+
|
|
1417
|
+
### Changed — 17 component yamls populate `synonyms.tags` (§72)
|
|
1418
|
+
|
|
1419
|
+
The alias data that previously lived in `@adia-ai/a2ui-corpus/patterns/_components.json` (retired in §72 as the §65 carry-over from v0.4.6) has been folded into per-component yamls. 17 components touched: `calendar-picker`, `canvas`, `card`, `command`, `input`, `inspector`, `kbd`, `modal`, `otp-input`, `pane`, `pipeline-status`, `progress`, `richtext`, `segmented`, `swiper`, `switch` (plus `chat-thread` in `@adia-ai/web-modules`). Sidecars regenerated by `npm run components` carry the aliases under `x-adiaui.synonyms.tags`.
|
|
1420
|
+
|
|
1421
|
+
Four legacy-only alias entries from the retired `_components.json` were merged into their modern canonicals: `Chat` → `ChatThread` (alongside `chat-log` / `conversation` / `message-thread`), `Panel` → `Pane`, `SegmentedControl` → `Segmented`, `Toggle` → `Switch`.
|
|
1422
|
+
|
|
1423
|
+
### Coverage closure on FEEDBACK-adia-packages.md (final)
|
|
1424
|
+
|
|
1425
|
+
| # | Friction | Status |
|
|
1426
|
+
|---|---|---|
|
|
1427
|
+
| 1 | Typed events | ✅ v0.4.5 (CustomEvent.detail) + v0.4.6 (per-primitive `.d.ts`) |
|
|
1428
|
+
| 2 | `disconnected()` discoverability | ✅ v0.4.6 (USAGE.md § Lifecycle) |
|
|
1429
|
+
| 3 | Property reactivity discoverability | ✅ v0.4.6 (USAGE.md § Property reactivity) |
|
|
1430
|
+
| 4 | `.d.ts` shipment | ✅ v0.4.6 (19 files for 17 form-bearing primitives) + **v0.4.7 (73 codegen'd for non-form primitives — 90/95 total)** |
|
|
1431
|
+
| 5 | USAGE.md reference | ✅ v0.4.6 (430-line guide) |
|
|
1432
|
+
| 6 | CSS via package specifier | ✅ v0.4.5 |
|
|
1433
|
+
| 7 | Registration helpers + non-side-effect class import | ✅ **v0.4.7 (this release — class subpath)** + v0.4.6 (`defineIfFree`) |
|
|
1434
|
+
| 8 | Form-associated discoverability | ✅ v0.4.6 (USAGE.md § Form participation) |
|
|
1435
|
+
|
|
1436
|
+
**All 8 friction points from the original FEEDBACK doc are now closed.** The §61 meta-finding (5 of 8 traced to undiscoverable docs, not missing features) is fully resolved.
|
|
1437
|
+
## [0.4.6] - 2026-05-12
|
|
1438
|
+
|
|
1439
|
+
### Fixed — `<pane-ui>` resize tracking 1:1 + pointer-capture under touch
|
|
1440
|
+
|
|
1441
|
+
`<pane-ui>` resize handle previously delegated `pointermove`/`pointerup` to `document` (assuming the cursor stayed close to the handle). Two consequences: (a) on touch / fast pointer races the handle lost grip mid-drag; (b) cursor flicker around the 4-px handle as the browser swapped `col-resize` ↔ default. Refactored to handle-level listeners with `setPointerCapture()`:
|
|
1442
|
+
|
|
1443
|
+
- **Pointer capture on the resize grabber.** `setPointerCapture(pointerId)` is attempted (try/catch guards browsers without it); subsequent `pointermove` / `pointerup` / `pointercancel` listen on the grabber itself, not `document`. Pointer events flow to the grabber even if the cursor races past it.
|
|
1444
|
+
- **`isPrimary` guard** rejects secondary touches / scroll-pointers.
|
|
1445
|
+
- **Document-level cursor lock** — during a drag, `documentElement.style.cursor = 'col-resize'` is set + restored on `pointerup` / `pointercancel`, so the cursor stays `col-resize` across the entire viewport instead of flickering at the handle boundary. Previous cursor captured into `#prevDocCursor` for restore.
|
|
1446
|
+
- **`touch-action: none`** on the grabber suppresses native scroll-pan during touch drags.
|
|
1447
|
+
- **`[data-resizing]` host attribute** — set during drag, removed on release. CSS adds `:scope[data-resizing] { user-select: none; transition: none; }` to bypass any consumer-declared width transition (e.g. editor-shell's collapse animation) so pointer movements track 1:1 instead of interpolating.
|
|
1448
|
+
|
|
1449
|
+
Same shape pattern as `<admin-sidebar>` (mirrored — keeps the two resize behaviors consistent).
|
|
1450
|
+
|
|
1451
|
+
### Added — `<toggle-scheme-ui>` primitive
|
|
1452
|
+
|
|
1453
|
+
New focused primitive that toggles `color-scheme` (light ↔ dark) on a target element (default `:root`). Encapsulates the `prefers-color-scheme` initial-resolution, the inline-style write to the target, optional `localStorage` persistence (default prefix `adia-theme-`, matching `<theme-panel>` for cross-element interop), and the moon ↔ sun icon swap. Replaces the hand-wired `<button-ui id="theme-toggle">` + `applyScheme()` pattern previously duplicated across `apps/genui`, `apps/construct-canvas`, and `playgrounds/chat`.
|
|
1454
|
+
|
|
1455
|
+
Authoring API: `[scheme="auto"|"light"|"dark"]`, `[target]`, `[persist]`, `[storage-prefix]`, `[icon-light]` / `[icon-dark]`, `[label-light]` / `[label-dark]`, plus `[size]` / `[variant]` / `[color]` / `[disabled]` forwarded to the internal `<button-ui>`. Reflects `[active-scheme]` (read-only). Public methods: `.toggle()`, `.setScheme("light"|"dark"|"auto")`. Bubbles a `scheme-change` `CustomEvent` with `detail: { scheme, source }` where `source ∈ "press" | "media" | "programmatic"`.
|
|
1456
|
+
|
|
1457
|
+
When `scheme="auto"` and there is no persisted override, the element wires a `prefers-color-scheme` `matchMedia` listener and updates `active-scheme` on OS preference flips. The first explicit user choice (click, keyboard, or `.toggle()` / `.setScheme('light'|'dark')`) defeats auto and the listener detaches. `.setScheme('auto')` re-attaches.
|
|
1458
|
+
|
|
1459
|
+
### Added — TypeScript declarations + consumer guide + registration helpers (§68 consumer-feedback v0.4.6 deferrals)
|
|
1460
|
+
|
|
1461
|
+
Closes the three items deferred from the §61 consumer-feedback follow-up arc (Design Tokens Studio FEEDBACK doc, 2026-05-12). The §61 audit found that 5 of 8 consumer friction points trace to undiscoverable documentation rather than missing features; this release closes 4 of those 5 via hand-written `.d.ts` types + a single landing reference at `USAGE.md`. The fifth (typed events at compile time) is now solved by the `.d.ts` shipment.
|
|
1462
|
+
|
|
1463
|
+
**`USAGE.md` — comprehensive consumer guide** (~430 lines) at the package root, also shipped in the published tarball. Single landing surface for engineers + agents integrating AdiaUI into an app. Sections: Install, mental model, property reactivity (signal-backed), property binding patterns (the eager-evaluation trap), event contract (`CustomEvent.detail`), form participation (`UIFormElement` + `ElementInternals`), lifecycle (`connected`/`render`/`updated`/`disconnected`), theming/density/size, registration (auto vs explicit + `defineIfFree`), TypeScript, anti-patterns. Cross-linked from `README.md`.
|
|
1464
|
+
|
|
1465
|
+
**Hand-written `.d.ts` declarations** for the public API. Adding the package to dependencies now picks up TypeScript types for:
|
|
1466
|
+
|
|
1467
|
+
- **Core types** at `core/*.d.ts` — `UIElement`, `UIFormElement`, signal/computed/effect/batch/untracked, html/css/repeat/stamp templating, register/defineIfFree/isRegistered helpers
|
|
1468
|
+
- **Per-primitive types** at `components/<name>/<name>.d.ts` for 17 form-bearing primitives: input, select, slider, range, textarea, switch, check, radio, segmented, search, otp-input, option-card, color-picker, rating, code, calendar-picker, upload. Each declares typed properties + typed `CustomEvent` payloads
|
|
1469
|
+
- **`HTMLElementTagNameMap` augmentation** at `index.d.ts` — `document.querySelector('slider-ui')` now returns `UISlider`, not `Element`
|
|
1470
|
+
- **`package.json` `types` field + `exports` types conditions** — module resolution under `bundler` / `node16` / `nodenext` picks up the declarations automatically
|
|
1471
|
+
|
|
1472
|
+
Eliminates the `(e.target as any).value` pattern at compile time:
|
|
1473
|
+
|
|
1474
|
+
```ts
|
|
1475
|
+
import type { SliderChangeEvent } from '@adia-ai/web-components';
|
|
1476
|
+
slider.addEventListener('change', (e: SliderChangeEvent) => {
|
|
1477
|
+
const v: number = e.detail.value; // typed; would error if value were string
|
|
1478
|
+
});
|
|
1479
|
+
```
|
|
1480
|
+
|
|
1481
|
+
Verified with negative type tests — string-to-number assignment errors fire; wrong-tag inference fires; wrong detail-shape fires.
|
|
1482
|
+
|
|
1483
|
+
**`core/register.js` + `core/register.d.ts`** — explicit registration helpers exported from the `core` barrel:
|
|
1484
|
+
|
|
1485
|
+
- `register(tagName, ctor)` — alias for `customElements.define` (no-magic; provided for symmetry)
|
|
1486
|
+
- `defineIfFree(tagName, ctor)` — no-op + returns `false` if tag already registered. **Solves the consumer's #7 friction** (`customElements.define` throwing `NotSupportedError` when two packages register the same tag). Backwards-compatible — existing auto-register paths in component `.js` files continue to use `customElements.define` directly
|
|
1487
|
+
- `isRegistered(tagName)` — returns `true` if the tag is taken
|
|
1488
|
+
|
|
1489
|
+
The future non-side-effect `class` subpath per component (allowing class import without auto-registration for test isolation) is documented as roadmap in USAGE.md's Registration section; ships v0.4.7+ when the 95 component-file refactor lands.
|
|
1490
|
+
|
|
1491
|
+
**`package.json` `files:` array** updated to include `index.d.ts` + `USAGE.md` in the published tarball. CSS-export negation patterns already cover `.d.ts` (no exclude rules needed).
|
|
1492
|
+
|
|
1493
|
+
### Coverage
|
|
1494
|
+
|
|
1495
|
+
- 19 new `.d.ts` files (1 root + 6 core + 17 per-component – overlap = 19 total)
|
|
1496
|
+
- 1 new helper module (`core/register.js`, 56 LOC) + its `.d.ts`
|
|
1497
|
+
- 1 new documentation file (`USAGE.md`, ~430 lines)
|
|
1498
|
+
- Updated `README.md` consumer-guide section (collapsed to a quick-reference card + pointer to `USAGE.md`)
|
|
1499
|
+
- Updated `package.json` `types`, `exports`, `files` to expose the types properly
|
|
1500
|
+
|
|
1501
|
+
### Refreshed (§69 stale-audit sweep) — `traits/` docs currency
|
|
1502
|
+
|
|
1503
|
+
- `traits/CATEGORIES.md` — primitive count updated 93 → 95 (current verified count).
|
|
1504
|
+
- `traits/resettable/resettable.examples.html` — `AdiaFormElement` → `UIFormElement` in the "When NOT to use" description prose (per ADR-0016 v0.0.32 rename; stale class-name reference caught by post-§68 audit).
|
|
1505
|
+
## [0.4.5] - 2026-05-12
|
|
1506
|
+
|
|
1507
|
+
### Added — `CustomEvent.detail` sweep across 17 form-bearing primitives (§61)
|
|
1508
|
+
|
|
1509
|
+
All `change` / `input` event dispatches across form-bearing components now emit a `CustomEvent` carrying `detail: { value: this.value }` (value-semantic primitives) or `detail: { value: this.value, checked: this.checked }` (boolean-semantic — switch / check / radio / option-card). Backwards-compatible — `e.target.value` still works since the host's `value` property is updated before dispatch.
|
|
1510
|
+
|
|
1511
|
+
Driven by [consumer feedback](/Users/kimba/Projects/adia/color-app/docs/outbound/FEEDBACK-adia-packages.md) from Design Tokens Studio (2026-05-12) — eliminates the `(e.target as any).value` pattern in TypeScript consumers.
|
|
1512
|
+
|
|
1513
|
+
**Value-semantic primitives swept** (`detail: { value }`):
|
|
1514
|
+
- `<input-ui>` (input.js — 9 dispatch sites)
|
|
1515
|
+
- `<select-ui>` (select.js — 2 sites)
|
|
1516
|
+
- `<slider-ui>` (slider.js — 4 sites)
|
|
1517
|
+
- `<textarea-ui>` (textarea.js — 2 sites)
|
|
1518
|
+
- `<range-ui>` (range.js — 3 sites)
|
|
1519
|
+
- `<rating-ui>` (rating.js — 1 site)
|
|
1520
|
+
- `<search-ui>` (search.js — 2 sites)
|
|
1521
|
+
- `<otp-input-ui>` (otp-input.js — 3 sites)
|
|
1522
|
+
- `<calendar-picker-ui>` (calendar-picker.js — 1 site)
|
|
1523
|
+
- `<upload-ui>` (upload.js — 1 site; detail also carries `files: this.files`)
|
|
1524
|
+
|
|
1525
|
+
**Boolean-semantic primitives swept** (`detail: { value, checked }`):
|
|
1526
|
+
- `<switch-ui>` (switch.js — 1 site)
|
|
1527
|
+
- `<check-ui>` (check.js — 1 site)
|
|
1528
|
+
- `<radio-ui>` (radio.js — 1 site)
|
|
1529
|
+
- `<option-card-ui>` (option-card.js — 1 site)
|
|
1530
|
+
|
|
1531
|
+
**Already canonical** (no change needed):
|
|
1532
|
+
- `<segmented-ui>` — emits `detail.value` since pre-v0.4.0
|
|
1533
|
+
- `<code-ui>` — emits `detail.value` (CodeMirror state)
|
|
1534
|
+
- `<color-picker-ui>` — emits multiple typed events with structured detail
|
|
1535
|
+
- `<demo-toggle-ui>`, `<toggle-group-ui>`, `<tabs-ui>`, `<swiper-ui>` — already typed
|
|
1536
|
+
|
|
1537
|
+
### Added — `slider.test.js` locks in property reactivity (§61)
|
|
1538
|
+
|
|
1539
|
+
7-case vitest spec for `<slider-ui>` validating the contract that the consumer feedback questioned (claim #5: "doesn't react to property changes"):
|
|
1540
|
+
|
|
1541
|
+
1. Initial render places thumb at correct % for `value=50`
|
|
1542
|
+
2. **Programmatic `slider.value = 75` moves thumb to 75%** (the contested behavior — UIElement's signal-backed property setter at `core/element.js:31-50` triggers the host's render effect on every property change; verified working)
|
|
1543
|
+
3. `setAttribute('value', '25')` also propagates through `attributeChangedCallback` → property setter → signal
|
|
1544
|
+
4. `[slot="value"]` readout text syncs on value change
|
|
1545
|
+
5. `change` event is a `CustomEvent` with `detail.value` on keyboard step (`ArrowRight`)
|
|
1546
|
+
6. `input` event is a `CustomEvent` with `detail.value` on keyboard step (`ArrowUp`)
|
|
1547
|
+
7. `aria-valuenow` reflects current value for screen readers
|
|
1548
|
+
|
|
1549
|
+
The consumer's claim was wrong about the library — `<slider-ui>` IS reactive to property changes. Their specific binding pattern (`.value=${signal.value * 100}`) is non-reactive because the expression evaluates eagerly to a number, never reaching the template-system's signal/function detector at `template.js:179-183`. The fix on the consumer side is `.value=${signal}` (signal direct) or `.value=${() => signal.value * 100}` (function); the binding system effect-wraps both. v0.4.6 ships a USAGE.md reference making this pattern obvious.
|
|
1550
|
+
|
|
1551
|
+
### Added — `/site/tokens/colors` design-tokens export panel (§52)
|
|
1552
|
+
|
|
1553
|
+
In-page exporter that snapshots the live OKLCH token surface as Figma-
|
|
1554
|
+
importable JSON. Supports W3C DTCG (Figma native direct-import, default
|
|
1555
|
+
— two files: `light.tokens.json` + `dark.tokens.json` with structured
|
|
1556
|
+
`{colorSpace, components, alpha, hex}` color objects at float precision),
|
|
1557
|
+
Variables Pro legacy format (single file, `modes` wrapper, hex/rgba
|
|
1558
|
+
strings matching the canonical `parseColor` regex), and a float-RGB
|
|
1559
|
+
sub-byte-precision experimental path. Polarity-collapsed tonal primitives
|
|
1560
|
+
(`neutral.50` is a single Figma variable with per-mode values; the
|
|
1561
|
+
underlying `-tint` / `-shade` cssVars are internal implementation detail
|
|
1562
|
+
that don't surface in the export). Pure-JS OKLCH → OKLab → linear-sRGB
|
|
1563
|
+
→ sRGB → HSL math (Björn Ottosson's matrices), no canvas quantization.
|
|
1564
|
+
|
|
1565
|
+
- **`styles/design-tokens-export.js`** (new ~430 lines) — extraction module:
|
|
1566
|
+
CSSOM scanner with authoritative-selector filter (`:root, theme-ui,
|
|
1567
|
+
[data-theme]` only — skipping attribute-scoped overrides that would
|
|
1568
|
+
pollute the cssVar map under last-wins semantics), symbolic
|
|
1569
|
+
`var()` / `light-dark()` chain walker, OKLCH color-math pipeline, four
|
|
1570
|
+
output formatters (DTCG / hex / float-RGB / HSL-decimal). Public API:
|
|
1571
|
+
`buildFigmaJson({ format })`, `buildDtcgFiles()`, `getExportStats()`,
|
|
1572
|
+
`downloadJson(filename, data)`, `copyJson(data)`.
|
|
1573
|
+
- **`styles/colors.examples.html`** — export panel section: 5-button row +
|
|
1574
|
+
stats banner + workflow documentation for Figma's manual multi-mode
|
|
1575
|
+
import (add mode → right-click → "Import mode").
|
|
1576
|
+
- **`styles/colors.examples.js`** — wires the export panel: DTCG (Light +
|
|
1577
|
+
Dark) primary download, Light-only / Dark-only single-mode, Variables Pro
|
|
1578
|
+
legacy hex, clipboard copy. Theme-aware filenames (`design-tokens-${theme}-
|
|
1579
|
+
hex.json` for legacy; DTCG path keeps `light.tokens.json` /
|
|
1580
|
+
`dark.tokens.json` because Figma derives mode names from filename).
|
|
1581
|
+
- **`styles/colors.html`** (standalone path) — loads `button-ui` +
|
|
1582
|
+
`swatch-ui` CSS+JS for the panel chrome.
|
|
1583
|
+
|
|
1584
|
+
### Fixed — SPA-router-vs-download-anchor interaction (§52)
|
|
1585
|
+
|
|
1586
|
+
`UIRouter` in `core/provider.js:185` installs a document-level click listener
|
|
1587
|
+
that intercepts `<a href>` clicks for client-side navigation. Programmatic
|
|
1588
|
+
download anchors with `blob:` URLs would trigger `history.pushState(blob:...)`
|
|
1589
|
+
which throws cross-origin. The export's `downloadJson` helper now dispatches
|
|
1590
|
+
a non-bubbling synthetic click (`a.dispatchEvent(new MouseEvent('click',
|
|
1591
|
+
{ bubbles: false }))`) — browser's `<a download>` default action still
|
|
1592
|
+
fires because it's bound to the event target, not propagation. Worth
|
|
1593
|
+
mirroring in any future in-page download workflow.
|
|
1594
|
+
## [0.4.4] - 2026-05-12
|
|
1595
|
+
|
|
1596
|
+
### Added — corpus drift yaml gaps closed (§44, §50, §51)
|
|
1597
|
+
|
|
1598
|
+
Companion to the corpus simplification arc in `@adia-ai/a2ui-{runtime,compose,corpus}@[Unreleased]`. Yaml + js additions for props that were runtime-supported but yaml-under-declared — surfaced by the new `verify:corpus` validator (§39).
|
|
1599
|
+
|
|
1600
|
+
**Text strong attribute (§43):**
|
|
1601
|
+
- **`text.yaml` + `text.js` — `strong: boolean` prop** (was: styled via `:scope[strong]` selector in text.css line 35 but never declared in yaml/js). Caught by §43's audit as a genuine yaml gap; added with `default: false, reflect: true` so the corpus codemod's `Text.weight="semibold"` → `strong: true` rename has a yaml-declared target.
|
|
1602
|
+
|
|
1603
|
+
**Renderer-auto-routed textContent props (§44):**
|
|
1604
|
+
- **`badge.yaml` + `badge.js` — `textContent: string, dynamic`.** Renderer's `#applyProps` lines 294-297 auto-routes `textContent` → `text` attribute for non-text-bearing tags; yaml under-declared.
|
|
1605
|
+
- **`button.yaml` + `button.js` — `textContent: string`.** Same pattern.
|
|
1606
|
+
- **`tag.yaml` + `tag.js` — `textContent: string`.** Same pattern.
|
|
1607
|
+
- **`code.yaml` + `code.js` — `textContent: string`.** Same pattern.
|
|
1608
|
+
|
|
1609
|
+
**Universal layout grow attribute (§44):**
|
|
1610
|
+
- **`col.yaml` + `col.js` — `grow: boolean, reflect: true`.** `:scope[grow]` selector at col.css line 38 supports it; yaml under-declared.
|
|
1611
|
+
- **`row.yaml` + `row.js` — `grow: boolean, reflect: true`.** Same pattern at row.css line 56. Discovered during synthesis (Row.grow had only 5 corpus records, didn't make the top-20 audit; added anyway for symmetry with col.yaml).
|
|
1612
|
+
|
|
1613
|
+
**Pass-through HTML/ARIA attributes (§44):**
|
|
1614
|
+
- **`button.yaml` — `aria-label: string`.** Pass-through ARIA attribute, native HTML, no js change needed.
|
|
1615
|
+
- **`textarea.yaml` — `name: string`.** Inherited from UIFormElement; yaml under-declared.
|
|
1616
|
+
|
|
1617
|
+
**#JS_PROPS-resident table/select props (§44):**
|
|
1618
|
+
- **`table.yaml` — `columns: array` + `data: array`.** Already in renderer's `#JS_PROPS` set (line 233) but yaml under-declared.
|
|
1619
|
+
- **`select.yaml` — `options: array`.** Runtime supports both prop AND children patterns.
|
|
1620
|
+
|
|
1621
|
+
**Universal [size] system (§50):**
|
|
1622
|
+
- **`select.yaml` — `size: enum [sm, md, lg], reflect: true`.** Sizing via the universal `[size]` attribute system at `packages/web-components/styles/tokens.css:206-260`; select.examples.html already shipped `size="sm"`/`size="lg"` examples. Matches Input's sizing tokens so a Select rendered alongside an Input feels coherent in a form row.
|
|
1623
|
+
|
|
1624
|
+
**HTML standard input attributes (§51):**
|
|
1625
|
+
- **`input.yaml` — `inputmode: enum [text, decimal, numeric, tel, search, email, url, none]`.** Routed via setAttribute to the host element. Mobile keyboard hint per HTML inputmode spec.
|
|
1626
|
+
- **`input.yaml` — `autocomplete: string`.** Routed via setAttribute. Browser autofill behavior per HTML autocomplete spec. Common values documented inline: `off`, `on`, `cc-number`, `cc-exp`, `cc-csc`, `cc-name`, `email`, `username`, `current-password`, `new-password`, `one-time-code`, `given-name`, `family-name`, `street-address`, `postal-code`.
|
|
1627
|
+
|
|
1628
|
+
Companion to the §51 renderer kebab-casing fix in `@adia-ai/a2ui-runtime` — yaml declarations close `verify:corpus` warns AND tell LLM generators these are first-class Input props with specific enum/value lists. The documentation win matters more than the validation win.
|
|
1629
|
+
|
|
1630
|
+
Catalog (`packages/a2ui/corpus/catalog-a2ui_0_9.json`) regenerated to pick up every yaml addition. `verify:traits` clean at 56/56; `components --verify` clean at 125 files.
|
|
1631
|
+
|
|
1632
|
+
See root [CHANGELOG.md `[Unreleased]`](../../CHANGELOG.md) for the cross-cutting arc narrative + [docs/journal/2026/05/2026-05-12.md](../../docs/journal/2026/05/2026-05-12.md) §§ 43 / 44 / 50 / 51 for per-§ details.
|
|
1633
|
+
## [0.4.3] - 2026-05-11
|
|
1634
|
+
|
|
1635
|
+
### Added
|
|
1636
|
+
|
|
1637
|
+
- **`<input-ui type="number">` — `locale` attribute** (BCP-47 tag, e.g. `de-DE`, `fr-FR`, `en-IN`). When set, the input accepts both `.` AND the locale's decimal separator (so `<input-ui type="number" locale="de-DE">` parses `"1,5"` and `"1.5"` interchangeably) and uses `Intl.NumberFormat` for display — `valueAsNumber = 9.5` renders as `"9,5"` under `locale="de-DE"`. Internal storage stays canonical so `.value` round-trips through `Number(v)` after `#toCanonical`. Default empty = en-US-equivalent path (no behavior change for existing consumers). Closes v0.4.2 known-limitation #1.
|
|
1638
|
+
- **`<input-ui type="number">` — thousands grouping on blur** when `locale` is set. The textContent renders grouped (e.g. en-US `1,234,567.89`, de-DE `1.234.567,89`, fr-FR `1 234 567,89` with U+202F, en-IN `12,34,567.89`) on initial render and post-blur; on focus the input reverts to the ungrouped form so the user can edit naturally without the group separator jumping around mid-keystroke. `this.value` always stores the ungrouped, locale-decimal form; `valueAsNumber` round-trips correctly. Paste of a grouped value (in either canonical or locale form) sanitizes correctly — e.g. en-US `"1,234,567.89"` and de-DE `"1.234.567,89"` both yield `1234567.89` via `valueAsNumber`.
|
|
1639
|
+
- **`<input-ui type="number">` — hold-to-repeat on stepper buttons.** Pressing and holding a `[+]` or `[−]` button now fires an initial step on `pointerdown` then autorepeats after a 400ms delay at a 60ms cadence (matches native `<input type="number">` cadence in Chromium/Safari). Release anywhere (`pointerup`/`pointercancel` on `document`) stops it — supports the "drag off then lift" abort path without per-button leave/cancel bookkeeping. Boundary hit (`value === min` or `max`) cancels the autorepeat early so no-op events don't keep firing. Keyboard `↑/↓` auto-repeat (already provided by browser key-repeat) is unchanged; this addition covers the pointer-only path that v0.4.2 documented as "not implemented" in known limitations.
|
|
1640
|
+
|
|
1641
|
+
### Fixed
|
|
1642
|
+
|
|
1643
|
+
- `<input-ui type="number">` `#commitOnBlur` — pre-existing latent bug exposed by the new `locale` support. Was `Number(raw)` directly; locale-formatted values like `"1,5"` (de-DE) parsed as `NaN` on blur, so the function returned early without formatting/snapping. Fixed to `Number(#toCanonical(raw))` — canonicalize first.
|
|
1644
|
+
- `<input-ui type="number">` `#sanitizeNumeric` — was accepting `.` as decimal when locale's separator is `,`. Paste of `"1.234.567,89"` (de-DE grouped) parsed as `1,23456789` (first `.` mistaken for decimal). Now only the locale's separator is accepted as decimal; `.` silently drops as group separator when sep=`,`. Programmatic `.value = "1.5"` on a `locale="de-DE"` element still works (UIFormElement's setter bypasses sanitizer; `valueAsNumber` canonicalizes via `#toCanonical`).
|
|
1645
|
+
|
|
1646
|
+
### Lockstep
|
|
1647
|
+
|
|
1648
|
+
9-package coordinated PATCH cut to v0.4.3 (per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy)). Internal `@adia-ai/*` dep ranges stay at `^0.4.0` (patch-cut asymmetry — `^0.4.0` covers `0.4.x` under semver). Ratifies [ADR-0027](../../.brain/adrs/0027-cross-primitive-composition-imports.md) — cross-primitive composition imports are the consumer's responsibility; the primitive's `.js` does NOT side-effect-import composed primitives. Source files touched: `components/input/input.{js,css,yaml,a2ui.json}`. See root [CHANGELOG.md `## [0.4.3]`](../../CHANGELOG.md) for the cut narrative.
|
|
1649
|
+
## [0.4.2] - 2026-05-11
|
|
1650
|
+
|
|
1651
|
+
### Changed
|
|
1652
|
+
|
|
1653
|
+
- **`<input-ui type="number">` — drop native `<input type="number">` wrapping; render contenteditable + `[+]/[−]` stepper-button column instead.** Number mode now matches every other input variant (range / select / check / radio / slider) as a "we own the affordance" widget — no native browser stepper, no `-webkit-appearance` suppression, no native min/max coercion. Composes `<button-ui>` + `<icon-ui>` for the stepper column. Password (`type="password"`) remains the only branch that wraps native, kept for `-webkit-text-security` disc masking which has no contenteditable equivalent. Demo shell `input.html` now imports `button.css` + `icon.css` + `button.js` + `icon.js`; any consumer that imports `input-ui` piecemeal (not via the barrel) **AND** uses `type="number"` must also register `button-ui` + `icon-ui`. The component barrel `packages/web-components/components/index.js` handles registration order automatically.
|
|
1654
|
+
- `<input-ui type="number">` host now carries `role="spinbutton"` + `aria-valuenow` / `aria-valuemin` / `aria-valuemax` / `aria-valuetext` (suffix-aware: `<input-ui type="number" value="70" suffix="kg">` announces "70 kg") + `aria-readonly` / `aria-required` / `aria-invalid` mirrored from props. Stepper-button wrapper carries `aria-hidden="true"` — redundant with keyboard ↑/↓.
|
|
1655
|
+
- Existing `type` section's number example in [input.examples.html](./components/input/input.examples.html) upgraded with `min="0" max="100"` so the demo's stepper buttons surface working boundary-disable behavior.
|
|
1656
|
+
|
|
1657
|
+
### Added
|
|
1658
|
+
|
|
1659
|
+
- `<input-ui type="number">` — four new props:
|
|
1660
|
+
- `min` (Number, default `null`) — minimum value. Drives `aria-valuemin` + the `[−]` button's disabled state.
|
|
1661
|
+
- `max` (Number, default `null`) — maximum value. Drives `aria-valuemax` + the `[+]` button's disabled state.
|
|
1662
|
+
- `step` (Number, default `1`) — increment magnitude for ↑/↓ ArrowUp/Down, PageUp/Down × 10, and the `[+]`/`[−]` buttons. Also drives the implicit decimal count for display formatting unless `precision` is set.
|
|
1663
|
+
- `precision` (Number, default `null`) — decimal places to format + clamp to. Overrides the `step`-derived decimal count — e.g. `step=1 precision=2` formats `"10.00"`.
|
|
1664
|
+
- `<input-ui type="number">` — `valueAsNumber` getter (mirrors the standard HTML5 `<input type="number">.valueAsNumber` read pattern). Returns `NaN` when empty / unparseable / lone-sign-or-decimal. Setter coerces and clamps via `#snap`.
|
|
1665
|
+
- `<input-ui type="number">` — full WAI-ARIA APG spinbutton keyboard model: `ArrowUp` / `ArrowDown` step by `step`, `PageUp` / `PageDown` step by `step × 10`, `Home` → `min` (no-op when null), `End` → `max` (no-op when null), `Enter` commits + fires `change` + `submit`, `Escape` reverts to value at focus-in. `wheel` deliberately **not** bound — wheel-changes-value-on-scroll is an antipattern; users can scroll past an input without fearing silent value changes.
|
|
1666
|
+
- `<input-ui type="number">` — `beforeinput` filter enforces digits / single decimal / leading minus (when `min == null || min < 0`). Permissive during typing (allows lone `"-"`, lone `"."`, trailing `"1."`) + normalizes on blur via `#commitOnBlur` → `#snap` → `#format`. Paste handler sanitizes clipboard text to the same alphabet before insertion.
|
|
1667
|
+
- `<input-ui type="number">` — number-range constraint validation. `#runNumberConstraints` layers `badInput` / `rangeUnderflow` / `rangeOverflow` on top of `UIFormElement`'s base constraints (required / pattern / minlength / maxlength). Custom message data attributes: `data-msg-bad-input`, `data-msg-min`, `data-msg-max` (parallels the existing `data-msg-required` / `data-msg-pattern` convention).
|
|
1668
|
+
- New dedicated demo section in [input.examples.html](./components/input/input.examples.html) (`data-property="number"`) — 8 variants: Quantity (integer min/max) · Price ($ prefix + precision 2) · Weight (kg suffix + step 0.1) · Discount (% suffix + step 5) · Temperature (negative allowed) · sm size · lg size · disabled state.
|
|
1669
|
+
- Five new `examples[]` entries in [input.yaml](./components/input/input.yaml) for retrieval signal: `quantity-stepper`, `price-with-currency`, `weight-with-unit`, `percent-bounded`, `temperature-negative`.
|
|
1670
|
+
|
|
1671
|
+
### Fixed
|
|
1672
|
+
|
|
1673
|
+
- `<input-ui type="number">` chrome height regression. After the rewrite, number-mode fields initially measured **+6-10 px past** the canonical `--a-size` baseline (38/34/46 vs target 30/24/36 at md/sm/lg) because the stepper-button column's children pushed the field's flex height past `min-height: var(--input-height)`. Resolved by switching the controls column from flex flow to `position: absolute` (`[data-number] { position: relative }` + column `inset-block: 0; inset-inline-end: 0`) so the column never participates in field-height calculation. Value/suffix reserve space via `padding-inline-end` / `margin-inline-end`. Number-mode fields now measure exactly 24/30/36 px at sm/md/lg — identical to text/email/password/etc.
|
|
1674
|
+
- `<input-ui type="number">` stepper-button width collapse. button-ui's `:scope:not([text]) { width: var(--button-height) }` icon-only rule was collapsing the buttons to 0 wide when our scope overrode `--button-height` to 0 (to defeat its square min-width/min-height contract). Resolved by bumping our override's selector specificity from `[slot="controls"] button-ui` (0,1,1) to `[data-number] [slot="controls"] button-ui` (0,2,2).
|
|
1675
|
+
- `<input-ui type="number">` stepper icon overshoot. `<icon-ui>`'s default `--icon-size: calc(1em + 0.125rem)` overshoots the half-column cell, causing 1-2 px vertical clipping. CSS-custom-property declarations on self override inherited values, so the override has to target `icon-ui` directly: `[data-number] [slot="controls"] icon-ui { --icon-size: calc(var(--input-height) * 0.4) }`. Chevrons now measure 12/9.6/14.4 px at md/sm/lg — proportional and well within the half-column.
|
|
1676
|
+
|
|
1677
|
+
### Known limitations
|
|
1678
|
+
|
|
1679
|
+
- ~~`<input-ui type="number">` filter assumes en-US numeric formatting (`.` as decimal separator). Locale-aware separators (e.g. German `,`) are not parsed. Tracked as a deferred follow-up; right answer is an opt-in `locale="…"` attribute that swaps the filter regex + uses `Intl.NumberFormat` for display.~~ **Resolved in [0.4.3]** above. `locale` attribute + thousands grouping on blur both shipped.
|
|
1680
|
+
- Scientific notation (`"1e3"`) is rejected by the filter. Deliberately out of scope.
|
|
1681
|
+
- ~~Hold-to-repeat on the stepper buttons is not implemented. Browser keyboard auto-repeat on ↑/↓ covers the same affordance.~~ **Resolved post-v0.4.2** — see `[0.4.3]` above. Pointer hold now autorepeats at native cadence.
|
|
1682
|
+
|
|
1683
|
+
### Lockstep
|
|
1684
|
+
|
|
1685
|
+
9-package coordinated PATCH cut to v0.4.2 (per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy)). Internal `@adia-ai/*` dep ranges stay at `^0.4.0` (patch-cut asymmetry — `^0.4.0` covers `0.4.x` under semver). ADR-0025 ([`.brain/adrs/0025-no-native-form-controls.md`](../../.brain/adrs/0025-no-native-form-controls.md)) ratified — codifies the "no native or suppressed-native interactive widgets in primitives" principle that the `<input-ui type="number">` rewrite implements; `password` remains the documented exception (physically requires `<input type="password">` for `-webkit-text-security`). See root [CHANGELOG.md `## [0.4.2]`](../../CHANGELOG.md) for the cut narrative.
|
|
1686
|
+
## [0.4.1] - 2026-05-10
|
|
1687
|
+
|
|
1688
|
+
### Ride-along (no source changes)
|
|
1689
|
+
|
|
1690
|
+
Lockstep PATCH cut alongside `@adia-ai/web-modules@0.4.1` (simple cluster) + `@adia-ai/a2ui-validator@0.4.1` (Phase 3 foundation) + `@adia-ai/a2ui-corpus@0.4.1` (fragment metrics reconciliation). Source byte-identical to v0.4.0.
|
|
1691
|
+
|
|
1692
|
+
Internal `@adia-ai/*` dep ranges bumped from `^0.4.0` to `^0.4.1`. See root [CHANGELOG.md `## [0.4.1]`](../../CHANGELOG.md) for the cut narrative.
|
|
1693
|
+
## [0.4.0] - 2026-05-10
|
|
1694
|
+
|
|
1695
|
+
### Ride-along (no source changes)
|
|
1696
|
+
|
|
1697
|
+
Lockstep MINOR cut alongside `@adia-ai/web-modules@0.4.0` (ADR-0024 legacy shell shapes retired). Source byte-identical to v0.3.6.
|
|
1698
|
+
|
|
1699
|
+
Internal `@adia-ai/*` dep ranges bumped from `^0.3.0` to `^0.4.0`. See root [CHANGELOG.md `## [0.4.0]`](../../CHANGELOG.md) for the cut narrative.
|
|
1700
|
+
## [0.3.6] - 2026-05-10
|
|
1701
|
+
|
|
1702
|
+
### Ride-along (no source changes)
|
|
1703
|
+
|
|
1704
|
+
Lockstep version bump only — source byte-identical to v0.3.5. Internal `@adia-ai/*` dep ranges remain at `^0.3.0`. See root [CHANGELOG.md `## [0.3.6]`](../../CHANGELOG.md) for the cut narrative.
|
|
1705
|
+
## [0.3.5] - 2026-05-07
|
|
1706
|
+
|
|
1707
|
+
### Ride-along (no source changes)
|
|
1708
|
+
|
|
1709
|
+
Lockstep version bump only — source byte-identical to v0.3.4. Internal `@adia-ai/*` dep ranges remain at `^0.3.0`. See root [CHANGELOG.md `## [0.3.5]`](../../CHANGELOG.md) for the cut narrative.
|
|
1710
|
+
## [0.3.4] - 2026-05-07
|
|
1711
|
+
|
|
1712
|
+
### Ride-along (no source changes)
|
|
1713
|
+
|
|
1714
|
+
Lockstep version bump only — source byte-identical to v0.3.3. Internal `@adia-ai/*` dep ranges remain at `^0.3.0`. See root [CHANGELOG.md `## [0.3.4]`](../../CHANGELOG.md) for the cut narrative.
|
|
1715
|
+
## [0.3.3] - 2026-05-07
|
|
1716
|
+
|
|
1717
|
+
**Lockstep cut.** All 9 published `@adia-ai/*` packages now share version `0.3.3`, governed by [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy).
|
|
1718
|
+
|
|
1719
|
+
### Changed
|
|
1720
|
+
|
|
1721
|
+
- `version`: `0.3.2` → `0.3.3`.
|
|
1722
|
+
- `dependencies["@adia-ai/...]`: `^0.3.0` (patch-cut asymmetry — caret already covers 0.3.x; ranges unchanged).
|
|
1723
|
+
|
|
1724
|
+
### No source changes
|
|
1725
|
+
|
|
1726
|
+
`@adia-ai/web-components` source is byte-identical to `0.3.2`. The cut is a version bump + ride-along on the lockstep policy.
|
|
1727
|
+
## [0.3.2] - 2026-05-06
|
|
1728
|
+
|
|
1729
|
+
**9-package lockstep patch cut to v0.3.2.** All lockstep members share
|
|
1730
|
+
one version per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy).
|
|
1731
|
+
Internal `@adia-ai/*` dep ranges unchanged at `^0.3.0`.
|
|
1732
|
+
|
|
1733
|
+
### No source changes
|
|
1734
|
+
|
|
1735
|
+
This package's source is byte-identical to v0.3.1. The cut bumps
|
|
1736
|
+
version only.
|
|
1737
|
+
|
|
1738
|
+
### Changed
|
|
1739
|
+
|
|
1740
|
+
- `version`: `0.3.1` → `0.3.2`.
|
|
1741
|
+
## [0.3.1] - 2026-05-06
|
|
1742
|
+
|
|
1743
|
+
**9-package lockstep patch cut + folder-per-trait restructure.** All 9 published `@adia-ai/*` packages bump 0.3.0 → 0.3.1 per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges remain at `^0.3.0` (covers `0.3.1` under semver — patch-cut asymmetry).
|
|
1744
|
+
|
|
1745
|
+
This is a **patch cut on top of v0.3.0, no BREAKING changes for npm consumers.** The barrel API (`@adia-ai/web-components/traits`, `@adia-ai/web-components/components`, etc.) is byte-equivalent to v0.3.0 at the public surface. The change is internal: the trait library moved from a flat `traits/<name>.{html,js,examples.html,examples.js,test.js}` layout to one folder per trait (`traits/<name>/<name>.{...}`), mirroring the existing `components/<name>/` convention.
|
|
1746
|
+
|
|
1747
|
+
### Changed
|
|
1748
|
+
|
|
1749
|
+
- **Trait file layout: folder-per-trait.** 56 traits restructured. The barrel re-exports remain unchanged — `import { activeState } from '@adia-ai/web-components/traits'` is byte-equivalent. **Internal subpath shape changes**: imports that reach into specific trait files (e.g. `import { confettiBurst } from '@adia-ai/web-components/traits/confetti-burst'`) now point at `traits/confetti-burst/confetti-burst.js`. The `package.json` `exports` field doesn't declare per-trait subpaths, so the formal published API is unchanged; consumers using deep imports through the file system would need to update paths.
|
|
1750
|
+
- **Stage companions move with their trait.** `confetti-stage.js` lives under `traits/confetti/`, `announcer-stage.js` under `traits/announcer/`. These were never public; they're co-located with the trait that owns them.
|
|
1751
|
+
- `components/card/card.js` + `components/row/row.js` updated to import `traits/draggable/draggable.js` (was `traits/draggable.js`).
|
|
1752
|
+
- `version`: `0.3.0` → `0.3.1`. Internal `@adia-ai/*` dep ranges: unchanged at `^0.3.0` (covers `0.3.1` under semver — patch-cut asymmetry).
|
|
1753
|
+
|
|
1754
|
+
### Why
|
|
1755
|
+
|
|
1756
|
+
Symmetry with `components/<name>/` (already folder-per for months) — easier to find related files when working on one trait, allows trait-specific helpers without name pollution at the top level. Survey of the import graph confirmed safety: 247 of 251 `@traits/<X>.js` imports use the barrel (unchanged); 4 reached into specific files (all in-repo, updated in same commit).
|
|
1757
|
+
|
|
1758
|
+
### Repo-only (not in tarball — but commit graph for transparency)
|
|
1759
|
+
|
|
1760
|
+
- `packages/web-components/traits/` directory restructure: ~280 file moves preserving `git mv` history.
|
|
1761
|
+
- `packages/a2ui/compose/transpiler/transpiler-maps.js` — no change since v0.3.0 (the v0.3.0 entry mentioned this file; correction: that update was part of v0.3.0).
|
|
1762
|
+
## [0.3.0] - 2026-05-05
|
|
1763
|
+
|
|
1764
|
+
**9-package lockstep cut.** All 9 published `@adia-ai/*` packages bump 0.2.5 → 0.3.0 per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges bump `^0.2.0` → `^0.3.0`.
|
|
1765
|
+
|
|
1766
|
+
The lockstep policy expanded from 8 to 9 packages with this cut — `@adia-ai/llm` joins as a foundational primitive (extracted from `@adia-ai/a2ui-compose/llm`), and `@adia-ai/a2ui-utils` was renamed to `@adia-ai/a2ui-runtime`. Both are BREAKING for npm consumers (acceptable under pre-1.0 semver).
|
|
1767
|
+
|
|
1768
|
+
This package itself ships **no source changes** in v0.3.0. The cut bumps version + the internal dep range only. Substantive content lives in `@adia-ai/llm` (first publish), `@adia-ai/a2ui-runtime` (rename), `@adia-ai/web-modules` (chat-shell now imports from `@adia-ai/llm`), `@adia-ai/a2ui-compose` (drops `./llm` subpath), and `@adia-ai/a2ui-mcp` (synthesis tool dep update).
|
|
1769
|
+
|
|
1770
|
+
### Changed
|
|
1771
|
+
|
|
1772
|
+
- `version`: `0.2.5` → `0.3.0`.
|
|
1773
|
+
- `dependencies["@adia-ai/a2ui-utils"]` removed from any consumer; consumers requiring the runtime should now depend on `@adia-ai/a2ui-runtime`.
|
|
1774
|
+
|
|
1775
|
+
### Repo-only (not in tarball)
|
|
1776
|
+
|
|
1777
|
+
The following directories saw significant in-repo changes between v0.2.5 and v0.3.0, but the additions are **excluded from the published tarball** via the `files:` array's `!components/**/*.html` negation (per [`feedback_npm_files_array_negation.md`](https://github.com/adiahealth/gen-ui-kit/blob/main/.claude/projects/-Users-kimba-Projects-chat-ui/memory/feedback_npm_files_array_negation.md)) and similar rules for non-shipping demo content. Consumers see byte-identical source for the published surface.
|
|
1778
|
+
|
|
1779
|
+
- `components/` — co-located per-component demo trio (`<name>.html` shell + `<name>.examples.html` + `<name>.examples.js`) added across ~85 components per ADR-0021 (page-trio convention). These are dev-only artifacts; not bundled into the tarball.
|
|
1780
|
+
- `core/` — `streams-bridge.js` import path updated for the runtime rename (`@adia-ai/a2ui-utils` → `@adia-ai/a2ui-runtime`).
|
|
1781
|
+
- `traits/` — `tilt-hover.examples.html` regenerated from the components build (slot-marker convention update). No trait API changes.
|
|
1782
|
+
- `styles/` — no source changes; touched only via the build's catalog-regeneration sweep.
|
|
1783
|
+
- `patterns/` — no source changes since v0.2.5.
|
|
1784
|
+
## [0.2.5] - 2026-05-04
|
|
1785
|
+
|
|
1786
|
+
**Lockstep cut + new `<fields-ui>` form-grid primitive + `draggable-list-item` last-item drop-zone fix.** All 8 published `@adia-ai/*` packages bump 0.2.4 → 0.2.5 per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — **no BREAKING changes**.
|
|
1787
|
+
|
|
1788
|
+
### Added
|
|
1789
|
+
|
|
1790
|
+
- **New `<fields-ui>` primitive** at `components/fields/`. A form-category container that hosts multiple `<field-ui>` children on a shared 6-column grid (configurable via `[columns="1..12"]`). Each `<field-ui rows="N">` spans `N` columns; default span (no attr) fills the row. The host's `[inline]` attribute propagates onto every direct `<field-ui>` child via a MutationObserver — a whole sub-form switches label-position from one host attribute. Solves the wrap-flex jitter pattern where authors stacked `<field-ui>` children inside `<row-ui wrap>` and labels/controls would refuse to align across rows. Yaml + js + css + 6/6 tests. Catalog: 97 → 98 yamls.
|
|
1791
|
+
- `components/fields/fields.yaml` — declarative API with 2 examples (3-up stacked, inline-search-form) + 2 anti-patterns flagged.
|
|
1792
|
+
- `components/fields/fields.js` — `UIFields extends UIElement`. Properties `[columns]` (Number, default 6, reflective) + `[inline]` (Boolean, reflective). MutationObserver re-syncs `[inline]` propagation on `childList` changes.
|
|
1793
|
+
- `components/fields/fields.css` — single `@scope (fields-ui)` block. `display: grid; grid-template-columns: repeat(var(--fields-columns, 6), minmax(0, 1fr))`. Per-`rows` selectors unrolled 1..12 (CSS doesn't do attribute arithmetic).
|
|
1794
|
+
- `components/fields/fields.test.js` — covers default no-propagation, propagation on connect, on add (post-mount `appendChild`), on remove, non-field-child isolation, and registration. **6/6 PASS**.
|
|
1795
|
+
|
|
1796
|
+
### Fixed
|
|
1797
|
+
|
|
1798
|
+
- **`traits/draggable-list-item.js` — last-item drop-zone**. In a 3-item list `[A, B, C]`, dragging `B` onto `C` was impossible to land at the bottom slot — the lifted source's DOM still occupied its old position, and the standard mid-line test resolved upper-half-of-`C` to "before `C`" (no-op). Fix: the LAST visible item's whole height is now the "drop after" zone (`indexWithinTarget` returns `visible.length` whenever cursor `y >= rect.top` on the last item). Non-last items keep the standard mid-line; the gap above the last item still resolves through mid-line (so "between second-to-last and last" stays reachable). Universal trait fix — list, kanban, and any future `droppable-collection` consumer benefit. New visual-test assertion in the Tasks UI Playground covers this case.
|
|
1799
|
+
|
|
1800
|
+
### Changed
|
|
1801
|
+
|
|
1802
|
+
- `version`: `0.2.4` → `0.2.5`.
|
|
1803
|
+
- `dependencies["@adia-ai/a2ui-utils"]`: `^0.2.0` (covers `0.2.5` under semver — patch-cut asymmetry).
|
|
1804
|
+
- `components/index.js` adds `UIFields` export.
|
|
1805
|
+
- `styles/components.css` adds `@import "../components/fields/fields.css"`.
|
|
1806
|
+
## [0.2.4] - 2026-05-04
|
|
1807
|
+
|
|
1808
|
+
**Lockstep cut + Tier 4 capability adds + 2 architectural rewrites.** All 8 published `@adia-ai/*` packages bump 0.2.3 → 0.2.4 per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
1809
|
+
|
|
1810
|
+
### Changed
|
|
1811
|
+
|
|
1812
|
+
- `version`: `0.2.3` → `0.2.4`.
|
|
1813
|
+
- `dependencies["@adia-ai/a2ui-utils"]`: `^0.2.0` (covers `0.2.4`).
|
|
1814
|
+
- New `components/demo-toggle/` directory; `components/index.js` adds `UIDemoToggle` export; `styles/components.css` adds `@import "../components/demo-toggle/demo-toggle.css"`.
|
|
1815
|
+
- `traits/index.js` adds 12 new exports (the 11 Tier-4 traits + droppable from the parallel Tasks UI initiative); `traits/_catalog.json` regenerated to 56 entries; `core/icons.js` extended with ~25 new aliases.
|
|
1816
|
+
|
|
1817
|
+
The substantive content of the next cut, surfaced from the
|
|
1818
|
+
2026-05-04 trait-library lift initiative (`docs/PLAN.md`,
|
|
1819
|
+
`docs/reports/traits-creative-director-audit-2026-05-04.md`).
|
|
1820
|
+
**No BREAKING changes.** Every public tag, prop, event, and
|
|
1821
|
+
declarative `traits=` attribute from v0.2.3 still works.
|
|
1822
|
+
|
|
1823
|
+
### Added — 11 new traits (Tier 4 capability adds)
|
|
1824
|
+
|
|
1825
|
+
Catalog: 41 → 56 traits across 9 categories (12 net new + droppable
|
|
1826
|
+
already in flight from the Tasks UI parallel session). 100% test
|
|
1827
|
+
coverage maintained; trait-suite footprint **59 files / 365 tests**
|
|
1828
|
+
(was 44 / 169 at v0.2.3).
|
|
1829
|
+
|
|
1830
|
+
- **`layout-animation`** (motion-positioning) — FLIP primitive:
|
|
1831
|
+
capture old bounds, project transform from old to new, hand to a
|
|
1832
|
+
spring tick loop. Triggered by parent `MutationObserver` (sortable
|
|
1833
|
+
lists) or by toggling `data-layout-animate-trigger`. Closes the
|
|
1834
|
+
most-asked-for Framer Motion feature.
|
|
1835
|
+
- **`drop-target`** (motion-positioning) — declarative drop zone with
|
|
1836
|
+
hit-testing + accept-reject (file types, MIME csv list). Counterpart
|
|
1837
|
+
to `draggable`/`drag-ghost`; emits `drop-enter` / `drop-leave` /
|
|
1838
|
+
`drop-receive` / `drop-rejected`.
|
|
1839
|
+
- **`view-transition`** (motion-positioning) — wraps
|
|
1840
|
+
`document.startViewTransition()` for morph animations between DOM
|
|
1841
|
+
states. Sets `view-transition-name` on the host; installs a
|
|
1842
|
+
`host.startTransition(callback)` method. Same-document baseline
|
|
1843
|
+
Chromium 111+ / Safari 18+ / Firefox 129+; graceful-degrade path
|
|
1844
|
+
fires start+end synchronously when the API is missing.
|
|
1845
|
+
- **`input-mask`** (forms-data) — locale-aware as-you-type formatter
|
|
1846
|
+
with 6 built-in patterns (phone-us, phone-intl, credit-card,
|
|
1847
|
+
date-iso, time-24h, cvv) and caret preservation against entered
|
|
1848
|
+
chars (not mask chars). Closes the structurally-thinnest category
|
|
1849
|
+
per the audit.
|
|
1850
|
+
- **`long-press`** (input-interaction) — press-and-hold trigger with
|
|
1851
|
+
configurable duration / tolerance / progress events; suppresses the
|
|
1852
|
+
trailing `click` and the native `contextmenu` while in flight.
|
|
1853
|
+
- **`scroll-progress`** (layout-measurement) — page or element scroll
|
|
1854
|
+
progress as `data-scroll-progress` (0..1) + CSS variable + event.
|
|
1855
|
+
Three modes: `in-view` (default), `page`, `scrolled`.
|
|
1856
|
+
- **`error-shake`** (animation-feedback) — horizontal lateral
|
|
1857
|
+
oscillation on validation failure. Composes with `validation`
|
|
1858
|
+
trait via the `validated` event.
|
|
1859
|
+
- **`success-checkmark`** (animation-feedback) — SVG stroke-draw
|
|
1860
|
+
checkmark on validation success. **Renders to body-level
|
|
1861
|
+
`position: fixed`** so the trait can't be clipped by the host's
|
|
1862
|
+
`overflow: hidden` ancestor (cards, buttons). Composes with
|
|
1863
|
+
`validation` via `validated` event.
|
|
1864
|
+
- **`focus-restore`** (keyboard-navigation) — captures
|
|
1865
|
+
`document.activeElement` on connect, restores via `el.focus({
|
|
1866
|
+
preventScroll: true })` on disconnect. Falls back to body when the
|
|
1867
|
+
captured target is removed/disabled. Closes the modal-close-leaves-
|
|
1868
|
+
focus-dangling a11y bug class.
|
|
1869
|
+
- **`arrow-grid-nav`** (keyboard-navigation) — 2D arrow-key navigation
|
|
1870
|
+
for grids/calendars/menubars (APG `grid` pattern). Two structural
|
|
1871
|
+
modes: `row-flat` (infers row/col by index ÷ columns) and
|
|
1872
|
+
`row-nested` (each direct child is a row container).
|
|
1873
|
+
- **`announcer`** (audio-haptics-sensory) — singleton aria-live mirror
|
|
1874
|
+
with polite/assertive routing + throttling. Two body-level
|
|
1875
|
+
`aria-live` regions (`#adia-live-polite`, `#adia-live-assertive`)
|
|
1876
|
+
shared across all announcer instances. Lifts every audio/haptic/
|
|
1877
|
+
visual trait above WCAG 4.1.3.
|
|
1878
|
+
|
|
1879
|
+
Plus four traits that landed via the parallel Tasks UI initiative,
|
|
1880
|
+
exported through this package's barrel: `droppable` (input-
|
|
1881
|
+
interaction), `droppable-collection` (input-interaction),
|
|
1882
|
+
`draggable-list-item` (motion-positioning), `keyboard-reorderable`
|
|
1883
|
+
(keyboard-navigation).
|
|
1884
|
+
|
|
1885
|
+
### Added — `<demo-toggle-ui>` primitive
|
|
1886
|
+
|
|
1887
|
+
New custom element at `components/demo-toggle/`. A side-by-side "with
|
|
1888
|
+
trait / without trait" comparison wrapper that any trait detail page
|
|
1889
|
+
(or example) can drop into a hero. Reflects `data-state="on"|"off"`
|
|
1890
|
+
on the host; emits a `change` event with `detail.state`. Optional
|
|
1891
|
+
`data-mode="overlay"` stacks the slots in place so layout doesn't
|
|
1892
|
+
shift between states. 9/9 tests passing. Integrated into 3 trait
|
|
1893
|
+
pages (`parallax`, `shimmer-loading`, `noise-texture`) and ready for
|
|
1894
|
+
broader retrofit.
|
|
1895
|
+
|
|
1896
|
+
### Changed — `confetti` + `confetti-burst` rendered to top-layer
|
|
1897
|
+
|
|
1898
|
+
Both traits now render particles into a singleton body-level
|
|
1899
|
+
`<div popover="manual">` stage at z-index 99999, derived from the
|
|
1900
|
+
host's `getBoundingClientRect()` at fire time. Particles escape any
|
|
1901
|
+
`overflow: hidden` ancestor (modals, drawers, cards), no z-index
|
|
1902
|
+
wars, no per-trait container. Both traits share the stage via a new
|
|
1903
|
+
private `confetti-stage.js` helper. Disconnect cleans up the
|
|
1904
|
+
attribute and the listener; in-flight particles outlive the trait
|
|
1905
|
+
and self-remove on `animationend` (matching the spec's "disconnect
|
|
1906
|
+
doesn't yank particles" requirement).
|
|
1907
|
+
|
|
1908
|
+
### Changed — `anchor-positioning` uses native CSS Anchor Positioning where supported
|
|
1909
|
+
|
|
1910
|
+
On Chromium 125+ and Safari 18.0+, the trait now writes
|
|
1911
|
+
`anchor-name` on the anchor + `position-anchor` / `position-area` on
|
|
1912
|
+
the host, calls `host.showPopover()` to promote into the top layer,
|
|
1913
|
+
and lets the browser handle reflow on its own (no JS scroll/resize
|
|
1914
|
+
loop). The v0 JS-positioning path remains for Firefox + Safari
|
|
1915
|
+
< 18.0 as a fallback. The host carries
|
|
1916
|
+
`data-anchor-mode="native"|"fallback"` so consumers and DevTools
|
|
1917
|
+
sessions can see which path actually ran. Public attribute API
|
|
1918
|
+
(`data-anchor`, `data-anchor-placement`, `data-anchor-gap`) is
|
|
1919
|
+
unchanged.
|
|
1920
|
+
|
|
1921
|
+
### Changed — `count-up` adds Intl.NumberFormat + prefix/suffix/decimals/locale
|
|
1922
|
+
|
|
1923
|
+
The trait now formats the displayed value via `Intl.NumberFormat` so
|
|
1924
|
+
`2438000` renders as `2,438,000` by default. Four new optional
|
|
1925
|
+
config attrs:
|
|
1926
|
+
- `data-count-prefix` — string prepended to the formatted value
|
|
1927
|
+
(e.g., `$`).
|
|
1928
|
+
- `data-count-suffix` — string appended (e.g., `%`).
|
|
1929
|
+
- `data-count-decimals` — fraction-digit count for currency
|
|
1930
|
+
(`$1,234.56`) or percentage (`12.5%`) cases. Default 0.
|
|
1931
|
+
- `data-count-locale` — BCP 47 language tag override.
|
|
1932
|
+
|
|
1933
|
+
Reduced-motion path also formats via the formatter so the snapped
|
|
1934
|
+
value matches the animated path's final frame.
|
|
1935
|
+
|
|
1936
|
+
### Changed — `noise-texture` strength attribute + visibility default
|
|
1937
|
+
|
|
1938
|
+
Earlier defaults stacked SVG rect opacity (0.08) × overlay div
|
|
1939
|
+
opacity (0.5) = effective 0.04, visually no grain. New defaults: rect
|
|
1940
|
+
opacity = 0.15, overlay's CSS opacity removed (single multiplier).
|
|
1941
|
+
New `data-noise-strength` config attr (0..1, default 0.15) lets
|
|
1942
|
+
consumers dial intensity without touching the trait source.
|
|
1943
|
+
|
|
1944
|
+
### Changed — Trait helpers dropped underscore prefix
|
|
1945
|
+
|
|
1946
|
+
`_motion.js` → `motion.js`, `_test-helpers.js` → `test-helpers.js`,
|
|
1947
|
+
`_announcer-stage.js` → `announcer-stage.js`, `_confetti-stage.js`
|
|
1948
|
+
→ `confetti-stage.js`. The catalog walker
|
|
1949
|
+
(`scripts/build/traits-catalog.mjs`) switched from filename-prefix
|
|
1950
|
+
detection to an explicit `HELPERS` Set so the convention can keep a
|
|
1951
|
+
uniform naming style. Internal consumers updated; no public API
|
|
1952
|
+
change.
|
|
1953
|
+
|
|
1954
|
+
### Changed — `--a-section-weight` flipped semibold → normal
|
|
1955
|
+
|
|
1956
|
+
Visible on every `<h2>` and `<h3>` consuming the `section` role
|
|
1957
|
+
token. Lighter weight reads less heavy at the doc-section level —
|
|
1958
|
+
closer to a label than a title — and pairs better with the `heading`
|
|
1959
|
+
role above it (already at semibold). Single-line CSS change at
|
|
1960
|
+
`packages/web-components/styles/typography.css:259`. No API surface
|
|
1961
|
+
change; pure visual.
|
|
1962
|
+
|
|
1963
|
+
### Fixed — `inertia-drag` / `tossable` / `draggable` translate-read
|
|
1964
|
+
|
|
1965
|
+
`parseTranslate()` now reads `style.translate` first (the trait
|
|
1966
|
+
writes to it), falling back to `style.transform` matrix. Same class
|
|
1967
|
+
as the v0.2.3 `spring-animate` fix (commit `07fb2841`). Pre-fix:
|
|
1968
|
+
every drag after the first read the wrong CSS property and got
|
|
1969
|
+
`m41 = 0`, so subsequent drags jumped the host back near the origin
|
|
1970
|
+
instead of moving from its current position.
|
|
1971
|
+
|
|
1972
|
+
### Fixed — `drag-ghost` rect-snap pixel-identical clone
|
|
1973
|
+
|
|
1974
|
+
Position the cloned ghost over the host's exact viewport rect at
|
|
1975
|
+
`position: fixed; left/top/width/height; box-sizing: border-box`,
|
|
1976
|
+
copy host's `transform`/`transform-origin`, then call
|
|
1977
|
+
`setDragImage(ghost, clickX, clickY)`. Pre-fix: ghost was offscreen
|
|
1978
|
+
with default content-box width/height; for content-box hosts, the
|
|
1979
|
+
ghost rendered larger than the host and the offset coordinates
|
|
1980
|
+
landed at the wrong bitmap pixel — the ghost drifted off the cursor
|
|
1981
|
+
as the click moved away from the host's top-left corner. Hide via
|
|
1982
|
+
`visibility: hidden` after the synchronous `setDragImage` snapshot.
|
|
1983
|
+
|
|
1984
|
+
### Fixed — `<list-item-ui>` `[data-active]` CSS state
|
|
1985
|
+
|
|
1986
|
+
`list.css` — added `[data-active]` block inside
|
|
1987
|
+
`@scope (list-item-ui)`: `--a-accent-muted` background,
|
|
1988
|
+
`--a-accent-strong` text + icon, 2px accent-strong inset rail.
|
|
1989
|
+
Reuses the same token pair as the existing
|
|
1990
|
+
`list-ui[selectable] [aria-selected="true"]` rule so the two
|
|
1991
|
+
selection mechanisms paint consistently. Closes the keyboard-nav
|
|
1992
|
+
demo "broken" report at v0.2.3 — events fired correctly, the active
|
|
1993
|
+
state had no visible style.
|
|
1994
|
+
|
|
1995
|
+
### Fixed — `list-item-ui` empty items collapsed to 0 height
|
|
1996
|
+
|
|
1997
|
+
Empty `<list-item-ui></list-item-ui>` (no `text`, no `icon`, no
|
|
1998
|
+
children) rendered with 0 height and silently disappeared from the
|
|
1999
|
+
layout. Add a 24px floor via `min-height: var(--a-space-6)` so empty
|
|
2000
|
+
items always show a visible row. Aligns with WCAG 2.2 SC 2.5.8
|
|
2001
|
+
(Target Size, Minimum) for `list-ui[selectable]` where the row is
|
|
2002
|
+
the click target.
|
|
2003
|
+
|
|
2004
|
+
### Fixed — `<button-ui type="reset">` triggers `form.requestReset()`
|
|
2005
|
+
|
|
2006
|
+
Previously a no-op (only `type="submit"` was handled). Pre-fix:
|
|
2007
|
+
`<button-ui type="reset">` clicks fired `press` but never the form's
|
|
2008
|
+
`reset` event, so the `resettable` trait's reset chain dead-ended at
|
|
2009
|
+
the click.
|
|
2010
|
+
|
|
2011
|
+
### Fixed — `<input-ui>` / `<textarea-ui>` programmatic value sync
|
|
2012
|
+
|
|
2013
|
+
`render()` now syncs `this.value` into the inner contenteditable
|
|
2014
|
+
when they diverge (preserving caret if already in sync). Pre-fix:
|
|
2015
|
+
programmatic `host.value = "x"` updated the reactive prop but not
|
|
2016
|
+
the visible content, so the `resettable` trait's snap-back wrote a
|
|
2017
|
+
value the user couldn't see.
|
|
2018
|
+
|
|
2019
|
+
### Fixed — `resettable` discriminates checkable controls
|
|
2020
|
+
|
|
2021
|
+
Previously wrote `host.value = initialValue` for everything, which
|
|
2022
|
+
silently no-op'd on `switch-ui`/`check-ui`/`radio-ui` (whose primary
|
|
2023
|
+
state is `checked`, not `value`). The trait now detects boolean
|
|
2024
|
+
controls (native `[type=checkbox|radio]` + custom elements
|
|
2025
|
+
declaring `checked`) and resets via `host.checked` for those.
|
|
2026
|
+
|
|
2027
|
+
### Fixed — `confetti-burst` fires on press, not just connect
|
|
2028
|
+
|
|
2029
|
+
Refactored `setup()` to extract `fireBurst()` and install it as a
|
|
2030
|
+
`press` listener (composes with the `pressable` trait's published
|
|
2031
|
+
event surface). Old behavior fired exactly once at
|
|
2032
|
+
`connectedCallback` and was inert thereafter. Multiple in-flight
|
|
2033
|
+
bursts tracked in a `Set` so rapid clicks don't clobber each other.
|
|
2034
|
+
|
|
2035
|
+
### Fixed — `droppable` self-recursion (RangeError stack overflow)
|
|
2036
|
+
|
|
2037
|
+
The trait listened for `dnd-drop` on `document` AND dispatched
|
|
2038
|
+
`dnd-drop` on the host with `bubbles: true`. The bubbled event
|
|
2039
|
+
re-reached `document` → re-fired the same handler → recursion to
|
|
2040
|
+
stack overflow. Renamed the host-emitted event to `dnd-drop-receive`
|
|
2041
|
+
(distinct from the document-level signal). `droppable-collection`
|
|
2042
|
+
also updated to listen for `dnd-drop-receive` on its host. Memory
|
|
2043
|
+
entry filed at `feedback_event_name_collision_recursion.md`.
|
|
2044
|
+
|
|
2045
|
+
### Fixed — Icon registry: ~25 new aliases across multiple commits
|
|
2046
|
+
|
|
2047
|
+
`core/icons.js` aliases mapping consumer-friendly names to canonical
|
|
2048
|
+
Phosphor names. Suppresses repeated `[icon-ui] Icon "X" not found`
|
|
2049
|
+
warnings on every page that referenced these:
|
|
2050
|
+
|
|
2051
|
+
- `bold` / `italic` / `underline` → `text-b` / `text-italic` /
|
|
2052
|
+
`text-underline`
|
|
2053
|
+
- `reset` / `undo` → `arrow-counter-clockwise`; `redo` →
|
|
2054
|
+
`arrow-clockwise`
|
|
2055
|
+
- `success-checkmark` → `seal-check`; `circuit` → `circuitry`;
|
|
2056
|
+
`contrast` / `theme` → `circle-half`; `dark-mode` → `moon`;
|
|
2057
|
+
`light-mode` → `sun`
|
|
2058
|
+
- `alert-triangle` / `alert-octagon` / `alert-diamond` → Phosphor
|
|
2059
|
+
`warning` / `warning-octagon` / `warning-diamond`
|
|
2060
|
+
- `number` / `numeric` → `hash`; `numbered-list` → `list-numbers`
|
|
2061
|
+
- `circle-warning` → `warning-circle`; `circle-x` → `x-circle`;
|
|
2062
|
+
`circle-check` → `check-circle`; `circle-info` → `info`;
|
|
2063
|
+
`circle-question` → `question`; `circle-plus` → `plus-circle`;
|
|
2064
|
+
`circle-minus` → `minus-circle`
|
|
2065
|
+
- `fade` / `fade-presence` → `gradient` (from v0.2.3 cut)
|
|
2066
|
+
|
|
2067
|
+
---
|
|
2068
|
+
## [0.2.3] - 2026-05-04
|
|
2069
|
+
|
|
2070
|
+
**Lockstep cut + accumulated fixes.** All 8 published `@adia-ai/*`
|
|
2071
|
+
packages bump 0.2.2 → 0.2.3 per
|
|
2072
|
+
[`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy).
|
|
2073
|
+
Patch cut — no breaking changes. The substantive content is
|
|
2074
|
+
`web-components`-only; the other 7 packages have no source change.
|
|
2075
|
+
|
|
2076
|
+
### Changed
|
|
2077
|
+
|
|
2078
|
+
- `version`: `0.2.2` → `0.2.3`.
|
|
2079
|
+
- `dependencies["@adia-ai/a2ui-utils"]`: `^0.2.0` (covers `0.2.3`).
|
|
2080
|
+
|
|
2081
|
+
### Fixed — `<list-item-ui>` slot layout CSS (2026-05-02)
|
|
2082
|
+
|
|
2083
|
+
`components/list/list.css` — added the `@scope (list-item-ui)` track plan that was missing since the element shipped: a 2-column grid with the icon column at `auto` (icon spans rows, center-aligned), the text + description stacked in column 2, and `[slot="content"]` spanning all columns. Tokens (`--list-item-gap-{column,row}`, `--list-item-{desc,icon}-color`, `--list-item-desc-font-size`) match the rest of the list family. Before this fix, icon / text / description rendered inline as a single line of text in flow order — visible on every consumer of the element. CSS-only; no JS or API change.
|
|
2084
|
+
|
|
2085
|
+
### Fixed — `traits/confetti-burst.js` fires on press, not connect (2026-05-02)
|
|
2086
|
+
|
|
2087
|
+
Refactored the trait's `setup()` to extract a `fireBurst()` function and install it as a listener on the host's `press` event (composes with the `pressable` trait's published event surface). Old behavior fired exactly once at `connectedCallback` time and never again — meaning the element with `traits="confetti-burst"` was inert after the initial mount. New behavior preserves the connect-time burst (so animation-page demos still self-demonstrate) but additionally re-fires on every press; multiple in-flight bursts are tracked in a `Set` so back-to-back clicks don't clobber each other.
|
|
2088
|
+
|
|
2089
|
+
### Fixed — Icon registry: `fade` / `fade-presence` aliases (2026-05-04)
|
|
2090
|
+
|
|
2091
|
+
`core/icons.js` — added two registry aliases mapping the trait-doc names `fade` and `fade-presence` to Phosphor's `gradient` glyph (the closest visual proxy). Without these the trait detail pages logged `[icons] unknown icon: fade-presence` warnings on every load.
|
|
2092
|
+
|
|
2093
|
+
### Fixed — Trait runtime bugs surfaced by user testing on `/site/traits/*` (2026-05-02)
|
|
2094
|
+
|
|
2095
|
+
- `traits/spring-animate.js`: read initial position from `getComputedStyle(host).translate` first, then fall back to the transform matrix. The trait writes to `style.translate`, but the read previously parsed `cs.transform`, which is independent of `translate` in the modern CSS model — callers nudging via `style.translate = '100px 0'` were observed at position 0, so the spring never animated.
|
|
2096
|
+
- `traits/drag-ghost.js`: capture the pointerdown offset within the host and pass it to `dataTransfer.setDragImage(ghost, x, y)`. The old `(0, 0)` offset snapped the ghost to the cursor's top-left corner regardless of where the user grabbed. The ghost clone is also now sized to the host's bounding rect so it doesn't render undersized.
|
|
2097
|
+
|
|
2098
|
+
### Changed — Legacy tag-name sweep across nav cluster + 2 docs (2026-05-04)
|
|
2099
|
+
|
|
2100
|
+
Removed 11 references to deleted tag names (`<section-nav-item-ui>`,
|
|
2101
|
+
`<section-nav-group-ui>`) that survived ADR-0015 + nav consolidation
|
|
2102
|
+
in non-historical files. Source files swept:
|
|
2103
|
+
`components/nav-item/{nav-item.yaml,nav-item.css,nav-item.a2ui.json}`,
|
|
2104
|
+
`components/nav-group/{nav-group.yaml,nav-group.css,nav-group.a2ui.json}`.
|
|
2105
|
+
Description text + cascade-context comments rephrased to drop the
|
|
2106
|
+
legacy tag names without losing the design rationale ("section variant
|
|
2107
|
+
doesn't reserve icon space when absent; section-variant groups render
|
|
2108
|
+
as kicker labels with always-visible children"). Catalog regenerated
|
|
2109
|
+
to match.
|
|
2110
|
+
|
|
2111
|
+
### Changed — `<agent-trace-ui>` STAGE column + detail alignment (2026-05-04)
|
|
2112
|
+
|
|
2113
|
+
`agent-trace.css` row track plan tightened so multi-word stage labels
|
|
2114
|
+
("Rows returned", "Query duration", "Drift vs. SFDC") stay on one line:
|
|
2115
|
+
`--agent-trace-row-label-col` shifts from a fixed `80px` to
|
|
2116
|
+
`minmax(7rem, max-content)`, letting the longest label set the track.
|
|
2117
|
+
The DETAIL column's text and its column header (`[data-trace-aux]`,
|
|
2118
|
+
`[data-trace-header]:nth-of-type(3)`) are right-aligned so 1-3 word
|
|
2119
|
+
qualifiers ("warehouse", "reconciled") sit flush with the row's right
|
|
2120
|
+
edge instead of leaving the column reading as dead width. Per-row
|
|
2121
|
+
`subgrid` keeps the alignment in lockstep across every row.
|
|
2122
|
+
|
|
2123
|
+
---
|
|
2124
|
+
## [0.2.2] - 2026-05-02
|
|
2125
|
+
|
|
2126
|
+
**Lockstep cut + trait coverage 100% + `<traits-host>` wrapper.** All 8 published `@adia-ai/*` packages bump 0.2.1 → 0.2.2 per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
2127
|
+
|
|
2128
|
+
### Changed
|
|
2129
|
+
|
|
2130
|
+
- `version`: `0.2.1` → `0.2.2`.
|
|
2131
|
+
- `dependencies["@adia-ai/a2ui-utils"]`: `^0.2.0` (covers `0.2.2`).
|
|
2132
|
+
- `traits/` is the surface that gained the new behavior below; `traits/index.js` adds a side-effect import of the new wrapper, `scripts/build/traits-catalog.mjs` flipped to hard-fail.
|
|
2133
|
+
|
|
2134
|
+
### Added — Trait test coverage at 100% + `<traits-host>` wrapper (2026-05-02)
|
|
2135
|
+
|
|
2136
|
+
Follow-up landing on top of the v0.2.1 trait-system work — closes the two follow-up items from [ADR-0018](../../.brain/adrs/0018-trait-source-of-truth-and-declarative-attribute.md).
|
|
2137
|
+
|
|
2138
|
+
- **31 new per-trait behavior test files.** Every trait in `traits/` now has a sibling `.test.js`. Total trait-suite footprint: **44 files / 169 tests** (was 12 / 68). Coverage: **42/42 = 100%** (41 trait files + `traits-host`).
|
|
2139
|
+
- **`verify:traits` CI gate flipped from soft-warning to hard-fail.** `npm run verify:traits` exits non-zero if any trait file lacks a sibling `.test.js`, with the offending names listed in the failure message. Verified via mutation test: deleting `active-state.test.js` immediately fails the gate; restoring it returns to clean.
|
|
2140
|
+
- **`<traits-host>` wrapper element** at [`traits/traits-host.js`](./traits/traits-host.js). Tiny pass-through `UIElement` subclass that lets raw HTML opt into declarative trait composition — wrap any markup in `<traits-host traits="pressable scale-press">…</traits-host>` and the named traits attach to the wrapper. Uses `display: contents` so the wrapper has no layout box; children participate in the parent's flex/grid as if the wrapper weren't there. Auto-registered on import of `traits/index.js`. 6 behavior tests covering attribute swap, child event bubbling, and pure-pass-through with no `traits=`.
|
|
2141
|
+
|
|
2142
|
+
---
|
|
2143
|
+
## [0.2.1] - 2026-05-02
|
|
2144
|
+
|
|
2145
|
+
**Lockstep cut + 41-trait library overhaul + `<stat-ui>` ad-blocker rename.** All 8 published `@adia-ai/*` packages bump 0.2.0 → 0.2.1 per [`docs/specs/package-architecture.md` § 15](../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
2146
|
+
|
|
2147
|
+
### Changed
|
|
2148
|
+
|
|
2149
|
+
- `version`: `0.2.0` → `0.2.1`.
|
|
2150
|
+
- `dependencies["@adia-ai/a2ui-utils"]`: `^0.2.0` (covers `0.2.1`).
|
|
2151
|
+
- `styles/colors/semantics.css` — neutral-surface border tokens (`--a-canvas-border-{subtle,strong}` + base) shift to lower-numbered scrim levels (1→0, 3→2, 6→4) for a subtler default polarity. Visible on cards/inputs/buttons that consume `--a-canvas-border*`. No public API change.
|
|
2152
|
+
- `styles/components.css` — `@import` swept to the new `<stat-ui>` filename (see Fixed below).
|
|
2153
|
+
|
|
2154
|
+
### Added — Trait system source-of-truth + declarative `traits=` attribute (2026-05-02)
|
|
2155
|
+
|
|
2156
|
+
Rolls up under [ADR-0018](../../.brain/adrs/0018-trait-source-of-truth-and-declarative-attribute.md). Consumer-visible additions and one core change to UIElement's lifecycle.
|
|
2157
|
+
|
|
2158
|
+
- **`defineTrait()` schema extended.** Now requires `category` (one of nine canonical values, frozen in `define.js`) and `description` (≥ 11 chars). All 40 trait files updated to declare both inline. Build-time throw on missing fields.
|
|
2159
|
+
- **New `getTrait(name)` export from `traits/define.js`.** Returns the trait factory for a kebab-case name, or null if not yet imported. `getTraitSchema(name)` now reads from the same registry (was a separate map).
|
|
2160
|
+
- **New `_motion.js` helper module.** `prefersReducedMotion()` cached check + `onReducedMotionChange()` subscriber. Used by 7 motion-bearing traits (`shimmer-loading`, `attention-pulse`, `typewriter`, `count-up`, `gradient-shift`, `ripple`, `confetti`, `confetti-burst`) to bail or render static fallbacks under `prefers-reduced-motion: reduce`.
|
|
2161
|
+
- **Generated trait catalog at `traits/_catalog.json`.** Single source of truth for downstream consumers (a2ui-corpus, demo pages, MCP `get_traits`). Regenerated by `node scripts/build/traits-catalog.mjs` (added to `package.json` as `build:traits` / `verify:traits` at the repo root).
|
|
2162
|
+
- **UIElement now reads the `traits` attribute.** `<comp-ui traits="ripple confetti-burst">` works on every UIElement subclass. `traits` is always in `observedAttributes`; `attributeChangedCallback` swaps declarative trait instances live without disturbing static or `addTrait()` instances. Static + declarative coexist; double-apply is prevented.
|
|
2163
|
+
|
|
2164
|
+
### Fixed — Trait brittleness bugs surfaced by new tests (2026-05-02)
|
|
2165
|
+
|
|
2166
|
+
- **`confetti.js` and `confetti-burst.js` no longer crash without canvas.** Both called `canvas.getContext('2d').clearRect(...)` on null in environments without canvas (SSR, JSDOM, happy-dom). Now null-check `ctx` and degrade gracefully — set the active attribute, return a no-op cleanup. Caught by `_smoke.test.js` connect/disconnect contract test.
|
|
2167
|
+
|
|
2168
|
+
### Test surface
|
|
2169
|
+
|
|
2170
|
+
- 12 trait test files / 68 tests passing (was 0). Universal contract in `_smoke.test.js`; high-fidelity behavior tests for `pressable`, `focusable`, `validation`, `dirty-state`, `hotkey`, `typewriter`, `count-up`, `shimmer-loading`, `confetti-burst`, `resettable`; declarative-attribute integration in `declarative.test.js`.
|
|
2171
|
+
|
|
2172
|
+
### Added — `resettable` trait
|
|
2173
|
+
|
|
2174
|
+
- New 41st trait at `traits/resettable.js`. Listens for the host's enclosing `<form>` reset event and restores the host's connect-time initial value; dispatches `reset-applied` event with the initial value in detail. Outside a form: clean no-op. Closes the one phantom-trait claim from the original 2026-05-02 audit that survived as a real behavior gap.
|
|
2175
|
+
|
|
2176
|
+
### Changed — UI field hover-bg flattened to default
|
|
2177
|
+
|
|
2178
|
+
`--a-ui-bg-hover` was `var(--a-canvas-2-scrim)` (an elevation-2 lift on
|
|
2179
|
+
hover); it's now `var(--a-canvas-0-scrim)` (same as the default). The
|
|
2180
|
+
hover affordance for FIELD UI surfaces (`<input-ui>`, `<textarea-ui>`,
|
|
2181
|
+
`<nav-item-ui>`, `<chat-input-ui>`) is now carried by border-color +
|
|
2182
|
+
foreground transitions, not bg lift. Reduces hover noise on dense
|
|
2183
|
+
form surfaces; matches the visual flatness of the default-elevation
|
|
2184
|
+
canvas.
|
|
2185
|
+
|
|
2186
|
+
Affects 4 components (1-line `semantics.css` change). No API change;
|
|
2187
|
+
no component code change. `--a-ui-bg-active` (canvas-0) and
|
|
2188
|
+
`--a-ui-bg-disabled` (canvas-1) unchanged — active still drops,
|
|
2189
|
+
disabled still raises.
|
|
2190
|
+
|
|
2191
|
+
### Changed — `<chat-input-ui>` color isolation
|
|
2192
|
+
|
|
2193
|
+
The composite host now owns every color the inner `<textarea-ui>`
|
|
2194
|
+
ships with. Previously, textarea-ui's hover (bg/border/color), focus
|
|
2195
|
+
(color brightening + redundant ring), invalid focus, disabled (color),
|
|
2196
|
+
and placeholder treatments all leaked through `<chat-input-ui>` because
|
|
2197
|
+
each was wired to the generic `--a-ui-*` family with no host-level
|
|
2198
|
+
override. Result: a hover bg flash on the editable area, a brightened
|
|
2199
|
+
fg on focus, two stacked focus rings under invalid state, and a
|
|
2200
|
+
disabled-bg rectangle inside the host's own disabled chrome.
|
|
2201
|
+
|
|
2202
|
+
`chat-input.css` now suppresses every textarea-ui state rule and
|
|
2203
|
+
re-paints them with `--chat-input-*` tokens:
|
|
2204
|
+
|
|
2205
|
+
- `--chat-input-fg` (was implicit via `--a-ui-text`).
|
|
2206
|
+
- `--chat-input-bg-hover`, `-border-hover`, `-fg-hover` — default to
|
|
2207
|
+
`--a-ui-bg-hover` / `--a-ui-border-hover` / `--a-fg`, matching
|
|
2208
|
+
`<input-ui>`'s hover affordance. The host paints the lift on
|
|
2209
|
+
`chat-input-ui:not([disabled]):hover`; the inner textarea-ui's own
|
|
2210
|
+
hover bg/border is forced transparent so the alpha doesn't compound.
|
|
2211
|
+
- `--chat-input-bg-disabled`, `-fg-disabled` — inner-text disabled
|
|
2212
|
+
color is owned here; host-level disabled chrome unchanged.
|
|
2213
|
+
- `--chat-input-placeholder-fg` — was leaking `--a-ui-text-placeholder`.
|
|
2214
|
+
|
|
2215
|
+
Hover lives outside the `@scope` block (Safari 17.x bug — `:scope …
|
|
2216
|
+
[descendant]:hover` doesn't match in Safari 17.x; same workaround
|
|
2217
|
+
input.css and textarea.css already use). Focus / invalid / disabled /
|
|
2218
|
+
placeholder rules stay inside the `@scope` and use the
|
|
2219
|
+
`:scope textarea-ui:STATE [slot="text"]:STATE` (0,4,1) pattern to beat
|
|
2220
|
+
textarea.css's matching rules (0,3,0).
|
|
2221
|
+
|
|
2222
|
+
`--chat-input-duration` shifted from `--a-duration` to `--a-duration-fast`
|
|
2223
|
+
(120 ms) to match `<input-ui>`'s transition speed; the host now
|
|
2224
|
+
transitions `background`, `border-color`, `color`, and `box-shadow`
|
|
2225
|
+
together — same 4-property surface `<input-ui>` and `<select-ui>` use —
|
|
2226
|
+
so hover / focus / invalid / disabled all interpolate as one.
|
|
2227
|
+
|
|
2228
|
+
Inner `[slot="text"]` color overrides changed from explicit
|
|
2229
|
+
`var(--chat-input-fg)` to `color: inherit` so the host's transitioned
|
|
2230
|
+
`color` cascades to the contenteditable. The host's `:scope[disabled]`
|
|
2231
|
+
now sets `color: var(--chat-input-fg-disabled)` directly; the inner
|
|
2232
|
+
inherits, and the disabled-fg shift fades on the host's `color`
|
|
2233
|
+
transition rather than snapping. No JS changes; no API changes.
|
|
2234
|
+
## [0.2.0] - 2026-05-02
|
|
2235
|
+
|
|
2236
|
+
**Lockstep cut.** All 8 published `@adia-ai/*` packages now share one
|
|
2237
|
+
version, governed by [`docs/specs/package-architecture.md` § 15
|
|
2238
|
+
(Versioning Policy)](../../docs/specs/package-architecture.md#15-versioning-policy)
|
|
2239
|
+
and enforced by `npm run check:lockstep` + the
|
|
2240
|
+
`lockstep-versioning` job in
|
|
2241
|
+
[`.github/workflows/docs-lint.yml`](../../.github/workflows/docs-lint.yml).
|
|
2242
|
+
|
|
2243
|
+
Big version jump (0.0.34 → 0.2.0) signals the lockstep era starts here;
|
|
2244
|
+
this is **not** a breaking change to the component surface — every tag
|
|
2245
|
+
+ prop + event from 0.0.34 still works identically. The jump aligns
|
|
2246
|
+
this package with the highest sibling version (a2ui-mcp@0.1.3 → 0.2.0)
|
|
2247
|
+
and avoids the `^0.0.x` caret-lock trap that bit `a2ui-mcp@0.1.3 →
|
|
2248
|
+
a2ui-corpus@0.0.6` (the new `^0.X.0` ranges work properly under npm
|
|
2249
|
+
pre-1.0 semver — see § 15 for the math).
|
|
2250
|
+
|
|
2251
|
+
### Changed
|
|
2252
|
+
|
|
2253
|
+
- `version`: `0.0.34` → `0.2.0`.
|
|
2254
|
+
- `dependencies["@adia-ai/a2ui-utils"]`: `^0.0.2` → `^0.2.0`.
|
|
2255
|
+
|
|
2256
|
+
### No source changes
|
|
2257
|
+
|
|
2258
|
+
This package's source tree is byte-identical to 0.0.34. The cut bumps
|
|
2259
|
+
version and the internal dep range only. Consumers who want the
|
|
2260
|
+
substantive 0.0.34 work (the `<step-progress-ui>` primitive) get it
|
|
2261
|
+
via either 0.0.34 or 0.2.0 — both ship the same component code.
|
|
2262
|
+
|
|
2263
|
+
|
|
2264
|
+
---
|
|
2265
|
+
|
|
2266
|
+
## Pre-0.2.0 history
|
|
2267
|
+
|
|
2268
|
+
The 0.0.x release series (0.0.34 → 0.0.1, 2026-04-21 to 2026-05-02) is
|
|
2269
|
+
archived in [`CHANGELOG-pre-0.2.0.md`](./CHANGELOG-pre-0.2.0.md). That
|
|
2270
|
+
file covers every entry shipped before the lockstep cut.
|