@adia-ai/web-components 0.6.50 → 0.7.1

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 (106) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/components/action-list/action-list.css +1 -1
  3. package/components/agent-artifact/agent-artifact.class.js +10 -10
  4. package/components/agent-artifact/agent-artifact.css +1 -1
  5. package/components/agent-reasoning/agent-reasoning.class.js +51 -0
  6. package/components/agent-reasoning/agent-reasoning.css +49 -22
  7. package/components/alert/alert.class.js +8 -1
  8. package/components/alert/alert.css +13 -1
  9. package/components/avatar/avatar.a2ui.json +2 -14
  10. package/components/avatar/avatar.class.js +3 -15
  11. package/components/avatar/avatar.d.ts +2 -4
  12. package/components/avatar/avatar.yaml +1 -18
  13. package/components/breadcrumb/breadcrumb.css +4 -1
  14. package/components/button/button.a2ui.json +3 -0
  15. package/components/button/button.css +14 -3
  16. package/components/button/button.yaml +5 -0
  17. package/components/calendar-grid/calendar-grid.css +1 -1
  18. package/components/calendar-picker/calendar-picker.css +5 -2
  19. package/components/chart/chart.a2ui.json +0 -18
  20. package/components/chart/chart.class.js +8 -50
  21. package/components/chart/chart.css +1 -15
  22. package/components/chart/chart.d.ts +0 -4
  23. package/components/chart/chart.yaml +0 -24
  24. package/components/color-input/color-input.css +4 -1
  25. package/components/combobox/combobox.class.js +11 -0
  26. package/components/combobox/combobox.css +8 -0
  27. package/components/date-range-picker/date-range-picker.class.js +5 -1
  28. package/components/date-range-picker/date-range-picker.css +12 -2
  29. package/components/datetime-picker/datetime-picker.class.js +3 -0
  30. package/components/datetime-picker/datetime-picker.css +16 -2
  31. package/components/empty-state/empty-state.css +11 -4
  32. package/components/field/field.css +17 -6
  33. package/components/grid/grid.a2ui.json +5 -0
  34. package/components/grid/grid.class.js +16 -6
  35. package/components/grid/grid.css +17 -3
  36. package/components/grid/grid.d.ts +2 -0
  37. package/components/grid/grid.yaml +9 -0
  38. package/components/heatmap/heatmap.class.js +9 -3
  39. package/components/heatmap/heatmap.css +19 -2
  40. package/components/image/image.css +4 -1
  41. package/components/input/input.class.js +38 -0
  42. package/components/input/input.css +9 -5
  43. package/components/input/input.test.js +57 -0
  44. package/components/integration-card/integration-card.class.js +31 -7
  45. package/components/integration-card/integration-card.test.js +12 -1
  46. package/components/kbd/kbd.a2ui.json +3 -2
  47. package/components/kbd/kbd.css +7 -4
  48. package/components/kbd/kbd.d.ts +2 -2
  49. package/components/kbd/kbd.yaml +2 -1
  50. package/components/list/list.class.js +8 -1
  51. package/components/menu/menu.class.js +12 -3
  52. package/components/menu/menu.css +4 -1
  53. package/components/menu/menu.test.js +130 -0
  54. package/components/modal/modal.class.js +10 -1
  55. package/components/modal/modal.css +9 -0
  56. package/components/option-card/option-card.a2ui.json +3 -0
  57. package/components/option-card/option-card.css +44 -19
  58. package/components/option-card/option-card.yaml +5 -0
  59. package/components/otp-input/otp-input.css +25 -10
  60. package/components/page/page.css +64 -11
  61. package/components/pagination/pagination.class.js +1 -1
  62. package/components/pagination/pagination.css +9 -1
  63. package/components/pipeline-status/pipeline-status.css +6 -0
  64. package/components/popover/popover.css +12 -1
  65. package/components/preview/preview.css +30 -3
  66. package/components/progress-row/progress-row.css +3 -1
  67. package/components/qr-code/qr-code.css +4 -1
  68. package/components/segmented/segmented.css +4 -1
  69. package/components/select/select.a2ui.json +1 -1
  70. package/components/select/select.class.js +63 -7
  71. package/components/select/select.css +18 -0
  72. package/components/select/select.yaml +9 -2
  73. package/components/stack/stack.a2ui.json +12 -1
  74. package/components/stack/stack.d.ts +2 -2
  75. package/components/stack/stack.yaml +13 -1
  76. package/components/stat/stat.a2ui.json +5 -0
  77. package/components/stat/stat.css +55 -0
  78. package/components/stat/stat.d.ts +2 -0
  79. package/components/stat/stat.js +4 -0
  80. package/components/stat/stat.yaml +9 -0
  81. package/components/swiper/swiper.class.js +14 -6
  82. package/components/switch/switch.css +13 -0
  83. package/components/table/table.a2ui.json +2 -2
  84. package/components/table/table.css +13 -1
  85. package/components/table/table.yaml +2 -2
  86. package/components/time-picker/time-picker.css +4 -1
  87. package/components/timeline/timeline.class.js +3 -3
  88. package/components/timeline/timeline.css +23 -5
  89. package/components/toggle-group/toggle-group.css +4 -1
  90. package/components/toggle-scheme/toggle-scheme.css +4 -1
  91. package/components/tree/tree.class.js +24 -4
  92. package/components/tree/tree.test.js +108 -0
  93. package/dist/web-components.min.css +1 -1
  94. package/dist/web-components.min.js +83 -83
  95. package/package.json +3 -3
  96. package/styles/api/layout.css +7 -0
  97. package/styles/api/text.css +9 -5
  98. package/styles/index.css +11 -2
  99. package/styles/prose.css +8 -0
  100. package/styles/resets.css +5 -5
  101. package/styles/themes.css +8 -1
  102. package/styles/tokens.css +3 -3
  103. package/styles/type/elements.css +73 -0
  104. package/styles/type/roles.css +14 -49
  105. package/styles/type/scale.css +0 -5
  106. package/styles/typography.css +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,139 @@
1
1
  # Changelog — @adia-ai/web-components
2
2
 
3
+ ## [0.7.1] — 2026-05-31
4
+
5
+ ### Fixed
6
+
7
+ - **`<input-ui>` leading/trailing affordance vertical centering** — the affordance slots used `align-self: stretch`, which top-aligned any child carrying a definite `height` (a `<kbd-ui slot="trailing">` ⌘K hint sat ~4px high in a 30px chrome) and also overrode a `<button-ui>` child's own `--button-height`. Changed to `align-self: center` so each affordance keeps its token height and sits on the field's vertical center. Affects every intrinsic-height affordance (kbd / icon / badge); button affordances are unchanged (they already filled the chrome). (bug-60)
8
+ - **`<tree-ui>` nested items now satisfy the WAI-ARIA tree pattern** — the `tree-item-ui` host is now `role="group"` and its focusable `[slot="row"]` is the `role="treeitem"` (with `aria-expanded`/`aria-selected` moved onto the row). Previously the host was the `treeitem` and nested items had no `group`/`tree` required parent, tripping axe-core `aria-required-parent` (critical) on every nested node. Done without re-homing children, so it holds for static markup AND template-engine `.map()` trees; no CSS/yaml change. Validated with real axe-core (0 violations). (FEEDBACK-91)
9
+ - **`<menu-ui>` renders dynamically-generated items** — `#show()` collected items with a direct-child `:scope >` query, which missed `menu-item-ui` rendered via `.map()`/`repeat()` (the template engine nests them in `display:contents` wrapper spans) → the popover opened empty. Now uses a descendant query (skipping items already relocated into the popover), matching `#hide()` and resolving the show/hide asymmetry. Static children unaffected. (FEEDBACK-92)
10
+ - **`<input-ui>` reactive `prefix=`/`suffix=` bindings resolve** — a reactive attribute binding (`suffix="${expr}"`) leaked the literal template placeholder `{{p:N}}` as affix text, because the shell was snapshotted once in `connected()` before the binding resolved and never re-synced. `render()` now re-resolves the prefix/suffix slots each cycle (handling text↔icon affixes), mirroring the slider-ui FB-45 fix. Literal and `.property` affixes are unchanged. (FEEDBACK-93)
11
+ - **`dist/` CDN bundles regenerated** (`web-components.min.css` + `web-components.min.js`) to carry the input/tree/menu fixes above.
12
+
13
+ ### Changed — demos
14
+
15
+ - **`<field-ui>` inline-layout demo** — the "Results: 12" count moved from a field-level `<span slot="trailing">` (beside the input) into the input's `suffix` prop, so it renders **in-chrome, left of the Clear button** (DOM order value → `suffix` → `trailing`). The demo now shows all three affordances inside the input chrome and the note explains the suffix-vs-trailing split. (bug-60)
16
+
17
+ ## [0.7.0] — 2026-05-31
18
+
19
+ ### Added — component features from the docs-QA pass
20
+
21
+ - **`<stat-ui bleed>`** — horizontal-bleed KPI tile. With a `slot="chart"` child, value/label/change stack on the left while the chart fills the right column at full height and bleeds to the card's top/right/bottom edges (the horizontal counterpart to a chart in a `<section bleed>`). First-class reflected Boolean attr (yaml + `static properties`; not a `data-*` hook).
22
+ - **`<page-ui>` region model** — `--page-inset` vertical rhythm between `header`/`section`/`footer` children + `[bleed]` (edge-to-edge, cancels the page `[padding]`) + `section[padding]` (padded sub-surface), mirroring card-ui's section model. The docs promised `@scope` styled the regions but no such rules existed — regions stacked with zero spacing.
23
+ - **`<timeline-ui>` `--timeline-marker-box-size`** — unified marker footprint (1rem; 0.875rem at `size=sm`) the dot/icon/spinner center within; icon-mode chips gain a ring (`--timeline-icon-border`) so they read as markers even when the muted fill blends with the surface.
24
+ - **`<integration-card-ui>` provider→icon fallback** — a card with only `[provider]` (no `[logo]`) now renders a per-provider Phosphor glyph (slack→chat-circle, github→git-branch, …) or a generic `plug`, instead of a blank logo disc.
25
+ - **`<kbd-ui>` `size="lg"`** — added the missing `lg` to the size enum (CSS + docs already shipped three sizes; the yaml capped at sm/md).
26
+
27
+ ### Fixed — docs-QA pass (browser-verified)
28
+
29
+ - **`<datetime-picker-ui>`** — committed value now uses the picker-family value color (`--a-ui-text`, bright) + `space-between` alignment (value left, caret right), matching input-ui/select-ui/time-picker (was a centered, dim default button); `[data-has-value]` gates the brightening.
30
+ - **`<kbd-ui>`** — `md` glyph was `--a-ui-tiny` (10px), identical to `sm`; now `--a-ui-xs` (12px) for a real 10/12/14 sm/md/lg ramp.
31
+ - **`<empty-state-ui>`** — heading moved from `--a-ui-lg` (15px control-label ramp; only 1.07× the description) to `--a-heading-md` (17px → 1.21×); the `[minimal]` inline variant keeps the heading bolder + non-muted so it stays distinct from the description.
32
+ - **`<heatmap-ui>`** — `type="day-grid"` keeps fixed cell tracks + scrolls horizontally (GitHub-contributions model) instead of crushing fixed cells into an overlapping smear in narrow containers; `matrix`/`density` keep fitting-and-shrinking.
33
+ - **`<option-card-ui>` `layout="tile"`** — DOM-order-independent (via `order`) with the radio pinned to the card's top-right (cleared the base `grid-area:indicator` that stranded it in a collapsed 8px gutter); token-driven padding. Fixes plan-picker's tile cards.
34
+ - **`<preview-ui>` form-demo width** — the docs render cell capped `<field-ui>` at `max-width:28rem` (448px) together with bare form controls; since field-ui is a full-width form _row_ (its own CSS is `width:100%`), the cap stranded it mid-cell, reading as "not using the available space" on wide single-block demos. Split the rule: field-ui now fills the stage (no cap); bare atomic controls (input/select/combobox/textarea/tags-input/color-input) keep the 28rem measure cap so a lone control doesn't sprawl. (bug-55 follow-up)
35
+
36
+ ### Changed — demos + corpus hygiene (docs-QA pass)
37
+
38
+ - **`<field-ui>` demos** — migrated in-chrome affordances (copy / clear / ⌘K) onto `input-ui`'s `leading`/`trailing` slots (inside the input box); field's `trailing`/`action` reserved for beside-field captions + submit buttons. Slots table + A2UI guidance now state the boundary. Short in-chrome _status_ text (e.g. "Required") now uses `input-ui`'s `suffix`/`prefix` attribute rather than a `<span slot="trailing">` _outside_ the input — keeps the status inside the field chrome and lets the input fill the full field width (demo `field-default-trailing-caption` → `field-default-inchrome-required`). (bug-55)
39
+ - **`<inline-edit-ui>` form-participation demo** — key-labelled rows (title/description) + instructional placeholder so the form-field semantics are legible.
40
+ - **`<integration-card-ui>` CRUD-drawer demo** — fixed an invisible drawer: the demo used `side="trailing"`, which is not in the `drawer-ui` `side` enum (`left|right|top|bottom`), so the panel `showModal()`'d but rendered at `opacity:0` collapsed in the top-left. Switched to `side="right"`. (bug-50)
41
+ - **Dead `size="sm"` swept** off layout primitives (`row-ui`/`col-ui`/`grid-ui`) + bare `<span slot="action">` across `patterns/` demos (68 sites repo-wide) — the attribute is a no-op on those tags and polluted the gen-UI corpus.
42
+ - **`dist/` CDN bundles regenerated** (`web-components.min.css` + `web-components.min.js`) for the docs-QA CSS/JS changes + the breaking removals.
43
+
44
+ ### Removed (BREAKING) — `<avatar-ui name="…">` deprecated alias retired
45
+
46
+ - **`<avatar-ui>` no longer accepts the `name` attribute** — use `text` instead.
47
+ `name` was a deprecated alias for `text` since 0.4.x (`deprecated_since: "0.4.x"`,
48
+ scheduled for v0.6.0; the codebase reached v0.6.50 still carrying it). Retired in
49
+ full: removed from `avatar.yaml`, the `static properties` map + `displayName`
50
+ fallback + the one-shot deprecation `console.warn` + the `#nameWarned` flag in
51
+ `avatar.class.js`, the `name: string` typing in `avatar.d.ts`, and the
52
+ regenerated `avatar.a2ui.json` sidecar. The `<img>` `alt` now derives from
53
+ `displayName` (= `text`). **Migration:** `<avatar-ui name="Ada">` →
54
+ `<avatar-ui text="Ada">`. No in-repo markup, demo, or corpus chunk used the
55
+ alias (the corpus was swept long ago; the one stray demo was fixed in
56
+ `d3b482c61`). _Pre-1.0 breaking change — bump MINOR on the next cut._
57
+
58
+ ### Removed (BREAKING) — `<chart-ui>` `aspect` + `heading` retired (OD-CHART-02)
59
+
60
+ - **`<chart-ui>` no longer accepts `aspect` or `heading`** — both were
61
+ deprecated-but-functional with no removal date; retired across yaml + class.js +
62
+ d.ts + css + sidecar.
63
+ - **`aspect`** (`std`/`wide`/`square`/`tall` — derived the chart's implicit
64
+ height from width): charts without an explicit height now always use the
65
+ standard 4:3 ratio (the prior default, so default charts are unchanged; only
66
+ explicit `aspect="wide|square|tall"` changes). **Migration:** size the chart
67
+ via its parent (width/height on the enclosing card/container).
68
+ - **`heading`** (rendered a title element + fed `aria-label`): **Migration:** put
69
+ the visual title in an enclosing `card-ui` `<header><span slot="heading">`; for
70
+ a descriptive accessible name set `aria-label` directly. With neither,
71
+ `aria-label` now falls back to `"<type> chart"` (e.g. "bar chart"). Verified:
72
+ 69 demo charts render, 0 console errors. _Pre-1.0 breaking — bump MINOR._
73
+
74
+ ### Removed — `<avatar-ui size>` long-form aliases (were non-functional)
75
+
76
+ - **`<avatar-ui size>` drops `small`/`medium`/`large`/`xlarge`** — use the
77
+ canonical `xs`/`sm`/`md`/`lg`/`xl`. These were declared in `avatar.yaml` +
78
+ `avatar.d.ts` "for back-compat" but had **no CSS implementation** (`avatar.css`
79
+ only defines `:scope[size="xs|sm|md|lg|xl"]`), so `size="small"` silently
80
+ rendered at the base default size — they never worked. Runtime behavior is
81
+ unchanged; this removes the misleading values from the typed API + the sidecar
82
+ the LLM prompt builder reads (training-data noise). No in-repo markup used them.
83
+
84
+ ### Changed — global styles assigned to `@layer` cascade layers (ADR-0038)
85
+
86
+ - `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).
87
+ - **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 + `docs/specs/cascade-layer-architecture.md`.
88
+
89
+ ### Added — `<select-ui>` per-option `icon` / `avatar`, reflected in the trigger
90
+
91
+ - **`components/select/{select.class.js,select.css,select.yaml}`** — `<option>` now accepts `icon` (Phosphor name) and `avatar` (image URL): `<option value="light" icon="sun">`. Each option renders its glyph in the listbox row **and** the trigger reflects the **selected** option's icon/avatar (theme pickers, assignee/account switchers). Previously a host-level `[icon]` was static — selecting "Light" still showed the fixed `moon`. `#parseOptions` now captures `icon`/`avatar` from declarative `<option>`/`<optgroup>` children (and the `.options` array shape gains `icon?`/`avatar?`); a new `#syncLeading()` reconciles the trigger's `[slot="leading"]` to the selected option on every render (avatar beats icon; host `[icon]`/`[avatar]` is the fallback). Only manages the component-stamped trigger (`[data-select-leading]`) — a consumer-custom trigger owns its own leading. Multi-select is unaffected (chips). +CSS for `[role="option"] img[data-option-avatar]`; sidecar regenerated. Verified in-browser: trigger shows `sun` for selected "Light", updates to `moon` on selecting "Dark"; per-option avatars render in trigger + rows; 21/21 unit tests green.
92
+
93
+ ### Changed — block-level display by default + universal `[inline]` attribute (ADR-0037)
94
+
95
+ - 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 + `docs/specs/attribute-api-system.md` §5.
96
+
97
+ ### Changed — `chevron` → `caret` terminology sweep (FEEDBACK-90, ADR-0036 follow-up)
98
+
99
+ - Renamed residual `chevron` terminology to `caret` across 14 component files so the codebase carries one vocabulary (matching the `slot="caret"` convention + the Phosphor `caret-*` icon names). **`agent-artifact`** is the only behavioral surface: `[data-artifact-chevron]` → `[data-artifact-caret]` + `#chevronEl` → `#caretEl` (internal-render collapse indicator — a data-attr styling hook, not a slot, same as `agent-trace`/`agent-reasoning`). The rest is comment/description terminology (`timeline`; `table`/`select` yaml + regenerated a2ui descriptions; `input`/`pagination`/`action-list`/`calendar-grid`/`calendar-picker` comments). **Carve-out:** kept breadcrumb's `data-chunk="…-chevron-sep"` corpus identifier — the separator is semantically a chevron, not a disclosure caret, and renaming a harvested chunk name is a separate re-harvest. No consumer-facing behavior change.
100
+
101
+ ### Fixed — form-field demos collapsed to content-width in `<preview-ui>` (demos)
102
+
103
+ - **`components/preview/preview.css`** — a `<field-ui>` (and bare text-field controls) is a flex item in the render cell, so form-field demos sized to their content — a placeholder-only `combobox-ui` shrank to a ~52px "Sel…" stub (input/select were also content-width, just less obvious). The render cell now stretches `field-ui` + text-field controls (`input-ui`/`select-ui`/`combobox-ui`/`textarea-ui`/`tags-input-ui`/`color-input-ui`) to the cell width, capped at `28rem` so single-block stages don't sprawl. Lifts **every** form-field demo to a realistic width at once (combobox 52→202px rows / 448px single-block); non-form demos (buttons, badges, …) keep content-width. Verified 0 console errors across 12 component + pattern pages.
104
+
105
+ ### Fixed — `<combobox-ui>` `[size]` didn't step the field height
106
+
107
+ - **`components/combobox/combobox.css`** — the editable `[data-input]` span picked up `8px` block padding from an outer source that out-cascaded the `@scope` rule, pinning the field to ~36px at **every** `[size]` (sm/md/lg measured 36.2 / 37.6 / 39px — barely distinguishable). A higher-specificity guard (`combobox-ui [data-field] [data-input] { padding-block: 0 }`) zeroes it so the field height tracks `--a-size` like `input-ui`/`select-ui` — now **24 / 30 / 36px** for sm/md/lg. (The 8px source isn't in combobox/global/inline CSS — likely a leaked reset or a `contenteditable="plaintext-only"` behavior; flagged for a follow-up audit.)
108
+
109
+ ### Added — `<combobox-ui>` demo depth (demos)
110
+
111
+ - **`components/combobox/combobox.examples.html`** — +5 attribute sections closing the depth gap surfaced by the demo-coverage audit (was ~7/17 demonstrable attributes): `prefix`/`suffix` slot (search-icon prefix), `highlight-match`, `loading`, `disabled`, `readonly`. All render correctly now that the width fix above is in place (the prefix demo had appeared collapsed only because of the content-width bug).
112
+
113
+ ### Fixed — `<alert-ui>` `slot="action"` rendered wedged between icon and message
114
+
115
+ - **`components/alert/alert.css`** — a trailing `[slot="action"]` button rendered on the **left** (between the leading icon and the message) instead of trailing right, contradicting the documented "right-aligned trailing affordance." Cause: `alert.js` appends the auto-stamped `[slot="content"]`/`[slot="leading"]` *after* any author-provided action button, and the standard render path (unlike the dunning path) gave the action/close slots no `order`, so they sorted in DOM order. Added explicit `order: 1` (action) + `order: 2` (close) so the layout is always `icon → content → action → close`, with content's `flex: 1` pushing both affordances to the trailing edge. Latent since the feature shipped — first exercised by the new demo (no prior `alert-ui` consumer used `slot="action"`). Verified via DOM geometry probe (`iconX < contentX < actionX ≤ closeX`).
116
+
117
+ ### Fixed — `<alert-ui>` dunning `due-at` showed the previous calendar day
118
+
119
+ - **`components/alert/alert.class.js`** — `#formatDueDate()` parsed a date-only ISO string (`"2026-05-20"`) as UTC midnight, which a behind-UTC locale then formatted as the *previous* day ("May 19"). Date-only strings are now pinned to local midnight (`"…T00:00:00"`) so the authored calendar day is preserved; full timestamps (with time/offset) keep their exact instant. Invisible in jsdom (UTC) — only manifested in a real browser, so the lenient existing tests (`/May/`, `/2026/`) stayed green (30/30); also corrects the shared `billing-overview` dunning banner.
120
+
121
+ ### Added — `<alert-ui>` demo depth (demos)
122
+
123
+ - **`components/alert/alert.examples.html`** — +3 sections taking attribute coverage 33% → **100%** (demo-coverage audit): `title`+`description` (two-line headline/body), `action slot` (trailing button), and the full `dunning` payment-failed pattern (SPEC-006 — `pattern`/`amount`/`currency`/`due-at`/`card-last4`/`reason` across all four reasons + a warning grace-period), plus the `dismissible` alias. Props/Events/Slots tables extended to document the dunning API (`actions` slot, `dunning-action` event). Grounded against SPEC-006 + the real `billing-overview` consumer; surfaced the two `alert-ui` fixes above.
124
+
125
+ ### Fixed — `<switch-ui>` `[hint]` rendered beside the label instead of below
126
+
127
+ - **`components/switch/switch.css`** — the `[hint]` caption is documented (yaml + props table + the rule's own comment "Caption beneath the toggle row") as rendering BELOW the label, but the base `inline-flex` row laid the stamped `[slot="hint"]` out as a third inline item beside the label. A `:has([slot="hint"])`-scoped `flex-wrap` + `flex-basis: 100%` now wraps the hint onto its own full-width line, indented under the label. No display-model change (stays `inline-flex`); hint-less switches are 100% unchanged (the hint span is stamped only when `[hint]` is set). Latent since §184 — surfaced by the demo-depth pass.
128
+
129
+ ### Fixed — `<list-ui>` `[selectable]` selection chrome was never applied (upgrade race)
130
+
131
+ - **`components/list/list.class.js`** — `selectable` + `selected-key` set no visual selection (`aria-selected` null on every row). Light-DOM upgrade race: `render()`'s `#items()` filtered children by `role="listitem"`, but each `<list-item-ui>` sets that role in its OWN `connected()`, which hasn't run when the parent first `render()`s → `#items()` returned `[]` → `aria-selected` never stamped → the `[aria-selected="true"]` selection CSS never matched. `#items()` now also matches by tag name (`LIST-ITEM-UI`, present pre-upgrade); the attribute persists through the child's later upgrade. Latent since the selection feature shipped (no demo exercised it); +0 test changes, 5/5 green.
132
+
133
+ ### Added — primitive demo-depth wave, Phase 3 (demos)
134
+
135
+ - Drove six audit-`critical` primitives to full attribute coverage (demo-coverage audit), each authored from source/spec grounding and browser-probed (0 console errors, visual QA): **`swatch`** 27% → 100% (detail/copyable/copy-value, badge gamut pips, selectable/selected, label-position overlay + auto-contrast); **`color-picker`** 44% → 100% (OKLCH generation constraints — max-chroma / min-l·max-l / base-hue·hue-drift-max — plus corrected the `format` demo to the real `[hex, oklch]` enum and dropped a non-existent `required` prop from its table); **`switch`** 43% → 100% (hint, name/value/required); **`list`** 40% → 100% (contained, selectable/selected-key, + real `selection-change` event docs); **`context-menu`** 33% → 100% (open, long-press-ms); **`toggle-scheme`** 33% → 92% (scoped `target` + icon/label-light/dark + color + storage-prefix; the read-only reflected `active-scheme` is intentionally not authored, + corrected two table defaults vs yaml). Demo-only `examples.html` changes except the two `switch`/`list` fixes above.
136
+
3
137
  ## [0.6.50] — 2026-05-30
4
138
 
5
139
  ### Changed — `slot="caret"` disclosure-indicator convention + FEEDBACK-89 (ADR-0036)
@@ -98,7 +98,7 @@ action-item-ui:hover [slot="icon"] {
98
98
  text-overflow: ellipsis;
99
99
  }
100
100
 
101
- /* Default slot (trailing content: kbd, badge, chevron) pushed to far right */
101
+ /* Default slot (trailing content: kbd, badge, caret) pushed to far right */
102
102
  & > :not([slot="icon"]):not([slot="text"]) {
103
103
  flex-shrink: 0;
104
104
  margin-inline-start: auto;
@@ -58,7 +58,7 @@ export class UIAgentArtifact extends UIElement {
58
58
  tone: { type: String, default: 'neutral', reflect: true },
59
59
  };
60
60
 
61
- // §205 (v0.5.7): dynamic chevron icons stamped on collapse/expand state
61
+ // §205 (v0.5.7): dynamic caret icons stamped on collapse/expand state
62
62
  // transition (agent-artifact.class.js:119+188). Per FEEDBACK-16 §1 + §209 slot-11 ternary-
63
63
  // walker discovery. Note: `this.icon` consumer-supplied — not declared here.
64
64
  static requiredIcons = ['caret-right', 'caret-down'];
@@ -69,7 +69,7 @@ export class UIAgentArtifact extends UIElement {
69
69
  #iconEl = null;
70
70
  #titleEl = null;
71
71
  #kindEl = null;
72
- #chevronEl = null;
72
+ #caretEl = null;
73
73
  #bodyEl = null;
74
74
 
75
75
  connected() {
@@ -80,7 +80,7 @@ export class UIAgentArtifact extends UIElement {
80
80
  this.#headerEl?.removeEventListener('click', this.#onHeaderClick);
81
81
  this.#headerEl?.removeEventListener('keydown', this.#onHeaderKey);
82
82
  this.#headerEl = this.#iconEl = this.#titleEl = null;
83
- this.#kindEl = this.#chevronEl = this.#bodyEl = null;
83
+ this.#kindEl = this.#caretEl = this.#bodyEl = null;
84
84
  }
85
85
 
86
86
  #onHeaderClick = (e) => {
@@ -120,8 +120,8 @@ export class UIAgentArtifact extends UIElement {
120
120
  this.#kindEl.setAttribute('variant', TONE_TO_BADGE_VARIANT[this.tone] || 'default');
121
121
  this.#kindEl.hidden = !this.kind;
122
122
  }
123
- if (this.#chevronEl) {
124
- this.#chevronEl.setAttribute('name', this.collapsed ? 'caret-right' : 'caret-down');
123
+ if (this.#caretEl) {
124
+ this.#caretEl.setAttribute('name', this.collapsed ? 'caret-right' : 'caret-down');
125
125
  }
126
126
  if (this.#bodyEl) {
127
127
  this.#bodyEl.hidden = this.collapsed;
@@ -187,12 +187,12 @@ export class UIAgentArtifact extends UIElement {
187
187
  for (const btn of secondaryBtns) actions.appendChild(btn);
188
188
  for (const btn of primaryBtns) actions.appendChild(btn);
189
189
 
190
- this.#chevronEl = document.createElement('icon-ui');
191
- this.#chevronEl.setAttribute('color', 'muted');
192
- this.#chevronEl.setAttribute('data-artifact-chevron', '');
193
- this.#chevronEl.setAttribute('name', this.collapsed ? 'caret-right' : 'caret-down');
190
+ this.#caretEl = document.createElement('icon-ui');
191
+ this.#caretEl.setAttribute('color', 'muted');
192
+ this.#caretEl.setAttribute('data-artifact-caret', '');
193
+ this.#caretEl.setAttribute('name', this.collapsed ? 'caret-right' : 'caret-down');
194
194
 
195
- this.#headerEl.append(this.#iconEl, this.#titleEl, this.#kindEl, actions, this.#chevronEl);
195
+ this.#headerEl.append(this.#iconEl, this.#titleEl, this.#kindEl, actions, this.#caretEl);
196
196
 
197
197
  // Body
198
198
  this.#bodyEl = document.createElement('div');
@@ -89,7 +89,7 @@
89
89
  flex-shrink: 0;
90
90
  }
91
91
 
92
- [data-artifact-chevron] {
92
+ [data-artifact-caret] {
93
93
  flex-shrink: 0;
94
94
  transition: transform var(--agent-artifact-duration, var(--agent-artifact-duration-default));
95
95
  }
@@ -105,6 +105,8 @@ export class UIAgentReasoning extends UIElement {
105
105
  #summaryEl = null;
106
106
  #bodyEl = null;
107
107
  #bound = false;
108
+ #resizeObserver = null;
109
+ #spineRaf = 0;
108
110
 
109
111
  get entries() { return this.#entries; }
110
112
 
@@ -114,6 +116,19 @@ export class UIAgentReasoning extends UIElement {
114
116
  this.#startTime = Date.now();
115
117
  this.#timerInterval = setInterval(() => this.#tickTimers(), 1000);
116
118
  this.#buildShell();
119
+ // Re-measure the connector spine when row heights shift (text reflow on
120
+ // resize moves the dot Ys). The spine writes only absolutely-positioned
121
+ // ::before vars, so observing the host can't feed back into a resize loop.
122
+ if (typeof ResizeObserver !== 'undefined') {
123
+ this.#resizeObserver = new ResizeObserver(() => {
124
+ if (this.#spineRaf) return;
125
+ this.#spineRaf = requestAnimationFrame(() => {
126
+ this.#spineRaf = 0;
127
+ this.#layoutSpine();
128
+ });
129
+ });
130
+ this.#resizeObserver.observe(this);
131
+ }
117
132
  }
118
133
 
119
134
  // Single delegated handler for every nested timeline-item's toggle event.
@@ -136,6 +151,12 @@ export class UIAgentReasoning extends UIElement {
136
151
  clearTimeout(this.#finishTimer);
137
152
  this.#finishTimer = null;
138
153
  }
154
+ if (this.#spineRaf) {
155
+ cancelAnimationFrame(this.#spineRaf);
156
+ this.#spineRaf = 0;
157
+ }
158
+ this.#resizeObserver?.disconnect();
159
+ this.#resizeObserver = null;
139
160
  this.#summaryEl?.removeEventListener('click', this.#onSummaryClick);
140
161
  this.#summaryEl?.removeEventListener('keydown', this.#onSummaryKey);
141
162
  this.#bodyEl?.removeEventListener('timeline-toggle', this.#onStepToggle);
@@ -404,6 +425,36 @@ export class UIAgentReasoning extends UIElement {
404
425
  this.#bodyEl.appendChild(this.#renderNonStep(entry));
405
426
  }
406
427
  }
428
+
429
+ this.#layoutSpine();
430
+ }
431
+
432
+ // Draw one continuous connector line down the marker column from the first
433
+ // step dot to the last — bridging plan / thought / iteration interstitials
434
+ // that otherwise fragment the per-block timeline connectors into stubs. The
435
+ // endpoints are measured (not pure CSS) because interstitial row heights are
436
+ // dynamic; the per-item connectors are suppressed in CSS (the spine owns the
437
+ // line). No spine for 0–1 dots (nothing to connect → no trailing line).
438
+ #layoutSpine() {
439
+ const body = this.#bodyEl;
440
+ if (!body) return;
441
+ if (this.collapsed) { body.removeAttribute('data-spine'); return; }
442
+ const items = body.querySelectorAll('timeline-item-ui');
443
+ if (items.length < 2) { body.removeAttribute('data-spine'); return; }
444
+
445
+ const bodyTop = body.getBoundingClientRect().top;
446
+ // Dot center within an item = top:(1.4em − dot)/2 + 1px + dot/2 = 0.7em + 1px
447
+ // (the dot size cancels), where em is the item's computed font-size.
448
+ const dotY = (el) => {
449
+ const r = el.getBoundingClientRect();
450
+ const fs = parseFloat(getComputedStyle(el).fontSize) || 14;
451
+ return (r.top - bodyTop) + 0.7 * fs + 1;
452
+ };
453
+ const top = dotY(items[0]);
454
+ const height = Math.max(0, dotY(items[items.length - 1]) - top);
455
+ body.style.setProperty('--reasoning-spine-top', `${Math.round(top)}px`);
456
+ body.style.setProperty('--reasoning-spine-h', `${Math.round(height)}px`);
457
+ body.setAttribute('data-spine', '');
407
458
  }
408
459
 
409
460
  #makeTimeline() {
@@ -122,35 +122,56 @@
122
122
  grid-template-columns: subgrid;
123
123
  grid-column: 1 / -1;
124
124
  row-gap: var(--agent-reasoning-gap-row, var(--agent-reasoning-gap-row-default));
125
+ position: relative;
125
126
  }
126
127
 
127
128
  [data-reasoning-body][hidden] { display: none; }
128
129
 
130
+ /* ═══════ Connector spine ═══════
131
+ A single continuous line down the marker column from the first step dot to
132
+ the last, bridging plan / thought / iteration interstitials so the run
133
+ reads as one timeline rather than fragmented per-block stubs. Endpoints are
134
+ JS-measured into --reasoning-spine-top / -h (#layoutSpine) — interstitial
135
+ heights are dynamic, so pure CSS can't place them. The x matches the step
136
+ dot center (timeline-item uses var(--timeline-marker-w, 1.25rem) for its
137
+ dot math). Sits behind the dots (z-index 0 < the dots' z-index 1). The
138
+ per-item timeline connectors are suppressed below so they don't double-draw. */
139
+ [data-reasoning-body][data-spine]::before {
140
+ content: '';
141
+ position: absolute;
142
+ left: calc(var(--timeline-marker-w, 1.25rem) / 2 - var(--agent-reasoning-line-w, 1.5px) / 2);
143
+ top: var(--reasoning-spine-top, 0);
144
+ height: var(--reasoning-spine-h, 0);
145
+ width: var(--agent-reasoning-line-w, 1.5px);
146
+ background: var(--agent-reasoning-border, var(--agent-reasoning-border-default));
147
+ z-index: 0;
148
+ }
149
+
129
150
  /* All direct children of body span the grid */
130
151
  [data-reasoning-body] > * {
131
152
  grid-column: 1 / -1;
132
153
  }
133
154
 
155
+ /* Step rows + their readouts use the mono family — a technical step trace
156
+ (generate:/validate:/…) reads better fixed-width, matching the reference.
157
+ The iteration header ([data-reasoning-iter-n]) keeps the UI sans font. */
158
+ [data-reasoning-body] timeline-item-ui {
159
+ font-family: var(--a-font-family-code);
160
+ }
161
+
134
162
  /* ═══════ Thought — horizontal dash in marker column, text in content ═══════ */
135
163
 
164
+ /* Thoughts are free-form annotations beside the spine — text in the content
165
+ column, no marker dot/dash (the continuous spine passes behind them). */
136
166
  [data-reasoning-thought] {
137
167
  display: grid;
138
168
  grid-template-columns: subgrid;
139
169
  align-items: center;
140
170
  line-height: 1.5;
141
- color: var(--agent-reasoning-fg, var(--agent-reasoning-fg-default));
171
+ color: var(--agent-reasoning-fg-muted, var(--agent-reasoning-fg-muted-default));
142
172
  animation: _ar-fade var(--agent-reasoning-duration, var(--agent-reasoning-duration-default)) var(--agent-reasoning-easing, var(--agent-reasoning-easing-default));
143
173
  }
144
174
 
145
- [data-reasoning-thought]::before {
146
- content: '';
147
- grid-column: marker;
148
- height: 1px;
149
- background: var(--agent-reasoning-border, var(--agent-reasoning-border-default));
150
- align-self: center;
151
- width: 100%;
152
- }
153
-
154
175
  [data-reasoning-thought] > [data-reasoning-thought-text] {
155
176
  grid-column: content / -1;
156
177
  min-width: 0;
@@ -159,15 +180,15 @@
159
180
 
160
181
  /* ═══════ Plan — card in content+aside, marker empty ═══════ */
161
182
 
183
+ /* Plan reads as a flat up-front checklist in the content column — no bordered
184
+ box (that competed with the now-flattened iteration sections, the original
185
+ bug-03 "inconsistent card hierarchy" complaint). The PLAN label + ordered
186
+ list carry the distinction; the spine passes down its left. */
162
187
  [data-reasoning-plan] {
163
188
  grid-column: content / -1;
164
189
  display: flex;
165
190
  flex-direction: column;
166
191
  gap: var(--a-space-1);
167
- padding: var(--a-space-2) var(--a-space-3);
168
- border: 1px solid var(--agent-reasoning-border, var(--agent-reasoning-border-default));
169
- border-radius: var(--agent-reasoning-radius, var(--agent-reasoning-radius-default));
170
- background: var(--agent-reasoning-iter-bg, var(--agent-reasoning-iter-bg-default));
171
192
  }
172
193
 
173
194
  [data-reasoning-plan-label] {
@@ -191,6 +212,10 @@
191
212
 
192
213
  /* ═══════ Iteration — card with its own grid ═══════ */
193
214
 
215
+ /* Iterations read as continuous timeline sections (a status-icon header row
216
+ + its nested steps tied by the timeline connector), NOT as bordered cards
217
+ that compete with the PLAN block. Flattened: no border / no fill / no box
218
+ padding — just the grid + row rhythm. (bug-03) */
194
219
  [data-reasoning-iteration] {
195
220
  display: grid;
196
221
  grid-template-columns:
@@ -199,14 +224,6 @@
199
224
  [aside] auto;
200
225
  column-gap: var(--agent-reasoning-gap-col, var(--agent-reasoning-gap-col-default));
201
226
  row-gap: var(--a-space-2);
202
- padding: var(--agent-reasoning-iter-padding, var(--agent-reasoning-iter-padding-default));
203
- border: 1px solid var(--agent-reasoning-iter-border, var(--agent-reasoning-iter-border-default));
204
- border-radius: var(--agent-reasoning-radius, var(--agent-reasoning-radius-default));
205
- background: var(--agent-reasoning-iter-bg, var(--agent-reasoning-iter-bg-default));
206
- }
207
-
208
- [data-reasoning-iteration][data-active] {
209
- background: var(--agent-reasoning-iter-bg-active, var(--agent-reasoning-iter-bg-active-default));
210
227
  }
211
228
 
212
229
  [data-reasoning-iter-header] {
@@ -282,3 +299,13 @@
282
299
  [data-reasoning-spinner] { animation: none; }
283
300
  }
284
301
  }
302
+
303
+ /* ═══════ Suppress timeline's own per-row connector inside agent-reasoning ═══════
304
+ The continuous body spine (see [data-reasoning-body][data-spine]::before)
305
+ owns the connector here; timeline-item's own ::after would double-draw and
306
+ fragment at every block boundary (each timeline-ui block stamps data-last on
307
+ its own last item, dropping that segment mid-run). This lives OUTSIDE @scope
308
+ and carries [data-step-id] (stamped on every step by #makeStepItem) to clear
309
+ timeline.css's :scope::after specificity ([0,1,1] → this is [0,1,3]). The
310
+ step dots (::before) are untouched. */
311
+ agent-reasoning-ui timeline-item-ui[data-step-id]::after { display: none; }
@@ -331,7 +331,14 @@ export class UIAlert extends UIElement {
331
331
 
332
332
  #formatDueDate() {
333
333
  if (!this.dueAt) return '';
334
- const d = new Date(this.dueAt);
334
+ // A date-only ISO string ("2026-05-20") parses as UTC midnight, which a
335
+ // behind-UTC locale then formats as the PREVIOUS calendar day. Consumers
336
+ // author these as plain calendar dates, so pin them to local midnight to
337
+ // preserve the authored day. Full timestamps (with time / offset) keep
338
+ // their exact instant.
339
+ const d = /^\d{4}-\d{2}-\d{2}$/.test(this.dueAt)
340
+ ? new Date(`${this.dueAt}T00:00:00`)
341
+ : new Date(this.dueAt);
335
342
  if (Number.isNaN(d.getTime())) return '';
336
343
  try {
337
344
  const lang = this.getAttribute('lang') || this.lang || undefined;
@@ -107,10 +107,18 @@
107
107
 
108
108
  /* Trailing action area — optional single button or small button group.
109
109
  flex-shrink:0 keeps it from collapsing; align-self:start anchors it
110
- to the first text line under the `align-items:start` root. */
110
+ to the first text line under the `align-items:start` root.
111
+ `order: 1` sorts it AFTER the content slot regardless of DOM order:
112
+ alert.js appends the auto-stamped [slot="content"] / [slot="leading"]
113
+ *after* any author-provided [slot="action"], so without an explicit
114
+ order the action button renders wedged between the icon and the
115
+ message instead of trailing. content's `flex: 1` then pushes the
116
+ action (+ close) to the right edge. Mirrors the dunning path, which
117
+ already assigns explicit per-slot order integers. */
111
118
  :scope [slot="action"] {
112
119
  flex-shrink: 0;
113
120
  align-self: start;
121
+ order: 1;
114
122
  }
115
123
 
116
124
  /* Close button is a `<button-ui icon="x" variant="ghost" size="sm">`
@@ -123,6 +131,10 @@
123
131
  rather than disconnected grey. */
124
132
  :scope [slot="close"] {
125
133
  flex-shrink: 0;
134
+ /* Sort last (after content order:0 and action order:1) so the dismiss
135
+ button is the right-most affordance. content's flex:1 pushes both
136
+ action + close to the trailing edge. */
137
+ order: 2;
126
138
  min-height: calc(var(--alert-font, var(--alert-font-default)) * var(--alert-line-height, var(--alert-line-height-default)));
127
139
  --button-fg-ghost: var(--alert-fg, var(--alert-fg-default));
128
140
  --button-fg-ghost-hover: var(--alert-icon-fg, var(--alert-icon-fg-default));
@@ -21,14 +21,6 @@
21
21
  "type": "string",
22
22
  "default": ""
23
23
  },
24
- "name": {
25
- "description": "Deprecated alias for `text` (logs a one-shot console warning; will be removed in a future release). New code should use `text=` instead.",
26
- "type": "string",
27
- "default": "",
28
- "deprecated": true,
29
- "deprecated_reason": "Use `text` instead. Will be removed in v0.6.0.",
30
- "deprecated_since": "0.4.x"
31
- },
32
24
  "shape": {
33
25
  "description": "Avatar shape",
34
26
  "type": "string",
@@ -39,18 +31,14 @@
39
31
  "default": "circle"
40
32
  },
41
33
  "size": {
42
- "description": "Avatar size. Canonical scale (xs/sm/md/lg/xl); long-form aliases (small/medium/large/xlarge) accepted for back-compat.",
34
+ "description": "Avatar size canonical scale.",
43
35
  "type": "string",
44
36
  "enum": [
45
37
  "xs",
46
38
  "sm",
47
39
  "md",
48
40
  "lg",
49
- "xl",
50
- "small",
51
- "medium",
52
- "large",
53
- "xlarge"
41
+ "xl"
54
42
  ],
55
43
  "default": "md"
56
44
  },
@@ -16,7 +16,6 @@
16
16
  *
17
17
  * Fallback chain: image → initials → empty.
18
18
  * If src fails to load, falls back to initials derived from text.
19
- * `name` is a deprecated alias for `text` (warns on use).
20
19
  *
21
20
  * <avatar-group-ui max="4" size="md">
22
21
  * <avatar-ui text="Alice"></avatar-ui>
@@ -35,33 +34,22 @@ export class UIAvatar extends UIElement {
35
34
  static properties = {
36
35
  src: { type: String, default: '', reflect: true },
37
36
  text: { type: String, default: '', reflect: true },
38
- name: { type: String, default: '', reflect: true }, // backcompat alias for text
39
37
  icon: { type: String, default: '', reflect: true },
40
38
  size: { type: String, default: 'md', reflect: true },
41
39
  shape: { type: String, default: 'circle', reflect: true },
42
40
  };
43
41
 
44
- /** Display string `text` takes priority, `name` is backcompat alias */
45
- get displayName() { return this.text || this.name; }
42
+ /** Display string (full name or initials derived from it). */
43
+ get displayName() { return this.text; }
46
44
 
47
45
  static template = () => null;
48
46
 
49
- static #nameWarned = false;
50
-
51
47
  #imgEl = null;
52
48
  #initialsEl = null;
53
49
  #iconEl = null;
54
50
 
55
51
  connected() {
56
52
  this.setAttribute('role', 'img');
57
- if (this.name && !this.text && !UIAvatar.#nameWarned) {
58
- UIAvatar.#nameWarned = true;
59
- // eslint-disable-next-line no-console
60
- console.warn(
61
- `[AdiaUI] <avatar-ui name="…"> is deprecated — use text="…" instead. ` +
62
- `Docs: https://ui-kit.exe.xyz/site/components/avatar`
63
- );
64
- }
65
53
  }
66
54
 
67
55
  render() {
@@ -78,7 +66,7 @@ export class UIAvatar extends UIElement {
78
66
  };
79
67
  }
80
68
  this.#imgEl.src = this.src;
81
- this.#imgEl.alt = this.name || '';
69
+ this.#imgEl.alt = this.displayName || '';
82
70
  if (!this.#imgEl.parentElement) this.appendChild(this.#imgEl);
83
71
 
84
72
  // Remove initials when image is showing
@@ -21,12 +21,10 @@ import { UIElement } from '../../core/element.js';
21
21
  export class UIAvatar extends UIElement {
22
22
  /** Phosphor icon name shown instead of initials when `src`/`text` are empty. */
23
23
  icon: string;
24
- /** Deprecated alias for `text` (logs a one-shot console warning; will be removed in a future release). New code should use `text=` instead. */
25
- name: string;
26
24
  /** Avatar shape */
27
25
  shape: 'circle' | 'square';
28
- /** Avatar size. Canonical scale (xs/sm/md/lg/xl); long-form aliases (small/medium/large/xlarge) accepted for back-compat. */
29
- size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'small' | 'medium' | 'large' | 'xlarge';
26
+ /** Avatar size canonical scale. */
27
+ size: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
30
28
  /** Image source URL. Falls back to initials on error. */
31
29
  src: string;
32
30
  /** Display string (full name or initials). Initials derive from spaces — first letter of each word, max 2. */
@@ -23,17 +23,6 @@ props:
23
23
  description: Display string (full name or initials). Initials derive from spaces — first letter of each word, max 2.
24
24
  type: string
25
25
  default: ""
26
- name:
27
- description: "Deprecated alias for `text` (logs a one-shot console warning; will be removed in a future release). New code should use `text=` instead."
28
- type: string
29
- # §179 (v0.5.5): principled deprecation metadata. The build pipeline
30
- # propagates this into the sidecar + catalog; the LLM prompt builder
31
- # surfaces "(deprecated, do not use)" based on this field rather than
32
- # substring-matching the description.
33
- deprecated: true
34
- deprecated_since: "0.4.x"
35
- deprecated_reason: "Use `text` instead. Will be removed in v0.6.0."
36
- default: ""
37
26
  icon:
38
27
  description: Phosphor icon name shown instead of initials when `src`/`text` are empty.
39
28
  type: string
@@ -46,9 +35,7 @@ props:
46
35
  - circle
47
36
  - square
48
37
  size:
49
- description: >-
50
- Avatar size. Canonical scale (xs/sm/md/lg/xl); long-form aliases
51
- (small/medium/large/xlarge) accepted for back-compat.
38
+ description: Avatar size — canonical scale.
52
39
  type: string
53
40
  default: md
54
41
  enum:
@@ -57,10 +44,6 @@ props:
57
44
  - md
58
45
  - lg
59
46
  - xl
60
- - small
61
- - medium
62
- - large
63
- - xlarge
64
47
  src:
65
48
  description: Image source URL. Falls back to initials on error.
66
49
  type: string