@adia-ai/web-components 0.8.0 → 0.8.2

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/MIGRATION.md ADDED
@@ -0,0 +1,2328 @@
1
+ <!-- GENERATED COPY — do not edit. Canonical source:
2
+ .claude/docs/MIGRATION GUIDE.md (framework monorepo). Regenerate:
3
+ npm run check:migration-sync -- --fix -->
4
+
5
+ # Migration Guide: @agent-ui-kit → @adia-ai
6
+
7
+ Migrating from `@agent-ui-kit/web-components` to the current
8
+ `@adia-ai/*` 9-package monorepo (web-components, web-modules,
9
+ llm, a2ui-runtime, a2ui-compose, a2ui-corpus, a2ui-mcp, a2ui-retrieval,
10
+ a2ui-validator).
11
+
12
+ Current versions: all 9 `@adia-ai/*` packages at `0.7.1` (lockstep,
13
+ 2026-06-01). Internal `@adia-ai/*` ranges are caret-locked at `^0.7.0`
14
+ (PATCH-cut asymmetry: `^0.6.0` covers all `0.6.x` per npm pre-1.0
15
+ semver; minor cuts bump ranges, patch cuts hold). Base class is
16
+ `UIElement` (was `AdiaElement` pre-0.0.x); design tokens use the
17
+ `--a-*` prefix.
18
+
19
+ Version cuts and migration scope:
20
+ - **`0.0.5` through `0.0.11`** — additive polish / hotfix; no migration needed.
21
+ - **`0.0.12` through `0.0.19`** — additive (table-toolbar primitive, smart filters, Construct Canvas, more docs); no breaking changes.
22
+ - **`0.0.20`** — large BREAKING cut. Safari floor raise, ui-audit-coherence fixes, Phase 6 contract decisions, and the deprecation-window closure. Use the [§ 0.0.x → 0.0.20 section below](#migrating-to-adia-aiweb-components0020-2026-04-27) — it's the most comprehensive break in the `0.0.x` line.
23
+ - **`0.0.21`** — same-day patch. Pure source-doc / JSDoc refresh + repo-tooling. **No runtime change.** No migration needed beyond the `0.0.20` sweep; bumping to `0.0.21` is a drop-in upgrade.
24
+ - **`0.0.29` / `web-modules@0.0.1`** — three-tier extraction. Use the [§ 0.0.29 + web-modules section below](#migrating-to-adia-aiweb-components0029--adia-aiweb-modules001-2026-05-01).
25
+ - **`0.3.0` through `0.3.6`** — lockstep series. Additive: ADR-0023 bespoke shell-tier children landed in `web-modules@0.3.4-0.3.6` with backwards compatibility — both legacy and bespoke authoring shapes coexisted. No breaking change at the cluster boundary, though new authoring should use bespoke (see § v0.3.6 below).
26
+ - **`0.4.0`** — large BREAKING cut. **Legacy shell authoring shapes RETIRED** per `ADR-0024`. Closes the ADR-0023 arc. See [§ v0.4.0 section below](#migrating-to-adia-aiv040-2026-05-10) — it's the most comprehensive break since `0.0.20`.
27
+ - **`0.5.0`** — MINOR lockstep cut. Internal ranges `^0.4.0` → `^0.5.0`. **Free-form composer graduation** (cov 21% → 92%) + 5 FEEDBACK rounds from Tokens Studio closed. No code-breaking changes; soft-API graduation only — see [§ v0.5.0 section below](#migrating-to-adia-aiv050-2026-05-13).
28
+ - **`0.5.1`** — PATCH cut. Internal ranges stay at `^0.5.0`. Free-form maturation (cov 92% → 93%, F1 59 → 62) via Haiku-pin + INTENT-PARAPHRASE prompt + Mode-C corpus. **Soft-API graduations:** `result.usedIngredients` + `result.rationale` lifted from `_debug.*` to top-level on `generateFreeFormAdapter`. See [§ v0.5.1 section below](#migrating-to-adia-aiv051-2026-05-13).
29
+ - **`0.5.2`** — PATCH cut. Internal ranges stay at `^0.5.0`. Audit-script family extended to 10 trip-wires (added §128 `check-standalone-html-phosphor` + §135 `check-substitutable-set-drift`). **Soft-API addition:** `result.plan` lifted from `_debug.plan` to top-level on `generateFreeFormAdapter` (the `_debug.plan` fallback was already redundant; v0.5.2 just removes the dead read path). See [§ v0.5.2 section below](#migrating-to-adia-aiv052-2026-05-13).
30
+ - **`0.5.3`** — PATCH cut. Internal ranges stay at `^0.5.0`. **FEEDBACK-06 + FEEDBACK-07 response cycle**: §140 `resolveLoader` filename-suffix fallback (handles pnpm / yarn-berry / custom-Vite-root loader-map keys); §154 NEW `installIconLoadersForRegistered()` + `static requiredIcons` declarations (consumers can auto-discover the icon set their imported primitives need instead of hand-curating brace-lists); §143 8 new UI-primitive corpus chunks closing §127's coverage gap; §142 broadened smoke retrieval probes; §144 yaml-events drift cleanup; §153 slider function-typed `.value` dev-mode guard; §157 responsive-shell-sidebar pattern; §162 yaml-events audit false-positive fix + table row-collapse declaration. **No breaking changes.** Recommended migration for color-app and similar consumers: replace hand-curated `installIconLoaders` brace-lists with `installIconLoadersForRegistered`. See [§ v0.5.3 section below](#migrating-to-adia-aiv053-2026-05-13).
31
+ - **`0.5.4` through `0.5.21`** — PATCH series. Consumer-feedback close-out (FB-29 through FB-53), drift-class lockdown graduation (7 surfaces, 33 trip-wires), `<editor-canvas-toolbar>` module, `<color-input-ui>` form-bearing primitive, `<color-scale-ui>` token composer, and 20 UI-primitive improvements. **No breaking changes.** Upgrade is a drop-in; no migration needed beyond recommended icon-registration upgrade from v0.5.3.
32
+ - **`0.6.0`** — MINOR lockstep cut. Internal ranges `^0.5.0` → `^0.6.0`. **BREAKING:** `stat-ui.{js,css}` renamed to `stat.{js,css}` — deep-importers must update paths. TypeScript substrate Phase 0+1 landed (tsconfig scaffold, `exports.types` on all 9 packages, 38 stub `.d.ts` files). See [§ v0.6.0 section below](#migrating-to-adia-aiv060-2026-05-18).
33
+ - **`0.6.1`** — PATCH cut. Internal ranges stay at `^0.6.0`. **BREAKING:** `<link-ui>` token rename `--link-color-*` → `--link-fg-*`. TypeScript Phase 2 (`@adia-ai/llm` → `.ts`) + Phase 3 (`@adia-ai/a2ui-compose` → `.ts`). See [§ v0.6.1 section below](#migrating-to-adia-aiv061-2026-05-18).
34
+ - **`0.6.2` through `0.6.6`** — PATCH series. TypeScript Phase 4 (`@adia-ai/a2ui-retrieval` + `@adia-ai/a2ui-mcp` → `.ts`), Phase 5 (real `.d.ts` + `a2ui.schema.json` codegen + branded IDs), Phase 6 (strict-flag ratchet sealed, ADR-0029). `<field-ui align>` prop (§304). `mcp/server.ts` thin-dispatcher refactor. **No breaking changes.** Upgrade is a drop-in.
35
+
36
+ - **`0.6.7`** — PATCH cut (2026-05-19). Internal ranges stay at `^0.6.0`. **Closed 17 repo-improvement findings (§367)** — adds shipping artifacts and quality-of-life upgrades; no breaking changes. Highlights:
37
+ - **`@adia-ai/web-components`** ships 96 `.examples.md` files, a W3C-spec `custom-elements.json` manifest, and an `adia-ui-doc` CLI bin (`npx adia-ui-doc <name>`).
38
+ - **`@adia-ai/web-modules`** ships a new `/generative` subpath barrel — single import registers `canvas-ui` + `a2ui-root` + re-exports `registerResolver` (closes the ADR-0027 cross-package barrel footgun).
39
+ - **`@adia-ai/a2ui-mcp`** now exposes 30 tools (was 24): adds `list_patterns`, `refine_ui`, `server_status`. Dual stdio + StreamableHTTP transport (set `MCP_HTTP_PORT` to enable HTTP at `/mcp`). Real MCP sampling support — when run via Claude Code / Cursor / Hermes, the host's LLM is used via `server.createMessage()` instead of falling back to `.env` keys.
40
+ - **Tarball hygiene fixes**: `@adia-ai/web-modules` no longer leaks 28 `.examples.html` authoring artifacts; `@adia-ai/a2ui-mcp` / `a2ui-compose` / `a2ui-retrieval` no longer leak 24 `.ts` source files.
41
+ - **Recommended consumer migration:** if you were using `@adia-ai/web-modules/runtime/a2ui-root/a2ui-root.js` + `@adia-ai/web-components/components/canvas/canvas.js` for generative UI surfaces, collapse to a single `import '@adia-ai/web-modules/generative'`. Both old paths still work.
42
+ - See [§ v0.6.7 section below](#migrating-to-adia-aiv067-2026-05-19).
43
+
44
+ - **Upcoming (`<theme-provider>` cut)** — **BREAKING:** the token-theme attribute is renamed `data-theme` → `theme` repo-wide. Replace `<html data-theme="ocean">` → `<html theme="ocean">` and any `[data-theme="…"]` selectors → `[theme="…"]`. Mechanical: a word-boundary find-replace of `data-theme` → `theme` (preserve compound attrs like `data-theme-slug` / `data-themed`). Pre-1.0 PATCH cadence. Also new: the **`<theme-provider>`** element adopts the AdiaUI foundation into the document from anywhere (no `<head>` stylesheet link), with opt-in `theme="…"` (named preset) + `scale="verse|prose"` (typographic register) attributes that fetch their layer on demand.
45
+ - **`theme` ≠ `scheme` — don't conflate the two axes.** This rename is purely the *theme* axis (a named preset: ocean / forest / slate / …). A light/dark *mode* is the orthogonal *scheme* axis — it belongs on `color-scheme` / `data-scheme`, **never** on `[theme]`. If you'd encoded a mode as `data-theme="dark"`, that was a category error: after the rename it is a no-op on *both* axes. Move it to the scheme axis — `<html style="color-scheme: dark">`, `data-scheme`, or `<toggle-scheme-ui>`. (Surfaced by color-app, 2026-06-07.)
46
+
47
+ - **`0.8.0`** — MINOR lockstep cut (2026-07-15). Internal ranges `^0.7.0` → `^0.8.0`. **BREAKING (3 items):** the Material color-token adoption — `--md-sys-color-*` (a static export) is now the color system's source of truth and public API. Removed: the 19 `--a-accent-*` back-compat aliases (→ `--a-primary-*`), the 189 raw per-family `--a-{family}-{0..6}-{tint-|shade-}scrim` primitives (→ the static `--md-sys-color-{family}-scrim-*` ladder), and the `primitives-accent.css` deep-import path (→ `primitives-primary.css`). **Behavioral:** the 8 named `[theme]` presets no longer re-color components (only brand hue + radius/density/shadow knobs still respond). See [§ v0.8.0 section below](#migrating-to-adia-aiv080-2026-07-15).
48
+
49
+ Live demos and per-component docs at [ui-kit.exe.xyz/site/](https://ui-kit.exe.xyz/site/). The `adia-ui-migration` skill (in `.agents/skills/`) automates most of the mechanical sweeps in this guide.
50
+
51
+ ---
52
+
53
+ ## Migrating to `@adia-ai/*@v0.8.0` (2026-07-15)
54
+
55
+ **MINOR cut.** All 9 packages bumped `0.7.x → 0.8.0`; internal `@adia-ai/*` ranges **bump to `^0.8.0`**. The headline: **AdiaUI adopted the Material Design token system as its color source of truth** (`.claude/docs/specs/material-color-bridge-contract.md`, Phases 1–5). `--md-sys-color-*` roles (59 per palette, 8 palettes, static OKLCH literals in `colors/material-static.css`) are the public color API; the `--a-*` semantic layer remains fully functional as a thin alias layer reading FROM it. 3 breaking items + 1 behavioral change.
56
+
57
+ ### `--a-accent-*` tokens removed (`--a-accent-*` → `--a-primary-*`)
58
+
59
+ The `accent` family was renamed `primary` (matches Material's single `primary` family and the pre-existing L3 CTA names); the deprecated alias block shipped during the transition has been removed now that its zero-consumers condition was met. Pure rename — same values, same roles.
60
+
61
+ **Audit:**
62
+ ```bash
63
+ git grep -nE -- '--a-accent'
64
+ ```
65
+
66
+ **Sweep (mechanical):**
67
+ ```bash
68
+ git grep -lE -- '--a-accent' | xargs perl -i -pe 's/--a-accent(?![a-z0-9])/--a-primary/g'
69
+ ```
70
+
71
+ (The `(?![a-z0-9])` guard keeps suffixed forms like `--a-accent-strong` → `--a-primary-strong` correct while never touching unrelated names. Prefer consuming `--md-sys-color-primary*` directly in new code.)
72
+
73
+ ### Raw per-family scrim primitives removed (`--a-{family}-{0..6}-scrim` → `--md-sys-color-{family}-scrim-*`)
74
+
75
+ `scrims.css` (189 computed alpha-ramp declarations: `--a-{family}-N-tint-scrim` / `-shade-scrim` / `-scrim` for 9 families) is retired — zero in-repo consumers remained once the semantic layer moved to the static export's own 7-step scrim ladder. **Note:** the semantic `--a-canvas-{0..6}-scrim` and `--a-scrim-{weak|toast|default|dialog|strong}` role names still exist and keep working — only the RAW per-family primitives are gone.
76
+
77
+ **Audit:**
78
+ ```bash
79
+ git grep -nE -- '--a-(neutral|primary|secondary|tertiary|brand|info|success|warning|danger)-[0-9]-(tint-scrim|shade-scrim|scrim)\b'
80
+ ```
81
+
82
+ **Sweep: manual review** — the old ramp ran 10–70% alpha over an adaptive near-black/near-white base; the static ladder runs 5–60% over each family's fixed mid-tone. Match by ALPHA VALUE, not name position: `-1-scrim` (20%) → `-scrim-weak`, `-2-` (30%) → `-scrim`, `-3-` (40%) → `-scrim-strong`, `-4-` (50%) → `-scrim-stronger`, `-5/-6-` (60/70%) → `-scrim-strongest` (60% is now the ceiling). A blind rename would shift every overlay one step lighter.
83
+
84
+ ### `primitives-accent.css` file removed (deep-import path)
85
+
86
+ Deep importers of `@adia-ai/web-components/styles/colors/primitives-accent.css` must retarget `primitives-primary.css` (same ramp, renamed family). Consumers of the barrel (`styles/colors/index.css`, `styles/index.css`, `host.css`) are unaffected.
87
+
88
+ **Audit:**
89
+ ```bash
90
+ git grep -n 'primitives-accent'
91
+ ```
92
+
93
+ **Sweep (mechanical):**
94
+ ```bash
95
+ git grep -l 'primitives-accent' | xargs perl -i -pe 's/primitives-accent/primitives-primary/g'
96
+ ```
97
+
98
+ ### Behavioral: named `[theme]` presets no longer re-color (manual review)
99
+
100
+ The 8 `[theme="default|ocean|forest|sunset|lavender|rose|slate|midnight"]` presets worked by overriding parametric `--a-{family}-hue/-c-min/-c-max` knobs that the calc()-based engine consumed. The static export doesn't read those knobs, so the presets no longer change component colors — only `--a-brand-hue` and the non-color knobs (`--a-radius-k`, `--a-density`, `--a-shadow-intensity`) still respond to `[theme]`. **No symbol was removed** — `themes.css` still ships and applying `[theme]` is harmless — but a consumer relying on live re-theming must now theme by overriding `--md-sys-color-*` roles directly (or regenerate a static export per theme). Operator-accepted tradeoff of the adoption; there is no mechanical sweep.
101
+
102
+ **Audit (find consumers that set a theme):**
103
+ ```bash
104
+ git grep -nE 'theme="(ocean|forest|sunset|lavender|rose|slate|midnight)"'
105
+ ```
106
+
107
+ ### Verify the sweep landed (all four items)
108
+
109
+ ```bash
110
+ git grep -cE -- '--a-accent' || echo clean # expect clean (item 1)
111
+ git grep -c 'primitives-accent' || echo clean # expect clean (item 3)
112
+ git grep -cE -- '--a-[a-z]+-[0-9]-(tint-|shade-)?scrim\b' || echo clean # expect clean (item 2)
113
+ ```
114
+
115
+ Then the browser gate on the migrated screens (`adia-verify`): zero console errors,
116
+ non-zero bounding boxes, and read the screenshot — the scrim remap (item 2) and the
117
+ `[theme]` behavioral change are visual; only the pixels prove overlay weights and
118
+ brand color survived. Compare a before/after screenshot of one themed page if the
119
+ app set a named theme.
120
+
121
+ ---
122
+
123
+ ## Migrating to `@adia-ai/*@0.6.0` (2026-05-18)
124
+
125
+ **MINOR cut.** All 9 packages bumped `0.5.x → 0.6.0`. Internal `@adia-ai/*` ranges **bump to `^0.6.0`** (minor-cut asymmetry: all consumers must update their lockstep ranges). TypeScript substrate landed.
126
+
127
+ ### Breaking changes
128
+
129
+ #### `@adia-ai/web-components` — `stat-ui.{js,css}` → `stat.{js,css}` filename rename
130
+
131
+ `<stat-ui>` was the only primitive with a `-ui` suffix in its CSS/JS filenames. Corrected to match the rest of the catalog.
132
+
133
+ **Consumers who deep-import the stat primitive must update:**
134
+
135
+ ```js
136
+ // Before
137
+ import '@adia-ai/web-components/components/stat/stat-ui.js';
138
+ // After
139
+ import '@adia-ai/web-components/components/stat/stat.js';
140
+ ```
141
+
142
+ ```css
143
+ /* Before */
144
+ @import '@adia-ai/web-components/components/stat/stat-ui.css';
145
+ /* After */
146
+ @import '@adia-ai/web-components/components/stat/stat.css';
147
+ ```
148
+
149
+ Consumers who import via the barrel (`@adia-ai/web-components/components/index.js`) or via the component auto-register path (`@adia-ai/web-components/components/stat`) are **not affected** — those paths were already updated.
150
+
151
+ ### Non-breaking additions
152
+
153
+ - **TypeScript substrate Phase 0+1:** all 9 packages now ship `exports.types` pointing to real `.d.ts` declarations. TypeScript consumers get IDE autocomplete and type checking without any config change. No import path changes.
154
+ - **`verify:exports-conditionals` CI gate** added — ensures every `exports.import` has a matching `exports.types` entry.
155
+
156
+ ---
157
+
158
+ ## Migrating to `@adia-ai/*@0.6.1` (2026-05-18)
159
+
160
+ **PATCH cut.** All 9 packages bumped `0.6.0 → 0.6.1`. Internal ranges **stay at `^0.6.0`**.
161
+
162
+ ### Breaking changes
163
+
164
+ #### `@adia-ai/web-components` — `<link-ui>` CSS token rename
165
+
166
+ `--link-color-*` tokens renamed to `--link-fg-*` to match the property-first naming convention used by all other primitives.
167
+
168
+ | Old token | New token |
169
+ |---|---|
170
+ | `--link-color` | `--link-fg` |
171
+ | `--link-color-hover` | `--link-fg-hover` |
172
+ | `--link-color-visited` | `--link-fg-visited` |
173
+
174
+ **Action required if you customise `<link-ui>` colours in CSS:**
175
+
176
+ ```css
177
+ /* Before */
178
+ link-ui { --link-color: var(--brand-blue); }
179
+ link-ui:hover { --link-color-hover: var(--brand-blue-dark); }
180
+
181
+ /* After */
182
+ link-ui { --link-fg: var(--brand-blue); }
183
+ link-ui:hover { --link-fg-hover: var(--brand-blue-dark); }
184
+ ```
185
+
186
+ If you do not override these tokens (i.e. you use the default theme colours), **no action needed**.
187
+
188
+ ### Non-breaking additions
189
+
190
+ - **`@adia-ai/llm` TypeScript Phase 2:** sources moved to `src/*.ts`; real `.d.ts` files generated; import paths unchanged (`@adia-ai/llm`, `@adia-ai/llm/bridge`, `@adia-ai/llm/stub`, `@adia-ai/llm/adapters/*` all work as before). TypeScript consumers now get accurate parameter and return types.
191
+ - **`@adia-ai/a2ui-compose` TypeScript Phase 3:** internal sources typed; no public API change.
192
+
193
+ ---
194
+
195
+ ## Migrating to `@adia-ai/*@0.6.7` (2026-05-19)
196
+
197
+ **PATCH cut.** Internal `@adia-ai/*` ranges stay at `^0.6.0`. No breaking changes; upgrade is a drop-in from any `0.6.x`. This release closes 17 repo-improvement findings (§367) — most user-visible changes are net-new shipping artifacts and quality-of-life upgrades.
198
+
199
+ ### What's new in the published packages
200
+
201
+ **`@adia-ai/web-components` now ships:**
202
+
203
+ - **`components/<name>/<name>.examples.md`** (96 files, ~67KB total). 1-3 canonical fragments per component as plain markdown. Previously `.examples.html` was monorepo-only; consumers had no first-class markup reference. Read with `cat node_modules/@adia-ai/web-components/components/<name>/<name>.examples.md` or via `npx adia-ui-doc <name>`.
204
+ - **`custom-elements.json`** (W3C Custom Elements Manifest v2.1.0, 110 modules, ~300KB). Enables VS Code LSP autocomplete and Storybook/wider WC-tool interop without configuration.
205
+ - **`bin/doc.mjs`** + `bin` field — exposes a `npx adia-ui-doc` CLI:
206
+ ```bash
207
+ npx adia-ui-doc # list all 96 components
208
+ npx adia-ui-doc field # summary + live demo URL + first example
209
+ ```
210
+
211
+ **`@adia-ai/web-modules` ships a new `generative` subpath:**
212
+
213
+ ```js
214
+ // One import registers <canvas-ui> + <a2ui-root> + re-exports registerResolver
215
+ import '@adia-ai/web-modules/generative';
216
+ import { registerResolver, Canvas, A2UIRoot } from '@adia-ai/web-modules/generative';
217
+ ```
218
+
219
+ Closes the ADR-0027 "cross-package primitives don't auto-register" footgun for the generative-UI use case. Both the previous-form imports continue to work:
220
+
221
+ ```js
222
+ // Still supported (more verbose; 0.6.6 and earlier shape)
223
+ import '@adia-ai/web-modules/runtime/a2ui-root/a2ui-root.js';
224
+ import '@adia-ai/web-components/components/canvas/canvas.js';
225
+ import { registerResolver } from '@adia-ai/a2ui-runtime';
226
+ ```
227
+
228
+ **`@adia-ai/a2ui-mcp` adds three tools (24 → 30):**
229
+
230
+ - `list_patterns({ domain?, category? })` — enumerate the corpus with optional filters. Useful when you want to browse rather than keyword-search.
231
+ - `refine_ui({ intent, previousMessages, validationErrors })` — re-run monolithic generation feeding validation errors back to the LLM. Closes the missing-refine path for the monolithic engine (zettel already had `refine_composition`).
232
+ - `server_status()` — returns `{ version, transport, sampling, corpus: { totalComponents, compositionCount, chunkCount } }`. Useful for health-checks and observability.
233
+
234
+ **Dual transport — set `MCP_HTTP_PORT` to enable HTTP:**
235
+
236
+ ```bash
237
+ # stdio (default) — for Claude Code / Cursor / Hermes IDE integration
238
+ node node_modules/.bin/adiaui-mcp
239
+
240
+ # HTTP — for deployed services, exposed at <host>:<port>/mcp
241
+ MCP_HTTP_PORT=3460 node node_modules/.bin/adiaui-mcp
242
+ ```
243
+
244
+ The HTTP transport implements the MCP Streamable HTTP protocol (MCP spec 2025-11-25). The Node-side `mcpStream()` adapter in `@adia-ai/a2ui-runtime` was also extended to dispatch by URL scheme — `ws://` / `wss://` use the original WebSocket path, `http://` / `https://` use the new Streamable HTTP client.
245
+
246
+ **MCP sampling is now wired through** — when run via Claude Code / Cursor / Hermes, `generate_ui` and `plan_app_state` will request inference from the host's LLM via `server.createMessage()` instead of falling back to `.env` API keys. The host LLM choice (model + budget + provider) is transparently used. Falls back to `.env` keys if the client doesn't declare sampling capability.
247
+
248
+ ### Tarball hygiene fixes
249
+
250
+ These don't change the API but eliminate authoring-artifact bloat in published tarballs:
251
+
252
+ - **`@adia-ai/web-modules`** — was leaking 28 `.examples.html` files into the tarball. Now filtered (matches `@adia-ai/web-components` convention via `!**/*.examples.html` in `files`).
253
+ - **`@adia-ai/a2ui-mcp` / `@adia-ai/a2ui-compose` / `@adia-ai/a2ui-retrieval`** — were leaking 24 TypeScript source files alongside the emitted `.js` (a hangover from the Phase-4/5 TS migration). Now filtered via `!**/*.ts` + re-include `**/*.d.ts` in `files`.
254
+
255
+ ### Recommended consumer migration (optional, non-breaking)
256
+
257
+ If you have a generative-UI surface and were using the verbose three-import pattern, collapse to the new subpath:
258
+
259
+ ```diff
260
+ - import '@adia-ai/web-modules/runtime/a2ui-root/a2ui-root.js';
261
+ - import '@adia-ai/web-components/components/canvas/canvas.js';
262
+ - import { registerResolver } from '@adia-ai/a2ui-runtime';
263
+ + import '@adia-ai/web-modules/generative';
264
+ + import { registerResolver } from '@adia-ai/web-modules/generative';
265
+ ```
266
+
267
+ No further changes needed; `<canvas-ui>` and `<a2ui-root>` register identically.
268
+
269
+ If you have an MCP server registration in `.claude/settings.json` / `.cursor/mcp.json`, **no change required**. Existing stdio registration continues to work and now picks up the new tools + sampling capability automatically.
270
+
271
+ ### Verification gates added
272
+
273
+ - `node scripts/verify-pack.mjs` — validates tarball shape across all 9 packages (yaml/a2ui.json/d.ts count parity, no .ts source leaks, required artifacts present, CSS-only + child components allowlisted). Wired into the `npm run check` umbrella.
274
+ - `npm run smoke:mcp-extended` — three smokes covering HTTP transport initialize handshake, sampling capability detection, new-tool callability. Bundled into `npm run mcp:smoke`.
275
+
276
+ ---
277
+
278
+ ## Migrating to `@adia-ai/*@0.6.2` – `0.6.6` (2026-05-18)
279
+
280
+ **PATCH series.** No breaking changes. Upgrade is a drop-in from any `0.6.x`.
281
+
282
+ ### New in `0.6.2` — TypeScript Phase 4
283
+
284
+ `@adia-ai/a2ui-retrieval` and `@adia-ai/a2ui-mcp` sources converted to TypeScript. TS-MIG-001 `skipLibCheck` override closed — all packages fully type-checked. No public API change.
285
+
286
+ ### New in `0.6.3` – `0.6.4` — TypeScript Phase 5 (real runtime declarations)
287
+
288
+ `@adia-ai/a2ui-runtime` ships real `.d.ts` declarations replacing Phase 1 stub files. Includes:
289
+ - `A2UIMessage` discriminated union type (all 6 message kinds: `createSurface`, `updateComponents`, `updateDataModel`, `wireComponents`, `deleteSurface`, `meta`)
290
+ - `A2UIComponent` interface with full property set
291
+ - `a2ui.schema.json` (JSON Schema 2020-12) as the authoritative source; `a2ui.schema.d.ts` generated from it
292
+ - Branded ID types: `FragmentId`, `ChunkId`, `CompositionId` in `@adia-ai/a2ui-compose`
293
+ - Subpath exports: `@adia-ai/a2ui-runtime/schema` → `a2ui.schema.d.ts`; `@adia-ai/a2ui-runtime/types` → `types.d.ts`
294
+
295
+ TypeScript consumers writing custom compose strategies or MCP tools can now import the A2UI protocol types directly:
296
+
297
+ ```ts
298
+ import type { A2UIMessage, A2UIComponent } from '@adia-ai/a2ui-runtime/schema';
299
+ ```
300
+
301
+ ### New in `0.6.5` — TypeScript Phase 6 sealed
302
+
303
+ All 6 TypeScript migration phases complete. `tsconfig.base.json` is now normative — zero untracked strict-flag overrides across all 9 packages. See `.claude/docs/specs/typescript-first-substrate.md` and ADR-0029.
304
+
305
+ ### New in `0.6.6` — `<field-ui align>` prop
306
+
307
+ `<field-ui>` gains an `align` attribute (`start` | `end`, default `start`). `align="end"` right-aligns the label within its grid cell — useful in multi-field forms where labels should be flush to the control column:
308
+
309
+ ```html
310
+ <!-- Default: label left-aligned -->
311
+ <field-ui label="Email"><input-ui type="email"></input-ui></field-ui>
312
+
313
+ <!-- Trailing-flush label alignment -->
314
+ <field-ui label="Email" align="end"><input-ui type="email"></input-ui></field-ui>
315
+ ```
316
+
317
+ CSS-only; no layout structure change.
318
+
319
+ ---
320
+
321
+ ## Migrating to `@adia-ai/*@0.5.3` (2026-05-13)
322
+
323
+ **PATCH cut.** All 9 packages bumped `0.5.2 → 0.5.3`. Internal `@adia-ai/*` ranges **stay at `^0.5.0`** per PATCH-cut asymmetry. **No breaking changes.**
324
+
325
+ Headline response: **FEEDBACK-06 + FEEDBACK-07** from external consumers (Tokens Studio / color-app). Two complementary icon-registry fixes + the broader v0.5.3 cycle's quality + audit work.
326
+
327
+ ### 🌟 Recommended icon-registration upgrade (FEEDBACK-06 §4 / FEEDBACK-07 §4 / §154)
328
+
329
+ Consumers who use `installIconLoaders` with a hand-curated brace-list can now switch to **`installIconLoadersForRegistered`** — auto-discovers the icon set from every primitive's `static requiredIcons` declaration. No more "I added a new component and got `warnMissingIcon` for an icon I didn't even author."
330
+
331
+ **Before (v0.5.2):**
332
+
333
+ ```ts
334
+ import { installIconLoaders } from '@adia-ai/web-components/core/icons'
335
+ import '@adia-ai/web-components/components/select' // needs caret-up-down internally
336
+ import '@adia-ai/web-components/components/tag' // needs x for dismiss
337
+
338
+ installIconLoaders({
339
+ regular: import.meta.glob(
340
+ '/node_modules/@phosphor-icons/core/assets/regular/{caret-up-down,x,sun,moon}.svg',
341
+ { query: '?raw', import: 'default', eager: true }
342
+ ),
343
+ })
344
+ ```
345
+
346
+ Pitfall: every time you add a primitive, you must figure out which icons it auto-stamps + extend the brace-list. Easy to miss (`<color-picker-ui>` needs `check`/`warning`/`copy`; `<select-ui>` needs `caret-up-down`; `<tag-ui>` needs `x`; etc.).
347
+
348
+ **After (v0.5.3):**
349
+
350
+ ```ts
351
+ import { installIconLoadersForRegistered } from '@adia-ai/web-components/core/icons'
352
+ import '@adia-ai/web-components/components/select'
353
+ import '@adia-ai/web-components/components/tag'
354
+
355
+ // Builds the loader map by walking customElements + reading
356
+ // `static requiredIcons` on each defined primitive. Add or remove
357
+ // component imports + the icon set stays correct automatically.
358
+ installIconLoadersForRegistered({
359
+ regular: import.meta.glob('/node_modules/@phosphor-icons/core/assets/regular/*.svg', {
360
+ query: '?raw',
361
+ import: 'default',
362
+ eager: true,
363
+ }),
364
+ });
365
+ ```
366
+
367
+ The `static requiredIcons` declaration is a class-level array on every primitive that auto-stamps an `<icon-ui>` internally:
368
+
369
+ ```js
370
+ // packages/web-components/components/select/class.js
371
+ export class UISelect extends UIFormElement {
372
+ static requiredIcons = ['caret-up-down'];
373
+ // ...
374
+ }
375
+ ```
376
+
377
+ For consumers who prefer to keep a narrow brace-list (smallest bundle), the `discover()` helper returns the discovered list so you can build a tighter glob:
378
+
379
+ ```ts
380
+ import { installIconLoadersForRegistered } from '@adia-ai/web-components/core/icons'
381
+
382
+ const required = installIconLoadersForRegistered.discover()
383
+ // required = ['caret-up-down', 'caret-right', 'x', 'check', 'warning', 'copy', ...]
384
+ ```
385
+
386
+ ### §140 — `resolveLoader` filename-suffix fallback
387
+
388
+ Loader-map keys no longer need to match the canonical `/node_modules/@phosphor-icons/core/assets/<weight>/<filename>` prefix. pnpm hoist (`/node_modules/.pnpm/@phosphor-icons+core@.../`), yarn berry PnP virtual paths, custom Vite roots, and manually-built loader maps now resolve correctly. Public API unchanged; relaxes lookup-key discipline only. **You don't need to do anything** — your existing `installIconLoaders(modules)` call will work regardless of key prefix.
389
+
390
+ ### Other arcs in v0.5.3 (no consumer action)
391
+
392
+ - §142: smoke retrieval probes broadened post-§125 chunk refactor
393
+ - §143: 8 new UI-primitive corpus chunks (calendar, color-picker, slider, pagination, popover, avatar-group, video-player, +1) closing v0.5.2 §127's Haiku-vs-Opus coverage gap
394
+ - §144: yaml-events drift cleanup on 4 components
395
+ - §153: slider `.value` function-typed dev-mode guard (FEEDBACK-07 §3)
396
+ - §157: NEW `<responsive-shell-sidebar>` pattern (FEEDBACK-06 §3)
397
+ - §162: `check:yaml-events` audit false-positive fix + table row-collapse event declaration
398
+
399
+ ### Recipe
400
+
401
+ ```bash
402
+ npm install -E @adia-ai/web-components@0.5.3 \
403
+ @adia-ai/web-modules@0.5.3 \
404
+ @adia-ai/a2ui-runtime@0.5.3 \
405
+ @adia-ai/a2ui-compose@0.5.3 \
406
+ @adia-ai/a2ui-corpus@0.5.3 \
407
+ @adia-ai/a2ui-mcp@0.5.3 \
408
+ @adia-ai/a2ui-retrieval@0.5.3 \
409
+ @adia-ai/a2ui-validator@0.5.3 \
410
+ @adia-ai/llm@0.5.3
411
+ ```
412
+
413
+ If you have a hand-curated `installIconLoaders` brace-list, consider switching to `installIconLoadersForRegistered` (see above). Otherwise drop-in upgrade.
414
+
415
+ ---
416
+
417
+ ## Migrating to `@adia-ai/*@0.5.2` (2026-05-13)
418
+
419
+ **PATCH cut.** All 9 packages bumped `0.5.1 → 0.5.2`. Internal `@adia-ai/*` ranges **stay at `^0.5.0`** per the PATCH-cut asymmetry — `^0.5.0` covers all `0.5.x` automatically; only minor cuts bump the floor.
420
+
421
+ **No breaking changes.** Audit-script family extended + small soft-API addition; consumers stay drop-in.
422
+
423
+ ### Soft-API addition (`@adia-ai/a2ui-compose`)
424
+
425
+ `generateFreeFormAdapter(ctx)` return value now exposes `result.plan` as a top-level field (was previously read from `result._debug?.plan`). Internal consumers updated:
426
+
427
+ - `eval-diff.mjs` line 147: `const plan = result.plan || result._debug?.plan || null` → `result.plan || null` (the dead fallback is gone).
428
+
429
+ External consumers reading `result._debug?.plan` will get `undefined` after upgrading to `@adia-ai/a2ui-compose@0.5.2`. **Recommended migration**: read `result.plan` directly. Defensive optional chaining keeps the path safe either way.
430
+
431
+ ### Audit-script family extensions
432
+
433
+ Two new pre-flight trip-wires added (slots 9 + 10 in the existing §72 / §81 / §83 / §84 / §98 / §100a / §102 / §115 family):
434
+
435
+ | Script | Closes |
436
+ |---|---|
437
+ | `npm run check:standalone-html-phosphor` | Standalone-HTML phosphor wiring drift (§107 bug class — `<icon-ui>` blank in iframed demo HTMLs) |
438
+ | `npm run check:substitutable-set-drift` | `SUBSTITUTABLE` set drift between `eval-diff.mjs` and `transpile.js` SoTs |
439
+
440
+ Both are wired into the `lockstep-release` SKILL Step 1 pre-flight. No consumer action required.
441
+
442
+ ### Toast → feed facade soak verdict
443
+
444
+ Per the soak window (2026-05-01 → 2026-05-15), `<toast-ui>` facade was reviewed for stability. Verdict: **PASS-WITH-CAVEAT** (zero internal consumers exercised it in-window; facade is bug-free but data sparse). v0.6.0 will include a "toast-ui element deprecation review" gated on external-consumer audit. Until then: no consumer action; `<toast-ui>` element + `UIToast.show()` API both continue to work.
445
+
446
+ ### `_debug.*` volatility contract
447
+
448
+ The `_debug` block on `generateFreeFormAdapter`'s return value is now formally documented as volatile / dialog-recorder-gated:
449
+
450
+ ```js
451
+ const result = await generateFreeFormAdapter(ctx);
452
+
453
+ // ✓ Stable first-class fields (post-§109 / §107a)
454
+ result.usedIngredients // array of chunk names
455
+ result.rationale // LLM rationale text
456
+ result.plan // LLM plan { ingredients: [...] }
457
+
458
+ // ⚠ Volatile, dialog-recorder-gated; do not depend on shape
459
+ result._debug?.attempts
460
+ result._debug?.warnings
461
+ result._debug?.systemPrompt
462
+ result._debug?.rawLLMResponse
463
+ result._debug?.tokens
464
+ ```
465
+
466
+ The `_debug.*` block remains; only the API contract is documented as volatile. v0.6.0 schedules folding `attempts` + `warnings` into first-class fields.
467
+
468
+ ### Recurring eval gate
469
+
470
+ `.github/workflows/free-form-eval-weekly.yml` now schedules monthly (`cron: '0 6 1 * *'`, 1st of each month at 06:00 UTC). Cost: ~$4/yr post-§118 Haiku-pin. Flip to weekly (`0 6 * * 1`) for ~$16/yr if higher cadence is needed.
471
+
472
+ ### Recipe
473
+
474
+ Drop-in upgrade:
475
+
476
+ ```bash
477
+ npm install -E @adia-ai/web-components@0.5.2 \
478
+ @adia-ai/web-modules@0.5.2 \
479
+ @adia-ai/a2ui-runtime@0.5.2 \
480
+ @adia-ai/a2ui-compose@0.5.2 \
481
+ @adia-ai/a2ui-corpus@0.5.2 \
482
+ @adia-ai/a2ui-mcp@0.5.2 \
483
+ @adia-ai/a2ui-retrieval@0.5.2 \
484
+ @adia-ai/a2ui-validator@0.5.2 \
485
+ @adia-ai/llm@0.5.2
486
+ ```
487
+
488
+ If you read `_debug.plan` directly, switch to `result.plan` (one-line fix; optional chaining keeps old code safe).
489
+
490
+ ---
491
+
492
+ ## Migrating to `@adia-ai/*@0.5.1` (2026-05-13)
493
+
494
+ **PATCH cut.** All 9 packages bumped `0.5.0 → 0.5.1`. Internal `@adia-ai/*` ranges **stay at `^0.5.0`** per PATCH-cut asymmetry. **No breaking changes.**
495
+
496
+ ### Soft-API graduations (`@adia-ai/a2ui-compose`)
497
+
498
+ §109 + §118 lifted two fields from `result._debug.*` to top-level on `generateFreeFormAdapter`:
499
+
500
+ ```js
501
+ // v0.5.0 — fields read from _debug.* (silently undefined when not recording)
502
+ result._debug?.usedIngredients // could be undefined
503
+ result._debug?.rationale // could be undefined
504
+
505
+ // v0.5.1 — fields are first-class (always populated)
506
+ result.usedIngredients // array of chunk names
507
+ result.rationale // LLM rationale text
508
+ ```
509
+
510
+ The `_debug.*` block keeps `plan`, `attempts`, `warnings`, `systemPrompt`, `rawLLMResponse`, `tokens` (those gate on the recording state). External consumers reading `result._debug?.usedIngredients` / `result._debug?.rationale` will get `undefined` after upgrade — optional chaining handles this safely, but the recommended migration is to read the top-level fields.
511
+
512
+ Internal consumers updated (commit `8c07a007`):
513
+ - `apps/genui/app/factory-chat/factory-chat.contents.js:674`
514
+ - `apps/genui/app/gen-ui/_handlers/handleAuto.js:107`
515
+
516
+ ### Free-form composer maturation (no consumer action)
517
+
518
+ - **Coverage**: 92% → 93% on full-100 held-out set (via §117 INTENT-PARAPHRASE block + paraphrase-retry on empty-plan)
519
+ - **F1**: 59 → 62 (via §107a/b ALWAYS-substitute prompt push + substitution-coverage measurement infra)
520
+ - **Model**: free-form ingredient picker now uses Claude Haiku 4.5 by default (was Opus). ~5× cheaper per intent (~$0.015 → ~$0.003). No quality regression expected. Empirical A/B deferred to v0.5.2 §127.
521
+ - **Corpus**: 10 new annotated chunks via `catalog/ui-patterns/v050-mode-c-blocks/`
522
+
523
+ ### Audit-script family (no consumer action)
524
+
525
+ - §115: NEW `npm run check:free-form-eval-regression` — reads `eval-diff` output's free-form coverage/F1/avgScore, gates against the v0.5.1 baseline.
526
+ - §128: NEW `.github/workflows/free-form-eval-weekly.yml` — manual-only at v0.5.1 (schedule block commented); v0.5.2 flips to monthly cron.
527
+
528
+ ### Recipe
529
+
530
+ ```bash
531
+ npm install -E @adia-ai/web-components@0.5.1 @adia-ai/web-modules@0.5.1 \
532
+ @adia-ai/a2ui-runtime@0.5.1 @adia-ai/a2ui-compose@0.5.1 @adia-ai/a2ui-corpus@0.5.1 \
533
+ @adia-ai/a2ui-mcp@0.5.1 @adia-ai/a2ui-retrieval@0.5.1 @adia-ai/a2ui-validator@0.5.1 \
534
+ @adia-ai/llm@0.5.1
535
+ ```
536
+
537
+ If reading `_debug.usedIngredients` or `_debug.rationale`: switch to top-level. One-line fix per call site.
538
+
539
+ ---
540
+
541
+ ## Migrating to `@adia-ai/*@0.5.0` (2026-05-13)
542
+
543
+ **MINOR lockstep cut.** All 9 packages bumped `0.4.9 → 0.5.0`. Internal `@adia-ai/*` ranges bumped `^0.4.0` → `^0.5.0` (MINOR convention).
544
+
545
+ **No code-breaking changes.** First MINOR since the lockstep era began at v0.2.0; the graduation cut for the v0.4.x consumer-feedback arc.
546
+
547
+ ### What v0.5.0 closed
548
+
549
+ - **5 rounds of FEEDBACK from Tokens Studio** (consumer ID: `colorapp`) — 27 total claims closed across v0.4.5–v0.5.0:
550
+ - FEEDBACK-01: initial v0.4.x integration audit (8 claims)
551
+ - FEEDBACK-02: color-picker constraint surface (7 claims)
552
+ - FEEDBACK-03: package import surface + `core/icons.js` registry split (3 claims)
553
+ - FEEDBACK-04: color-picker.d.ts P0 + isFocusInInput utility (7 claims)
554
+ - FEEDBACK-05: `core/element.d.ts` runtime re-export mirror (1 claim)
555
+
556
+ - **Audit-script family complete on every known hand-authored drift class** — 7 trip-wires at v0.5.0: §72 + §81 + §83 + §84 + §98 + §100a + §102. v0.5.1 adds §115; v0.5.2 adds §128 + §135.
557
+
558
+ - **Free-form composer graduation** (cov 21% → 92% on full-100):
559
+ - §93: layout-chunk regrowth (15 chunks)
560
+ - §94: forms + data + navigation regrowth (~10 chunks per domain)
561
+ - §95: picker promotion (free-form available alongside zettel + monolithic)
562
+ - §97: threshold rebaseline against the honest 92% baseline
563
+ - §103: auto-grouping (Column / Row / Grid root container per LLM-emitted `plan.layout`)
564
+ - §104: 22 new annotated chunks across 6 catalog/ui-patterns/v050-*-blocks/ pages
565
+ - §105: structural substitutions (Button.text / Badge.text / Tag.text / Icon.name / Image.alt / Link.href / Kbd.textContent)
566
+
567
+ ### Soft-API additions (no breaking changes)
568
+
569
+ `generateFreeFormAdapter` (in `@adia-ai/a2ui-compose`) is the headline new strategy. It composes UI from the LLM-driven free-form picker against the 86-chunk corpus. Auto-engine routes intents to it as one of multiple strategies (zettel / free-form / monolithic).
570
+
571
+ If you previously called `generateAdapter(ctx)` directly: no change. The strategy registry handles routing.
572
+
573
+ ### Recipe
574
+
575
+ ```bash
576
+ npm install -E @adia-ai/web-components@0.5.0 @adia-ai/web-modules@0.5.0 \
577
+ @adia-ai/a2ui-runtime@0.5.0 @adia-ai/a2ui-compose@0.5.0 @adia-ai/a2ui-corpus@0.5.0 \
578
+ @adia-ai/a2ui-mcp@0.5.0 @adia-ai/a2ui-retrieval@0.5.0 @adia-ai/a2ui-validator@0.5.0 \
579
+ @adia-ai/llm@0.5.0
580
+ ```
581
+
582
+ For consumers on `^0.4.0`, this is a single `npm install` away (internal ranges bump from `^0.4.0` to `^0.5.0` per MINOR convention). No code changes required.
583
+
584
+ ### Pre-v0.5.0 cleanup landed
585
+
586
+ - `<icon-ui>` registry split (§89, FEEDBACK-03): three barrels (`web-components/index.js` / `core/index.js` / `components/index.js`) auto-load `core/icons-phosphor.js`. Piecemeal-component consumers either import a barrel OR explicitly import `core/icons-phosphor` OR call `installIconLoaders()` with a scoped glob. Standalone-template demo HTMLs got phosphor wiring in v0.5.1 §107 (followed by a v0.5.2 §128 trip-wire to prevent the regression).
587
+
588
+ ---
589
+
590
+ ## Migrating to `@adia-ai/*@0.4.0` (2026-05-10)
591
+
592
+ **⚠️ First non-patch release in the 0.x line.** All 9 published `@adia-ai/*` packages bumped to `0.4.0` as a lockstep cut. Internal `@adia-ai/*` ranges bumped from `^0.3.0` to `^0.4.0`. The legacy shell authoring shapes (across all 3 shell hosts) are RETIRED. Consumers MUST use the bespoke vocabulary established by ADR-0023 in v0.3.4–v0.3.6.
593
+
594
+ **Migration window**: 9 days. Bespoke landed in `web-modules@0.3.4` (2026-05-10), all 6 in-repo consumers migrated in `web-modules@0.3.6` (2026-05-10), legacy retired in `0.4.0` (2026-05-10). Any consumer pinned to `0.3.x` had backwards-compat reads available for the entire transition window.
595
+
596
+ ### Removed (BREAKING)
597
+
598
+ #### admin cluster — `<admin-shell>`
599
+ - `<aside-ui slot="leading|trailing">` — replaced by `<admin-sidebar slot="leading|trailing">`
600
+ - `<aside data-sidebar="leading|trailing">` — replaced by `<admin-sidebar slot="leading|trailing">`
601
+ - `<dialog data-command>` — replaced by `<admin-command>`
602
+ - `[data-resize]` external handle children — resize now internal to `<admin-sidebar>`
603
+ - Shell host no longer reads any of the legacy paths
604
+
605
+ #### chat cluster — `<chat-shell>`
606
+ - `<section data-chat-messages>` — replaced by `<chat-thread>`
607
+ - `<chat-input-ui data-chat-input>` — replaced by `<chat-composer>` wrapping `<chat-input-ui>`
608
+ - `<empty-state-ui data-chat-empty>` — replaced by `<chat-empty>` wrapping `<empty-state-ui>`
609
+ - `<header>` with `[data-chat-name]` / `[data-chat-status]` — replaced by `<chat-header>` with `<chat-status>`
610
+ - `<footer>` with `<chat-input-ui>` — replaced by `<chat-composer>`
611
+ - The shell only listens for `composer-submit` events now (was: `submit` + `composer-submit` dual)
612
+
613
+ #### editor cluster — `<editor-shell>`
614
+ - `<header>` toolbar — replaced by `<editor-toolbar>`
615
+ - `<div data-editor-body>` wrapper — dropped entirely (use direct grid children)
616
+ - `<pane-ui data-left|data-right>` — replaced by `<editor-sidebar slot="leading|trailing">` wrapping `<pane-ui resizable>`
617
+ - `<div data-canvas>` — replaced by `<editor-canvas>`
618
+ - `<footer>` statusbar — replaced by `<editor-statusbar>`
619
+
620
+ ### Migration recipe per cluster
621
+
622
+ #### admin cluster diff
623
+ ```diff
624
+ - <admin-shell>
625
+ - <aside-ui slot="leading"> ← or <aside data-sidebar="leading">
626
+ - <header-ui>…</header-ui>
627
+ - <section-ui>…</section-ui>
628
+ - <footer-ui>…</footer-ui>
629
+ - <div data-resize></div>
630
+ - </aside-ui>
631
+ - <main>…</main>
632
+ - <dialog data-command>
633
+ - <command-ui></command-ui>
634
+ - </dialog>
635
+ - </admin-shell>
636
+ + <admin-shell>
637
+ + <admin-sidebar slot="leading" resizable collapsible>
638
+ + <header-ui>…</header-ui>
639
+ + <section-ui>…</section-ui>
640
+ + <footer-ui>…</footer-ui>
641
+ + <!-- resize handle now internal to <admin-sidebar> -->
642
+ + </admin-sidebar>
643
+ + <main>…</main>
644
+ + <admin-command>
645
+ + <command-ui></command-ui>
646
+ + </admin-command>
647
+ + </admin-shell>
648
+ ```
649
+
650
+ #### chat cluster diff
651
+ ```diff
652
+ - <chat-shell>
653
+ - <header>
654
+ - <span data-chat-name>Title</span>
655
+ - <span data-chat-status></span>
656
+ - </header>
657
+ - <section data-chat-messages>
658
+ - <empty-state-ui data-chat-empty>…</empty-state-ui>
659
+ - </section>
660
+ - <footer>
661
+ - <chat-input-ui data-chat-input></chat-input-ui>
662
+ - </footer>
663
+ - </chat-shell>
664
+ + <chat-shell>
665
+ + <chat-header>
666
+ + <span slot="name">Title</span>
667
+ + <chat-status slot="status"></chat-status>
668
+ + </chat-header>
669
+ + <chat-thread>
670
+ + <chat-empty>
671
+ + <empty-state-ui>…</empty-state-ui>
672
+ + </chat-empty>
673
+ + </chat-thread>
674
+ + <chat-composer>
675
+ + <chat-input-ui></chat-input-ui>
676
+ + </chat-composer>
677
+ + </chat-shell>
678
+ ```
679
+
680
+ #### editor cluster diff
681
+ ```diff
682
+ - <editor-shell>
683
+ - <header>Toolbar</header>
684
+ - <div data-editor-body>
685
+ - <pane-ui data-left side="leading" resizable>Inspector</pane-ui>
686
+ - <div data-canvas>Workspace</div>
687
+ - <pane-ui data-right side="trailing" resizable>Properties</pane-ui>
688
+ - </div>
689
+ - <footer>Status</footer>
690
+ - </editor-shell>
691
+ + <editor-shell>
692
+ + <editor-toolbar>Toolbar</editor-toolbar>
693
+ + <editor-sidebar slot="leading" collapsible>
694
+ + <pane-ui side="leading" resizable>Inspector</pane-ui>
695
+ + </editor-sidebar>
696
+ + <editor-canvas>Workspace</editor-canvas>
697
+ + <editor-sidebar slot="trailing" collapsible>
698
+ + <pane-ui side="trailing" resizable>Properties</pane-ui>
699
+ + </editor-sidebar>
700
+ + <editor-statusbar>Status</editor-statusbar>
701
+ + </editor-shell>
702
+ ```
703
+
704
+ ### JS selector migration
705
+
706
+ Queries against legacy data-attributes need to change:
707
+
708
+ ```diff
709
+ - chat.querySelector('[data-chat-input]') → chat.querySelector('chat-input-ui')
710
+ - chat.querySelector('[data-chat-messages]') → chat.querySelector('chat-thread')
711
+ - chat.querySelector('[data-chat-empty]') → chat.querySelector('empty-state-ui')
712
+ - chat.querySelector('[data-chat-status]') → chat.querySelector('chat-status')
713
+ - document.querySelector('[data-canvas]') → document.querySelector('editor-canvas')
714
+ - document.querySelector('[data-editor-body]') → (drop — bespoke layout doesn't need wrapper)
715
+ - document.querySelector('[data-sidebar="leading"]') → document.querySelector('admin-sidebar[slot="leading"]')
716
+ - document.querySelector('[data-sidebar="trailing"]') → document.querySelector('admin-sidebar[slot="trailing"]')
717
+ ```
718
+
719
+ ### Trigger attributes that still work
720
+
721
+ These attributes are NOT removed — they still target the bespoke shell children:
722
+
723
+ - `[data-sidebar-toggle="leading|trailing"]` — buttons that toggle the matching `<admin-sidebar>` rail (forwards to `.toggle()`)
724
+ - `[data-command-trigger]` — buttons that open `<admin-command>` (forwards to `.show()`)
725
+ - `[data-toolbar-action="<name>"]` — buttons inside `<editor-toolbar>` that bubble `toolbar-action` events
726
+
727
+ ### Sweep recipes
728
+
729
+ ```bash
730
+ # 1. Find all legacy shell shape usages
731
+ git grep -nE '<aside-ui slot|<aside data-sidebar|<dialog data-command'
732
+ git grep -nE 'data-chat-messages|data-chat-input|data-chat-empty|data-chat-status|data-chat-name'
733
+ git grep -nE 'data-canvas[^-]|data-editor-body|<pane-ui data-(left|right)'
734
+
735
+ # 2. Mechanical Perl rewrite for chat (review before applying)
736
+ perl -i.bak -pe '
737
+ s/<section data-chat-messages>/<chat-thread>/g;
738
+ s|</section>(\s*<!--.*chat-messages.*-->)?|</chat-thread>|g;
739
+ s/<chat-input-ui data-chat-input/<chat-composer><chat-input-ui/g;
740
+ s|</chat-input-ui>(\s*</footer>)|</chat-input-ui></chat-composer>$1|g;
741
+ s/data-chat-empty/<chat-empty>/g;
742
+ s/data-chat-status//g;
743
+ ' apps/**/*.html
744
+
745
+ # 3. Verify with the smoke probe (Playwright-based)
746
+ npm run smoke:consumers
747
+ ```
748
+
749
+ ### What to test after migrating
750
+
751
+ The repo includes a Playwright probe (`scripts/smoke-consumer-migrations.mjs`, wired to `npm run smoke:consumers`) that verifies bespoke-only markup renders correctly. Run it after each consumer migrates. The probe:
752
+
753
+ 1. Loads each migrated URL in headless Chromium
754
+ 2. Verifies expected bespoke elements appear in DOM (e.g., `chat-thread`, `chat-composer`, `chat-empty`)
755
+ 3. Watches for console errors
756
+ 4. Watches for HTTP failures
757
+
758
+ Non-zero exit on regression. Used internally for the 6 in-repo consumers — passed 6/6 at v0.4.0.
759
+
760
+ ### Architectural payoff (information for downstream consumers)
761
+
762
+ If you maintain your own shell-style components in your fork or extension:
763
+ - `<admin-shell>` host: 305 → **87 LOC** (-71%) at v0.4.0
764
+ - The bespoke pattern moves resize / collapse / persistence / dialog behavior INTO each child. The host coordinates only.
765
+ - See [`bespoke-shell-children` skill](../../.agents/skills/adia-author/SKILL.md) for the canonical decomposition recipe.
766
+
767
+ ### Don't roll back
768
+
769
+ Once on `0.4.0`, the legacy paths cannot be reactivated by config — they're physically removed from the source. Pin to `0.3.x` if you need legacy behavior; commit to bespoke if you upgrade.
770
+
771
+ ---
772
+
773
+ ## Author-error sweep — `<grid-ui cols="N">` was never functional
774
+
775
+ `grid-ui` has only ever accepted `columns="N"` (see [`packages/web-components/components/grid/grid.js:12`](../../packages/web-components/components/grid/grid.js#L12)). Pages authored with `cols=` were silently rendering as the default 3-column grid — the attribute was ignored. Sweep:
776
+
777
+ ```bash
778
+ git grep -nlE '<grid-ui[^>]*\bcols=' \
779
+ | xargs perl -i -pe 's/(<grid-ui[^>]*?)\bcols=/$1columns=/g'
780
+ ```
781
+
782
+ Then re-run `npm run harvest:chunks` if any of the touched pages live under `site/pages/` and are tagged with `data-chunk` (extracts to `packages/a2ui/corpus/chunks/`).
783
+
784
+ ---
785
+
786
+ ## Migrating to `@adia-ai/web-components@0.0.29` + `@adia-ai/web-modules@0.0.1` (2026-05-01)
787
+
788
+ **The first BREAKING release since `0.0.20`.** All composite custom
789
+ elements (the former `patterns/` directory) move out of
790
+ `@adia-ai/web-components` into a new sibling package
791
+ `@adia-ai/web-modules`, organized into clusters via subpath exports.
792
+ Decision in `ADR-0012`;
793
+ full session narrative in `.claude/docs/journal/2026/05/2026-05-01.md` §18.
794
+
795
+ **Install:**
796
+
797
+ ```diff
798
+ - npm install @adia-ai/web-components@^0.0.20
799
+ + npm install @adia-ai/web-components@^0.0.29
800
+ + npm install @adia-ai/web-modules@^0.0.1
801
+ ```
802
+
803
+ `web-modules` has a peer-dep on `>=0.0.28` of `web-components` — the
804
+ two install together. If you don't use any composite element
805
+ (app-shell, app-nav, adia-chat, adia-editor, gen-ui, a2ui-root)
806
+ you can stay on web-components alone.
807
+
808
+ ### Three-tier architecture
809
+
810
+ ```
811
+ @adia-ai/web-components primitives (button, table, card, …)
812
+ @adia-ai/web-modules composites (shell + chat + editor + runtime)
813
+ @adia-ai/web-themes (future) token sets per vendor / brand
814
+ ```
815
+
816
+ Lateral siblings — `web-modules` and `web-themes` peer-depend
817
+ `web-components` only. No cross-tier imports above primitives;
818
+ composition happens at your site, not inside the library.
819
+
820
+ ### What moved (cluster mapping)
821
+
822
+ | Cluster | Elements (current per ADR-0015 / 0.0.31+) |
823
+ |---|---|
824
+ | `shell` | `<admin-shell>` (nav primitives below live in `web-components`) |
825
+ | `chat` | `<chat-shell>` |
826
+ | `editor` | `<editor-shell>` |
827
+ | `runtime` | `<gen-root>`, `<a2ui-root>` |
828
+
829
+ > **Update — 0.0.31 (ADR-0015 § Element renames).** Module tags moved
830
+ > to the `<namespace-thing>` two-word convention: `<adia-chat-ui>` →
831
+ > `<chat-shell>`; `<adia-editor-ui>` → `<editor-shell>`; `<app-shell-ui>`
832
+ > → `<admin-shell>`; `<gen-ui-ui>` → `<gen-root>`. Cluster directories
833
+ > + class names + CSS sub-files renamed in lockstep.
834
+
835
+ > **Update — 0.0.33 (ADR-0015 § Nav consolidation).** The 6-element
836
+ > nav family (`<app-nav-ui>`, `<app-nav-group-ui>`, `<app-nav-item-ui>`,
837
+ > `<section-nav-ui>`, `<section-nav-group-ui>`, `<section-nav-item-ui>`)
838
+ > consolidated into 3 primitives in `web-components` —
839
+ > `<nav-ui>`, `<nav-group-ui>`, `<nav-item-ui>` — with
840
+ > `[variant="primary"|"section"]` driving visual treatment. Section-
841
+ > variant migration: `<section-nav-ui …>` → `<nav-ui variant="section" …>`.
842
+ > The old per-element CSS link rels under
843
+ > `web-modules/shell/{app-nav*,section-nav*}/` are gone — nav CSS now
844
+ > ships in `@adia-ai/web-components/css`.
845
+
846
+ **Tags, CSS class names, CSS variables, yaml + a2ui.json contracts
847
+ for non-nav modules — apart from the ADR-0015 renames listed above —
848
+ are unchanged.** Beyond the rename map + nav consolidation, only the
849
+ import path moves.
850
+
851
+ ### Migration mapping (deep imports)
852
+
853
+ ```diff
854
+ # JS — every cluster, individual element
855
+ - import '@adia-ai/web-components/patterns/app-shell/app-shell.js';
856
+ + import '@adia-ai/web-modules/shell/app-shell/app-shell.js';
857
+
858
+ - import { AdiaA2UIRoot } from '@adia-ai/web-components/patterns/a2ui-root/a2ui-root.js';
859
+ + import { AdiaA2UIRoot } from '@adia-ai/web-modules/runtime/a2ui-root/a2ui-root.js';
860
+
861
+ - import '@adia-ai/web-components/patterns/adia-chat/adia-chat.js';
862
+ + import '@adia-ai/web-modules/chat/adia-chat/adia-chat.js';
863
+ ```
864
+
865
+ ```diff
866
+ <!-- CSS — site/<link rel="stylesheet"> tags -->
867
+ - href="node_modules/@adia-ai/web-components/patterns/app-shell/app-shell.css"
868
+ + href="node_modules/@adia-ai/web-modules/shell/app-shell/app-shell.css"
869
+
870
+ - href="node_modules/@adia-ai/web-components/patterns/adia-chat/adia-chat.css"
871
+ + href="node_modules/@adia-ai/web-modules/chat/adia-chat/adia-chat.css"
872
+ ```
873
+
874
+ **Idiomatic — import the cluster, let the bundler tree-shake:**
875
+
876
+ ```js
877
+ import '@adia-ai/web-modules'; // every cluster (barrel)
878
+ import '@adia-ai/web-modules/shell'; // app-shell + nav family
879
+ import '@adia-ai/web-modules/chat'; // adia-chat
880
+ import '@adia-ai/web-modules/editor'; // adia-editor
881
+ import '@adia-ai/web-modules/runtime'; // gen-ui + a2ui-root
882
+ ```
883
+
884
+ ### What was removed from `@adia-ai/web-components`
885
+
886
+ ```diff
887
+ # package.json — exports
888
+ - "./patterns": "./patterns/index.js",
889
+ - "./patterns/*": "./patterns/*/*.js",
890
+
891
+ # package.json — files
892
+ - "patterns/",
893
+
894
+ # package.json — sideEffects
895
+ - "./patterns/**/*.js",
896
+
897
+ # index.js
898
+ - export * from './patterns/index.js';
899
+ ```
900
+
901
+ Plus deletion of `packages/web-components/styles/layouts/admin.css`
902
+ (orphaned shell-CSS aggregator with no active consumers; would have
903
+ created a reverse-dep CSS-import edge from web-components into
904
+ web-modules).
905
+
906
+ ### `import '@adia-ai/web-components'` no longer registers patterns
907
+
908
+ The barrel side-effect dropped:
909
+
910
+ ```diff
911
+ # Before — barrel registered every primitive AND every pattern
912
+ - import '@adia-ai/web-components';
913
+
914
+ # After — barrel registers primitives only; modules are explicit
915
+ + import '@adia-ai/web-components'; // primitives
916
+ + import '@adia-ai/web-modules'; // every cluster
917
+ ```
918
+
919
+ If you were relying on the `0.0.28` barrel registering
920
+ `<admin-shell>` etc. for free, add the corresponding
921
+ `web-modules` import.
922
+
923
+ ### Sweep recipes
924
+
925
+ ```bash
926
+ # Find every deep-import of patterns/
927
+ git grep -nE "@adia-ai/web-components/patterns/"
928
+
929
+ # Find every CSS link href referencing patterns/
930
+ git grep -nE "web-components/patterns/[^\"']+\.css"
931
+
932
+ # Mechanical Perl rewrite (review before applying):
933
+ perl -i -pe 's{\@adia-ai/web-components/patterns/(app-shell\|app-nav(?:-group\|-item)?\|section-nav(?:-group\|-item)?)/}{\@adia-ai/web-modules/shell/$1/}g' $(git grep -lE "@adia-ai/web-components/patterns/")
934
+ perl -i -pe 's{\@adia-ai/web-components/patterns/(adia-chat)/}{\@adia-ai/web-modules/chat/$1/}g' $(git grep -lE "@adia-ai/web-components/patterns/")
935
+ perl -i -pe 's{\@adia-ai/web-components/patterns/(adia-editor)/}{\@adia-ai/web-modules/editor/$1/}g' $(git grep -lE "@adia-ai/web-components/patterns/")
936
+ perl -i -pe 's{\@adia-ai/web-components/patterns/(a2ui-root\|gen-ui)/}{\@adia-ai/web-modules/runtime/$1/}g' $(git grep -lE "@adia-ai/web-components/patterns/")
937
+ ```
938
+
939
+ ### Stay on `0.0.28` to defer
940
+
941
+ The [`0.0.28`](https://github.com/adiahealth/gen-ui-kit/releases/tag/web-components-v0.0.28)
942
+ snapshot still ships `patterns/` in-place. If the migration window
943
+ isn't yours, pin to `0.0.28` and migrate when convenient — the
944
+ 0.0.28 → 0.0.29 path is purely import-rewrite, no semantic deltas.
945
+
946
+ ### Additive features bundled in `0.0.29`
947
+
948
+ Three additive features ride along (no migration required):
949
+
950
+ - `<feed-item-ui>[action]` — focus-trap + `role="alertdialog"`. Phase 2 of [`feed-channel.md`](../../.claude/docs/specs/feed-channel.md).
951
+ - `<editor-shell>` (formerly `<adia-editor-ui>`) Phase C — multi-select + localStorage clipboard.
952
+ - Construct Canvas adapter-preview tabs (OD-001).
953
+ - `<toast-ui>` is now a thin facade over `<feed-ui>` — API surface preserved; small visual delta on lane styling, themable via `--feed-item-*`.
954
+
955
+ ---
956
+
957
+ ## Migrating to `@adia-ai/web-components@0.0.20` (2026-04-27)
958
+
959
+ The biggest BREAKING release in the `0.0.x` line. Ten attribute / event surface changes across the catalog, plus a Safari-floor raise. Full release narrative in `.claude/docs/journal/2026/04/2026-04-27.md` §§5–13. ADR for the Safari floor: `ADR-0007`.
960
+
961
+ **Install:**
962
+
963
+ ```diff
964
+ - npm install @adia-ai/web-components@^0.0.10
965
+ + npm install @adia-ai/web-components@^0.0.20
966
+ ```
967
+
968
+ The npm publish is gated on the visual-smoke runbook (`.brain/archive/2026-Q2/visual-smoke-polyfill-cleanup-2026-04-27.md`) — check whether `0.0.20` is on the registry before pinning.
969
+
970
+ ### Browser baseline
971
+
972
+ ```diff
973
+ - Chromium 125+ / Safari 17.4+ / Firefox 129+
974
+ + Chromium 125+ / Safari 18.0+ / Firefox 129+
975
+ ```
976
+
977
+ Safari raised by one major. Closes two engine-level WebKit bugs:
978
+
979
+ - `color-mix(in oklch, …, transparent)` red-shift below Safari 18 (the transparent operand's hue resolves to 0).
980
+ - iOS Safari `popover="auto"` light-dismiss broken on 17.0–18.2 (residual on iOS 18.0–18.2 documented as a known quirk).
981
+
982
+ If your target audience still includes Safari 17.4–17.7, the `core/polyfills.js` opt-in loader remains for consumers extending below the floor. See the live [breaking-changes reference](https://ui-kit.exe.xyz/site/reference/breaking-changes) for the full migration path.
983
+
984
+ ### 1. `<button-ui>` — variant axis split (variant=danger removed)
985
+
986
+ `variant` is now style-only across the catalog; semantics ride a new `[color]` attribute. The two compose: `<button-ui variant="solid" color="danger">` is "filled destructive button"; `<button-ui variant="outline" color="success">` is "outlined success button".
987
+
988
+ ```diff
989
+ - <button-ui variant="danger" text="Delete" icon="trash"></button-ui>
990
+ + <button-ui variant="solid" color="danger" text="Delete" icon="trash"></button-ui>
991
+ ```
992
+
993
+ Sweep:
994
+ ```bash
995
+ # Find all uses
996
+ git grep -nE 'button-ui[^>]*variant="danger"'
997
+ # Migration (Perl in-place)
998
+ perl -i -pe 's/(<button-ui[^>]*?)variant="danger"/$1color="danger"/g' path/to/file.html
999
+ ```
1000
+
1001
+ `progress-row-ui` `variant="primary"` is renamed to `variant="accent"` in the same release — no consumers in the wild, but if you hand-set the variant, swap.
1002
+
1003
+ `<button-ui>` accepts the full `[color]` enum: `default | accent | info | success | warning | danger`. Demos at [/site/components/button](https://ui-kit.exe.xyz/site/components/button).
1004
+
1005
+ ### 2. Stage-progress — single `status` enum replaces multi-Boolean
1006
+
1007
+ Three components now expose `status="idle | active | completed | error"` instead of legacy Boolean attributes. Mutually-exclusive states prevent the `active && completed` footgun.
1008
+
1009
+ | Component | Before | After |
1010
+ |---|---|---|
1011
+ | [`<timeline-item-ui>`](https://ui-kit.exe.xyz/site/components/timeline) | `[completed]`, `[active]`, `[error]` | `status="completed | active | error | idle"` |
1012
+ | [`<stepper-item-ui>`](https://ui-kit.exe.xyz/site/components/stepper) | `[completed]`, `[active]` | `status="…"` |
1013
+ | [`<pipeline-status-ui>`](https://ui-kit.exe.xyz/site/components/pipeline-status) | `[complete]` (legacy spelling — `complete`, not `completed`) | `status="completed"` |
1014
+
1015
+ ```diff
1016
+ - <timeline-item-ui completed text="Submitted"></timeline-item-ui>
1017
+ - <timeline-item-ui active text="Processing"></timeline-item-ui>
1018
+ - <timeline-item-ui error text="Failed"></timeline-item-ui>
1019
+ + <timeline-item-ui status="completed" text="Submitted"></timeline-item-ui>
1020
+ + <timeline-item-ui status="active" text="Processing"></timeline-item-ui>
1021
+ + <timeline-item-ui status="error" text="Failed"></timeline-item-ui>
1022
+ ```
1023
+
1024
+ `<timeline-item-ui spinner>` is **retained** — it's a presentation hint that animates the active dot as a spinning ring; orthogonal to `status`. Combine: `<timeline-item-ui status="active" spinner>`.
1025
+
1026
+ Sweep:
1027
+ ```bash
1028
+ git grep -nE '<timeline-item-ui[^>]*\b(completed|active|error)\b'
1029
+ git grep -nE '<stepper-item-ui[^>]*\b(completed|active)\b'
1030
+ git grep -nE '<pipeline-status-ui[^>]*\bcomplete\b'
1031
+ ```
1032
+
1033
+ ### 3. `<table-toolbar-ui>` Boolean affordances inverted
1034
+
1035
+ The four flags `filterable`, `sortable`, `columns`, `searchable` defaulted to `true` — unrepresentable in HTML's attribute model (authors couldn't turn the affordance OFF via attribute). Renamed to opt-out form.
1036
+
1037
+ | Before (default `true`) | After (default `false`) |
1038
+ |---|---|
1039
+ | `filterable` | `noFilter` (attr: `no-filter`) |
1040
+ | `sortable` | `noSort` (attr: `no-sort`) |
1041
+ | `columns` | `noColumns` (attr: `no-columns`) |
1042
+ | `searchable` | `noSearch` (attr: `no-search`) |
1043
+
1044
+ ```diff
1045
+ - <table-toolbar-ui for="users"></table-toolbar-ui>
1046
+ <!-- Bare element — same visual; all four affordances shown by default -->
1047
+ + <table-toolbar-ui for="users"></table-toolbar-ui>
1048
+
1049
+ - <table-toolbar-ui for="users" searchable="false"></table-toolbar-ui>
1050
+ <!-- Explicit suppression — the legacy form was always-truthy -->
1051
+ + <table-toolbar-ui for="users" no-search></table-toolbar-ui>
1052
+ ```
1053
+
1054
+ Note: bare `<table-toolbar-ui>` renders identically to before. The migration only matters if you were explicitly hiding affordances — `searchable="false"` was always-truthy under the old contract anyway, so it likely was rendering them all.
1055
+
1056
+ ### 4. `<chat-input-ui>` `[busy]` → `[loading]`
1057
+
1058
+ ```diff
1059
+ - <chat-input-ui busy></chat-input-ui>
1060
+ + <chat-input-ui loading></chat-input-ui>
1061
+ ```
1062
+
1063
+ ```diff
1064
+ - chatInput.busy = true;
1065
+ + chatInput.loading = true;
1066
+ ```
1067
+
1068
+ `busy` was the only component in the catalog using that name for the in-flight / streaming state — every other component uses `loading`. Direct rename.
1069
+
1070
+ ### 5. `error` variant alias removed (toast / alert / tag)
1071
+
1072
+ ```diff
1073
+ - <toast-ui variant="error" text="Save failed"></toast-ui>
1074
+ + <toast-ui variant="danger" text="Save failed"></toast-ui>
1075
+
1076
+ - <alert-ui variant="error">…</alert-ui>
1077
+ + <alert-ui variant="danger">…</alert-ui>
1078
+
1079
+ - <tag-ui variant="error" text="Failed"></tag-ui>
1080
+ + <tag-ui variant="danger" text="Failed"></tag-ui>
1081
+ ```
1082
+
1083
+ Affects [`<toast-ui>`](https://ui-kit.exe.xyz/site/components/toast), [`<alert-ui>`](https://ui-kit.exe.xyz/site/components/alert), [`<tag-ui>`](https://ui-kit.exe.xyz/site/components/tag). `error` was a deprecated alias for `danger` since `0.0.x` — `0.0.20` removes it.
1084
+
1085
+ ### 6. Event-name renames — drop the prefix
1086
+
1087
+ ```diff
1088
+ - chat.addEventListener('chat-submit', (e) => { … });
1089
+ + chat.addEventListener('submit', (e) => { … });
1090
+
1091
+ - legend.addEventListener('legend-toggle', (e) => { … });
1092
+ + legend.addEventListener('toggle', (e) => { … });
1093
+
1094
+ - swiper.addEventListener('slide-change', (e) => { … });
1095
+ + swiper.addEventListener('change', (e) => { … });
1096
+ ```
1097
+
1098
+ Detail shape is identical for all three. Rule of thumb in `0.0.20`: components dispatch canonical short verbs (`change`, `toggle`, `submit`, `select`, `press`, etc.) when one fits the host's semantic. Prefixed names (`chart-hover`, `cell-click`, `noodle-connect`, `feedback-rate`, etc.) are retained when the event carries domain-specific payload that isn't covered by the canonical verb. See [`component-token-contract.md` §"Event-naming convention"](../../.claude/docs/specs/component-token-contract.md).
1099
+
1100
+ If you compose `<chart-ui>` + `<chart-legend-ui>` and the chart's internal listener was wiring `legend-toggle`, no consumer change needed — the chart's listener migrated too. The break only affects consumer code listening directly.
1101
+
1102
+ ### 7. `<field-ui>.error` removed (read child's error)
1103
+
1104
+ The validation message belongs to the input, not the wrapper. `field-ui` now reads its slotted control's `error` property and mirrors into its `[data-field-error]` slot — `AdiaFormElement.error` is the single source of truth.
1105
+
1106
+ ```diff
1107
+ - <field-ui label="Email" error="Invalid format">
1108
+ - <input-ui type="email"></input-ui>
1109
+ - </field-ui>
1110
+ + <field-ui label="Email">
1111
+ + <input-ui type="email" error="Invalid format"></input-ui>
1112
+ + </field-ui>
1113
+ ```
1114
+
1115
+ Field subscribes to the child's `invalid | change | input` events and keeps its message in sync. Programmatic API: set `inputEl.error = "…"`.
1116
+
1117
+ ### 8. `<agent-trace-ui>` `[open]` → `[collapsed]`
1118
+
1119
+ Default-visibility flipped. Bare `<agent-trace-ui>` now shows expanded by default, matching the rest of the agent-* family ([`<agent-reasoning-ui>`](https://ui-kit.exe.xyz/site/components/agent-reasoning), [`<agent-artifact-ui>`](https://ui-kit.exe.xyz/site/components/agent-artifact)).
1120
+
1121
+ ```diff
1122
+ - <agent-trace-ui open></agent-trace-ui> <!-- was needed to expand -->
1123
+ + <agent-trace-ui></agent-trace-ui> <!-- expanded by default -->
1124
+
1125
+ - <agent-trace-ui></agent-trace-ui> <!-- was hidden -->
1126
+ + <agent-trace-ui collapsed></agent-trace-ui> <!-- explicit hide -->
1127
+ ```
1128
+
1129
+ Event payload also renamed: `trace-toggle` events now carry `{ collapsed }` instead of `{ open }` in the detail.
1130
+
1131
+ ### 9. agent-questions-ui / agent-feedback-bar-ui — kebab-string → camelCase prop keys
1132
+
1133
+ If you were setting these props programmatically, the JS access form changed:
1134
+
1135
+ ```diff
1136
+ - el['submit-label'] = 'Continue';
1137
+ + el.submitLabel = 'Continue';
1138
+
1139
+ - el['save-label'] = 'Bookmark';
1140
+ - el['save-icon'] = 'star';
1141
+ + el.saveLabel = 'Bookmark';
1142
+ + el.saveIcon = 'star';
1143
+ ```
1144
+
1145
+ The HTML attribute name is unchanged (`<agent-questions-ui submit-label="Continue">` still works). Only the JS property name flipped to canonical camelCase.
1146
+
1147
+ ### 10. New `[color]` axis on `<button-ui>` — composes with `[variant]`
1148
+
1149
+ Not a break, but pairs with §1. `<button-ui>` now accepts `[color="default | accent | info | success | warning | danger"]` alongside `[variant]`. The two compose orthogonally — see [§ Variants and color](https://ui-kit.exe.xyz/site/components/button) for the full matrix.
1150
+
1151
+ ### Quick search-and-replace summary
1152
+
1153
+ ```bash
1154
+ # 1. button variant=danger → color=danger (sweep HTML)
1155
+ git grep -nlE 'button-ui[^>]*variant="danger"' \
1156
+ | xargs perl -i -pe 's/(<button-ui[^>]*?)variant="danger"/$1color="danger"/g'
1157
+
1158
+ # 2. timeline-item-ui Booleans → status enum
1159
+ git grep -nlE '<timeline-item-ui[^>]*\bcompleted\b' \
1160
+ | xargs perl -i -pe 's/(<timeline-item-ui[^>]*?)\bcompleted\b/$1status="completed"/g'
1161
+ git grep -nlE '<timeline-item-ui[^>]*\bactive\b' \
1162
+ | xargs perl -i -pe 's/(<timeline-item-ui[^>]*?)\bactive\b/$1status="active"/g'
1163
+ git grep -nlE '<timeline-item-ui[^>]*\berror\b' \
1164
+ | xargs perl -i -pe 's/(<timeline-item-ui[^>]*?)\berror\b/$1status="error"/g'
1165
+
1166
+ # 3. stepper-item-ui similarly
1167
+ git grep -nlE '<stepper-item-ui[^>]*\bcompleted\b' \
1168
+ | xargs perl -i -pe 's/(<stepper-item-ui[^>]*?)\bcompleted\b/$1status="completed"/g'
1169
+
1170
+ # 4. pipeline-status-ui complete → status=completed (note spelling)
1171
+ git grep -nlE '<pipeline-status-ui[^>]*\bcomplete\b' \
1172
+ | xargs perl -i -pe 's/(<pipeline-status-ui[^>]*?)\bcomplete\b/$1status="completed"/g'
1173
+
1174
+ # 5. event listeners
1175
+ git grep -nE "addEventListener.*'chat-submit'" \
1176
+ | xargs perl -i -pe "s/'chat-submit'/'submit'/g"
1177
+ git grep -nE "addEventListener.*'legend-toggle'" \
1178
+ | xargs perl -i -pe "s/'legend-toggle'/'toggle'/g"
1179
+ git grep -nE "addEventListener.*'slide-change'" \
1180
+ | xargs perl -i -pe "s/'slide-change'/'change'/g"
1181
+
1182
+ # 6. error → danger on toast/alert/tag (one component at a time so other variant=error don't collide)
1183
+ git grep -nlE '<toast-ui[^>]*variant="error"' \
1184
+ | xargs perl -i -pe 's/(<toast-ui[^>]*?)variant="error"/$1variant="danger"/g'
1185
+ git grep -nlE '<alert-ui[^>]*variant="error"' \
1186
+ | xargs perl -i -pe 's/(<alert-ui[^>]*?)variant="error"/$1variant="danger"/g'
1187
+ git grep -nlE '<tag-ui[^>]*variant="error"' \
1188
+ | xargs perl -i -pe 's/(<tag-ui[^>]*?)variant="error"/$1variant="danger"/g'
1189
+
1190
+ # 7. chat-input busy → loading
1191
+ git grep -nlE '<chat-input-ui[^>]*\bbusy\b' \
1192
+ | xargs perl -i -pe 's/(<chat-input-ui[^>]*?)\bbusy\b/$1loading/g'
1193
+ git grep -nlE 'chatInput\.busy' \
1194
+ | xargs perl -i -pe 's/chatInput\.busy/chatInput.loading/g'
1195
+
1196
+ # 8. agent-trace open → no attr (default visible) OR collapsed
1197
+ # Manual review: default-visible is the new default; consumers that wrote
1198
+ # <agent-trace-ui open> get the same visual now without the attr; consumers
1199
+ # that wrote bare <agent-trace-ui> wanting it hidden need [collapsed].
1200
+ git grep -nE '<agent-trace-ui'
1201
+
1202
+ # 9. avatar-ui name= → text= (deprecated alias, scheduled for removal)
1203
+ # `name=` still works in 0.0.20+ but fires a one-shot console warning
1204
+ # per page. Sweep before the next major to avoid the upcoming break.
1205
+ git grep -nlE '<avatar-ui[^>]*\bname=' \
1206
+ | xargs perl -i -pe 's/(<avatar-ui[^>]*?\s)name=/\1text=/g'
1207
+ ```
1208
+
1209
+ The `adia-ui-migration` skill in `.claude/skills/adia-ui-migration/` automates these sweeps and runs the verification gate after.
1210
+
1211
+ ### Visual changes (no API change)
1212
+
1213
+ These are not breaks but are user-visible if you upgrade:
1214
+
1215
+ - **Shadows now paint.** `--a-shadow-{sm,md,lg}` were silently `none` for every consumer (`tooltip`, `card`, `drawer`, `segmented`, `chart`, `toast`) due to invalid CSS color/alpha syntax. Switched to relative-color form. Visual change wherever shadows are referenced — soft 4-layer Material-style lift now visible.
1216
+ - **`--a-chrome-light` / `--a-chrome-dark` are scheme-aware.** Were absolute `oklch(1 0 0)` / `oklch(0 0 0)`; now resolve via `--a-neutral-0-tint` / `--a-neutral-0-shade` so dark mode flips polarity correctly. If you read these in a custom theme override, the value resolves slightly differently in dark mode.
1217
+ - **Code-editor selection / active-line** no longer red-shifts on Safari < 18.
1218
+ - **`<swiper-ui>`** no longer renders double pagination dots on Chrome 135+.
1219
+ - **`<input-ui>` icon-affixes** no longer render as literal text on non-Vite static deploys.
1220
+
1221
+ ---
1222
+
1223
+ ## Migrating from `@adia-ai/web-components@0.0.4` to `0.0.10` / `0.0.11`
1224
+
1225
+ `0.0.5` through `0.0.11` were additive polish + hotfix releases. No migration needed — upgrade by bumping the dependency version. New components and tokens added; existing surface unchanged. See [packages/web-components/CHANGELOG.md](../../packages/web-components/CHANGELOG.md) for per-version detail.
1226
+
1227
+ ---
1228
+
1229
+ ## Migrating from `@adia-ai/web-components@0.0.2` to `0.0.4` (2026-04-22)
1230
+
1231
+ The A2UI runtime (renderer, registry, streams, surface manifest, wiring
1232
+ primitives, dockable base classes, controllers) was extracted into its
1233
+ own package `@adia-ai/a2ui-utils`. The `<a2ui-root>` declarative custom
1234
+ element moved to the `patterns/` directory. `0.0.3` (web-components)
1235
+ and `0.0.1` (a2ui-utils) shipped this split but were broken — the
1236
+ lazy controller imports in `wiring-registry.js` couldn't resolve
1237
+ because the `controllers/` subdir still lived under `web-components/`.
1238
+ `0.0.4` / `0.0.2` ship the fix (controllers moved into `a2ui-utils`,
1239
+ imports retargeted). **Upgrade past `0.0.3` / `0.0.1` if you're on
1240
+ them; any surface declaring a controller 500's on the broken cut.**
1241
+
1242
+ **Install the new leaf package:**
1243
+
1244
+ ```diff
1245
+ - npm install @adia-ai/web-components@^0.0.2
1246
+ + npm install @adia-ai/web-components@^0.0.4 @adia-ai/a2ui-utils@^0.0.2
1247
+ ```
1248
+
1249
+ (`@adia-ai/web-components@0.0.4` declares `@adia-ai/a2ui-utils` as a
1250
+ runtime dependency, so `npm install @adia-ai/web-components@^0.0.4`
1251
+ alone also pulls `a2ui-utils` transitively. The explicit dep is still
1252
+ recommended for consumers importing from it directly.)
1253
+
1254
+ **Runtime imports:**
1255
+
1256
+ ```diff
1257
+ - import { A2UIRenderer, registry, sseStream, wsStream } from '@adia-ai/web-components/a2ui';
1258
+ + import { A2UIRenderer, registry, sseStream, wsStream } from '@adia-ai/a2ui-utils';
1259
+
1260
+ - import { SurfaceManifest, WiringEngine } from '@adia-ai/web-components/a2ui';
1261
+ + import { SurfaceManifest, WiringEngine } from '@adia-ai/a2ui-utils';
1262
+
1263
+ - import { ActionDock, A2UI_EVENT_TO_DOM } from '@adia-ai/web-components/a2ui';
1264
+ + import { ActionDock, A2UI_EVENT_TO_DOM } from '@adia-ai/a2ui-utils';
1265
+ ```
1266
+
1267
+ **`<a2ui-root>` custom element:**
1268
+
1269
+ ```diff
1270
+ - import { AdiaA2UIRoot } from '@adia-ai/web-components/a2ui';
1271
+ + import { AdiaA2UIRoot } from '@adia-ai/web-components/patterns';
1272
+ // or
1273
+ import '@adia-ai/web-components/patterns/a2ui-root/a2ui-root.js';
1274
+ ```
1275
+
1276
+ Markup is unchanged:
1277
+
1278
+ ```html
1279
+ <a2ui-root src="/api/stream" transport="sse"></a2ui-root>
1280
+ ```
1281
+
1282
+ **Softened break.** The old `@adia-ai/web-components/a2ui` subpath
1283
+ still resolves in `0.0.4` via a re-export shim that prints a
1284
+ one-time deprecation warning. The subpath will be removed in `0.1.0`;
1285
+ update imports at your convenience before then.
1286
+
1287
+ **Removed.** `ManifestRuntime` and the `./context-store` subpath were
1288
+ dropped — the implementations depended on a `context-store.js` module
1289
+ that had never been authored. The context-store surface will return
1290
+ in a later release once designed.
1291
+
1292
+ ---
1293
+
1294
+ ## Within `0.0.x` — additive polish (0.0.4 → 0.0.5 → 0.0.6 → 0.0.7 → 0.0.8 → 0.0.9 → 0.0.10)
1295
+
1296
+ No migration required. Each release adds new authoring primitives
1297
+ alongside the existing ones; legacy hooks stay supported. Upgrade by
1298
+ bumping the dependency version.
1299
+
1300
+ - **`0.0.5`** — `app-shell-ui` adopts the `icon|heading|description|action`
1301
+ slot contract shared with `card-ui` / `drawer-ui` / `adia-editor-ui`.
1302
+ `pane-ui` gains a `side="leading|trailing"` attribute for one-edge
1303
+ border + grabber + resize-direction flip. `--a-chrome-{app,pane}-
1304
+ {header,footer,toolbar}-height` design tokens added. Internal
1305
+ `--nav-item-child-*` tokens relocated into `app-nav-group`'s own
1306
+ `@scope`. `pane-ui` section-content left-edge drift fixed.
1307
+ - **`0.0.6`** — `slot="action-leading"` added on `drawer-ui` /
1308
+ `card-ui` / `adia-editor-ui` / `app-shell-ui` footers. Pairs with
1309
+ the existing `slot="action"` to produce a dual-cluster footer
1310
+ (destructive / secondary cluster on the leading edge, primary
1311
+ cluster on the trailing edge):
1312
+
1313
+ ```diff
1314
+ <footer slot="footer">
1315
+ - <button-ui text="Delete" variant="danger" />
1316
+ - <span data-spacer />
1317
+ - <button-ui text="Cancel" />
1318
+ - <button-ui text="Save" variant="primary" />
1319
+ + <span slot="action-leading">
1320
+ + <button-ui text="Delete" variant="danger" />
1321
+ + </span>
1322
+ + <span slot="action">
1323
+ + <button-ui text="Cancel" />
1324
+ + <button-ui text="Save" variant="primary" />
1325
+ + </span>
1326
+ </footer>
1327
+ ```
1328
+
1329
+ `<span data-spacer>` stays supported for non-slotted toolbars
1330
+ (e.g. `toolbar-ui`, `row-ui` inside a filter-bar) where the
1331
+ footer-slot vocabulary doesn't apply. Migrate at your own pace.
1332
+
1333
+ - **`0.0.7`** — `<a2ui-root>` gains a `doc` property so authors can
1334
+ drive the renderer from a static message array without opening a
1335
+ transport. A new `doc-replaced` event fires after each full
1336
+ reset + replay:
1337
+
1338
+ ```js
1339
+ const root = document.querySelector('a2ui-root');
1340
+ root.doc = [
1341
+ { type: 'createSurface', surfaceId: 'root', root: 'root' },
1342
+ { type: 'updateComponents', surfaceId: 'root', components: [
1343
+ { id: 'root', component: 'Heading', text: 'Hi' }
1344
+ ]},
1345
+ ];
1346
+ ```
1347
+
1348
+ Existing stream-based callers (`src` + `transport`) are unaffected.
1349
+ Also in `0.0.7`: `modal-ui` silently wiped author content on connect
1350
+ in every release 0.0.2–0.0.6 — `0.0.7` fixes this. If you saw empty
1351
+ modal bodies, upgrade.
1352
+
1353
+ - **`0.0.8`** — hotfix + compat. `0.0.7` introduced a bad `typeof
1354
+ import.meta.glob === 'function'` guard in `icons.js` that always
1355
+ evaluated false under Vite; every icon disappeared in dev. `0.0.8`
1356
+ swaps to try/catch (Vite's AST rewrites the calls to literals, so
1357
+ the try succeeds; static serving falls back to a manifest loader).
1358
+ Also lands browser-compat guards: try/catch around `popover-ui`'s
1359
+ `showPopover`/`hidePopover`, `typeof X === 'undefined'` guards on
1360
+ `ResizeObserver` / `IntersectionObserver` traits, and a
1361
+ `replaceChildren()` polyfill for Safari 14.0. **Upgrade from 0.0.7
1362
+ to restore icons in dev.**
1363
+
1364
+ - **`0.0.9`** — follow-up hotfix for static deploys. On non-Vite
1365
+ hosts, `icons.js` initialises `EMPTY_WEIGHTS` synchronously and
1366
+ async-loads the icon manifest. `icon-ui` elements that rendered
1367
+ during that gap silently gave up when `resolveLoader` returned
1368
+ null — the manifest arrived ~100ms later but nothing re-requested
1369
+ the icons, so they stayed blank. `0.0.9` walks every
1370
+ `icon-ui[name]` in the DOM after the manifest swap-in and
1371
+ re-requests each. Vite dev was unaffected. **Upgrade if you host
1372
+ the library on plain static serving (exe.dev, Cloudflare Pages,
1373
+ Vercel static, etc.).**
1374
+
1375
+ - **`0.0.10`** — two targeted fixes. `AdiaElement` now wraps
1376
+ `this.connected()` in `untracked(...)` so element setup can't leak
1377
+ reactive subscriptions into the ancestor effect that caused the
1378
+ appendChild. Symptom this resolves: any time a parent effect
1379
+ `appendChild`s a custom element whose `connected()` reads its own
1380
+ reactive properties (via template-literal interpolation), the
1381
+ ancestor effect was silently subscribed to the child's signals —
1382
+ child state changes would then re-trigger the parent. Most
1383
+ visibly this made the Inspector in the A2UI Editor destroy + rebuild
1384
+ on every keystroke, blurring the focused input. Second fix:
1385
+ `A2UIRenderer` now honors `createSurface.root` (was hard-coding the
1386
+ attach id to `'root'`); the fallback preserves the old behavior
1387
+ for docs without an explicit root field. **Upgrade if you compose
1388
+ custom elements dynamically inside reactive render loops, or if
1389
+ you author A2UI docs with non-'root' root ids.**
1390
+
1391
+ ---
1392
+
1393
+ ## 1. Installation & Imports
1394
+
1395
+ ```diff
1396
+ - npm install @agent-ui-kit/web-components
1397
+ + npm install @adia-ai/web-components
1398
+ ```
1399
+
1400
+ ```diff
1401
+ // CSS — use the `/css` subpath export (resolves to index.css)
1402
+ - import "@agent-ui-kit/web-components/dist/agent-ui.css";
1403
+ + import "@adia-ai/web-components/css";
1404
+
1405
+ // JS (register all components)
1406
+ - import "@agent-ui-kit/web-components";
1407
+ + import "@adia-ai/web-components";
1408
+
1409
+ // Core element — the base class is AdiaElement (not AgentElement)
1410
+ - import { AgentElement } from "@agent-ui-kit/web-components/element";
1411
+ + import { AdiaElement } from "@adia-ai/web-components/core";
1412
+
1413
+ // Traits — no dedicated subpath export; importing the root registers all
1414
+ - import "@agent-ui-kit/web-components/traits";
1415
+ + import "@adia-ai/web-components";
1416
+ ```
1417
+
1418
+ The package's public exports map (from `package.json`) is:
1419
+ `.` → `./index.js`, `./css` → `./index.css`, `./core` → `./core/index.js`,
1420
+ `./a2ui` → `./a2ui/index.js`. Traits are registered via the default
1421
+ module import; there is no separate `/traits` subpath.
1422
+
1423
+ ---
1424
+
1425
+ ## 2. Tag Name Changes
1426
+
1427
+ All tags changed from `aui-` prefix to `-ui` suffix.
1428
+
1429
+ ### Direct Renames
1430
+
1431
+ | Old | New |
1432
+ |-----|-----|
1433
+ | `aui-button` | `button-ui` |
1434
+ | `aui-input` | `input-ui` |
1435
+ | `aui-textarea` | `textarea-ui` |
1436
+ | `aui-select` | `select-ui` |
1437
+ | `aui-option` | `<option>` (native) |
1438
+ | `aui-optgroup` | `<optgroup>` (native) |
1439
+ | `aui-checkbox` | `check-ui` |
1440
+ | `aui-radio` | `radio-ui` |
1441
+ | `aui-radio-group` | `radio-group-ui` |
1442
+ | `aui-switch` | `switch-ui` |
1443
+ | `aui-range` | `slider-ui` |
1444
+ | `aui-dialog` | `modal-ui` + `card-ui` | No dedicated `dialog-ui` custom element in v0.0.1; `dialog-ui` is only an A2UI protocol alias that resolves to `modal-ui`. See §3 dialog for structure. |
1445
+ | `aui-drawer` | `drawer-ui` |
1446
+ | `aui-modal` | `modal-ui` |
1447
+ | `aui-toast` | `toast-ui` |
1448
+ | `aui-tooltip` | `tooltip-ui` |
1449
+ | `aui-popover` | `popover-ui` |
1450
+ | `aui-alert` | `alert-ui` |
1451
+ | `aui-accordion` | `accordion-ui` |
1452
+ | `aui-tabs` | `tabs-ui` |
1453
+ | `aui-tab` | `tab-ui` |
1454
+ | `aui-breadcrumb` | `breadcrumb-ui` |
1455
+ | `aui-pagination` | `pagination-ui` |
1456
+ | `aui-segmented-control` | `segmented-ui` |
1457
+ | `aui-segment` | `segment-ui` |
1458
+ | `aui-command` | `command-ui` |
1459
+ | `aui-table` | `table-ui` |
1460
+ | `aui-sidebar` | `app-shell [slot="sidebar"]` |
1461
+ | `aui-divider` | `divider-ui` |
1462
+ | `aui-avatar` | `avatar-ui` |
1463
+ | `aui-avatar-group` | `avatar-group-ui` |
1464
+ | `aui-badge` | `badge-ui` |
1465
+ | `aui-icon` | `icon-ui` |
1466
+ | `aui-image` | `image-ui` |
1467
+ | `aui-progress` | `progress-ui` |
1468
+ | `aui-skeleton` | `skeleton-ui` |
1469
+ | `aui-kbd` | `kbd-ui` |
1470
+ | `aui-code-block` | `code-ui` |
1471
+ | `aui-calendar-picker` | `calendar-picker-ui` |
1472
+ | `aui-app-shell` | `app-shell` (no `-ui` suffix) |
1473
+ | `aui-nav-item` | `app-nav-item` (inside `app-shell [slot="sidebar"]`) |
1474
+ | `aui-grid` | `grid-ui` |
1475
+ | `aui-chip` | `tag-ui` |
1476
+ | `aui-input-otp` | `otp-input-ui` |
1477
+ | `aui-file-upload` | `upload-ui` |
1478
+ | `aui-spinner` | `progress-ui variant="spinner"` |
1479
+ | `aui-menu` | `menu-ui` |
1480
+ | `aui-text` | `text-ui` |
1481
+
1482
+ ### Structural Renames (changed composition)
1483
+
1484
+ | Old | New | Notes |
1485
+ |-----|-----|-------|
1486
+ | `aui-hstack` | `row-ui` | Gaps now use semantic tokens (`xs`–`xl`) |
1487
+ | `aui-vstack` | `col-ui` | Same |
1488
+ | `aui-stepper` | `steps-ui` | Parent manages child state via data attributes |
1489
+ | `aui-step` | `step-ui` | `text`, `description`, `icon` properties |
1490
+ | `aui-form` | `form-container-ui` | Dispatches `form-submit` event; supports `method="agent"` |
1491
+ | `aui-heading` | `<h1 data-heading="title">` | No component — use native element + attribute |
1492
+ | `aui-progress-circle` | `progress-ui variant="spinner"` | Merged into progress |
1493
+
1494
+ ### Removed (use native HTML or composition)
1495
+
1496
+ | Old | Replacement |
1497
+ |-----|-------------|
1498
+ | `aui-container` | `card-ui` | Use `card-ui raw` for chromeless wrapper, or standard `card-ui` with `<header>` / `<section>` / `<footer>` |
1499
+ | `aui-content` | `<section>` inside `card-ui` | Card children are native `<header>`, `<section>`, `<footer>` — styled by card.css via `@scope` |
1500
+ | `aui-header` | `<header>` inside `card-ui` | Header slots: `heading`, `description`, `icon`, `action`. Or use `text` attr on drawer-ui |
1501
+ | `aui-footer` | `<footer>` inside `card-ui` | Footer slots: `description`, `action`. Drawer has no footer — place buttons in body |
1502
+ | `aui-field` | Use `label` attribute on form controls directly |
1503
+ | `aui-fieldset` | Native `<fieldset>` |
1504
+ | `aui-link` | Native `<a>` |
1505
+ | `aui-page` | `app-shell` |
1506
+ | `aui-page-main` | `app-shell [slot="content"]` |
1507
+ | `aui-page-context` | `app-shell [slot="header"]` |
1508
+ | `aui-tab-panel` | `<div>` with manual visibility | **`panel-ui` is an accordion panel, NOT a tab panel.** See Tabs section below |
1509
+ | `aui-accordion-item` | `panel-ui` inside `accordion-ui` |
1510
+
1511
+ ### Not yet in new lib
1512
+
1513
+ | Old | Status |
1514
+ |-----|--------|
1515
+ | `aui-tree` / `aui-tree-item` | Not available |
1516
+ | `aui-carousel` | Not available |
1517
+ | `aui-sparkline` | Use `chart-ui` |
1518
+ | `aui-stat` | Compose with `card-ui` + `text-ui` |
1519
+ | `aui-empty-state` | Compose with `col-ui` + `text-ui` + `icon-ui` |
1520
+ | `aui-hover-card` | Use `popover-ui` |
1521
+ | `aui-meter` | Not available |
1522
+ | `aui-panes` / `aui-pane` | Not available |
1523
+ | `aui-description-list` | Use native `<dl>` |
1524
+ | `aui-notification-center` | Not available |
1525
+ | `aui-tag-group` | Compose with `row-ui` + `tag-ui` |
1526
+ | `aui-button-group` | Compose with `row-ui` + `button-ui` |
1527
+ | `aui-checkbox-group` | Compose with `col-ui` + `check-ui` |
1528
+ | `aui-disclosure` / `aui-disclosure-group` | Use `accordion-ui` |
1529
+ | `aui-tile` | Use `card-ui` |
1530
+ | `aui-bar` | Use `row-ui` |
1531
+
1532
+ ---
1533
+
1534
+ ## 2b. Card Content Model (Critical)
1535
+
1536
+ The biggest structural change. Cards now use native `<header>`, `<section>`, `<footer>` — no custom sub-elements.
1537
+
1538
+ ```diff
1539
+ - <aui-container>
1540
+ - <aui-header>Title</aui-header>
1541
+ - <aui-content>Body text</aui-content>
1542
+ - <aui-footer>
1543
+ - <aui-button label="Save"></aui-button>
1544
+ - </aui-footer>
1545
+ - </aui-container>
1546
+
1547
+ + <card-ui>
1548
+ + <header>
1549
+ + <h3 data-heading="section">Title</h3>
1550
+ + <span slot="description">Subtitle</span>
1551
+ + </header>
1552
+ + <section>
1553
+ + <col-ui gap="md">
1554
+ + <p>Body text</p>
1555
+ + </col-ui>
1556
+ + </section>
1557
+ + <footer>
1558
+ + <button-ui text="Save" variant="primary" slot="action"></button-ui>
1559
+ + </footer>
1560
+ + </card-ui>
1561
+ ```
1562
+
1563
+ **Rules:**
1564
+ - Header, Section, Footer are direct children of Card — never nest them inside each other
1565
+ - Section content must be wrapped in `col-ui` — never put content directly in section
1566
+ - Header slots: `heading` (on `<span>` only), `description`, `icon`, `action`
1567
+ - Footer slots: `description`, `action`
1568
+ - Card sizes: `xs`, `sm`, `md` (default), `lg`, `xl` — controls inset, radius, gap, typography
1569
+ - `[raw]` attribute strips background, border, shadow (structural wrapper only)
1570
+
1571
+ ---
1572
+
1573
+ ## 3. Attribute Changes by Component
1574
+
1575
+ ### button
1576
+
1577
+ ```diff
1578
+ - <aui-button label="Save" icon="check"></aui-button>
1579
+ + <button-ui text="Save" icon="check"></button-ui>
1580
+ ```
1581
+
1582
+ | Old attr | New attr | Notes |
1583
+ |----------|----------|-------|
1584
+ | `label` | `text` | |
1585
+ | `icon-leading` | `icon-leading` | Same |
1586
+ | `icon-trailing` | `icon-trailing` | Same |
1587
+ | `text-leading` | — | Removed |
1588
+ | `text-trailing` | — | Removed |
1589
+ | `href` | — | Removed; wrap in `<a>` |
1590
+ | `loading` | `loading` | Same |
1591
+ | `disabled` | `disabled` | Same |
1592
+ | `type` | `type` | Same |
1593
+ | — | `variant` | New: `solid`, `outline`, `ghost`, `danger`, `primary`, `secondary`, `soft` |
1594
+ | — | `size` | New: `xs`, `sm`, `md`, `lg`, `xl` |
1595
+ | — | `block` | New: full-width mode |
1596
+
1597
+ ### input
1598
+
1599
+ ```diff
1600
+ - <aui-input placeholder="Email" type="email" clearable></aui-input>
1601
+ + <input-ui placeholder="Email" type="email"></input-ui>
1602
+ ```
1603
+
1604
+ | Old attr | New attr | Notes |
1605
+ |----------|----------|-------|
1606
+ | `clearable` | — | Removed |
1607
+ | `autofocus` | — | Removed |
1608
+ | `font` | — | Removed |
1609
+ | `debounce` | — | Removed |
1610
+ | `no-clear` | — | Removed |
1611
+ | `prefix` | — | Removed; use `icon-leading` |
1612
+ | `suffix` | — | Removed; use `icon-trailing` |
1613
+ | — | `icon-leading` | New |
1614
+ | — | `icon-trailing` | New |
1615
+ | — | `min`, `max` | New: for number type |
1616
+ | — | `autocomplete` | New |
1617
+
1618
+ ### select
1619
+
1620
+ ```diff
1621
+ - <aui-select label="Country" placeholder="Choose...">
1622
+ - <aui-option value="us">United States</aui-option>
1623
+ - <aui-optgroup label="Europe">
1624
+ - <aui-option value="de">Germany</aui-option>
1625
+ - </aui-optgroup>
1626
+ - </aui-select>
1627
+ + <select-ui label="Country" placeholder="Choose...">
1628
+ + <option value="us">United States</option>
1629
+ + <optgroup label="Europe">
1630
+ + <option value="de">Germany</option>
1631
+ + </optgroup>
1632
+ + </select-ui>
1633
+ ```
1634
+
1635
+ | Old attr | New attr | Notes |
1636
+ |----------|----------|-------|
1637
+ | `mode` | — | Removed; dropdown only |
1638
+ | `orientation` | — | Removed |
1639
+ | `transparent` | — | Removed |
1640
+ | `fill` | — | Removed |
1641
+ | `padding` | — | Removed |
1642
+ | `hide-label` | — | Removed |
1643
+ | `target` | — | Removed |
1644
+
1645
+ ### dialog
1646
+
1647
+ **Status as of `@adia-ai/web-components@0.0.1`:** there is no standalone
1648
+ `dialog-ui` custom element — the name appears only as an A2UI protocol
1649
+ alias that resolves to `modal-ui` at render time. Both simple
1650
+ confirm/cancel dialogs and dialogs with custom content migrate to
1651
+ `modal-ui` + structured children.
1652
+
1653
+ `modal-ui`'s real API surface (per `components/modal/modal.js`): `text`
1654
+ (header title), `size` (`sm`/`md`/`lg`), `open` (Boolean). No built-in
1655
+ `description` / `confirm-text` / `cancel-text` / `variant="danger"` /
1656
+ `closable` / `confirm` / `cancel` event contract. Compose any of those
1657
+ using children.
1658
+
1659
+ ```diff
1660
+ # Simple confirm
1661
+ - <aui-dialog open size="md">
1662
+ - <aui-header><aui-heading>Confirm</aui-heading></aui-header>
1663
+ - <p>Are you sure?</p>
1664
+ - </aui-dialog>
1665
+ + <modal-ui text="Confirm" size="md" open>
1666
+ + <section>Are you sure?</section>
1667
+ + <footer>
1668
+ + <button-ui text="Cancel" variant="ghost" slot="action"></button-ui>
1669
+ + <button-ui text="Confirm" variant="primary" slot="action"></button-ui>
1670
+ + </footer>
1671
+ + </modal-ui>
1672
+ ```
1673
+
1674
+ **Dialogs with custom content** (input fields, forms, tables) — same
1675
+ structure; just richer body:
1676
+
1677
+ ```diff
1678
+ # Custom content → use modal-ui wrapping card-ui
1679
+ - <aui-dialog open style="--aui-dialog-width: 28rem">
1680
+ - <aui-header><aui-heading>Deactivate User</aui-heading></aui-header>
1681
+ - <aui-content>
1682
+ - <aui-input placeholder="Reason..."></aui-input>
1683
+ - </aui-content>
1684
+ - <aui-footer>
1685
+ - <aui-button label="Cancel"></aui-button>
1686
+ - <aui-button label="Confirm"></aui-button>
1687
+ - </aui-footer>
1688
+ - </aui-dialog>
1689
+ + <modal-ui open>
1690
+ + <card-ui style="max-width: 28rem; width: 100%; padding: var(--a-space-md);">
1691
+ + <h3 data-heading="section">Deactivate User</h3>
1692
+ + <input-ui placeholder="Reason..."></input-ui>
1693
+ + <row-ui justify="end" gap="sm" style="margin-top: var(--a-space-md);">
1694
+ + <button-ui variant="ghost" text="Cancel"></button-ui>
1695
+ + <button-ui variant="primary" text="Confirm"></button-ui>
1696
+ + </row-ui>
1697
+ + </card-ui>
1698
+ + </modal-ui>
1699
+ ```
1700
+
1701
+ **Note:** `--aui-dialog-width` has no equivalent token. Use `max-width` on `card-ui` inside `modal-ui`.
1702
+
1703
+ `modal-ui` real attribute surface (v0.0.1):
1704
+
1705
+ | attr | type | notes |
1706
+ |------|------|-------|
1707
+ | `text` | string | Header title; stamped into the header slot |
1708
+ | `size` | `sm` / `md` / `lg` | Preset width buckets |
1709
+ | `open` | Boolean | Show/hide; pair with `modal.show()` / `modal.hide()` |
1710
+
1711
+ Events: `close` fires after the modal finishes its closing animation.
1712
+ There are no built-in `confirm` / `cancel` events in v0.0.1 — wire
1713
+ button clicks yourself (as shown in the "Simple confirm" diff above).
1714
+ For custom widths, use `max-width` on the content subtree; there is no
1715
+ `--modal-width` token.
1716
+
1717
+ ### drawer
1718
+
1719
+ The drawer's internal structure changed completely. There are no `header`/`content`/`footer` sub-regions. The `text` attribute provides the header title, the drawer auto-stamps its own header and close button, and children become the body content.
1720
+
1721
+ ```diff
1722
+ - <aui-drawer side="right" open style="--aui-drawer-width: 40rem">
1723
+ - <aui-header>
1724
+ - <aui-heading>Filters</aui-heading>
1725
+ - <aui-button variant="ghost" icon-leading="x" label="Close"></aui-button>
1726
+ - </aui-header>
1727
+ - <aui-content>
1728
+ - <p>Filter content here</p>
1729
+ - </aui-content>
1730
+ - <aui-footer>
1731
+ - <aui-button label="Clear all"></aui-button>
1732
+ - </aui-footer>
1733
+ - </aui-drawer>
1734
+ + <drawer-ui text="Filters" side="right" open closable style="--drawer-width: 40rem">
1735
+ + <p>Filter content here</p>
1736
+ + <button-ui text="Clear all"></button-ui>
1737
+ + </drawer-ui>
1738
+ ```
1739
+
1740
+ **Key changes:**
1741
+ - Header is set via `text` attribute — do NOT add your own `<header>` inside
1742
+ - Close button is built-in via `closable` attribute — do NOT add your own
1743
+ - Children are adopted into the body automatically — just place content directly inside
1744
+ - Width token is `--drawer-width`, NOT `--a-drawer-width`
1745
+
1746
+ | Old attr | New attr | Notes |
1747
+ |----------|----------|-------|
1748
+ | `enable-scroll` | — | Removed |
1749
+ | `enable-pointer` | — | Removed |
1750
+ | — | `text` | New: header title (replaces `aui-header` + `aui-heading` inside) |
1751
+ | — | `size` | New: `sm`, `md`, `lg` |
1752
+ | — | `closable` | New: built-in close button (replaces manual close button) |
1753
+ | `style="--aui-drawer-width"` | `style="--drawer-width"` | Token renamed (NOT `--a-drawer-width`) |
1754
+
1755
+ ### toast
1756
+
1757
+ ```diff
1758
+ - <aui-toast message="Saved!" duration="3000" closeable></aui-toast>
1759
+ + <toast-ui text="Saved!" duration="3000" closable></toast-ui>
1760
+ ```
1761
+
1762
+ | Old attr | New attr | Notes |
1763
+ |----------|----------|-------|
1764
+ | `message` | `text` | Renamed |
1765
+ | `closeable` | `closable` | Spelling fix |
1766
+ | — | `variant` | New: `default`, `success`, `error`, `warning`, `info` |
1767
+
1768
+ ### breadcrumb
1769
+
1770
+ ```diff
1771
+ - <aui-breadcrumb joiner="/">
1772
+ - <aui-breadcrumb-item>Home</aui-breadcrumb-item>
1773
+ - </aui-breadcrumb>
1774
+ + <breadcrumb-ui separator="/">
1775
+ + <a href="/">Home</a>
1776
+ + </breadcrumb-ui>
1777
+ ```
1778
+
1779
+ | Old attr | New attr | Notes |
1780
+ |----------|----------|-------|
1781
+ | `joiner` | `separator` | Renamed |
1782
+ | `label` | — | Removed; use `aria-label` |
1783
+ | `max-depth` | — | Removed |
1784
+
1785
+ ### table
1786
+
1787
+ The table API changed significantly — from declarative HTML sub-components to a data-driven JavaScript API.
1788
+
1789
+ **For plain-text tables**, use `table-ui` with the data-driven API:
1790
+
1791
+ ```diff
1792
+ - <aui-table sortable paginate="10">
1793
+ - <aui-table-column key="name" label="Name" sortable></aui-table-column>
1794
+ - <aui-table-column key="email" label="Email"></aui-table-column>
1795
+ - </aui-table>
1796
+
1797
+ + <table-ui sortable paginate="10"></table-ui>
1798
+ + <script>
1799
+ + const table = document.querySelector('table-ui');
1800
+ + table.columns = [
1801
+ + { key: 'name', label: 'Name' },
1802
+ + { key: 'email', label: 'Email' },
1803
+ + ];
1804
+ + table.data = [
1805
+ + { name: 'Alice', email: 'alice@example.com' },
1806
+ + ];
1807
+ + </script>
1808
+ ```
1809
+
1810
+ **For tables with rich cell content** (badges, icons, links, etc.), `table-ui` does NOT support custom cell renderers — it only renders plain text via `td.textContent`. Use native HTML `<table>` instead and style it yourself:
1811
+
1812
+ ```diff
1813
+ - <aui-table cols="1fr 2fr 1fr">
1814
+ - <aui-table-head>
1815
+ - <aui-table-row>
1816
+ - <aui-table-header>ID</aui-table-header>
1817
+ - <aui-table-header>Name</aui-table-header>
1818
+ - <aui-table-header>Status</aui-table-header>
1819
+ - </aui-table-row>
1820
+ - </aui-table-head>
1821
+ - <aui-table-body>
1822
+ - <aui-table-row>
1823
+ - <aui-table-cell>001</aui-table-cell>
1824
+ - <aui-table-cell><aui-text weight="medium">Alice</aui-text></aui-table-cell>
1825
+ - <aui-table-cell><aui-badge intent="success">Active</aui-badge></aui-table-cell>
1826
+ - </aui-table-row>
1827
+ - </aui-table-body>
1828
+ - </aui-table>
1829
+
1830
+ + <table>
1831
+ + <thead>
1832
+ + <tr>
1833
+ + <th>ID</th>
1834
+ + <th>Name</th>
1835
+ + <th>Status</th>
1836
+ + </tr>
1837
+ + </thead>
1838
+ + <tbody>
1839
+ + <tr>
1840
+ + <td>001</td>
1841
+ + <td><text-ui weight="medium">Alice</text-ui></td>
1842
+ + <td><badge-ui intent="success">Active</badge-ui></td>
1843
+ + </tr>
1844
+ + </tbody>
1845
+ + </table>
1846
+ ```
1847
+
1848
+ **Note:** The `cols` attribute (CSS grid column template) only works on `table-ui`, not native `<table>`. Native tables use standard column sizing. You will need to add your own table CSS for borders, padding, and hover states.
1849
+
1850
+ ### sidebar
1851
+
1852
+ **Status as of `@adia-ai/web-components@0.0.1`:** there is no
1853
+ `sidebar-ui` / `sidebar-item-ui` / `sidebar-section-ui` custom element.
1854
+ The closest equivalent is the `app-nav` / `app-nav-group` / `app-nav-item`
1855
+ patterns (see `packages/web-components/patterns/app-nav*/`) composed
1856
+ inside the `app-shell` pattern (see §7 Layout Migration below). Those
1857
+ patterns do not auto-navigate either — wrap items in `<a>` for real
1858
+ routing.
1859
+
1860
+ ```diff
1861
+ - <aui-sidebar width="240" collapsible collapsed>
1862
+ - <aui-sidebar-header>
1863
+ - <aui-nav-item><aui-avatar label="A"></aui-avatar> My App</aui-nav-item>
1864
+ - </aui-sidebar-header>
1865
+ - <aui-sidebar-content>
1866
+ - <a href="/dashboard"><aui-nav-item active><aui-icon name="house"></aui-icon> Dashboard</aui-nav-item></a>
1867
+ - <a href="/settings"><aui-nav-item><aui-icon name="gear"></aui-icon> Settings</aui-nav-item></a>
1868
+ - </aui-sidebar-content>
1869
+ - <aui-sidebar-footer>
1870
+ - <aui-nav-item><aui-avatar label="U"></aui-avatar> User</aui-nav-item>
1871
+ - </aui-sidebar-footer>
1872
+ - </aui-sidebar>
1873
+ + <app-shell>
1874
+ + <div slot="sidebar">
1875
+ + <app-nav-item text="My App" icon="grid"></app-nav-item>
1876
+ + <app-nav-group>
1877
+ + <a href="/dashboard"><app-nav-item icon="house" text="Dashboard" active></app-nav-item></a>
1878
+ + <a href="/settings"><app-nav-item icon="gear" text="Settings"></app-nav-item></a>
1879
+ + </app-nav-group>
1880
+ + <app-nav-item text="User" icon="user"></app-nav-item>
1881
+ + </div>
1882
+ + <div slot="content">Main content</div>
1883
+ + </app-shell>
1884
+ ```
1885
+
1886
+ | Old | New | Notes |
1887
+ |-----|-----|-------|
1888
+ | `aui-sidebar` | `app-shell [slot="sidebar"]` | Sidebar is a slot on `app-shell`, not a standalone component in v0.0.1 |
1889
+ | `aui-sidebar-header` | `app-nav-item` as the first child | Place the branding item at the top of the slot |
1890
+ | `aui-sidebar-content` | `app-nav-group` | Groups items; supports multiple groups |
1891
+ | `aui-sidebar-footer` | `app-nav-item` as the last child | Same pattern as the header |
1892
+ | `aui-nav-item` | `app-nav-item` | Attributes: `icon`, `text`, `active`. Does NOT auto-navigate — wrap in `<a>` |
1893
+
1894
+ App-shell supports modes: `default`, `panel`, `collapsed`, `full`. The
1895
+ old sidebar attributes (`width`, `min-width`, `max-width`, `collapsible`,
1896
+ `side`) do not map 1:1 — width is a CSS custom-property tweak on the
1897
+ shell rather than a component attribute. See §7 Layout Migration.
1898
+
1899
+ ### tabs
1900
+
1901
+ **`panel-ui` is an accordion panel, NOT a tab panel.** There is no built-in tab panel component. `tabs-ui` only manages tab active state — you must implement panel visibility yourself.
1902
+
1903
+ Attribute changes: `value=` → `active=` on `tabs-ui`, `value=` → `name=` on `tab-ui`.
1904
+
1905
+ ```diff
1906
+ - <aui-tabs value="tab1">
1907
+ - <aui-tab value="tab1">First</aui-tab>
1908
+ - <aui-tab value="tab2">Second</aui-tab>
1909
+ - </aui-tabs>
1910
+ - <aui-tab-panel value="tab1">Content 1</aui-tab-panel>
1911
+ - <aui-tab-panel value="tab2">Content 2</aui-tab-panel>
1912
+
1913
+ + <tabs-ui active="tab1">
1914
+ + <tab-ui name="tab1">First</tab-ui>
1915
+ + <tab-ui name="tab2">Second</tab-ui>
1916
+ + </tabs-ui>
1917
+ + <div data-tab-panel="tab1">Content 1</div>
1918
+ + <div data-tab-panel="tab2" style="display: none;">Content 2</div>
1919
+ +
1920
+ + <script>
1921
+ + // You must wire up panel switching yourself
1922
+ + document.querySelectorAll("tabs-ui").forEach((tabs) => {
1923
+ + tabs.addEventListener("click", (e) => {
1924
+ + const tab = e.target.closest("tab-ui");
1925
+ + if (!tab) return;
1926
+ + const name = tab.getAttribute("name") || "";
1927
+ + let el = tabs.nextElementSibling;
1928
+ + while (el?.hasAttribute("data-tab-panel")) {
1929
+ + el.style.display = el.getAttribute("data-tab-panel") === name ? "" : "none";
1930
+ + el = el.nextElementSibling;
1931
+ + }
1932
+ + });
1933
+ + });
1934
+ + </script>
1935
+ ```
1936
+
1937
+ | Old attr | New attr | Notes |
1938
+ |----------|----------|-------|
1939
+ | `aui-tabs value="X"` | `tabs-ui active="X"` | Renamed |
1940
+ | `aui-tab value="X"` | `tab-ui name="X"` | Renamed |
1941
+ | `aui-tab-panel value="X"` | `<div data-tab-panel="X">` | **No component** — use div + manual show/hide |
1942
+
1943
+ ### accordion
1944
+
1945
+ ```diff
1946
+ - <aui-accordion multiple>
1947
+ - <aui-accordion-item>
1948
+ - <aui-header>Section 1</aui-header>
1949
+ - <p>Content</p>
1950
+ - </aui-accordion-item>
1951
+ - </aui-accordion>
1952
+ + <accordion-ui multiple>
1953
+ + <panel-ui text="Section 1">
1954
+ + <p>Content</p>
1955
+ + </panel-ui>
1956
+ + </accordion-ui>
1957
+ ```
1958
+
1959
+ ### heading
1960
+
1961
+ ```diff
1962
+ - <aui-heading size="lg">Dashboard</aui-heading>
1963
+ + <h1 data-heading="title">Dashboard</h1>
1964
+ ```
1965
+
1966
+ **`data-heading` is mandatory on all heading elements.** Without it, `h1-h6` are reset to `font-size: inherit` — they're semantic-only. All visual heading styles come from `[data-heading]` in `resets.css`.
1967
+
1968
+ Heading variants: `display`, `title`, `subtitle`, `section`, `label`, `eyebrow`, `caption`.
1969
+
1970
+ Apply to any element:
1971
+ ```html
1972
+ <span data-heading="eyebrow">STATUS</span>
1973
+ <h2 data-heading="section">Settings</h2>
1974
+ <h3 data-heading="section">Card Title</h3>
1975
+ <span data-heading="label">Revenue</span>
1976
+ <span data-heading="caption">Updated 2h ago</span>
1977
+ ```
1978
+
1979
+ **Inside `card-ui` headers:** Card CSS auto-targets native `h1-h6` and `small`/`p` inside `<header>` for grid positioning — so `slot="heading"` is only needed on non-heading elements like `<span>`:
1980
+ ```html
1981
+ <card-ui>
1982
+ <header>
1983
+ <h3 data-heading="section">Title</h3> <!-- no slot needed -->
1984
+ <small>Subtitle</small> <!-- no slot needed -->
1985
+ <span slot="heading" data-heading="section">Title</span> <!-- span needs slot -->
1986
+ </header>
1987
+ </card-ui>
1988
+ ```
1989
+
1990
+ ### text
1991
+
1992
+ ```diff
1993
+ - <aui-text>Some content</aui-text>
1994
+ + <text-ui text="Some content"></text-ui>
1995
+ ```
1996
+
1997
+ Or use the `text` attribute for CSS `attr()` rendering:
1998
+ ```html
1999
+ <text-ui text="Some content"></text-ui>
2000
+ ```
2001
+
2002
+ ### hstack / vstack
2003
+
2004
+ ```diff
2005
+ - <aui-hstack gap="4">...</aui-hstack>
2006
+ - <aui-vstack gap="6">...</aui-vstack>
2007
+ + <row-ui gap="md">...</row-ui>
2008
+ + <col-ui gap="md">...</col-ui>
2009
+ ```
2010
+
2011
+ Gap values changed from numeric units to semantic tokens: `none`, `xs`, `sm`, `md`, `lg`, `xl`.
2012
+
2013
+ New attributes: `justify`, `align`, `wrap` (row-ui only).
2014
+
2015
+ ### chip → tag
2016
+
2017
+ ```diff
2018
+ - <aui-chip removable>Beta</aui-chip>
2019
+ + <tag-ui text="Beta" removable></tag-ui>
2020
+ ```
2021
+
2022
+ New: `variant` (`default`, `success`, `warning`, `error`, `info`), `disabled`.
2023
+
2024
+ ### switch → toggle
2025
+
2026
+ ```diff
2027
+ - <aui-switch label="Notifications" checked></aui-switch>
2028
+ + <toggle-ui label="Notifications" checked></toggle-ui>
2029
+ ```
2030
+
2031
+ API is largely the same. New: `hint` property.
2032
+
2033
+ ---
2034
+
2035
+ ## 4. Token Changes
2036
+
2037
+ ### Namespace
2038
+
2039
+ ```diff
2040
+ - --aui-*
2041
+ + --a-*
2042
+ ```
2043
+
2044
+ ### Spacing
2045
+
2046
+ | Old | New |
2047
+ |-----|-----|
2048
+ | `--aui-space-xs` | `--a-space-xs` |
2049
+ | `--aui-space-sm` | `--a-space-sm` |
2050
+ | `--aui-space-md` | `--a-space-md` |
2051
+ | `--aui-space-lg` | `--a-space-lg` |
2052
+ | `--aui-space-xl` | `--a-space-xl` |
2053
+
2054
+ New lib also has numeric scale: `--a-space-1` through `--a-space-16`, plus `--a-space-unit` (0.25rem base) and `--a-space-k` multiplier.
2055
+
2056
+ ### Sizing
2057
+
2058
+ | Old | New |
2059
+ |-----|-----|
2060
+ | `--aui-size-xs` | Use `[size="xs"]` attribute |
2061
+ | `--aui-size-sm` | Use `[size="sm"]` attribute |
2062
+ | `--aui-size-md` | Use `[size="md"]` attribute |
2063
+ | `--aui-size-lg` | Use `[size="lg"]` attribute |
2064
+ | `--aui-size-xl` | Use `[size="xl"]` attribute |
2065
+ | `--aui-control-height-*` | `--a-content-height` (set by `[size]`) |
2066
+
2067
+ ### Typography
2068
+
2069
+ | Old | New |
2070
+ |-----|-----|
2071
+ | `--aui-font-family` | `--a-font-family` |
2072
+ | `--aui-font-family-display` | `--a-font-display` |
2073
+ | `--aui-font-family-mono` | `--a-font-mono` |
2074
+ | `--aui-font-xs` | `--a-font-size-xs` |
2075
+ | `--aui-font-sm` | `--a-font-size-sm` |
2076
+ | `--aui-font-md` | `--a-font-size-md` (default) |
2077
+ | `--aui-font-lg` | `--a-font-size-lg` |
2078
+ | `--aui-font-xl` | `--a-font-size-xl` |
2079
+ | `--aui-font-weight-regular` | `--a-font-weight-normal` |
2080
+ | `--aui-font-weight-medium` | `--a-font-weight-medium` |
2081
+ | `--aui-font-weight-semibold` | `--a-font-weight-semibold` |
2082
+ | `--aui-font-weight-bold` | `--a-font-weight-bold` |
2083
+
2084
+ ### Radius
2085
+
2086
+ | Old | New |
2087
+ |-----|-----|
2088
+ | `--aui-radius-sharp` | `--a-radius-xs` (or `[radius="sharp"]` → k=0) |
2089
+ | `--aui-radius-rounded` | `--a-radius-md` (or `[radius="rounded"]` → k=1.5) |
2090
+ | `--aui-radius-round` | `--a-radius-xl` (or `[radius="round"]` → k=2) |
2091
+ | `--aui-radius` (component) | `--a-radius` (set by `[radius]` attr or `[size]`) |
2092
+
2093
+ New lib uses t-shirt scale: `--a-radius-xs` through `--a-radius-xl`, plus `--a-radius-full` (pill). Dynamic via `clamp(--a-radius-min, --a-radius-k × --a-radius-base, --a-radius-max)`.
2094
+
2095
+ ### Shadows
2096
+
2097
+ | Old | New |
2098
+ |-----|-----|
2099
+ | `--aui-shadow-xs` | `--a-shadow-xs` |
2100
+ | `--aui-shadow-sm` | `--a-shadow-sm` |
2101
+ | `--aui-shadow-md` | `--a-shadow-md` |
2102
+ | `--aui-shadow-lg` | `--a-shadow-lg` |
2103
+ | `--aui-shadow-xl` | `--a-shadow-xl` |
2104
+
2105
+ New: `--a-shadow-intensity` multiplier, semantic aliases (`--a-shadow-dropdown`, `--a-shadow-dialog`).
2106
+
2107
+ ### Z-Index
2108
+
2109
+ | Old | New |
2110
+ |-----|-----|
2111
+ | `--aui-z-base` (0) | `--a-z-base` (0) |
2112
+ | `--aui-z-raised` (1) | `--a-z-raised` (10) |
2113
+ | `--aui-z-sticky` (10) | `--a-z-sticky` (200) |
2114
+ | `--aui-z-overlay` (100) | `--a-z-overlay` (300) |
2115
+ | `--aui-z-popover` (200) | `--a-z-popover` (500) |
2116
+ | `--aui-z-modal` (1000) | `--a-z-modal` (400) |
2117
+ | `--aui-z-toast` (9999) | `--a-z-toast` (600) |
2118
+
2119
+ ### Colors
2120
+
2121
+ | Old | New |
2122
+ |-----|-----|
2123
+ | `--aui-surface-text` | `--a-canvas-text` |
2124
+ | `--aui-surface-*` | `--a-canvas-*` |
2125
+ | `--aui-accent-*` | `--a-accent-*` |
2126
+ | `--aui-solid-*` | `--a-accent-strong` / `--a-accent-default` |
2127
+
2128
+ Color system changed from stepped primitives (`--aui-accent-500`) to OKLCH computational surfaces (`--a-accent-tint-50`, `--a-accent-shade-50`).
2129
+
2130
+ ---
2131
+
2132
+ ## 5. Theme System
2133
+
2134
+ ```diff
2135
+ - <html theme="forest">
2136
+ + <html data-theme="forest">
2137
+ ```
2138
+
2139
+ | Old theme | New theme | Notes |
2140
+ |-----------|-----------|-------|
2141
+ | `forest` | `forest` | Similar personality, different values |
2142
+ | `rose` | `rose` | Similar |
2143
+ | `zinc` | `slate` | Renamed |
2144
+ | — | `default` | New baseline |
2145
+ | — | `ocean` | New |
2146
+ | — | `sunset` | New |
2147
+ | — | `lavender` | New |
2148
+ | — | `midnight` | New |
2149
+
2150
+ New lib also supports `<theme-ui>` component for parametric control:
2151
+ ```html
2152
+ <theme-ui preset="ocean" space-scale="0.75" chroma="1.5">
2153
+ <!-- themed content -->
2154
+ </theme-ui>
2155
+ ```
2156
+
2157
+ ---
2158
+
2159
+ ## 6. Global Attributes
2160
+
2161
+ | Old | New | Notes |
2162
+ |-----|-----|-------|
2163
+ | `[density="compact"]` | `[density="compact"]` | Same name, new multiplier values |
2164
+ | `[density="spacious"]` | `[density="spacious"]` | Same |
2165
+ | `[radius="sharp"]` | `[radius="sharp"]` | Same |
2166
+ | `[radius="rounded"]` | `[radius="rounded"]` | Same |
2167
+ | `[radius="round"]` | `[radius="round"]` | Same |
2168
+ | `[scaling="compact"]` | `[size="sm"]` | Renamed + new semantic |
2169
+ | `[scaling="large"]` | `[size="lg"]` | Renamed |
2170
+ | `[shadow="flat"]` | — | Removed |
2171
+ | `[shadow="elevated"]` | — | Removed |
2172
+ | `[motion="none"]` | — | Removed |
2173
+ | `[motion="smooth"]` | — | Removed |
2174
+
2175
+ ---
2176
+
2177
+ ## 7. Layout Migration
2178
+
2179
+ ### App Shell
2180
+
2181
+ ```diff
2182
+ - <aui-app-shell>
2183
+ - <aui-sidebar slot="sidebar">
2184
+ - <aui-sidebar-header>Logo</aui-sidebar-header>
2185
+ - <aui-sidebar-content>
2186
+ - <aui-nav-item>Dashboard</aui-nav-item>
2187
+ - </aui-sidebar-content>
2188
+ - <aui-sidebar-footer>Settings</aui-sidebar-footer>
2189
+ - </aui-sidebar>
2190
+ - <aui-page>
2191
+ - <aui-page-context>
2192
+ - <aui-breadcrumb>...</aui-breadcrumb>
2193
+ - </aui-page-context>
2194
+ - <aui-page-main>
2195
+ - Content here
2196
+ - </aui-page-main>
2197
+ - </aui-page>
2198
+ - </aui-app-shell>
2199
+
2200
+ + <app-shell>
2201
+ + <div slot="sidebar">
2202
+ + <app-nav-item text="My App"></app-nav-item>
2203
+ + <app-nav-group>
2204
+ + <app-nav-item icon="house" text="Dashboard" active></app-nav-item>
2205
+ + </app-nav-group>
2206
+ + </div>
2207
+ + <div slot="header">
2208
+ + <breadcrumb-ui>...</breadcrumb-ui>
2209
+ + </div>
2210
+ + <div slot="content">
2211
+ + Content here
2212
+ + </div>
2213
+ + </app-shell>
2214
+ ```
2215
+
2216
+ New `app-shell` supports modes: `default`, `panel`, `collapsed`, `full`.
2217
+
2218
+ ---
2219
+
2220
+ ## 8. Quick Search & Replace
2221
+
2222
+ For most projects, start with these global replacements:
2223
+
2224
+ ```
2225
+ # Tag renames (most common)
2226
+ aui-button → button-ui
2227
+ aui-input → input-ui
2228
+ aui-textarea → textarea-ui
2229
+ aui-select → select-ui
2230
+ aui-option → option (native element)
2231
+ aui-optgroup → optgroup (native element)
2232
+ aui-checkbox → check-ui
2233
+ aui-radio → radio-ui
2234
+ aui-switch → switch-ui
2235
+ aui-icon → icon-ui
2236
+ aui-text → text-ui
2237
+ aui-badge → badge-ui
2238
+ aui-avatar → avatar-ui
2239
+ aui-divider → divider-ui
2240
+ aui-dialog → modal-ui (dialog-ui is only an A2UI protocol alias — no dedicated custom element)
2241
+ aui-drawer → drawer-ui
2242
+ aui-toast → toast-ui
2243
+ aui-tooltip → tooltip-ui
2244
+ aui-alert → alert-ui
2245
+ aui-tabs → tabs-ui
2246
+ aui-tab → tab-ui
2247
+ aui-accordion → accordion-ui
2248
+ aui-breadcrumb → breadcrumb-ui
2249
+ aui-pagination → pagination-ui
2250
+ aui-sidebar → app-shell [slot="sidebar"] (no sidebar-ui — use the app-nav-* pattern family inside the slot)
2251
+ aui-table → table-ui
2252
+ aui-progress → progress-ui
2253
+ aui-skeleton → skeleton-ui
2254
+ aui-kbd → kbd-ui
2255
+ aui-chip → tag-ui
2256
+ aui-hstack → row-ui
2257
+ aui-vstack → col-ui
2258
+ aui-grid → grid-ui
2259
+ aui-command → command-ui
2260
+ aui-app-shell → app-shell (NOTE: no -ui suffix — only exception)
2261
+ aui-segmented-control → segmented-ui
2262
+ aui-segment → segment-ui
2263
+
2264
+ # Attribute renames
2265
+ label= → text= (on button, alert, toast, drawer ONLY — NOT on form controls)
2266
+ message= → text= (on toast)
2267
+ joiner= → separator= (on breadcrumb)
2268
+ closeable → closable (on toast, dialog)
2269
+
2270
+ # ⚠️ label= is STILL CORRECT on form controls (select-ui, input-ui, etc.)
2271
+ # Do NOT blindly replace all label= → text=
2272
+ # Also update JS: setAttribute("label", ...) → setAttribute("text", ...) on button-ui elements
2273
+
2274
+ # Theme attribute
2275
+ theme= → data-theme=
2276
+
2277
+ # Token prefix
2278
+ --aui- → --a-
2279
+
2280
+ # Heading
2281
+ <aui-heading> → <h2 data-heading="section"> (choose appropriate level + variant)
2282
+ ```
2283
+
2284
+ ### Attributes that need manual review
2285
+
2286
+ These can't be search-and-replaced — they require understanding the context:
2287
+
2288
+ - `aui-button label="..."` → `button-ui text="..."` (but `label` is still used on form controls like `select-ui`)
2289
+ - `aui-button label="..."` in JS → `setAttribute("text", ...)` — also update runtime JS, not just HTML
2290
+ - `aui-container` → `card-ui` (raw wrapper, no header/content/footer sub-structure)
2291
+ - `aui-header` / `aui-footer` → removed inside drawers (use `text` attr) and cards (style children yourself)
2292
+ - `aui-field` → move `label`, `error`, `required` directly onto the form control
2293
+ - `aui-table` sub-components → `table-ui` data-driven API (plain text only) or native `<table>` (rich content)
2294
+ - `aui-tab-panel` → `<div>` with manual show/hide — `panel-ui` is for accordions, NOT tabs
2295
+ - `aui-dialog` with custom content → `modal-ui` + `card-ui`, NOT `dialog-ui`
2296
+ - `aui-page-*` hierarchy → flatten into `app-shell` slots
2297
+ - `aui-nav-item` → `app-nav-item` — does NOT navigate, wrap in `<a>` for real links
2298
+ - `--aui-dialog-width` / `--aui-drawer-width` → component tokens are unprefixed (`--drawer-width`), NOT `--a-*`
2299
+
2300
+ ---
2301
+
2302
+ ## 9. Event Changes
2303
+
2304
+ | Old event | New event | Component |
2305
+ |-----------|-----------|-----------|
2306
+ | `press` | `press` | button (same — normalized click/tap/keyboard) |
2307
+ | `search` | `input` (native) | input |
2308
+ | `submit` | `form-submit` | form |
2309
+ | `select` | `select` | select (same) |
2310
+ | `change` | `change` | form controls (same) |
2311
+ | `remove` | `remove` | chip/tag (same) |
2312
+ | — | `confirm` | dialog (new) |
2313
+ | — | `cancel` | dialog (new) |
2314
+ | — | `cell-edit` | table spreadsheet mode (new) |
2315
+
2316
+ ---
2317
+
2318
+ ## 10. Component CSS Token Names
2319
+
2320
+ Design system tokens use the `--a-` prefix (`--aui-space-md` → `--a-space-md`). But **component-specific tokens are unprefixed** — they do NOT use `--a-`:
2321
+
2322
+ | Old | Wrong | Correct |
2323
+ |-----|-------|---------|
2324
+ | `--aui-drawer-width` | ~~`--a-drawer-width`~~ | `--drawer-width` |
2325
+ | `--aui-dialog-width` | ~~`--a-dialog-width`~~ | No token — use `max-width` on `card-ui` inside `modal-ui` |
2326
+ | `--aui-table-*` | ~~`--a-table-*`~~ | `--table-font-size`, `--table-padding-x`, etc. |
2327
+
2328
+ The pattern: design tokens are `--a-*`, component tokens are `--{component}-*`.