@adia-ai/web-components 0.8.43 → 0.8.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/components/avatar/avatar.class.js +12 -1
  3. package/components/button/button.d.ts +4 -0
  4. package/components/chart/chart.a2ui.json +26 -0
  5. package/components/chart/chart.class.js +1304 -222
  6. package/components/chart/chart.css +151 -1
  7. package/components/chart/chart.d.ts +6 -0
  8. package/components/chart/chart.yaml +57 -0
  9. package/components/chart-legend/chart-legend.a2ui.json +17 -2
  10. package/components/chart-legend/chart-legend.class.js +69 -4
  11. package/components/chart-legend/chart-legend.css +65 -1
  12. package/components/chart-legend/chart-legend.d.ts +4 -2
  13. package/components/chart-legend/chart-legend.examples.md +4 -4
  14. package/components/chart-legend/chart-legend.yaml +43 -3
  15. package/components/combobox/combobox.a2ui.json +3 -0
  16. package/components/combobox/combobox.class.js +9 -8
  17. package/components/combobox/combobox.css +25 -4
  18. package/components/combobox/combobox.yaml +6 -0
  19. package/components/command/command.css +17 -1
  20. package/components/context-menu/context-menu.a2ui.json +8 -3
  21. package/components/context-menu/context-menu.class.js +46 -5
  22. package/components/context-menu/context-menu.d.ts +8 -3
  23. package/components/context-menu/context-menu.examples.md +2 -2
  24. package/components/context-menu/context-menu.yaml +22 -5
  25. package/components/heatmap/heatmap.a2ui.json +5 -0
  26. package/components/heatmap/heatmap.d.ts +2 -0
  27. package/components/heatmap/heatmap.yaml +8 -0
  28. package/components/input/input.a2ui.json +2 -2
  29. package/components/input/input.class.js +12 -7
  30. package/components/input/input.yaml +6 -5
  31. package/components/integration-card/integration-card.d.ts +2 -0
  32. package/components/nav/nav.a2ui.json +2 -2
  33. package/components/nav/nav.css +1 -1
  34. package/components/nav/nav.d.ts +1 -1
  35. package/components/nav/nav.yaml +14 -3
  36. package/components/nav-group/nav-group.css +37 -3
  37. package/components/noodles/noodles.a2ui.json +0 -15
  38. package/components/noodles/noodles.yaml +0 -12
  39. package/components/number-format/number-format.class.js +10 -0
  40. package/components/pagination/pagination.class.js +140 -26
  41. package/components/popover/popover.d.ts +2 -0
  42. package/components/progress/progress.class.js +11 -6
  43. package/components/range/range.class.js +9 -1
  44. package/components/search/search.class.js +39 -5
  45. package/components/select/select.a2ui.json +10 -1
  46. package/components/select/select.class.js +34 -14
  47. package/components/select/select.css +39 -1
  48. package/components/select/select.d.ts +2 -0
  49. package/components/select/select.yaml +19 -1
  50. package/components/stream/stream.d.ts +2 -0
  51. package/components/table/cell-types.js +9 -0
  52. package/components/table/table.a2ui.json +6 -1
  53. package/components/table/table.class.js +265 -34
  54. package/components/table/table.css +38 -10
  55. package/components/table/table.d.ts +3 -1
  56. package/components/table/table.examples.md +2 -2
  57. package/components/table/table.yaml +15 -2
  58. package/components/table-toolbar/table-toolbar.a2ui.json +43 -4
  59. package/components/table-toolbar/table-toolbar.class.js +407 -28
  60. package/components/table-toolbar/table-toolbar.css +299 -0
  61. package/components/table-toolbar/table-toolbar.d.ts +15 -1
  62. package/components/table-toolbar/table-toolbar.yaml +162 -15
  63. package/components/tag/tag.class.js +13 -1
  64. package/components/text/text.a2ui.json +3 -3
  65. package/components/text/text.d.ts +5 -3
  66. package/components/text/text.yaml +3 -3
  67. package/components/textarea/textarea.class.js +9 -1
  68. package/components/tour/tour.d.ts +10 -0
  69. package/core/a11y.d.ts +22 -0
  70. package/core/a11y.js +64 -0
  71. package/core/anchor.js +9 -5
  72. package/core/data-stream.js +37 -2
  73. package/core/element.js +1 -1
  74. package/core/index.d.ts +1 -0
  75. package/core/index.js +1 -0
  76. package/core/provider.d.ts +9 -13
  77. package/core/provider.js +9 -113
  78. package/core/store.d.ts +46 -0
  79. package/core/store.js +89 -0
  80. package/custom-elements.json +127 -33
  81. package/dist/host.min.css +1 -1
  82. package/dist/host.sheet.js +1 -1
  83. package/dist/theme-provider.min.js +1 -1
  84. package/dist/web-components.min.css +1 -1
  85. package/dist/web-components.min.js +119 -119
  86. package/dist/web-components.sheet.js +1 -1
  87. package/package.json +1 -1
  88. package/patterns/access-requests/access-requests.examples.html +1 -1
  89. package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +7 -7
  90. package/patterns/agent-cost/agent-cost.examples.html +6 -6
  91. package/patterns/agent-memory/agent-memory.examples.html +3 -3
  92. package/patterns/agent-prompt-library/agent-prompt-library.examples.html +8 -8
  93. package/patterns/agent-tool-call/agent-tool-call.examples.html +1 -1
  94. package/patterns/approvals/approvals.examples.html +6 -6
  95. package/patterns/audit-log/audit-log.examples.html +1 -1
  96. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +4 -4
  97. package/patterns/chart-in-card/chart-in-card.examples.html +114 -0
  98. package/patterns/chart-in-card/chart-in-card.examples.js +37 -0
  99. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +5 -5
  100. package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +2 -2
  101. package/patterns/diff-review/diff-review.examples.html +6 -6
  102. package/patterns/export-flow/export-flow.examples.html +2 -2
  103. package/patterns/filter-bar/filter-bar.examples.html +2 -2
  104. package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +2 -2
  105. package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
  106. package/patterns/marketing-engagement/marketing-engagement.examples.html +4 -4
  107. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +1 -1
  108. package/patterns/permissions-matrix/permissions-matrix.examples.html +1 -1
  109. package/patterns/permissions-sharing/permissions-sharing.examples.html +2 -2
  110. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +4 -4
  111. package/patterns/search-discovery/search-discovery.examples.html +2 -2
  112. package/styles/api/sizing.css +46 -0
  113. package/styles/type/roles.css +29 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,59 @@
1
1
  # Changelog — @adia-ai/web-components
2
2
 
3
+ ## [0.8.45] — 2026-08-20
4
+
5
+ ### Added
6
+ - **`createStore()` — a signal-backed store primitive in `core/store.js` (gh#1761).** `subscribe(cb) -> unsubscribe`, an `Object.is` no-notify guard, and interop with `UIElement.controller`; ships alongside a new `check-no-hand-rolled-stores.mjs` lint gate (gh#1779) that rejects new hand-rolled Set-of-listeners stores outside `core/`.
7
+
8
+ ### Changed
9
+ - **`for=`-carrying components normalized to an events-only interaction contract (gh#1764/#1780), ADR-0079.** `table-toolbar-ui` → `table-ui` direct writes/calls (`paginate=`, `search=`, `setFilter()`, `clearFilters()`, `columns=`) became five `toolbar-*` command CustomEvents with matching `table-ui` listeners — additive, zero observable-behavior change. `context-menu-ui`'s `for` (selector-flavored) renamed to `target-selector`, `for` kept as a deprecated back-compat alias.
10
+ - **`RouteController` deduplicated into `core/controller.js` (gh#1766).** `provider.js` now imports/re-exports the canonical location.
11
+ - **`[density="compact"|"spacious"]` re-declares `--a-space-*` at the scoped selector, not only `:root` (gh#1771, gh#570).** Element-scoped density was globally inert; `components/table/table.css`'s stale ADR-0054 comment corrected alongside.
12
+ - **Billing composites (`billing-overview`, `invoice-history`, `invoice-detail`, `plan-picker`) route fetch through `core/transport.js`, opting out of the `core/data-stream.js` auto-observer via a new `data-stream-managed="false"` marker (gh#1760).**
13
+ - **`select`/`table-toolbar` — visually-hidden `select` label (`[label-hidden]`) + actions-leading icon-only Filter/Columns reduction (gh#1748).**
14
+ - **`table-ui` adopts an `isEqualNode()`-based `adoptOrDiffChildren()` for SSR adopt-in-place, with `RENDERER_OWNED` `WeakSet` tagging for unconditional replacement of renderer-owned cells (gh#1678).**
15
+ - **`search-ui`/`pagination-ui` post-adopt attribute writes are idempotent under SSR zero-mutation (gh#1755).**
16
+ - **Three independently-authored path-walker implementations in `packages/gen-ui/a2ui/path-pointer.js` unified, preserving each call site's real divergent edge-case semantics rather than silently collapsing them (empty-path, primitive mid-path, doubled-slash) — mechanical staging toward ADR-0078's vendored-model migration.**
17
+
18
+ ### Docs
19
+ - **New `table-with-toolbar-in-card-header` demo** — `table-toolbar-ui` composed inside `card-ui`'s header (sole-child case; a real `card.css` grid/centering conflict documented for the heading+action-slot case, not yet supported).
20
+ - **`nav-group-ui`'s `[data-nav-label]` group-label hook documented (gh#1736).**
21
+ - **Render clock & external-store wiring doctrine ratified in `.claude/docs/specs/component-implementation-patterns.md` (gh#1777/#1778)** — `table-ui`'s rAF-batched render clock named as the sole verified exception to the microtask-flush contract; `BaseController` promoted as a `createStore()` adapter via its existing optional-chaining `controller` setter (no new adapter code needed — the contract was already satisfied).
22
+
23
+ ### Maintenance
24
+ - **`dist/` bundles rebuilt** in this cut's window (6 file(s)) — regenerated from the source changes described above, not independent edits.
25
+ - **`styles/` touched in this release window** (2 file(s), e.g. `api/sizing.css`) — carried by the entries above.
26
+
27
+ ## [0.8.44] — 2026-08-20
28
+
29
+ ### Added
30
+ - **`chart-ui[y-min]`/`[y-max]` — pins the value-axis domain for cartesian types (gh#1690, ADIA2-9137).** `bar`, `line`, `area`, `scatter`, `multi-line`, `stacked-bar`, `grouped-bar`, and `composed` all read the pinned domain instead of auto-scaling to the data's own range — unset (default) is byte-identical to today's auto-scale (floor 0, ceiling the data max). Auto-scale already zero-floors a positive series (a migrating d3 consumer's own "pin the floor to 0" habit is the built-in default, not something to configure) — the pins earn their keep for three OTHER cases (review correction, replacing an earlier draft's inaccurate "auto-scale reads a percent drift as a cliff" claim): zooming a narrow window (`y-min="0.9" y-max="1"` magnifies a percent series clustered near 92-95%, which reads flatter against the full auto-scaled [0,1]), a mixed-sign series (the unpinned floor never goes below 0, so negative values clip at the axis unless `y-min` is pinned negative), and aligning two charts to one shared scale. N/A for radial/part-to-whole types (pie, donut, radar, radial-bar, gauge, funnel, treemap, sankey, segments, sparkline) — those never read a shared linear value axis. New `evals/visual/fixtures/comp-chart-n-ydomain-pinned.json` golden (outside the strict 60-fixture Charts floor's ratio-suffix sweep, same convention as the pre-existing `chart-dashboard` fixture) exercises the pinned path; the 60-fixture floor itself stays green, proving the unset path is unchanged. Added to the `/site/patterns/charts` showcase's ratified-attributes table + a zoomed-window demo (verified in a rendered DOM to produce visibly different axis labels and plotted positions, not just different attributes). Review finding: a datum exceeding the pinned domain now CLAMPS to the nearest edge for rendering (chart-ui's SVG is `overflow: visible`, so an unclamped value previously rendered off-canvas — e.g. `y-max="1"`, value `1.5` resolved to a negative y-coordinate bursting above the plot) — the displayed value label/tooltip still shows the real, unclamped value. 7 new regression tests assert every render path's geometry stays within its own `viewBox` for an out-of-domain datum.
31
+
32
+ ### Fixed
33
+ - **`text-ui[variant="label"|"kicker"|"section"]` render in the mono font stack instead of the UI-sans/heading families (gh#1718).** `label`/`kicker` are now `--a-font-family-code` at regular (400) weight; `section` is the same mono stack at medium (500) — operator-ruled component-level, answering the issue's own open question. Fixed at the shared L3 role tokens (`styles/type/roles.css`'s `--a-kicker-family`/`-weight`, `--a-label-family`/`-weight`, `--a-section-family`/`-weight`), not `text.css`'s own `[variant]` rules — those per-variant `--text-family`/`--text-weight` overrides are dead code for these three properties, since `roles.css`'s `[variant="<role>"]` attribute rule lives in the `utilities` cascade layer, which always wins over `text.css`'s `components`-layer rule by layer order regardless of selector specificity (ADR-0038 step 6 — text-ui is deliberately not excluded from this shared grammar). Side effect of fixing the true single-source token: `menu-ui`'s kicker-styled group headers and `richtext-ui`'s h2 (aliases `--richtext-h2-weight` to `--a-section-weight`) also move to the mono stack, as does `@adia-ai/web-modules`'s `admin-shell` settings-tab section `<h2>` (`--page-section-weight: var(--a-kicker-weight)`) — a weight-only bleed to regular/400, since its own `--page-section-size` reads `--a-kicker-size` (unchanged); `nav`/`nav-item`/`nav-group`'s own structural `[variant="section"]` is already excluded from this token's global rule and is unaffected.
34
+ - **`pagination-ui` first-connect adoption — `connected()` no longer duplicates its `<nav>` when upgrading over server-rendered light DOM (gh#1687, ADIA2-6243).** It guarded on a private `#nav` field (always `null` at construction) and unconditionally appended a fresh `<nav>`; it now queries for a pre-existing `<nav slot="nav">` child first and adopts it, matching `empty-state-ui`'s existing adoption pattern. Adopting the element alone wasn't the whole fix (review finding) — `render()`'s keyed reconcile diffs against `parent[KEY_MAP]`, a keyed `Map` populated by this element's own prior render calls, which a freshly-parsed SSR fragment never has; without seeding it, the first render treated every adopted child as unrecognized and stamped a full duplicate set of buttons alongside the originals. `#seedKeyMapFromAdoptedNav()` positionally zips the adopted children against the same key order the next render would produce, falling back to a normal rebuild on any shape mismatch — two further review findings on that fallback: (1) it bare-returned without clearing the adopted nav's stale children, so `reconcile()`'s own cleanup (which only removes entries already IN its key-map) left the stale children sitting alongside a full fresh render (reproduced: 3 stale placeholders + a correct 9-item render = 12 nodes); (2) child COUNT alone isn't a reliable correlation signal — a same-length fixture with the wrong tag/marker per position (e.g. bare `<span>`s standing in for `<button-ui>` page-cells) would pass a count-only check and get seeded, then `#updateItem()` (attribute-only, never a tag swap) leaves it permanently wrong. Fixed by validating each adopted child's tag + `data-*` marker against its expected item shape (`#childMatchesItem()`) and clearing the adopted nav's children on ANY mismatch before falling through, so the fallback is a genuine clean rebuild either way. Steady-state reconcile is unaffected.
35
+ - **`ssr-linkedom-smoke.mjs` gains a nested-rendering sweep (gh#1699) — proves gen-ui-kit's own light-DOM lifecycle never drops content when one registered custom element's children are themselves other registered custom elements, covering both `col-ui` wrapping `card-ui` DIRECTLY (gh#1699's reported shape) and one level deeper via an anchor wrapper (the mapped-JSX shape gh#1699's own repro used).** Investigated as an SSR content-loss report (Astro dropping `col-ui`/`card-ui` children under `custom-elements-ssr`, adiav2 ADIA2-9483) — root-caused to Astro core's own `renderComponent`/`renderSlots` nesting resolution, entirely outside this repo's dependency graph (no `astro`/`custom-elements-ssr` dep here to reproduce that pipeline against). This sweep is the durable proof of the one thing gen-ui-kit's lifecycle IS responsible for: a fully synchronous `connectedCallback()` round-trip never loses nested light-DOM children on its own. No production code changed.
36
+ - **`command-ui`'s search input rendered its placeholder (and, structurally, any typed text) centered instead of left-aligned next to the leading icon (gh#1697).** Root cause: the search input span and the list's own "No results found." empty-state `<div>` both toggle the same `data-empty` attribute for unrelated reasons, and `command.css`'s empty-state rule was a bare, unscoped `[data-empty]` selector that matched both — its `text-align: center` (meant only for the centered empty-state message) leaked onto the input whenever the input itself was empty. Scoped the rule to `[slot="list"] [data-empty]`, matching the DOM position the empty-state `<div>` actually renders at, removing the collision at its root.
37
+ - **Restored kebab-case props silently dropped from `.d.ts` (gh#1686, `dts-codegen.mjs` fix — see repo-root CHANGELOG).** `button-ui[iconTrailing]`/`[ariaLabel]`, and props on `context-menu-ui`, `integration-card-ui`, `noodles-ui`, `popover-ui`, `stream-ui`, `text-ui`, and `tour-ui` are restored to their `.d.ts` files. No runtime behavior change — these props already worked at runtime; only the shipped TypeScript surface was affected.
38
+ - **Corpus dead-attribute sweep (gh#1669, gh#1611 pt 2 / PR #1668's full-depth harvest-gate findings) — 111 findings across 46 demo/pattern/app-shell source files burned down to zero.** Each fix rewrites the SOURCE usage to the component's real yaml-contract prop rather than inventing a new one: `button-ui[icon-leading|icon-position|icon-only|formnovalidate|tooltip]` → `icon`/`icon-trailing`/(dropped, already auto-computed)/(dropped, unwired)/`title`; `input-ui[icon|icon-leading|icon-trailing|hint]` → `prefix`/`prefix`/`suffix`/`error`; `tag-ui[icon|icon-leading]` dropped (tag-ui has no icon slot); `text-ui[muted|align|tracking]` → `color="subtle"`/`text-align`/dropped; `card-ui[span|compact]` → inline `style="grid-column: span N"`/`size="sm"`; `image-ui[span]` → same grid-column style move; `stat-ui[delta]` → `change`; `nav-item-ui[active]` → `selected`; `otp-input-ui[autocomplete]` dropped (hardcoded internally); `chat-composer[placeholder]` dropped (no such prop); `chart-ui[height]` → inline style; `popover-ui[anchor]` dropped (no such prop — anchoring is implicit); `integration-card-ui[icon]` → `logo`; `progress-ui[indeterminate]` dropped (component's own contract: omit `value`). `input.yaml`'s own `a2ui.rules` doc text corrected alongside — it falsely claimed input-ui supports an inline `[hint]` prop (only `field-ui` does); that false claim was itself feeding the misuse this sweep just fixed.
39
+
40
+ ### Changed
41
+ - **`harvest-chunks.mjs`'s attr-gate promoted from advisory to blocking-by-default (gh#1669)**, now that the 111 known findings are zero — `npm run build:components` / `harvest:chunks` now REFUSE to write when a dead attribute reappears; pass `--advisory-attrs` to warn-only for a one-off triage run. `findAllOpenTagsInRange` hardened to blank `<script>`/`<style>` bodies and HTML comments before matching (reviewer note on PR #1668 — previously harmless only because `attrSchemas` drops unknown tag names, but latent).
42
+
43
+ ### Added
44
+ - **`table-ui` render-cell truncation contract via `[data-truncate]` (gh#1681).** Built-in cell types get single-line ellipsis truncation for free because their output is always a bare `<span>`/`<a>` direct child of the gridcell — a `column.render` function's markup isn't guaranteed to match that shape, so consumer-rendered cells clipped with no ellipsis and no documented opt-in. Set `data-truncate` on whichever rendered element (any tag, including a custom element) should single-line-ellipsis to extend the identical CSS contract built-ins already have; `[wrap]`/`[data-wrap]` override it back to multi-line the same way they do for built-ins. Built-in cell truncation is unchanged.
45
+ - **`table-ui[clickable-rows]` cursor affordance (gh#1680).** adiav2's zero-overrides purge deleted an app-side `[data-clickable]` cursor rule with no kit-side replacement, leaving row-click tables reading as inert. `row-click` fires unconditionally regardless of whether a listener is attached, so the cursor can't be inferred from listener presence — `clickable-rows` is an explicit boolean opt-in (reflected attribute, default `false`) that sets `cursor: pointer` on body rows. No behavior change for tables without it.
46
+ - **`table-toolbar-ui` container-query substrate + `stage` override attribute + breakpoint custom properties (gh#1660 step 1, ADR-0076).** `:scope` now declares `container-type: inline-size; container-name: table-toolbar` (width-only measurement, per `chart.css`'s own documented `size`-containment trap). A new `stage` attribute (enum `full | search-tight | icon-only | overflow`, default `""` = auto-snap, reflects) pins a compaction stage regardless of container width. Three normative `--table-toolbar-bp-search-tight`/`-icon-only`/`-overflow` custom properties (defaults `56rem`/`40rem`/`26rem`) are the single source of truth the coming compaction stages' `@container` rules and the `data-stage-resolved` reflection will both read. No stage-specific rendering lands yet — this step only lands the measurement substrate (PLAN step 1 of the compaction ladder).
47
+ - **`table-toolbar-ui` search-tight compaction stage (gh#1660 step 2, ADR-0076).** The search field's `--table-toolbar-search-min`/`-max` now step down to `--table-toolbar-search-tight-min`/`-max` (defaults `9rem`/`14rem`) once the toolbar's own `inline-size` container crosses `--table-toolbar-bp-search-tight` (`56rem` default), via `@container table-toolbar (max-width: 56rem)`. An explicit `stage="search-tight"` (or the tighter `"icon-only"`/`"overflow"` pins, ahead of their own steps 3/5 CSS) forces the same narrowed extents regardless of the container's actual width, per ADR-0076's `stage` override.
48
+ - **`table-toolbar-ui` icon-only controls stage + title tooltip + range-summary compact/hide (gh#1660 steps 3+4, ADR-0076).** At `--table-toolbar-bp-icon-only` (`40rem` default) — or an explicit `stage="icon-only"`/`"overflow"` pin — Filter/Sort/Columns drop their rendered text label (`::after { content: none }`, overriding `button.css`'s own generated-content rule) and take on square icon-button geometry; `aria-label` stays intact throughout (set unconditionally by `button-ui`'s own `render()`). Every control button now also carries a native `title` attribute unconditionally — harmless at wider stages, the hover-tooltip affordance once the label is visually hidden. At the same breakpoint, the range summary (`"Showing X–Y of N"`) hides only when a visible `[page-size]` select already carries the same context; when page-size is absent, the summary compacts to a short form (`"1–25/320"`) instead of disappearing — the toolbar's sole range indicator never fully vanishes.
49
+ - **`table-toolbar-ui` overflow-menu compaction stage for Filter/Sort/Columns (gh#1660 step 5, ADR-0076).** At `--table-toolbar-bp-overflow` (`26rem` default) — or an explicit `stage="overflow"` pin — the three granular control buttons hide (CSS-only; they stay in the DOM, never destroyed) and one "More" trigger appears instead — reuses the existing `menu-ui`/`menu-item-ui` primitives; adds `menu-ui` to `table-toolbar-ui`'s composition list. Selecting a menu item routes through the same `#togglePopover(kind, btn)` every granular button already calls. The trigger carries a static `aria-label="More table actions"` + `aria-haspopup="menu"` (a genuinely new interactive element). The overflow menu mirrors `chrome-only`/`no-*` suppression — a suppressed control stays suppressed inside the menu too, and the whole trigger hides once every item it would offer is suppressed.
50
+ - **`table-toolbar-ui` visual-eval fixture floor for the compaction ladder (gh#1660 step 6, ADR-0076).** Seven golden fixtures under `evals/visual/` — the four compaction stages (`full`/`search-tight`/`icon-only`/`overflow`, pinned deterministically via `[stage]`), the ratified adiav2 `chrome-only` list-page-toolbar-row shape at the icon-only stage (REQ-A-003's reduced-region case), and AC-003b's two range-summary branches (hide vs compact) as separate fixtures — wired into `npm run check` as `check:table-toolbar-visual-eval`, mirroring the Charts 2.0 visual-eval floor's own harness shape (`scripts/eval/visual-charts-ci.mjs`, gh#1624 step 8).
51
+ - **`table-toolbar-ui` reflects its resolved compaction stage as `data-stage-resolved` (gh#1660 step 7, ADR-0076, ADIA2-9123 S4-ii).** A lightweight `ResizeObserver` classifies the toolbar's own live inline-size against the same three `--table-toolbar-bp-*` breakpoints its CSS `@container` rules use (read live via `getComputedStyle`, falling back to each breakpoint's documented default only when the custom property can't be read at all), reflecting the result onto the host — mirrors `chart-ui`'s `data-ratio-resolved` convention, including its is-different guard. Purely informational: never drives table-toolbar's own rendering, which stays 100% CSS-driven (REQ-M-002). An explicit `stage` pin reports itself; the reflection updates on both a live resize and a `stage` attribute change alone.
52
+
53
+ ### Maintenance
54
+ - **`dist/` bundles rebuilt** in this cut's window (6 file(s)) — regenerated from the source changes described above, not independent edits.
55
+ - **`test/` touched in this release window** (1 file(s), e.g. `test/ssr-linkedom-smoke.test.js`) — carried by the entries above.
56
+
3
57
  ## [0.8.43] — 2026-08-18
4
58
 
5
59
  ### Removed
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  import { UIElement } from '../../core/element.js';
30
+ import { syncAutoAriaLabel } from '../../core/a11y.js';
30
31
 
31
32
  // ── Avatar ──────────────────────────────────────────────────
32
33
 
@@ -47,6 +48,13 @@ export class UIAvatar extends UIElement {
47
48
  #imgEl = null;
48
49
  #initialsEl = null;
49
50
  #iconEl = null;
51
+ // gh#1647: tracks the aria-label VALUE this element itself last derived
52
+ // from `text`/`icon` (undefined when none) — value-tracking guard
53
+ // ported from tag.class.js/select.class.js (gh#1644/#1646). Scoped to
54
+ // the PER-AVATAR label only — avatar-group's own "Avatar group" label
55
+ // (avatar.class.js's UIAvatarGroup, :125) is already guarded separately
56
+ // and runs once in connected(), not the render loop; out of scope here.
57
+ #lastAutoAriaLabel = undefined;
50
58
 
51
59
  connected() {
52
60
  this.setAttribute('role', 'img');
@@ -90,7 +98,10 @@ export class UIAvatar extends UIElement {
90
98
  this.#showInitials();
91
99
  }
92
100
 
93
- this.setAttribute('aria-label', this.displayName || this.icon || '');
101
+ // A11y (gh#1647): never clobber a consumer's own aria-label
102
+ // (value-tracking guard, gh#1644/#1646).
103
+ const ariaSource = this.displayName || this.icon || '';
104
+ this.#lastAutoAriaLabel = syncAutoAriaLabel(this, this.#lastAutoAriaLabel, ariaSource);
94
105
  }
95
106
 
96
107
  #showInitials() {
@@ -17,12 +17,16 @@ export type ButtonPressEvent = CustomEvent<unknown>;
17
17
  export class UIButton extends UIElement {
18
18
  /** HTML button type (button, submit, reset) */
19
19
  type: string;
20
+ /** Accessible label for screen readers. Auto-set from `text` when text is non-empty; meaningful override for icon-only buttons. */
21
+ ariaLabel: string;
20
22
  /** Semantic intent — composes with [variant]. `<button-ui variant="solid" color="danger">` = filled destructive action; `<button-ui variant="outline" color="success">` = outlined success affordance. */
21
23
  color: 'default' | 'info' | 'success' | 'warning' | 'danger';
22
24
  /** Disables interaction and prevents click/press events */
23
25
  disabled: boolean;
24
26
  /** Leading Phosphor icon name (rendered before text). */
25
27
  icon: string;
28
+ /** Trailing Phosphor icon name (rendered after text). Use for forward affordances like "Next →" / wizards / pagination / product tours where the caret points away from the label. */
29
+ iconTrailing: string;
26
30
  /** Sizing scale (sm/md/lg). For a denser or larger register, set [scale] on an ancestor (scale="ui-sm" … "content-lg") — scale picks the table, size picks the row. */
27
31
  size: 'sm' | 'md' | 'lg';
28
32
  /** Makes the button stretch to fill the parent's width */
@@ -107,6 +107,16 @@
107
107
  "type": "boolean",
108
108
  "default": false
109
109
  },
110
+ "ratio": {
111
+ "description": "Chart 2.0 aspect-ratio bucket (ADR-0074). Unset (default) auto-snaps to the nearest of the three studied ratios by comparing the chart's own live box aspect against two midpoint boundaries (5:4 between 3:2/1:1, 4:5 between 1:1/2:3) — never interpolated; the resolved bucket reflects onto the host as `data-ratio-resolved`. Setting `ratio` explicitly pins that bucket regardless of the box's actual aspect, overriding the auto-snap. Orthogonal to `size` (overall scale) and `type`/`color` (ADR-0064's family axis) — this attribute lands the grammar + snap plumbing only; per-type studied renderings per bucket are later waves (gh#1624 plan steps 2-4).",
112
+ "type": "string",
113
+ "enum": [
114
+ "3:2",
115
+ "1:1",
116
+ "2:3"
117
+ ],
118
+ "default": ""
119
+ },
110
120
  "seriesEmphasis": {
111
121
  "description": "Multi-line only. Names one series key (matching a `y` key) to render at full strength — area fill + full-opacity line. Every other series drops its area fill and renders line-only at --chart-deemphasized-opacity. Empty (default) applies full treatment to every series, unchanged from pre-gh#561 behavior.",
112
122
  "type": "string",
@@ -136,6 +146,22 @@
136
146
  "description": "Y-axis key(s), comma-separated for multi-series",
137
147
  "type": "string",
138
148
  "default": ""
149
+ },
150
+ "yMax": {
151
+ "description": "Pins the value-axis domain ceiling for cartesian types (bar, line, area, scatter, multi-line, stacked-bar, grouped-bar, composed). Unset (default, null) keeps today's auto-scale ceiling (the data max). Pairs with `yMin` to pin the full domain; either may be set alone. N/A for radial/part-to-whole types — see `yMin` (gh#1690). A datum outside the pinned domain is CLAMPED to the nearest edge for rendering (the value label/tooltip still shows the real value) rather than escaping the plot box.",
152
+ "type": [
153
+ "number",
154
+ "null"
155
+ ],
156
+ "default": null
157
+ },
158
+ "yMin": {
159
+ "description": "Pins the value-axis domain floor for cartesian types (bar, line, area, scatter, multi-line, stacked-bar, grouped-bar, composed). Unset (default, null) already floors a positive series at 0 (the pre-1690 behavior, unchanged) — a migrating d3 consumer's own \"pin the floor to 0\" habit is the built-in default, not something to configure. Pin `y-min` explicitly for three OTHER cases: (1) zooming a narrow window — e.g. `y-min=\"0.9\" y-max=\"1\"` magnifies a percent series clustered near 92-95%, which reads flatter against the full auto-scaled [0,1] domain; (2) a mixed-sign series, where the unpinned floor never goes below 0 and negative values clip at the axis; (3) aligning two charts to one shared scale for a fair comparison. N/A for radial/part-to-whole types (pie, donut, radar, radial-bar, gauge, funnel, treemap, sankey, segments, sparkline) — those never read a shared linear value axis, so this prop is a no-op there (gh#1690). A datum outside the pinned domain is CLAMPED to the nearest edge for rendering (the value label/tooltip still shows the real value) rather than escaping the plot box.",
160
+ "type": [
161
+ "number",
162
+ "null"
163
+ ],
164
+ "default": null
139
165
  }
140
166
  },
141
167
  "required": [