@adia-ai/web-components 0.7.24 → 0.7.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -25
- package/README.md +2 -2
- package/USAGE.md +4 -4
- package/components/accordion/accordion-item.a2ui.json +30 -1
- package/components/accordion/accordion-item.yaml +33 -0
- package/components/accordion/accordion.a2ui.json +9 -0
- package/components/accordion/accordion.class.js +53 -3
- package/components/accordion/accordion.css +61 -3
- package/components/accordion/accordion.d.ts +12 -0
- package/components/accordion/accordion.yaml +17 -0
- package/components/code/code.class.js +1 -1
- package/components/drawer/drawer.class.js +2 -2
- package/components/empty-state/empty-state.yaml +5 -3
- package/components/feed/feed.a2ui.json +1 -1
- package/components/feed/feed.class.js +1 -1
- package/components/feed/feed.d.ts +1 -1
- package/components/feed/feed.yaml +2 -2
- package/components/field/field.class.js +1 -1
- package/components/loading-overlay/loading-overlay.class.js +1 -1
- package/components/loading-overlay/loading-overlay.yaml +1 -1
- package/components/modal/modal.class.js +1 -1
- package/components/nav/nav.class.js +1 -1
- package/components/nav/nav.examples.md +4 -4
- package/components/popover/popover.class.js +1 -1
- package/components/spinner/spinner.class.js +1 -1
- package/components/spinner/spinner.yaml +1 -1
- package/components/toast/toast.class.js +1 -1
- package/custom-elements.json +1 -1
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +1 -1
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/traits/CATEGORIES.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.7.26] — 2026-07-04
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **`empty-state-ui` (`components/empty-state/`) — the AI-composition rule no longer recommends `variant="outline"` for secondary/retry actions.** The `a2ui: rules:` guidance in `components/empty-state/empty-state.yaml` said "Prefer `[variant="primary"]` for create-flows; `[variant="outline"]` for retry / secondary actions" — reinforcing a repo-wide habit of reaching for `outline` just to mark a button as non-primary, when the unstyled default already IS the secondary look (`:where(:scope)` base tokens read `--a-ui-bg`, distinct from `variant="primary"`'s `--a-primary` accent fill). Corrected to: `variant="primary"` for the create-flow CTA, leave `variant` unset for retry/secondary. Regenerated `catalog-a2ui_0_9_rules.txt` from the yaml SoT (never hand-edited); mirrored the same correction into `components/empty-state/empty-state.examples.html`'s doc list. Root-cause investigation (corpus evidence: 446 `button-ui` tags harvested, only 30 bare vs. 91 explicit `outline` + 215 `ghost`) + the companion fixes in `@adia-ai/a2ui-compose` are in that package's changelog.
|
|
7
|
+
|
|
8
|
+
## [0.7.25] — 2026-07-03
|
|
9
|
+
|
|
10
|
+
Upstream consumer finding from `adia-pay` (F10, sibling of F1–F9 shipped in 0.7.24) — a token-modeled `variant="flat|contained"` posture for the accordion, plus its two footnote bugs.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`accordion-ui` / `accordion-item-ui` (`components/accordion/`) — `variant="flat|contained"` posture.** New reflected `variant` attribute on both the host and each item (default `flat`, pixel-unchanged from today — verified via the new `accordion-contained-probe.mjs`). `variant="contained"` on the host gives every child item a bounded surface — background, border, and radius spanning its header + open body, with a divider between them once expanded — the composition for embedding an accordion inside `<card-ui>`; a single item can opt out with its own `variant="flat"` (or opt IN against a flat host with `variant="contained"`). Four new item tokens carry the posture and are consumer-overridable in **both** postures: `--accordion-item-bg`, `--accordion-item-border` (full shorthand, mirrors `--card-border`), `--accordion-item-divider`, `--accordion-item-body-pt` — all default to the flat, invisible value. Contained is a token-only re-point plus three documented layout exceptions (`overflow:hidden` clip, `border-radius:0` on the header pill, and focus-ring relocation from the header onto the item surface) — added to `component-token-contract.md`'s sanctioned mode-attribute table alongside `progress-ui`/`pagination-ui`. Nested accordions stay isolated: a flat accordion inside a contained item's body is unaffected by the host's posture (direct-child `>` combinator, not a descendant selector). New examples: standalone contained, contained inside `card-ui`, and a per-item flat override. (upstream finding F10, ticket AC-1…AC-3/AC-5)
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **`accordion-item-ui` — the disclosure caret now survives a custom `[slot="header"]`.** Authoring your own header (icon + title + action buttons) previously suppressed the caret entirely — the component only ever stamped one alongside a header it ALSO stamped. `connected()` now stamps a `caret-down` `icon-ui` into any authored header that doesn't already contain a `[slot="caret"]`, scoped to the header element specifically (a caret placed in `[slot="body"]` no longer falsely suppresses it). Author your own `[slot="caret"]` (even empty) to opt out — no new attribute; documented on the `caret` slot in `accordion-item.yaml`. (upstream finding F10 footnote FN-1)
|
|
17
|
+
- **`accordion-item-ui` — `[text]` no longer clobbers an authored `[slot="header-text"]`.** The auto-stamped label is now marked with a `data-autolabel` DOM attribute (survives disconnect→reconnect), and `render()` only drives that marked label — a hand-authored `[slot="header-text"]` inside a custom header is never overwritten. Setting `text` alongside an authored header-text label is now a silent no-op by design (was a silent clobber before). (upstream finding F10 footnote FN-2)
|
|
18
|
+
- **`accordion-item-ui` — the default (auto-stamped) header is now keyboard-operable.** It was mouse-only: no `tabindex`, no keydown handling. The auto-stamped header now carries `tabindex="0"`, `role="button"`, and `aria-expanded` (kept in sync on every toggle); `Enter` and `Space` both toggle it, routed through the existing click handler (`header.click()`) so there is exactly one toggle code path. A consumer-authored header (e.g. `<button slot="header">`) already worked and is unaffected — this closes a pre-existing gap for the default header only, folded into this arc on operator review (an additive a11y improvement, not a regression).
|
|
19
|
+
|
|
20
|
+
### Maintenance
|
|
21
|
+
- **`dist/` bundles regenerated** (`web-components.min.{css,js}`, `web-components.sheet.js`, `theme-provider.min.js`) to carry the accordion changes above.
|
|
22
|
+
- **Doc-comment path references corrected** (`docs/specs/...` → `.claude/docs/specs/...`) across `patterns/` (2 `.examples.html` + 1 README) and `traits/` (`CATEGORIES.md` + 1 `.examples.html`) — propagated from the repo-wide `docs/` → `.claude/docs/` migration (2026-07-01) on the first full `components.mjs` regen since; no functional change, `styles/type-scale-review.examples.html` likewise.
|
|
23
|
+
|
|
3
24
|
## [0.7.24] — 2026-07-01
|
|
4
25
|
|
|
5
26
|
Upstream consumer findings from `adia-pay` against installed `0.7.23` (F1–F6).
|
|
@@ -41,7 +62,7 @@ Upstream consumer findings from `adia-pay` against installed `0.7.23` (F1–F6).
|
|
|
41
62
|
## [0.7.19] — 2026-06-10
|
|
42
63
|
|
|
43
64
|
### Fixed
|
|
44
|
-
- **`icon-ui` — glyphs always paint on the standalone import path.** Importing `components/icon` directly (or a demo page loading only `./icon.js`) never loaded `core/icons-phosphor.js`, so the weight-loader map stayed empty and every `getIcon()` returned `''` — **silently** (the not-ready guard suppressed the warning): blank icons, zero console errors. Two fixes: `icon.js` now imports the Phosphor loader as a side-effect (the barrel paths already did), and `icon.class.js` gains a signal-reactive retry (`#rev` bumped by `whenIconRegistryReady`, aborted symmetrically in `disconnected()`) so elements that connect *after* the loaders install — e.g. fetched-and-injected demo markup — re-render once the registry is ready. Production (barrel-served) was never affected; the docs/demo single-component path was. Regression probe: `scripts/dev/icon-paint-probe.mjs`. `dist/web-components.min.js` (and the web-modules kitchen-sink bundle) regenerated to carry the fix.
|
|
65
|
+
- **`icon-ui` — glyphs always paint on the standalone import path.** Importing `components/icon` directly (or a demo page loading only `./icon.js`) never loaded `core/icons-phosphor.js`, so the weight-loader map stayed empty and every `getIcon()` returned `''` — **silently** (the not-ready guard suppressed the warning): blank icons, zero console errors. Two fixes: `icon.js` now imports the Phosphor loader as a side-effect (the barrel paths already did), and `icon.class.js` gains a signal-reactive retry (`#rev` bumped by `whenIconRegistryReady`, aborted symmetrically in `disconnected()`) so elements that connect *after* the loaders install — e.g. fetched-and-injected demo markup — re-render once the registry is ready. Production (barrel-served) was never affected; the .claude/docs/demo single-component path was. Regression probe: `scripts/dev/icon-paint-probe.mjs`. `dist/web-components.min.js` (and the web-modules kitchen-sink bundle) regenerated to carry the fix.
|
|
45
66
|
|
|
46
67
|
## [0.7.18] — 2026-06-09
|
|
47
68
|
|
|
@@ -99,7 +120,7 @@ Upstream consumer findings from `adia-pay` against installed `0.7.23` (F1–F6).
|
|
|
99
120
|
|
|
100
121
|
### Changed
|
|
101
122
|
|
|
102
|
-
- **BREAKING (pre-1.0 PATCH cadence) — the token-theme attribute `data-theme` is renamed `theme`.** `<html data-theme="ocean">` → `<html theme="ocean">`; `[data-theme="…"]` selectors → `[theme="…"]`; the token-root selector `:root, theme-ui, [data-theme]` → `:root, theme-ui, [theme], theme-provider` across the 14 foundation files (so `<theme-provider>` is itself a token-root). Cleaner, and it converges with `<canvas-ui theme="…">`, which already scoped AdiaUI themes the same way. Done as a repo-wide word-boundary sweep — compound attributes (`data-theme-slug`, `data-themes-grid`, `data-themed`, …) are preserved (the sweep also touched the styles/, traits/, and patterns/ trees). **Consumers using `data-theme="…"` must switch to `theme="…"`** — see
|
|
123
|
+
- **BREAKING (pre-1.0 PATCH cadence) — the token-theme attribute `data-theme` is renamed `theme`.** `<html data-theme="ocean">` → `<html theme="ocean">`; `[data-theme="…"]` selectors → `[theme="…"]`; the token-root selector `:root, theme-ui, [data-theme]` → `:root, theme-ui, [theme], theme-provider` across the 14 foundation files (so `<theme-provider>` is itself a token-root). Cleaner, and it converges with `<canvas-ui theme="…">`, which already scoped AdiaUI themes the same way. Done as a repo-wide word-boundary sweep — compound attributes (`data-theme-slug`, `data-themes-grid`, `data-themed`, …) are preserved (the sweep also touched the styles/, traits/, and patterns/ trees). **Consumers using `data-theme="…"` must switch to `theme="…"`** — see `.claude/docs/MIGRATION GUIDE.md`.
|
|
103
124
|
- **CDN bundles rebuilt** — `dist/web-components.min.{css,js}` + `dist/host.min.css` regenerated so the `[theme]` rename, `<theme-provider>` registration, and the new register twins reach `@adia-ai/web-components@0.7` CDN consumers.
|
|
104
125
|
|
|
105
126
|
### Fixed
|
|
@@ -211,7 +232,7 @@ Upstream consumer findings from `adia-pay` against installed `0.7.23` (F1–F6).
|
|
|
211
232
|
|
|
212
233
|
### Changed
|
|
213
234
|
|
|
214
|
-
- **Reverted the OD-5 `-default` token-shadowing layer — component CSS now declares a single un-suffixed token per property** — `var(--card-bg, var(--card-bg-default))` → `var(--card-bg)` across 119 component + module CSS files; variants/states re-point the un-suffixed `--<component>-*` token directly (`:where(:scope)` keeps the base at zero specificity). The 2026-05-24 OD-5 split (internal `--<c>-X-default` + public `--<c>-X` read through a fallback chain) added read-past noise without paying for itself: the one capability it bought — ancestor-surface inheritance of *component-named* tokens — had no real usage (a repo sweep found only on-element attribute hooks + parent→child composition, both of which win by specificity and survive). **Consumer overriding is unchanged** for the four real vectors (`--a-*` upstream · on-element `card-ui { --card-bg: … }` / inline · parent→child composition · `@layer overrides`); the *only* behavior change is that a `--<component>-*` token set on a non-targeting **ancestor** no longer inherits in (theme via `--a-*` or `@layer overrides`). No public component/prop API change. Inverse codemod `scripts/refactor/undo-od5-token-shadowing.mjs` (2-level + 3-level chain collapse, precise pair-derived strip, collision-safe residual rewire); forward `od5-token-shadowing.mjs` retired;
|
|
235
|
+
- **Reverted the OD-5 `-default` token-shadowing layer — component CSS now declares a single un-suffixed token per property** — `var(--card-bg, var(--card-bg-default))` → `var(--card-bg)` across 119 component + module CSS files; variants/states re-point the un-suffixed `--<component>-*` token directly (`:where(:scope)` keeps the base at zero specificity). The 2026-05-24 OD-5 split (internal `--<c>-X-default` + public `--<c>-X` read through a fallback chain) added read-past noise without paying for itself: the one capability it bought — ancestor-surface inheritance of *component-named* tokens — had no real usage (a repo sweep found only on-element attribute hooks + parent→child composition, both of which win by specificity and survive). **Consumer overriding is unchanged** for the four real vectors (`--a-*` upstream · on-element `card-ui { --card-bg: … }` / inline · parent→child composition · `@layer overrides`); the *only* behavior change is that a `--<component>-*` token set on a non-targeting **ancestor** no longer inherits in (theme via `--a-*` or `@layer overrides`). No public component/prop API change. Inverse codemod `scripts/refactor/undo-od5-token-shadowing.mjs` (2-level + 3-level chain collapse, precise pair-derived strip, collision-safe residual rewire); forward `od5-token-shadowing.mjs` retired; `.claude/docs/specs/component-token-contract.md` rewritten (§History). Internal: `modal`/`swiper` `getComputedStyle` reads + 5 CSS-string-match tests re-pointed to the un-suffixed names. Verified: suite 1526/1526, `components --verify` clean, bundles fresh, visual QA (composition intact).
|
|
215
236
|
- **Typographic registers re-scaled — regular (default) + prose (MINOR behavior change)** — the regular register's inset compressed `8/16/24 → 14/16/18` and its gap re-based to a clean `value × --a-gap-k` multiplier (`8/12/16 → 10/12/14`, replacing the `half+half·k` form); `md` (the default tier) is unchanged for both, so only `[size=sm]`/`[size=lg]` containers shift. Prose moved one rung up (inset → 32/40/48, gap → 16/20/24). **Radius is now a register-scaled axis** — each register sets its own `--a-radius-min/max` (verse ≤16px · regular 20px=base · prose ≤28px) feeding the existing `clamp(min, k·max·tier-k, max)` formula. All values verified by `scripts/qa/register-scale-probe.mjs` (9 cells × 5 axes).
|
|
216
237
|
- **Demo scaffolds migrated to the `--a-font-family` token** — the ~114 `patterns/` + `traits/` demo `.html` scaffolds (plus the per-component demos) swapped their hand-rolled `:where(html, body) { font-family: var(--a-font) }` boilerplate to `var(--a-font-family)`, tracking the font-family-floor token rename; `patterns/search-discovery` additionally dropped a stray inline `max-width` so the results card self-frames. Demo-layer migration only — no component or CSS-API change.
|
|
217
238
|
|
|
@@ -336,7 +357,7 @@ Upstream consumer findings from `adia-pay` against installed `0.7.23` (F1–F6).
|
|
|
336
357
|
### Changed — global styles assigned to `@layer` cascade layers (ADR-0038)
|
|
337
358
|
|
|
338
359
|
- `packages/web-components/styles/` now assigns every rule to a named cascade layer — `@layer reset, tokens, elements, components, utilities, context, overrides` — so precedence is **declared once** instead of faked per-rule via specificity/`:where()`. The published bundle + barrel carry the layers; **rule content is unchanged** — only layer membership. Cuts: `resets.css` → `reset`; `colors/` + `foundation/` → `tokens`; `type/elements.css` → `elements`; the 128 scoped components → `components`; `api/{sizing,text,layout}` + `[variant]` → `utilities`; `themes.css` + `prose.css` → `context`; `overrides` declared topmost and **reserved (empty)** for consumer rules. A consumer rule in `@layer overrides` now wins by layer order with no `!important` and no specificity war (proven: a `(0,0,1)` `badge-ui{font-weight:321}` override beats both the component's `@scope` 500 and a `[weight="bold"]` 700).
|
|
339
|
-
- **One intentional behavior change (IPC-04).** Utility attributes — `[weight]` `[color]` `[transform]` `[text-align]` `[variant]` — now **override** a component's own `@scope` rule (they sit in `utilities`, above `components`). Previously they lost to component `@scope` by scope-proximity, and api/text.css documented that limitation — now retired. Measured blast radius: **39 component×property honorings across 128 components** (25 `color`, 10 `font-weight`, 3 `text-align`, 1 `text-transform`), zero breakage. Every *other* cut is behavior-neutral (real-browser computed-style probe 0 diffs; token identity byte-identical). The `ul/ol[role="list"]` reset and the `h1–h6` role defaults were relocated into `type/elements.css` (element-default refinements that must win by specificity *within* the `elements` layer). See ADR-0038 +
|
|
360
|
+
- **One intentional behavior change (IPC-04).** Utility attributes — `[weight]` `[color]` `[transform]` `[text-align]` `[variant]` — now **override** a component's own `@scope` rule (they sit in `utilities`, above `components`). Previously they lost to component `@scope` by scope-proximity, and api/text.css documented that limitation — now retired. Measured blast radius: **39 component×property honorings across 128 components** (25 `color`, 10 `font-weight`, 3 `text-align`, 1 `text-transform`), zero breakage. Every *other* cut is behavior-neutral (real-browser computed-style probe 0 diffs; token identity byte-identical). The `ul/ol[role="list"]` reset and the `h1–h6` role defaults were relocated into `type/elements.css` (element-default refinements that must win by specificity *within* the `elements` layer). See ADR-0038 + `.claude/docs/specs/cascade-layer-architecture.md`.
|
|
340
361
|
|
|
341
362
|
### Added — `<select-ui>` per-option `icon` / `avatar`, reflected in the trigger
|
|
342
363
|
|
|
@@ -344,7 +365,7 @@ Upstream consumer findings from `adia-pay` against installed `0.7.23` (F1–F6).
|
|
|
344
365
|
|
|
345
366
|
### Changed — block-level display by default + universal `[inline]` attribute (ADR-0037)
|
|
346
367
|
|
|
347
|
-
- Composite / control / container primitives now default to a **block-level** host `display` (`flex`/`block`/`grid`); the new universal **`[inline]`** boolean opts back to inline-level (`inline-flex`/`inline-block`/`inline-grid`). Flipped 14 primitives: `button` (text → full-width block, icon-only held inline via `:not([text])`), `color-input`, `date-range-picker`, `datetime-picker`, `time-picker`, `breadcrumb`, `pagination`, `segmented`, `toggle-group`, `toggle-scheme`, `menu`, `popover`, `image`, `qr-code`. **Text-flow atoms stay inline** (`text` `link` `mark` `number-format` `relative-time` `inline-edit` `inline-message` `badge` `tag` `chip` `kbd` `icon` `radio` `check` `switch` `avatar` `swatch` `rating` `spinner`). CSS-only — per-component `:scope[inline]` (specificity 0,2,0 reliably overrides `:scope`); no yaml/JS/sidecar (universal-attribute precedent: `[grow]`/`[hidden]`). **Inside `row-ui`/`col-ui`/`grid-ui` the flip is a no-op** (flex/grid items are blockified), so real-composition rendering is unchanged — only standalone-in-block-flow goes full-width. `field`/`fields` carve out `[inline]` for their single-row *layout* mode. `api/layout.css` documents the per-component rationale. See ADR-0037 +
|
|
368
|
+
- Composite / control / container primitives now default to a **block-level** host `display` (`flex`/`block`/`grid`); the new universal **`[inline]`** boolean opts back to inline-level (`inline-flex`/`inline-block`/`inline-grid`). Flipped 14 primitives: `button` (text → full-width block, icon-only held inline via `:not([text])`), `color-input`, `date-range-picker`, `datetime-picker`, `time-picker`, `breadcrumb`, `pagination`, `segmented`, `toggle-group`, `toggle-scheme`, `menu`, `popover`, `image`, `qr-code`. **Text-flow atoms stay inline** (`text` `link` `mark` `number-format` `relative-time` `inline-edit` `inline-message` `badge` `tag` `chip` `kbd` `icon` `radio` `check` `switch` `avatar` `swatch` `rating` `spinner`). CSS-only — per-component `:scope[inline]` (specificity 0,2,0 reliably overrides `:scope`); no yaml/JS/sidecar (universal-attribute precedent: `[grow]`/`[hidden]`). **Inside `row-ui`/`col-ui`/`grid-ui` the flip is a no-op** (flex/grid items are blockified), so real-composition rendering is unchanged — only standalone-in-block-flow goes full-width. `field`/`fields` carve out `[inline]` for their single-row *layout* mode. `api/layout.css` documents the per-component rationale. See ADR-0037 + `.claude/docs/specs/attribute-api-system.md` §5.
|
|
348
369
|
|
|
349
370
|
### Changed — `chevron` → `caret` terminology sweep (FEEDBACK-90, ADR-0036 follow-up)
|
|
350
371
|
|
|
@@ -1118,11 +1139,11 @@ Three pre-v0.4.0 `patterns/*.examples.html` files used legacy markup retired by
|
|
|
1118
1139
|
## [0.6.15] — 2026-05-21
|
|
1119
1140
|
|
|
1120
1141
|
### Fixed
|
|
1121
|
-
- **`installIconLoaders` / `installIconLoadersForRegistered` no longer silently accept a malformed shape (FB-07).** The previous behavior was `weightModules = { ...EMPTY_WEIGHTS, ...modules }` which spread any top-level keys verbatim. A flat path→svg glob (the documented quick-start shape; see FB-09) had its `/path/foo.svg` keys spread at the top level of `weightModules`, leaving every per-weight slot empty. Every `<icon-ui>` then rendered the icon NAME as visible text in its slot — confusing to debug because the per-icon `warnMissingIcon` console message points at name-resolution issues (Phosphor alias, `registerIcon`, etc.), not at loader-shape issues. The fix shape-detects three cases: (1) per-weight map keyed by `regular`/`thin`/`light`/`bold`/`fill`/`duotone` installs verbatim; (2) flat path→svg map auto-promotes to `{ regular: <flat> }` with a one-time `console.warn` so the caller knows to wrap explicitly (and so bold/fill/etc. aren't silently lost); (3) anything else logs `console.error` with the received key sample and aborts the install (registry stays unchanged). Net: the documented flat shape from
|
|
1142
|
+
- **`installIconLoaders` / `installIconLoadersForRegistered` no longer silently accept a malformed shape (FB-07).** The previous behavior was `weightModules = { ...EMPTY_WEIGHTS, ...modules }` which spread any top-level keys verbatim. A flat path→svg glob (the documented quick-start shape; see FB-09) had its `/path/foo.svg` keys spread at the top level of `weightModules`, leaving every per-weight slot empty. Every `<icon-ui>` then rendered the icon NAME as visible text in its slot — confusing to debug because the per-icon `warnMissingIcon` console message points at name-resolution issues (Phosphor alias, `registerIcon`, etc.), not at loader-shape issues. The fix shape-detects three cases: (1) per-weight map keyed by `regular`/`thin`/`light`/`bold`/`fill`/`duotone` installs verbatim; (2) flat path→svg map auto-promotes to `{ regular: <flat> }` with a one-time `console.warn` so the caller knows to wrap explicitly (and so bold/fill/etc. aren't silently lost); (3) anything else logs `console.error` with the received key sample and aborts the install (registry stays unchanged). Net: the documented flat shape from `.claude/docs/guides/02-quick-start.md` continues to work but emits one diagnostic warn per install; consumers on prior versions writing the flat shape needed to wrap manually to get icons at all. Files: `packages/web-components/core/icons.js` (+59 LOC: `WEIGHT_KEYS` const, `isFlatGlobShape()`, `warnedShapes` WeakSet, three-branch dispatch inside `installIconLoaders`).
|
|
1122
1143
|
- **`core/icons-phosphor.js` no longer silently swallows `import.meta.glob` failures (FB-08).** Two silent-fail paths fixed. (a) **Empty-glob path** — `import.meta.glob('/node_modules/@phosphor-icons/core/assets/<weight>/*.svg', …)` returns `{}` (not an error) when zero files match. This happens when the consumer's Vite root sits below `node_modules`, or with pnpm/yarn-berry virtual paths, or when this module is loaded from a published package directory (the absolute-style glob is resolved against the Vite root, not this file's directory). Previously `hasViteGlob` was set true and `installIconLoaders({ regular: {}, … })` ran anyway, leaving the registry empty with no diagnostic. The fix sums per-weight entry counts after the `try` block; if all six weights have zero entries, emits a `console.warn` with the canonical manual-install snippet. (b) **Caught-error path** — the bare `catch {}` was scoped to handle "no Vite at all" (`ReferenceError` because `import.meta.glob` doesn't exist in static serving), but it also swallowed every OTHER error type (plugin order issues, Vite-config misconfigs, etc.). The catch now logs non-`ReferenceError` failures via `console.warn` before falling back to the manifest fetch. Files: `packages/web-components/core/icons-phosphor.js` (+38 LOC, -2 LOC).
|
|
1123
1144
|
|
|
1124
1145
|
### Docs
|
|
1125
|
-
- **Quick-start + migration guide examples corrected (FB-09).**
|
|
1146
|
+
- **Quick-start + migration guide examples corrected (FB-09).** `.claude/docs/guides/02-quick-start.md` lines ~76-81 (boot sequence) and ~126-131 (the dedicated `installIconLoadersForRegistered` section) both showed the flat-glob form passed directly to `installIconLoadersForRegistered`. Both now wrap the glob in `{ regular: … }` to match the canonical contract. New `### Pitfall: flat glob silently auto-promoted (v0.6.15+)` section explains the FB-07 auto-promote behavior and when the per-weight form is strictly required (bold/fill/etc.). `.claude/docs/MIGRATION GUIDE.md` lines ~279-282 (the v0.5.3 §154 recommended upgrade example) had the same flat-glob bug — corrected. The skill `adia-ui-kit` v2.9.0 ships the same scaffold-template correction.
|
|
1126
1147
|
|
|
1127
1148
|
### Verification
|
|
1128
1149
|
- `verify:traits` 56/56 clean.
|
|
@@ -1356,7 +1377,7 @@ Files: `slider.css`, `slider.class.js`, `slider.examples.html`, `slider.yaml`, `
|
|
|
1356
1377
|
|
|
1357
1378
|
## [0.5.15] - 2026-05-16
|
|
1358
1379
|
|
|
1359
|
-
> **Scope note:** §325 + §326 were originally planned as a separate v0.5.16 cycle (see retired
|
|
1380
|
+
> **Scope note:** §325 + §326 were originally planned as a separate v0.5.16 cycle (see retired `.claude/docs/plans/0.5.16-release-plan.md`); absorbed into v0.5.15 since both landed within the same release window (same-day commits prior to bump). The peer's v0.5.16 plan-doc explicitly anticipated this absorption option ("Hermes's call per `/lockstep-release`"). v0.5.16 plan-doc marked SHIPPED-IN-V0.5.15.
|
|
1360
1381
|
|
|
1361
1382
|
### v0.5.15 §326 — `<swatch-ui>` `[slot="chrome"]` lost in template contexts (FB-37; P1)
|
|
1362
1383
|
|
|
@@ -2763,7 +2784,7 @@ Also fixed `code.yaml`: removed a phantom `copy` event declaration (no runtime e
|
|
|
2763
2784
|
|
|
2764
2785
|
### Audit summary — hand-authored `.d.ts` cleanliness as of v0.4.9
|
|
2765
2786
|
|
|
2766
|
-
After §90 + §91b sweeps, **all 17 form-bearing primitives' hand-authored `.d.ts` files are runtime-matched.** Audit recipe captured in
|
|
2787
|
+
After §90 + §91b sweeps, **all 17 form-bearing primitives' hand-authored `.d.ts` files are runtime-matched.** Audit recipe captured in `.claude/docs/plans/0.4.9-release-plan.md` §91b for future cycles — automatable as `scripts/release/check-form-bearing-dts.mjs` in a later cycle if drift returns.
|
|
2767
2788
|
|
|
2768
2789
|
### Documentation — USAGE.md "Derived reactive bindings" subsection (§91d, FEEDBACK-04 #3)
|
|
2769
2790
|
|
|
@@ -3213,7 +3234,7 @@ Companion to the corpus simplification arc in `@adia-ai/a2ui-{runtime,compose,co
|
|
|
3213
3234
|
|
|
3214
3235
|
Catalog (`packages/a2ui/corpus/catalog-a2ui_0_9.json`) regenerated to pick up every yaml addition. `verify:traits` clean at 56/56; `components --verify` clean at 125 files.
|
|
3215
3236
|
|
|
3216
|
-
See root [CHANGELOG.md `[Unreleased]`](../../CHANGELOG.md) for the cross-cutting arc narrative + [docs/journal/2026/05/2026-05-12.md](
|
|
3237
|
+
See root [CHANGELOG.md `[Unreleased]`](../../CHANGELOG.md) for the cross-cutting arc narrative + [.claude/docs/journal/2026/05/2026-05-12.md](../../.claude/docs/journal/2026/05/2026-05-12.md) §§ 43 / 44 / 50 / 51 for per-§ details.
|
|
3217
3238
|
## [0.4.3] - 2026-05-11
|
|
3218
3239
|
|
|
3219
3240
|
### Added
|
|
@@ -3229,7 +3250,7 @@ See root [CHANGELOG.md `[Unreleased]`](../../CHANGELOG.md) for the cross-cutting
|
|
|
3229
3250
|
|
|
3230
3251
|
### Lockstep
|
|
3231
3252
|
|
|
3232
|
-
9-package coordinated PATCH cut to v0.4.3 (per [
|
|
3253
|
+
9-package coordinated PATCH cut to v0.4.3 (per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy)). Internal `@adia-ai/*` dep ranges stay at `^0.4.0` (patch-cut asymmetry — `^0.4.0` covers `0.4.x` under semver). Ratifies [ADR-0027](../../.brain/adrs/0027-cross-primitive-composition-imports.md) — cross-primitive composition imports are the consumer's responsibility; the primitive's `.js` does NOT side-effect-import composed primitives. Source files touched: `components/input/input.{js,css,yaml,a2ui.json}`. See root [CHANGELOG.md `## [0.4.3]`](../../CHANGELOG.md) for the cut narrative.
|
|
3233
3254
|
## [0.4.2] - 2026-05-11
|
|
3234
3255
|
|
|
3235
3256
|
### Changed
|
|
@@ -3266,7 +3287,7 @@ See root [CHANGELOG.md `[Unreleased]`](../../CHANGELOG.md) for the cross-cutting
|
|
|
3266
3287
|
|
|
3267
3288
|
### Lockstep
|
|
3268
3289
|
|
|
3269
|
-
9-package coordinated PATCH cut to v0.4.2 (per [
|
|
3290
|
+
9-package coordinated PATCH cut to v0.4.2 (per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy)). Internal `@adia-ai/*` dep ranges stay at `^0.4.0` (patch-cut asymmetry — `^0.4.0` covers `0.4.x` under semver). ADR-0025 ([`.brain/adrs/0025-no-native-form-controls.md`](../../.brain/adrs/0025-no-native-form-controls.md)) ratified — codifies the "no native or suppressed-native interactive widgets in primitives" principle that the `<input-ui type="number">` rewrite implements; `password` remains the documented exception (physically requires `<input type="password">` for `-webkit-text-security`). See root [CHANGELOG.md `## [0.4.2]`](../../CHANGELOG.md) for the cut narrative.
|
|
3270
3291
|
## [0.4.1] - 2026-05-10
|
|
3271
3292
|
|
|
3272
3293
|
### Ride-along (no source changes)
|
|
@@ -3298,7 +3319,7 @@ Lockstep version bump only — source byte-identical to v0.3.4. Internal `@adia-
|
|
|
3298
3319
|
Lockstep version bump only — source byte-identical to v0.3.3. Internal `@adia-ai/*` dep ranges remain at `^0.3.0`. See root [CHANGELOG.md `## [0.3.4]`](../../CHANGELOG.md) for the cut narrative.
|
|
3299
3320
|
## [0.3.3] - 2026-05-07
|
|
3300
3321
|
|
|
3301
|
-
**Lockstep cut.** All 9 published `@adia-ai/*` packages now share version `0.3.3`, governed by [
|
|
3322
|
+
**Lockstep cut.** All 9 published `@adia-ai/*` packages now share version `0.3.3`, governed by [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy).
|
|
3302
3323
|
|
|
3303
3324
|
### Changed
|
|
3304
3325
|
|
|
@@ -3311,7 +3332,7 @@ Lockstep version bump only — source byte-identical to v0.3.3. Internal `@adia-
|
|
|
3311
3332
|
## [0.3.2] - 2026-05-06
|
|
3312
3333
|
|
|
3313
3334
|
**9-package lockstep patch cut to v0.3.2.** All lockstep members share
|
|
3314
|
-
one version per [
|
|
3335
|
+
one version per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy).
|
|
3315
3336
|
Internal `@adia-ai/*` dep ranges unchanged at `^0.3.0`.
|
|
3316
3337
|
|
|
3317
3338
|
### No source changes
|
|
@@ -3324,7 +3345,7 @@ version only.
|
|
|
3324
3345
|
- `version`: `0.3.1` → `0.3.2`.
|
|
3325
3346
|
## [0.3.1] - 2026-05-06
|
|
3326
3347
|
|
|
3327
|
-
**9-package lockstep patch cut + folder-per-trait restructure.** All 9 published `@adia-ai/*` packages bump 0.3.0 → 0.3.1 per [
|
|
3348
|
+
**9-package lockstep patch cut + folder-per-trait restructure.** All 9 published `@adia-ai/*` packages bump 0.3.0 → 0.3.1 per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges remain at `^0.3.0` (covers `0.3.1` under semver — patch-cut asymmetry).
|
|
3328
3349
|
|
|
3329
3350
|
This is a **patch cut on top of v0.3.0, no BREAKING changes for npm consumers.** The barrel API (`@adia-ai/web-components/traits`, `@adia-ai/web-components/components`, etc.) is byte-equivalent to v0.3.0 at the public surface. The change is internal: the trait library moved from a flat `traits/<name>.{html,js,examples.html,examples.js,test.js}` layout to one folder per trait (`traits/<name>/<name>.{...}`), mirroring the existing `components/<name>/` convention.
|
|
3330
3351
|
|
|
@@ -3345,7 +3366,7 @@ Symmetry with `components/<name>/` (already folder-per for months) — easier to
|
|
|
3345
3366
|
- `packages/a2ui/compose/transpiler/transpiler-maps.js` — no change since v0.3.0 (the v0.3.0 entry mentioned this file; correction: that update was part of v0.3.0).
|
|
3346
3367
|
## [0.3.0] - 2026-05-05
|
|
3347
3368
|
|
|
3348
|
-
**9-package lockstep cut.** All 9 published `@adia-ai/*` packages bump 0.2.5 → 0.3.0 per [
|
|
3369
|
+
**9-package lockstep cut.** All 9 published `@adia-ai/*` packages bump 0.2.5 → 0.3.0 per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges bump `^0.2.0` → `^0.3.0`.
|
|
3349
3370
|
|
|
3350
3371
|
The lockstep policy expanded from 8 to 9 packages with this cut — `@adia-ai/llm` joins as a foundational primitive (extracted from `@adia-ai/a2ui-compose/llm`), and `@adia-ai/a2ui-utils` was renamed to `@adia-ai/a2ui-runtime`. Both are BREAKING for npm consumers (acceptable under pre-1.0 semver).
|
|
3351
3372
|
|
|
@@ -3367,7 +3388,7 @@ The following directories saw significant in-repo changes between v0.2.5 and v0.
|
|
|
3367
3388
|
- `patterns/` — no source changes since v0.2.5.
|
|
3368
3389
|
## [0.2.5] - 2026-05-04
|
|
3369
3390
|
|
|
3370
|
-
**Lockstep cut + new `<fields-ui>` form-grid primitive + `draggable-list-item` last-item drop-zone fix.** All 8 published `@adia-ai/*` packages bump 0.2.4 → 0.2.5 per [
|
|
3391
|
+
**Lockstep cut + new `<fields-ui>` form-grid primitive + `draggable-list-item` last-item drop-zone fix.** All 8 published `@adia-ai/*` packages bump 0.2.4 → 0.2.5 per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy). Patch cut — **no BREAKING changes**.
|
|
3371
3392
|
|
|
3372
3393
|
### Added
|
|
3373
3394
|
|
|
@@ -3389,7 +3410,7 @@ The following directories saw significant in-repo changes between v0.2.5 and v0.
|
|
|
3389
3410
|
- `styles/components.css` adds `@import "../components/fields/fields.css"`.
|
|
3390
3411
|
## [0.2.4] - 2026-05-04
|
|
3391
3412
|
|
|
3392
|
-
**Lockstep cut + Tier 4 capability adds + 2 architectural rewrites.** All 8 published `@adia-ai/*` packages bump 0.2.3 → 0.2.4 per [
|
|
3413
|
+
**Lockstep cut + Tier 4 capability adds + 2 architectural rewrites.** All 8 published `@adia-ai/*` packages bump 0.2.3 → 0.2.4 per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
3393
3414
|
|
|
3394
3415
|
### Changed
|
|
3395
3416
|
|
|
@@ -3399,8 +3420,8 @@ The following directories saw significant in-repo changes between v0.2.5 and v0.
|
|
|
3399
3420
|
- `traits/index.js` adds 12 new exports (the 11 Tier-4 traits + droppable from the parallel Tasks UI initiative); `traits/_catalog.json` regenerated to 56 entries; `core/icons.js` extended with ~25 new aliases.
|
|
3400
3421
|
|
|
3401
3422
|
The substantive content of the next cut, surfaced from the
|
|
3402
|
-
2026-05-04 trait-library lift initiative (
|
|
3403
|
-
|
|
3423
|
+
2026-05-04 trait-library lift initiative (`.claude/docs/PLAN.md`,
|
|
3424
|
+
`.claude/docs/reports/traits-creative-director-audit-2026-05-04.md`).
|
|
3404
3425
|
**No BREAKING changes.** Every public tag, prop, event, and
|
|
3405
3426
|
declarative `traits=` attribute from v0.2.3 still works.
|
|
3406
3427
|
|
|
@@ -3653,7 +3674,7 @@ warnings on every page that referenced these:
|
|
|
3653
3674
|
|
|
3654
3675
|
**Lockstep cut + accumulated fixes.** All 8 published `@adia-ai/*`
|
|
3655
3676
|
packages bump 0.2.2 → 0.2.3 per
|
|
3656
|
-
[
|
|
3677
|
+
[`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy).
|
|
3657
3678
|
Patch cut — no breaking changes. The substantive content is
|
|
3658
3679
|
`web-components`-only; the other 7 packages have no source change.
|
|
3659
3680
|
|
|
@@ -3707,7 +3728,7 @@ edge instead of leaving the column reading as dead width. Per-row
|
|
|
3707
3728
|
---
|
|
3708
3729
|
## [0.2.2] - 2026-05-02
|
|
3709
3730
|
|
|
3710
|
-
**Lockstep cut + trait coverage 100% + `<traits-host>` wrapper.** All 8 published `@adia-ai/*` packages bump 0.2.1 → 0.2.2 per [
|
|
3731
|
+
**Lockstep cut + trait coverage 100% + `<traits-host>` wrapper.** All 8 published `@adia-ai/*` packages bump 0.2.1 → 0.2.2 per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
3711
3732
|
|
|
3712
3733
|
### Changed
|
|
3713
3734
|
|
|
@@ -3726,7 +3747,7 @@ Follow-up landing on top of the v0.2.1 trait-system work — closes the two foll
|
|
|
3726
3747
|
---
|
|
3727
3748
|
## [0.2.1] - 2026-05-02
|
|
3728
3749
|
|
|
3729
|
-
**Lockstep cut + 41-trait library overhaul + `<stat-ui>` ad-blocker rename.** All 8 published `@adia-ai/*` packages bump 0.2.0 → 0.2.1 per [
|
|
3750
|
+
**Lockstep cut + 41-trait library overhaul + `<stat-ui>` ad-blocker rename.** All 8 published `@adia-ai/*` packages bump 0.2.0 → 0.2.1 per [`.claude/docs/specs/package-architecture.md` § 15](../../.claude/docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
3730
3751
|
|
|
3731
3752
|
### Changed
|
|
3732
3753
|
|
|
@@ -3818,8 +3839,8 @@ transition rather than snapping. No JS changes; no API changes.
|
|
|
3818
3839
|
## [0.2.0] - 2026-05-02
|
|
3819
3840
|
|
|
3820
3841
|
**Lockstep cut.** All 8 published `@adia-ai/*` packages now share one
|
|
3821
|
-
version, governed by [
|
|
3822
|
-
(Versioning Policy)](
|
|
3842
|
+
version, governed by [`.claude/docs/specs/package-architecture.md` § 15
|
|
3843
|
+
(Versioning Policy)](../../.claude/docs/specs/package-architecture.md#15-versioning-policy)
|
|
3823
3844
|
and enforced by `npm run check:lockstep` + the
|
|
3824
3845
|
`lockstep-versioning` job in
|
|
3825
3846
|
[`.github/workflows/docs-lint.yml`](../../.github/workflows/docs-lint.yml).
|
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ web-components/
|
|
|
117
117
|
│ <traits-host> wrapper for raw-HTML declarative
|
|
118
118
|
│ composition. Generated catalog at _catalog.json
|
|
119
119
|
│ drives the MCP get_traits tool + per-trait demo
|
|
120
|
-
│ pages. Full contract in docs/specs/traits.md.
|
|
120
|
+
│ pages. Full contract in .claude/docs/specs/traits.md.
|
|
121
121
|
│
|
|
122
122
|
├── a2ui/ — deprecation shim for one release
|
|
123
123
|
│ └── index.js Re-exports @adia-ai/a2ui-runtime with a
|
|
@@ -247,7 +247,7 @@ class MyPanel extends UIElement {
|
|
|
247
247
|
|
|
248
248
|
The `el` parameter is the element instance — every signal-backed property is reactively read.
|
|
249
249
|
|
|
250
|
-
Full authoring contract: [
|
|
250
|
+
Full authoring contract: [`.claude/docs/specs/component-token-contract.md`](../../.claude/docs/specs/component-token-contract.md).
|
|
251
251
|
The `adia-ui-authoring` skill encodes the 20 non-negotiable rules.
|
|
252
252
|
|
|
253
253
|
## Card-n / drawer-ui composition parity
|
package/USAGE.md
CHANGED
|
@@ -466,7 +466,7 @@ export class UIModal extends UIElement {
|
|
|
466
466
|
}
|
|
467
467
|
```
|
|
468
468
|
|
|
469
|
-
Reference: [
|
|
469
|
+
Reference: [`.claude/docs/conventions/component-events.md`](../../.claude/docs/conventions/component-events.md) for the 1-page convention summary; [`scripts/build/dts-codegen.mjs`](../../scripts/build/dts-codegen.mjs) for the codegen logic that reads `x-adiaui.events`; [`scripts/release/check-form-bearing-dts.mjs`](../../scripts/release/check-form-bearing-dts.mjs) for the drift audit.
|
|
470
470
|
|
|
471
471
|
---
|
|
472
472
|
|
|
@@ -1631,8 +1631,8 @@ If your design needs label-on-tile (e.g. Tokens Studio's C1.3 hand-rolled `<div
|
|
|
1631
1631
|
- [`README.md`](./README.md) — package overview + authoring guide
|
|
1632
1632
|
- [Component yaml contracts](./components/) — every primitive's complete API (props, events, slots, examples)
|
|
1633
1633
|
- [Live demos](https://ui-kit.exe.xyz/site/components/) — every primitive in action
|
|
1634
|
-
- [
|
|
1635
|
-
- [
|
|
1636
|
-
- [
|
|
1634
|
+
- [`.claude/docs/specs/component-token-contract.md`](../../.claude/docs/specs/component-token-contract.md) — full authoring contract
|
|
1635
|
+
- [`.claude/docs/specs/component-implementation-patterns.md`](../../.claude/docs/specs/component-implementation-patterns.md) — render strategies
|
|
1636
|
+
- [`.claude/docs/specs/traits.md`](../../.claude/docs/specs/traits.md) — composable behaviors
|
|
1637
1637
|
|
|
1638
1638
|
For consumer questions not covered here, file an issue against [adiahealth/gen-ui-kit](https://github.com/adiahealth/gen-ui-kit/issues). This document is the canonical answer — if it doesn't have your answer, it's a doc gap worth fixing.
|
|
@@ -24,6 +24,15 @@
|
|
|
24
24
|
"text": {
|
|
25
25
|
"description": "Header text — the clickable label that toggles the section.",
|
|
26
26
|
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
"variant": {
|
|
29
|
+
"description": "Per-item posture override. Items normally inherit their host\naccordion-ui's [variant] — set this directly on ONE item only to\nopt it out of (`flat`) or into (`contained`) the host's posture.",
|
|
30
|
+
"type": "string",
|
|
31
|
+
"enum": [
|
|
32
|
+
"flat",
|
|
33
|
+
"contained"
|
|
34
|
+
],
|
|
35
|
+
"default": "flat"
|
|
27
36
|
}
|
|
28
37
|
},
|
|
29
38
|
"required": [
|
|
@@ -66,6 +75,9 @@
|
|
|
66
75
|
"body": {
|
|
67
76
|
"description": "The section's collapsible content. Renders below the header; hidden when `[open]` is unset. Author-fills with prose, lists, embedded forms, or any rich markup the panel needs."
|
|
68
77
|
},
|
|
78
|
+
"caret": {
|
|
79
|
+
"description": "The disclosure indicator icon. Auto-stamped (a caret-down icon-ui)\nwhen absent — under BOTH the default header and an authored\n[slot=\"header\"]. Author your own [slot=\"caret\"] element (even empty)\nto opt out of the auto-stamp; no separate attribute needed."
|
|
80
|
+
},
|
|
69
81
|
"header": {
|
|
70
82
|
"description": "Custom header content. By default `[text]` renders as a plain header\nlabel, but a `[slot=\"header\"]` override lets consumers author rich\nheaders (icon + title + action buttons + caret)."
|
|
71
83
|
}
|
|
@@ -81,7 +93,24 @@
|
|
|
81
93
|
]
|
|
82
94
|
},
|
|
83
95
|
"tag": "accordion-item-ui",
|
|
84
|
-
"tokens": {
|
|
96
|
+
"tokens": {
|
|
97
|
+
"--accordion-item-bg": {
|
|
98
|
+
"description": "Item surface background.",
|
|
99
|
+
"default": "transparent"
|
|
100
|
+
},
|
|
101
|
+
"--accordion-item-body-pt": {
|
|
102
|
+
"description": "Open body top padding.",
|
|
103
|
+
"default": 0
|
|
104
|
+
},
|
|
105
|
+
"--accordion-item-border": {
|
|
106
|
+
"description": "Item surface border (full shorthand — mirrors --card-border).",
|
|
107
|
+
"default": "none"
|
|
108
|
+
},
|
|
109
|
+
"--accordion-item-divider": {
|
|
110
|
+
"description": "Border between header and open body when expanded.",
|
|
111
|
+
"default": "none"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
85
114
|
"traits": [],
|
|
86
115
|
"version": 1
|
|
87
116
|
}
|
|
@@ -26,6 +26,17 @@ props:
|
|
|
26
26
|
description: Whether the section is expanded.
|
|
27
27
|
type: boolean
|
|
28
28
|
default: false
|
|
29
|
+
variant:
|
|
30
|
+
description: |-
|
|
31
|
+
Per-item posture override. Items normally inherit their host
|
|
32
|
+
accordion-ui's [variant] — set this directly on ONE item only to
|
|
33
|
+
opt it out of (`flat`) or into (`contained`) the host's posture.
|
|
34
|
+
type: string
|
|
35
|
+
default: flat
|
|
36
|
+
enum:
|
|
37
|
+
- flat
|
|
38
|
+
- contained
|
|
39
|
+
reflect: true
|
|
29
40
|
slots:
|
|
30
41
|
header:
|
|
31
42
|
description: |-
|
|
@@ -39,6 +50,12 @@ slots:
|
|
|
39
50
|
`[slot="actions"]`, or marked `[data-no-toggle]`) are excluded from
|
|
40
51
|
the toggle-on-click cascade — clicking them fires their own handler
|
|
41
52
|
without also toggling the section.
|
|
53
|
+
caret:
|
|
54
|
+
description: |-
|
|
55
|
+
The disclosure indicator icon. Auto-stamped (a caret-down icon-ui)
|
|
56
|
+
when absent — under BOTH the default header and an authored
|
|
57
|
+
[slot="header"]. Author your own [slot="caret"] element (even empty)
|
|
58
|
+
to opt out of the auto-stamp; no separate attribute needed.
|
|
42
59
|
body:
|
|
43
60
|
description: >-
|
|
44
61
|
The section's collapsible content. Renders below the header; hidden
|
|
@@ -52,6 +69,20 @@ events:
|
|
|
52
69
|
type: boolean
|
|
53
70
|
description: New open state.
|
|
54
71
|
|
|
72
|
+
tokens:
|
|
73
|
+
--accordion-item-bg:
|
|
74
|
+
description: Item surface background.
|
|
75
|
+
default: transparent
|
|
76
|
+
--accordion-item-border:
|
|
77
|
+
description: Item surface border (full shorthand — mirrors --card-border).
|
|
78
|
+
default: none
|
|
79
|
+
--accordion-item-divider:
|
|
80
|
+
description: Border between header and open body when expanded.
|
|
81
|
+
default: none
|
|
82
|
+
--accordion-item-body-pt:
|
|
83
|
+
description: Open body top padding.
|
|
84
|
+
default: 0
|
|
85
|
+
|
|
55
86
|
keywords:
|
|
56
87
|
- accordion-item
|
|
57
88
|
- collapsible
|
|
@@ -75,3 +106,5 @@ a2ui:
|
|
|
75
106
|
reason: 'Built-in cascade; do not wire onclick yourself.'
|
|
76
107
|
- rule: 'For single-button disclosures (one expanding panel without a list) use <details>/<summary> or compose <button-ui> + <section-ui>.'
|
|
77
108
|
reason: 'Accordion-item assumes sibling-context.'
|
|
109
|
+
- rule: 'An item inherits its host accordion-ui''s [variant]; set variant="flat" or variant="contained" directly on ONE item to override just that item against the host.'
|
|
110
|
+
reason: 'Per-item posture override.'
|
|
@@ -20,6 +20,15 @@
|
|
|
20
20
|
"description": "Allow multiple panels to be open simultaneously",
|
|
21
21
|
"type": "boolean",
|
|
22
22
|
"default": false
|
|
23
|
+
},
|
|
24
|
+
"variant": {
|
|
25
|
+
"description": "Visual posture, inherited by child accordion-item-ui elements unless a\nchild sets its own [variant]. `flat` (default) renders items with no\nchrome — settings pages, FAQ blocks, anywhere the accordion sits\ndirectly on the page canvas. `contained` gives every item a bounded\nsurface (background + border + radius spanning header and open body,\nplus a divider between them when open) — the composition to reach for\nwhen nesting the accordion inside <card-ui>.",
|
|
26
|
+
"type": "string",
|
|
27
|
+
"enum": [
|
|
28
|
+
"flat",
|
|
29
|
+
"contained"
|
|
30
|
+
],
|
|
31
|
+
"default": "flat"
|
|
23
32
|
}
|
|
24
33
|
},
|
|
25
34
|
"required": [
|
|
@@ -38,6 +38,12 @@ export class UIAccordion extends UIElement {
|
|
|
38
38
|
|
|
39
39
|
static properties = {
|
|
40
40
|
multiple: { type: Boolean, default: false, reflect: true },
|
|
41
|
+
// `reflect: true` is load-bearing: the CSS ancestor selector
|
|
42
|
+
// (accordion.css `@scope (accordion-item-ui)`) matches
|
|
43
|
+
// `accordion-ui[variant="contained"]`. Default 'flat' ⇒ absent-attribute
|
|
44
|
+
// = current behavior. No render/JS logic keys off it — inheritance of
|
|
45
|
+
// the contained posture into child items is pure CSS.
|
|
46
|
+
variant: { type: String, default: 'flat', reflect: true }, // 'flat' | 'contained'
|
|
41
47
|
};
|
|
42
48
|
|
|
43
49
|
static template = () => null;
|
|
@@ -70,6 +76,10 @@ export class UIAccordionItem extends UIElement {
|
|
|
70
76
|
static properties = {
|
|
71
77
|
text: { type: String, default: '', reflect: true },
|
|
72
78
|
open: { type: Boolean, default: false, reflect: true },
|
|
79
|
+
// Per-item posture override against the host accordion-ui's [variant]
|
|
80
|
+
// (see UIAccordion.variant above). Default 'flat'; CSS-only, pure
|
|
81
|
+
// token re-point in contained (accordion.css).
|
|
82
|
+
variant: { type: String, default: 'flat', reflect: true }, // 'flat' | 'contained'
|
|
73
83
|
};
|
|
74
84
|
|
|
75
85
|
static template = () => null;
|
|
@@ -77,13 +87,24 @@ export class UIAccordionItem extends UIElement {
|
|
|
77
87
|
#bound = false;
|
|
78
88
|
|
|
79
89
|
connected() {
|
|
80
|
-
// Stamp header if not present
|
|
81
|
-
|
|
90
|
+
// Stamp header if not present; otherwise restore the disclosure caret
|
|
91
|
+
// (FN-1) — a consumer's custom [slot="header"] previously suppressed it
|
|
92
|
+
// entirely because the caret only ever got stamped alongside the header.
|
|
93
|
+
const existingHeader = this.querySelector('[slot="header"]');
|
|
94
|
+
if (!existingHeader) {
|
|
82
95
|
const header = document.createElement('div');
|
|
83
96
|
header.setAttribute('slot', 'header');
|
|
97
|
+
// SPEC-R8: the auto-stamped header was mouse-only (no tabindex/keydown).
|
|
98
|
+
// Make it keyboard-operable; a consumer-authored header keeps owning
|
|
99
|
+
// its own semantics (data-autofocusable marks the header WE own).
|
|
100
|
+
header.setAttribute('tabindex', '0');
|
|
101
|
+
header.setAttribute('role', 'button');
|
|
102
|
+
header.setAttribute('aria-expanded', 'false');
|
|
103
|
+
header.dataset.autofocusable = '';
|
|
84
104
|
|
|
85
105
|
const label = document.createElement('span');
|
|
86
106
|
label.setAttribute('slot', 'header-text');
|
|
107
|
+
label.dataset.autolabel = ''; // marks THIS label as prop-driven (FN-2)
|
|
87
108
|
header.appendChild(label);
|
|
88
109
|
|
|
89
110
|
const caret = document.createElement('icon-ui');
|
|
@@ -92,6 +113,13 @@ export class UIAccordionItem extends UIElement {
|
|
|
92
113
|
header.appendChild(caret);
|
|
93
114
|
|
|
94
115
|
this.prepend(header);
|
|
116
|
+
} else if (!existingHeader.querySelector('[slot="caret"]')) {
|
|
117
|
+
// Scope to the HEADER, not the whole item — a caret placed in
|
|
118
|
+
// [slot="body"] must not suppress this (Finding 10).
|
|
119
|
+
const caret = document.createElement('icon-ui');
|
|
120
|
+
caret.setAttribute('name', 'caret-down');
|
|
121
|
+
caret.setAttribute('slot', 'caret');
|
|
122
|
+
existingHeader.appendChild(caret); // restore the disclosure signifier
|
|
95
123
|
}
|
|
96
124
|
|
|
97
125
|
// Stamp content wrapper if not present
|
|
@@ -112,17 +140,26 @@ export class UIAccordionItem extends UIElement {
|
|
|
112
140
|
if (!this.#bound) {
|
|
113
141
|
this.#bound = true;
|
|
114
142
|
this.addEventListener('click', this.#onClick);
|
|
143
|
+
this.addEventListener('keydown', this.#onKeydown);
|
|
115
144
|
}
|
|
116
145
|
}
|
|
117
146
|
|
|
118
147
|
disconnected() {
|
|
119
148
|
this.removeEventListener('click', this.#onClick);
|
|
149
|
+
this.removeEventListener('keydown', this.#onKeydown);
|
|
120
150
|
this.#bound = false;
|
|
121
151
|
}
|
|
122
152
|
|
|
123
153
|
render() {
|
|
124
|
-
|
|
154
|
+
// Only the auto-stamped label follows [text] — an authored
|
|
155
|
+
// [slot="header-text"] (no data-autolabel marker) is never touched (FN-2).
|
|
156
|
+
const label = this.querySelector('[slot="header-text"][data-autolabel]');
|
|
125
157
|
if (label) label.textContent = this.text;
|
|
158
|
+
|
|
159
|
+
// Keep aria-expanded in sync on the auto-stamped header — `open` is a
|
|
160
|
+
// reactive prop, so render() re-runs on every toggle (SPEC-R8).
|
|
161
|
+
const hdr = this.querySelector('[slot="header"][data-autofocusable]');
|
|
162
|
+
if (hdr) hdr.setAttribute('aria-expanded', String(this.open));
|
|
126
163
|
}
|
|
127
164
|
|
|
128
165
|
#onClick = (e) => {
|
|
@@ -140,4 +177,17 @@ export class UIAccordionItem extends UIElement {
|
|
|
140
177
|
detail: { open: this.open },
|
|
141
178
|
}));
|
|
142
179
|
};
|
|
180
|
+
|
|
181
|
+
// SPEC-R8: Enter/Space on the auto-stamped header toggles it. Scoped to
|
|
182
|
+
// OUR stamped header only (data-autofocusable) — never a consumer control
|
|
183
|
+
// inside a custom header. Routes through header.click() → #onClick, so
|
|
184
|
+
// there is exactly one toggle code path (DRY).
|
|
185
|
+
#onKeydown = (e) => {
|
|
186
|
+
const header = this.querySelector('[slot="header"][data-autofocusable]');
|
|
187
|
+
if (!header || e.target !== header) return;
|
|
188
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
189
|
+
e.preventDefault(); // Space: no page scroll
|
|
190
|
+
header.click();
|
|
191
|
+
}
|
|
192
|
+
};
|
|
143
193
|
}
|