@aceshooting/lyra-ui 2.11.0 → 2.12.0

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 (252) hide show
  1. package/custom-elements.json +2167 -62
  2. package/dist/components/app-rail/app-rail.class.d.ts.map +1 -1
  3. package/dist/components/app-rail/app-rail.class.js +2 -1
  4. package/dist/components/app-rail/app-rail.class.js.map +1 -1
  5. package/dist/components/attachment-chip/attachment-chip.class.d.ts +16 -22
  6. package/dist/components/attachment-chip/attachment-chip.class.d.ts.map +1 -1
  7. package/dist/components/attachment-chip/attachment-chip.class.js +37 -42
  8. package/dist/components/attachment-chip/attachment-chip.class.js.map +1 -1
  9. package/dist/components/attachment-chip/attachment-chip.styles.d.ts.map +1 -1
  10. package/dist/components/attachment-chip/attachment-chip.styles.js +3 -2
  11. package/dist/components/attachment-chip/attachment-chip.styles.js.map +1 -1
  12. package/dist/components/avatar/avatar.class.d.ts +4 -3
  13. package/dist/components/avatar/avatar.class.d.ts.map +1 -1
  14. package/dist/components/avatar/avatar.class.js +12 -6
  15. package/dist/components/avatar/avatar.class.js.map +1 -1
  16. package/dist/components/button/button.class.d.ts +8 -1
  17. package/dist/components/button/button.class.d.ts.map +1 -1
  18. package/dist/components/button/button.class.js +14 -2
  19. package/dist/components/button/button.class.js.map +1 -1
  20. package/dist/components/button/button.styles.d.ts.map +1 -1
  21. package/dist/components/button/button.styles.js +34 -0
  22. package/dist/components/button/button.styles.js.map +1 -1
  23. package/dist/components/card/card.class.d.ts +3 -0
  24. package/dist/components/card/card.class.d.ts.map +1 -1
  25. package/dist/components/card/card.class.js +3 -0
  26. package/dist/components/card/card.class.js.map +1 -1
  27. package/dist/components/card/card.styles.d.ts.map +1 -1
  28. package/dist/components/card/card.styles.js +7 -0
  29. package/dist/components/card/card.styles.js.map +1 -1
  30. package/dist/components/chart/box-plot.class.d.ts +4 -1
  31. package/dist/components/chart/box-plot.class.d.ts.map +1 -1
  32. package/dist/components/chart/box-plot.class.js +28 -8
  33. package/dist/components/chart/box-plot.class.js.map +1 -1
  34. package/dist/components/chart/box-plot.styles.d.ts.map +1 -1
  35. package/dist/components/chart/box-plot.styles.js +2 -0
  36. package/dist/components/chart/box-plot.styles.js.map +1 -1
  37. package/dist/components/chart/chart.class.d.ts +3 -1
  38. package/dist/components/chart/chart.class.d.ts.map +1 -1
  39. package/dist/components/chart/chart.class.js +17 -6
  40. package/dist/components/chart/chart.class.js.map +1 -1
  41. package/dist/components/chart/chart.styles.d.ts.map +1 -1
  42. package/dist/components/chart/chart.styles.js +2 -0
  43. package/dist/components/chart/chart.styles.js.map +1 -1
  44. package/dist/components/chart/histogram.class.d.ts +2 -0
  45. package/dist/components/chart/histogram.class.d.ts.map +1 -1
  46. package/dist/components/chart/histogram.class.js +6 -0
  47. package/dist/components/chart/histogram.class.js.map +1 -1
  48. package/dist/components/chart/lite-chart.class.d.ts +5 -5
  49. package/dist/components/chart/lite-chart.class.d.ts.map +1 -1
  50. package/dist/components/chart/lite-chart.class.js +35 -9
  51. package/dist/components/chart/lite-chart.class.js.map +1 -1
  52. package/dist/components/chart/lite-chart.styles.d.ts.map +1 -1
  53. package/dist/components/chart/lite-chart.styles.js +5 -0
  54. package/dist/components/chart/lite-chart.styles.js.map +1 -1
  55. package/dist/components/chat-composer/chat-composer.class.d.ts +28 -3
  56. package/dist/components/chat-composer/chat-composer.class.d.ts.map +1 -1
  57. package/dist/components/chat-composer/chat-composer.class.js +82 -4
  58. package/dist/components/chat-composer/chat-composer.class.js.map +1 -1
  59. package/dist/components/chat-message/chat-message.class.d.ts +3 -0
  60. package/dist/components/chat-message/chat-message.class.d.ts.map +1 -1
  61. package/dist/components/chat-message/chat-message.class.js +8 -6
  62. package/dist/components/chat-message/chat-message.class.js.map +1 -1
  63. package/dist/components/chat-message/chat-message.styles.d.ts.map +1 -1
  64. package/dist/components/chat-message/chat-message.styles.js +2 -1
  65. package/dist/components/chat-message/chat-message.styles.js.map +1 -1
  66. package/dist/components/checkbox/checkbox.class.d.ts +15 -2
  67. package/dist/components/checkbox/checkbox.class.d.ts.map +1 -1
  68. package/dist/components/checkbox/checkbox.class.js +28 -8
  69. package/dist/components/checkbox/checkbox.class.js.map +1 -1
  70. package/dist/components/chip/chip-group.class.d.ts +3 -3
  71. package/dist/components/chip/chip-group.class.d.ts.map +1 -1
  72. package/dist/components/chip/chip-group.class.js +3 -1
  73. package/dist/components/chip/chip-group.class.js.map +1 -1
  74. package/dist/components/citation-badge/citation-badge.class.d.ts +4 -1
  75. package/dist/components/citation-badge/citation-badge.class.d.ts.map +1 -1
  76. package/dist/components/citation-badge/citation-badge.class.js +8 -3
  77. package/dist/components/citation-badge/citation-badge.class.js.map +1 -1
  78. package/dist/components/code-block/code-block-core.class.d.ts +7 -1
  79. package/dist/components/code-block/code-block-core.class.d.ts.map +1 -1
  80. package/dist/components/code-block/code-block-core.class.js +11 -2
  81. package/dist/components/code-block/code-block-core.class.js.map +1 -1
  82. package/dist/components/code-block/code-block.class.d.ts +9 -0
  83. package/dist/components/code-block/code-block.class.d.ts.map +1 -1
  84. package/dist/components/code-block/code-block.class.js +13 -1
  85. package/dist/components/code-block/code-block.class.js.map +1 -1
  86. package/dist/components/combobox/combobox.class.d.ts +36 -0
  87. package/dist/components/combobox/combobox.class.d.ts.map +1 -1
  88. package/dist/components/combobox/combobox.class.js +111 -4
  89. package/dist/components/combobox/combobox.class.js.map +1 -1
  90. package/dist/components/combobox/option.class.d.ts.map +1 -1
  91. package/dist/components/combobox/option.class.js +3 -9
  92. package/dist/components/combobox/option.class.js.map +1 -1
  93. package/dist/components/combobox/option.styles.d.ts +2 -0
  94. package/dist/components/combobox/option.styles.d.ts.map +1 -0
  95. package/dist/components/combobox/option.styles.js +7 -0
  96. package/dist/components/combobox/option.styles.js.map +1 -0
  97. package/dist/components/context-meter/context-meter.class.d.ts +2 -0
  98. package/dist/components/context-meter/context-meter.class.d.ts.map +1 -1
  99. package/dist/components/context-meter/context-meter.class.js +18 -7
  100. package/dist/components/context-meter/context-meter.class.js.map +1 -1
  101. package/dist/components/context-meter/context-meter.styles.d.ts.map +1 -1
  102. package/dist/components/context-meter/context-meter.styles.js +3 -0
  103. package/dist/components/context-meter/context-meter.styles.js.map +1 -1
  104. package/dist/components/conversation-item/conversation-item.class.d.ts +5 -4
  105. package/dist/components/conversation-item/conversation-item.class.d.ts.map +1 -1
  106. package/dist/components/conversation-item/conversation-item.class.js +2 -0
  107. package/dist/components/conversation-item/conversation-item.class.js.map +1 -1
  108. package/dist/components/copy-button/copy-button.class.d.ts +10 -0
  109. package/dist/components/copy-button/copy-button.class.d.ts.map +1 -1
  110. package/dist/components/copy-button/copy-button.class.js +35 -4
  111. package/dist/components/copy-button/copy-button.class.js.map +1 -1
  112. package/dist/components/copy-button/copy-button.styles.d.ts.map +1 -1
  113. package/dist/components/copy-button/copy-button.styles.js +5 -1
  114. package/dist/components/copy-button/copy-button.styles.js.map +1 -1
  115. package/dist/components/date-picker/date-input.styles.d.ts.map +1 -1
  116. package/dist/components/date-picker/date-input.styles.js +4 -0
  117. package/dist/components/date-picker/date-input.styles.js.map +1 -1
  118. package/dist/components/diff-view/diff-view.styles.d.ts.map +1 -1
  119. package/dist/components/diff-view/diff-view.styles.js +3 -0
  120. package/dist/components/diff-view/diff-view.styles.js.map +1 -1
  121. package/dist/components/document-preview/document-preview.class.d.ts +14 -2
  122. package/dist/components/document-preview/document-preview.class.d.ts.map +1 -1
  123. package/dist/components/document-preview/document-preview.class.js +45 -6
  124. package/dist/components/document-preview/document-preview.class.js.map +1 -1
  125. package/dist/components/document-preview/document-preview.styles.js +1 -1
  126. package/dist/components/export-button/export-button.class.d.ts +9 -2
  127. package/dist/components/export-button/export-button.class.d.ts.map +1 -1
  128. package/dist/components/export-button/export-button.class.js +21 -3
  129. package/dist/components/export-button/export-button.class.js.map +1 -1
  130. package/dist/components/export-button/export-button.styles.d.ts.map +1 -1
  131. package/dist/components/export-button/export-button.styles.js +21 -2
  132. package/dist/components/export-button/export-button.styles.js.map +1 -1
  133. package/dist/components/file-input/file-input.class.d.ts +9 -3
  134. package/dist/components/file-input/file-input.class.d.ts.map +1 -1
  135. package/dist/components/file-input/file-input.class.js +23 -8
  136. package/dist/components/file-input/file-input.class.js.map +1 -1
  137. package/dist/components/flag/flag.class.d.ts +7 -1
  138. package/dist/components/flag/flag.class.d.ts.map +1 -1
  139. package/dist/components/flag/flag.class.js +11 -3
  140. package/dist/components/flag/flag.class.js.map +1 -1
  141. package/dist/components/flag/flag.styles.js +2 -2
  142. package/dist/components/generation-status/generation-status.class.d.ts.map +1 -1
  143. package/dist/components/generation-status/generation-status.class.js +35 -27
  144. package/dist/components/generation-status/generation-status.class.js.map +1 -1
  145. package/dist/components/graph/graph.class.d.ts +1 -0
  146. package/dist/components/graph/graph.class.d.ts.map +1 -1
  147. package/dist/components/graph/graph.class.js +11 -3
  148. package/dist/components/graph/graph.class.js.map +1 -1
  149. package/dist/components/heatmap/calendar-grid.d.ts +7 -1
  150. package/dist/components/heatmap/calendar-grid.d.ts.map +1 -1
  151. package/dist/components/heatmap/calendar-grid.js +9 -2
  152. package/dist/components/heatmap/calendar-grid.js.map +1 -1
  153. package/dist/components/heatmap/heatmap.class.d.ts +9 -0
  154. package/dist/components/heatmap/heatmap.class.d.ts.map +1 -1
  155. package/dist/components/heatmap/heatmap.class.js +33 -12
  156. package/dist/components/heatmap/heatmap.class.js.map +1 -1
  157. package/dist/components/heatmap/heatmap.styles.d.ts.map +1 -1
  158. package/dist/components/heatmap/heatmap.styles.js +6 -0
  159. package/dist/components/heatmap/heatmap.styles.js.map +1 -1
  160. package/dist/components/input/input.styles.d.ts.map +1 -1
  161. package/dist/components/input/input.styles.js +3 -0
  162. package/dist/components/input/input.styles.js.map +1 -1
  163. package/dist/components/json-viewer/json-viewer.class.js +1 -1
  164. package/dist/components/json-viewer/json-viewer.class.js.map +1 -1
  165. package/dist/components/json-viewer/json-viewer.styles.d.ts.map +1 -1
  166. package/dist/components/json-viewer/json-viewer.styles.js +7 -0
  167. package/dist/components/json-viewer/json-viewer.styles.js.map +1 -1
  168. package/dist/components/map/map.class.d.ts +3 -5
  169. package/dist/components/map/map.class.d.ts.map +1 -1
  170. package/dist/components/map/map.class.js +8 -6
  171. package/dist/components/map/map.class.js.map +1 -1
  172. package/dist/components/markdown/markdown.class.d.ts +5 -5
  173. package/dist/components/markdown/markdown.class.d.ts.map +1 -1
  174. package/dist/components/markdown/markdown.class.js +6 -6
  175. package/dist/components/markdown/markdown.class.js.map +1 -1
  176. package/dist/components/markdown/markdown.styles.d.ts.map +1 -1
  177. package/dist/components/markdown/markdown.styles.js +11 -4
  178. package/dist/components/markdown/markdown.styles.js.map +1 -1
  179. package/dist/components/media-card/media-card.class.d.ts +12 -1
  180. package/dist/components/media-card/media-card.class.d.ts.map +1 -1
  181. package/dist/components/media-card/media-card.class.js +27 -7
  182. package/dist/components/media-card/media-card.class.js.map +1 -1
  183. package/dist/components/mention-popover/mention-popover.styles.d.ts.map +1 -1
  184. package/dist/components/mention-popover/mention-popover.styles.js +2 -0
  185. package/dist/components/mention-popover/mention-popover.styles.js.map +1 -1
  186. package/dist/components/pagination/pagination.class.d.ts +11 -0
  187. package/dist/components/pagination/pagination.class.d.ts.map +1 -1
  188. package/dist/components/pagination/pagination.class.js +28 -1
  189. package/dist/components/pagination/pagination.class.js.map +1 -1
  190. package/dist/components/phone-input/phone-input.class.d.ts +16 -2
  191. package/dist/components/phone-input/phone-input.class.d.ts.map +1 -1
  192. package/dist/components/phone-input/phone-input.class.js +43 -2
  193. package/dist/components/phone-input/phone-input.class.js.map +1 -1
  194. package/dist/components/playback/playback.class.d.ts +11 -0
  195. package/dist/components/playback/playback.class.d.ts.map +1 -1
  196. package/dist/components/playback/playback.class.js +26 -1
  197. package/dist/components/playback/playback.class.js.map +1 -1
  198. package/dist/components/poll-status/poll-status.styles.d.ts.map +1 -1
  199. package/dist/components/poll-status/poll-status.styles.js +4 -0
  200. package/dist/components/poll-status/poll-status.styles.js.map +1 -1
  201. package/dist/components/segmented/segmented.styles.d.ts.map +1 -1
  202. package/dist/components/segmented/segmented.styles.js +3 -0
  203. package/dist/components/segmented/segmented.styles.js.map +1 -1
  204. package/dist/components/select/select.class.d.ts +10 -0
  205. package/dist/components/select/select.class.d.ts.map +1 -1
  206. package/dist/components/select/select.class.js +22 -2
  207. package/dist/components/select/select.class.js.map +1 -1
  208. package/dist/components/skeleton/skeleton.class.d.ts +5 -0
  209. package/dist/components/skeleton/skeleton.class.d.ts.map +1 -1
  210. package/dist/components/skeleton/skeleton.class.js +17 -2
  211. package/dist/components/skeleton/skeleton.class.js.map +1 -1
  212. package/dist/components/skeleton/skeleton.styles.js +2 -2
  213. package/dist/components/sparkline/sparkline.class.d.ts +3 -1
  214. package/dist/components/sparkline/sparkline.class.d.ts.map +1 -1
  215. package/dist/components/sparkline/sparkline.class.js +24 -8
  216. package/dist/components/sparkline/sparkline.class.js.map +1 -1
  217. package/dist/components/stepper/stepper.styles.d.ts.map +1 -1
  218. package/dist/components/stepper/stepper.styles.js +4 -0
  219. package/dist/components/stepper/stepper.styles.js.map +1 -1
  220. package/dist/components/table/table.class.d.ts +47 -0
  221. package/dist/components/table/table.class.d.ts.map +1 -1
  222. package/dist/components/table/table.class.js +95 -19
  223. package/dist/components/table/table.class.js.map +1 -1
  224. package/dist/components/table/table.styles.d.ts.map +1 -1
  225. package/dist/components/table/table.styles.js +39 -0
  226. package/dist/components/table/table.styles.js.map +1 -1
  227. package/dist/components/tool-call-chip/tool-call-chip.class.d.ts +8 -1
  228. package/dist/components/tool-call-chip/tool-call-chip.class.d.ts.map +1 -1
  229. package/dist/components/tool-call-chip/tool-call-chip.class.js +19 -16
  230. package/dist/components/tool-call-chip/tool-call-chip.class.js.map +1 -1
  231. package/dist/components/tool-call-chip/tool-call-chip.styles.d.ts.map +1 -1
  232. package/dist/components/tool-call-chip/tool-call-chip.styles.js +3 -2
  233. package/dist/components/tool-call-chip/tool-call-chip.styles.js.map +1 -1
  234. package/dist/components/tool-result-dialog/tool-result-dialog.class.d.ts +12 -1
  235. package/dist/components/tool-result-dialog/tool-result-dialog.class.d.ts.map +1 -1
  236. package/dist/components/tool-result-dialog/tool-result-dialog.class.js +25 -11
  237. package/dist/components/tool-result-dialog/tool-result-dialog.class.js.map +1 -1
  238. package/dist/components/tool-result-dialog/tool-result-dialog.styles.d.ts.map +1 -1
  239. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +3 -1
  240. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js.map +1 -1
  241. package/dist/internal/localization.d.ts +1 -1
  242. package/dist/internal/localization.d.ts.map +1 -1
  243. package/dist/internal/localization.js +21 -0
  244. package/dist/internal/localization.js.map +1 -1
  245. package/dist/internal/tokens.styles.d.ts.map +1 -1
  246. package/dist/internal/tokens.styles.js +17 -0
  247. package/dist/internal/tokens.styles.js.map +1 -1
  248. package/dist/lyra.d.ts +4 -4
  249. package/dist/lyra.d.ts.map +1 -1
  250. package/dist/lyra.js.map +1 -1
  251. package/llms-full.txt +204 -76
  252. package/package.json +1 -1
package/llms-full.txt CHANGED
@@ -206,7 +206,13 @@ shared `FormAssociated` mixin — see gotchas).
206
206
  - `errorText: string = ''` (attribute `error-text` — static error copy shown below the hint;
207
207
  overridden by slotted `error` content when provided)
208
208
  - `open: boolean = false` (reflected)
209
- - `withClear: boolean = false` (attribute **`with-clear`** not `clearable`, see gotchas)
209
+ - `clearable: boolean = false` (reflected) — displays the clear button while a value is selected
210
+ - `withClear: boolean = false` (attribute `with-clear`) — deprecated compatibility alias for
211
+ `clearable`; either property enables the same clear button
212
+ - `autocomplete: string = 'off'`, `inputMode: string = ''` (attribute `inputmode`),
213
+ `enterKeyHint: string = ''` (attribute `enterkeyhint`), `spellcheck: boolean = true`,
214
+ `autocapitalize: string = ''`, and `autoCorrect: string = ''` (attribute `autocorrect`) — native
215
+ editing-assistance attributes forwarded to the internal filter input
210
216
  - `maxOptionsVisible: number = 3` (attribute `max-options-visible` — caps how many selected tags
211
217
  show before collapsing to `+N`)
212
218
  - `emptyText: string = 'No results'` (attribute `empty-text`)
@@ -229,6 +235,11 @@ shared `FormAssociated` mixin — see gotchas).
229
235
  - `selectedRows: ComboboxSourceRow[]` (read-only getter) — structured rows for the current
230
236
  selection, including any opaque `data` payload supplied by an async source. Selected async rows
231
237
  remain available after the query changes or a later source result no longer contains them
238
+ - `selectionStart`, `selectionEnd`, and `selectionDirection` — selection getters/setters forwarded
239
+ to the internal input
240
+
241
+ **Methods:** `focus(options?)`, `blur()`, `select()`, `setSelectionRange()`, and `setRangeText()`
242
+ forward to the internal input. `setRangeText()` synchronizes the filter query and visible options.
232
243
 
233
244
  `ComboboxSourceRow = { value: string; label: string; sub?: string; icon?: unknown; badge?: string |
234
245
  number; accessibleLabel?: string; data?: unknown; dotColor?: string; group?: string; disabled?:
@@ -245,6 +256,7 @@ one bubbling/composed, non-cancelable plain `input` `Event`, immediately followe
245
256
  of `change` `Event`. Re-picking the current single value and programmatic/default/reset/restore
246
257
  writes are silent. The clear button emits one `lyra-clear` after its `input`/`change` pair.
247
258
  `lyra-show` and `lyra-hide` report listbox visibility transitions.
259
+ The internal input's `focus` and `blur` are re-dispatched as bubbling, composed host events.
248
260
 
249
261
  **Slots:** default (`<lyra-option>` children), `label`, `hint`, `error` (overrides the `errorText`
250
262
  attribute when provided)
@@ -315,9 +327,8 @@ collection, while `form.reset()` still returns to the declarative selected defau
315
327
  synchronous and fires no `input`/`change` event.
316
328
 
317
329
  **Known gotchas:**
318
- - naming drift from Web Awesome parity: the shipped attribute is **`with-clear`**, not
319
- `clearable` (which is what `<wa-combobox>` uses) — don't copy-paste WA docs assuming a 1:1
320
- attribute name here.
330
+ - `with-clear` remains supported for compatibility, but new code should use the mirrored
331
+ `clearable` property/attribute.
321
332
  - a host-level `aria-label` attribute on `<lyra-combobox>` now takes priority over `label`/
322
333
  `placeholder`/`"Combobox"` when resolving the accessible name on `[part="combobox-input"]` —
323
334
  previously it was silently ignored. Matches the same fallback on `<lyra-select>`.
@@ -716,7 +727,10 @@ shadow-internal native button doesn't participate in an ancestor form's submissi
716
727
 
717
728
  **Properties:**
718
729
  - `variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral'` (reflected)
719
- - `appearance: 'filled' | 'outlined' | 'plain' = 'filled'` (reflected)
730
+ - `appearance: 'accent' | 'filled' | 'outlined' | 'plain' = 'filled'` (reflected) — `'accent'` is a
731
+ loud, high-contrast filled tier (equivalent to `wa-button`'s own runtime-default appearance),
732
+ distinct from `'filled'` for `variant="neutral"` specifically (`'filled'` reads the ambient
733
+ surface color there; `'accent'` reads a solid neutral fill)
720
734
  - `size: 'xs' | 's' | 'm' | 'l' | 'xl' = 'm'` (reflected)
721
735
  - `type: 'button' | 'submit' | 'reset' = 'button'`
722
736
  - `loading: boolean = false` (reflected) — shows an internal spinner and disables the button without
@@ -734,12 +748,18 @@ unmodified; disabled while `disabled` or `loading`).
734
748
 
735
749
  **Themeable custom properties:** `--lyra-button-accent`, `--lyra-button-fill`,
736
750
  `--lyra-button-on-fill`, `--lyra-button-border` (each swapped by the active `variant`, default
737
- `neutral` falls back to plain text/surface/border tokens).
751
+ `neutral` falls back to plain text/surface/border tokens), `--lyra-button-accent-fill`,
752
+ `--lyra-button-accent-on-fill` (the `appearance="accent"` fill/foreground pair; `neutral` falls
753
+ back to `--wa-color-neutral-fill-loud`/`-on-loud`, every other variant reuses that variant's own
754
+ loud fill token), `--lyra-button-hover-brightness` (default `1.08`, the `:hover` filter intensity),
755
+ `--lyra-button-active-scale` (default `0.9875`, the `:active` press-scale, disabled under
756
+ `prefers-reduced-motion`).
738
757
 
739
758
  **Optional peer deps:** none.
740
759
 
741
760
  ```html
742
761
  <lyra-button variant="brand" appearance="filled">Save</lyra-button>
762
+ <lyra-button variant="neutral" appearance="accent">Save</lyra-button>
743
763
  <lyra-button appearance="plain" aria-label="Close dialog"><svg slot="start">...</svg></lyra-button>
744
764
  ```
745
765
 
@@ -747,6 +767,9 @@ unmodified; disabled while `disabled` or `loading`).
747
767
  - A host `aria-label` is forwarded to the internal button as a literal string (for an icon-only
748
768
  button); an external `aria-labelledby`/`aria-describedby` idref is not copied across the shadow
749
769
  boundary.
770
+ - Is form-associated (`static formAssociated = true` + `attachInternals()`), so it participates in
771
+ an ancestor `<form>.elements` the same way `wa-button` does — a sibling text field's own
772
+ Enter-to-submit lookup (which scans `form.elements` for a `type === 'submit'` control) finds it.
750
773
 
751
774
  ---
752
775
 
@@ -851,8 +874,9 @@ interface PhoneNumberAdapter {
851
874
  - `label: string = ''`, `hint: string = ''`, `errorText: string = ''` (attribute `error-text`) —
852
875
  visible form-field chrome; each has a matching named slot.
853
876
  - `placeholder: string = ''` — forwarded to the native telephone input.
854
- - host `aria-label` — forwarded to the internal telephone input. Name precedence is `phoneLabel`,
855
- host `aria-label`, visible `label`, then `placeholder`.
877
+ - `accessibleLabel: string | null = null` (attribute `aria-label`) — forwarded to the internal
878
+ telephone input. Name precedence is host `aria-label`, `phoneLabel`, visible `label`, then
879
+ `placeholder`.
856
880
  - `phoneLabel: string = ''` (attribute `phone-label`) — explicit accessible-name override for the
857
881
  native telephone input.
858
882
  - `countryLabel: string = 'Select'` (attribute `country-label`) — country-selector accessible name;
@@ -867,6 +891,8 @@ interface PhoneNumberAdapter {
867
891
  - readonly `input: HTMLInputElement | undefined` — the internal native telephone input.
868
892
  - readonly `inputValue: string` — editable formatted/partial text, which remains available even when
869
893
  canonical `value` is `''`.
894
+ - `selectionStart`, `selectionEnd`, and `selectionDirection` — native selection getters/setters
895
+ forwarded to the telephone input
870
896
  - readonly `phoneStatus: PhoneNumberStatus` — current parse state. The host also reflects it through
871
897
  `data-phone-status`.
872
898
  - readonly `form`, `labels`, `validity`, `validationMessage`, `willValidate`, and
@@ -878,7 +904,9 @@ text remains in `inputValue`/the native input so validation never makes a number
878
904
  but its canonical submitted `value` is blank. Native validation feedback is anchored to the
879
905
  telephone input, not the adjacent country selector.
880
906
 
881
- **Methods:** `focus(options?)`, `blur()`, and `select()` forward to the native telephone input.
907
+ **Methods:** `focus(options?)`, `blur()`, `select()`, `setSelectionRange()`, and `setRangeText()`
908
+ forward to the native telephone input. Range-text edits reparse the number and synchronize the
909
+ canonical value, form value, and validity.
882
910
  `setFormValue(value)`, `checkValidity()`, and `reportValidity()` come from `FormAssociated`.
883
911
  `form.reset()` restores the original declarative `value` and the default country.
884
912
 
@@ -1061,6 +1089,8 @@ Zero-dependency inline SVG trend chart (mirrors `<wa-sparkline>`).
1061
1089
  - `type: 'line' | 'bar' | 'area' = 'line'`
1062
1090
  - `min?: number` (defaults to data minimum)
1063
1091
  - `max?: number` (defaults to data maximum)
1092
+ - `accessibleLabel: string | null = null` (attribute `aria-label`) — overrides the localized
1093
+ generated summary on the internal SVG
1064
1094
 
1065
1095
  **Events:** none.
1066
1096
 
@@ -1081,9 +1111,9 @@ the reviewed family (pure CSS cascade, no JS/`getComputedStyle` bridging needed)
1081
1111
  ```
1082
1112
 
1083
1113
  **Known gotchas:**
1084
- - Auto-sets `role="img"` + a descriptive `aria-label` ("Trend of N values, last X" / "No data" when
1085
- empty) good default, but still just a single summary sentence with no tabular fallback; fine for
1086
- a glance-value sparkline, worth reconsidering if it's ever the *sole* representation of a metric.
1114
+ - The semantic `role="img"` and accessible name live on the SVG that owns the graphic. The generated
1115
+ summary is localized, formats the last value with `effectiveLocale`, and can be replaced through
1116
+ `accessibleLabel`/host `aria-label`. It remains a concise summary rather than a tabular fallback.
1087
1117
  - flat data (every value equal, so the auto-computed range spans zero) now renders a centered
1088
1118
  midline/mid-height bars instead of collapsing every point to the bottom edge, and a single-value
1089
1119
  series renders a visible flat line (a zero-length path was previously invisible). **Every** `type`
@@ -1113,6 +1143,8 @@ Country/language flag image. Flag artwork ships in a **separate, optional peer p
1113
1143
  alongside `src` since there's no `country`/`language` to derive a fallback `alt` from.)
1114
1144
  - `label?: string` (accessible name / `alt` text — **defaults to a localized, human-readable region
1115
1145
  name derived from the *resolved country* code via `Intl.DisplayNames` if omitted**, see gotchas)
1146
+ - `accessibleLabel: string | null = null` (attribute `aria-label`) — takes precedence over `label`
1147
+ and the derived region name; an explicit empty value marks the image decorative
1116
1148
  - `round: boolean = false` (reflected — circular crop)
1117
1149
  - `variant?: 'compact' | 'standard' | 'detailed'` (attribute `variant`, not reflected — picks a
1118
1150
  fidelity tier for the ~65 codes whose source art embeds a coat of arms/seal/emblem; every other
@@ -1132,9 +1164,8 @@ Country/language flag image. Flag artwork ships in a **separate, optional peer p
1132
1164
  **CSS parts:** `image`
1133
1165
 
1134
1166
  **Themeable custom properties:** `--lyra-flag-radius` (default `calc(var(--lyra-radius) * 0.33)` —
1135
- ≈2px at the library's default `--lyra-radius` of `0.375rem`; scales with `--lyra-radius` unless
1136
- overridden directly — non-`round` corner radius); also consumes `--lyra-color-border` (the inset
1137
- ring around the flag image).
1167
+ non-`round` corner radius), `--lyra-flag-aspect-ratio` (default `4 / 3`), and
1168
+ `--lyra-flag-object-fit` (default `cover`); also consumes `--lyra-color-border` for the inset ring.
1138
1169
 
1139
1170
  **Optional peer deps:** `@aceshooting/lyra-flags` — required for the component to actually render an
1140
1171
  image when `country` or `language` is used. Import `components/flag/flag-peer.js` once to opt into
@@ -1172,8 +1203,8 @@ import '@aceshooting/lyra-ui/components/flag/flag-peer.js';
1172
1203
  - Rendering is async even when the peer *is* installed: `src` resolves after an `import()` +
1173
1204
  resolver call, so there's a brief loading-skeleton window on first paint/attribute change — don't
1174
1205
  assume the `<img>` exists synchronously right after setting `country`/`language`.
1175
- - if `label` is omitted, the accessible name (`alt`) falls back to a localized region name via
1176
- `Intl.DisplayNames([navigator.language], { type: 'region' })` (e.g. `"United Kingdom"`) instead of
1206
+ - if both `aria-label` and `label` are omitted, the accessible name (`alt`) falls back to a localized
1207
+ region name via `Intl.DisplayNames([effectiveLocale], { type: 'region' })` (e.g. `"United Kingdom"`) instead of
1177
1208
  a bare code — for `language="en"` that's derived from `"GB"` (the mapped country), not `"EN"` (the
1178
1209
  language tag itself). Falls back further to the bare uppercase code if `Intl.DisplayNames` throws
1179
1210
  for an unrecognized region or isn't available. You can still pass an explicit `label` (e.g.
@@ -1265,6 +1296,9 @@ Loading placeholder (`text`/`circle`/`rect` shapes, `pulse`/`sheen` effects).
1265
1296
  - `label: string = 'Loading…'` — accessible name for this instance's own `role="status"` (rendered as
1266
1297
  visually-hidden text inside `[part="base"]`); override with a description of what's actually
1267
1298
  loading, e.g. `label="Loading chart"`
1299
+ - `announce: boolean = true` (reflected) — set false for decorative members of a skeleton group;
1300
+ removes the status role, live-region state, and visually hidden announcement while preserving
1301
+ the visual placeholder
1268
1302
 
1269
1303
  **Events:** none.
1270
1304
 
@@ -1273,7 +1307,8 @@ Loading placeholder (`text`/`circle`/`rect` shapes, `pulse`/`sheen` effects).
1273
1307
  **CSS parts:** `base`
1274
1308
 
1275
1309
  **Themeable custom properties:** `--lyra-skeleton-w`, `--lyra-skeleton-h` (set/cleared by the
1276
- `width`/`height` properties; default `100%` / `1em`).
1310
+ `width`/`height` properties; default `100%` / `1em`) and shared `--lyra-transition-ambient` for
1311
+ the pulse/sheen timing.
1277
1312
 
1278
1313
  **Optional peer deps:** none.
1279
1314
 
@@ -1283,14 +1318,8 @@ Loading placeholder (`text`/`circle`/`rect` shapes, `pulse`/`sheen` effects).
1283
1318
  ```
1284
1319
 
1285
1320
  **Known gotchas:**
1286
- - every instance is an independent, simultaneously-firing `role="status"` live region (set via
1287
- `willUpdate`) with its own visually-hidden `label` text (default `"Loading…"`). A realistic loading
1288
- state (e.g. a 10×5 skeleton table = 50 instances) mounts 50 separate live regions at nearly the same
1289
- tick — expect screen readers to announce the label dozens of times, not once, even if every
1290
- instance shares the same default `label`. A more specific per-instance `label` doesn't fix the
1291
- fan-out by itself; there's still no grouping primitive to dedupe it — if it matters, wrap your own
1292
- single `role="status"` region around the set of skeletons and mark the individual ones
1293
- `aria-hidden`.
1321
+ - Each instance announces by default. In a repeated skeleton layout, provide one parent status and
1322
+ set `announce="false"` on the decorative child placeholders to avoid duplicate announcements.
1294
1323
  - no `lines`/`count` shorthand for "N lines of skeleton text" — stamp out N elements
1295
1324
  yourself.
1296
1325
  - Respects `prefers-reduced-motion` (both effects) — safe to leave as-is for that concern.
@@ -1375,14 +1404,15 @@ Presentational, sort/select-aware data table. **The host owns actual sorting/fil
1375
1404
  of `rows` — this component only renders and emits intents.
1376
1405
 
1377
1406
  **Properties:**
1378
- - `columns: TableColumn<T>[] = []` (attribute: false) — `{ key, label, sortable?, align?:
1379
- 'start'|'end', priority?: 'medium'|'low', sticky?: boolean, cell: (row) => unknown }` —
1407
+ - `columns: TableColumn<T>[] = []` (attribute: false) — `{ key, label, headerCell?, width?,
1408
+ minWidth?, sortable?, align?: 'start'|'end', priority?: 'medium'|'low', sticky?: boolean |
1409
+ 'start' | 'end', footer?, cellStyle?, cell: (row) => unknown }` —
1380
1410
  `priority` progressively hides that column via a `@container` query as `[part='base']` narrows
1381
1411
  (`'low'` hides first, under a ~900px container width; `'medium'` next, under ~640px; both
1382
1412
  breakpoints are fixed in `table.styles.ts`, not themeable tokens), reversible via
1383
- `[part='reveal-columns-button']`; `sticky` pins that column's header cell/cells to the inline-start
1384
- edge (`position: sticky`) while the table scrolls horizontally — multiple `sticky` columns stack
1385
- left-to-right (each measures every earlier sticky column's rendered width via
1413
+ `[part='reveal-columns-button']`; `sticky` pins that column's header/cells to the logical start
1414
+ (`true`/`'start'`) or end edge while the table scrolls horizontally — multiple sticky columns stack
1415
+ in logical order (each measures every earlier sticky column's rendered width via
1386
1416
  `--lyra-table-sticky-offset`) instead of overlapping at the same edge; `footer` renders a
1387
1417
  sticky-bottom footer cell for that column, computed from every currently-rendered row (post-sort,
1388
1418
  pre-pagination) — e.g. a column total — omit it for a column with no footer value, and a
@@ -1407,6 +1437,11 @@ of `rows` — this component only renders and emits intents.
1407
1437
  when omitted, which is only safe while `rows` never reorders — set it whenever `rows` can be
1408
1438
  sorted/filtered/re-ordered across renders, or selection/click can silently attach to the wrong row
1409
1439
  - `selectedKey: string | number | null = null` (attribute: false) — **single**-selection only
1440
+ - `expandedContent?: (row: T) => unknown` (attribute: false) — enables a leading expand toggle and
1441
+ renders a full-width detail row beneath expanded records
1442
+ - `canExpand?: (row: T) => boolean` (attribute: false) — optional per-row gate for expansion
1443
+ - `expandedKeys: Set<string | number> = new Set()` (attribute: false) — consumer-controlled expanded
1444
+ state; update it in response to `lyra-row-expand-toggle`
1410
1445
  - `hasMore: boolean = false` (attribute `has-more`, reflected)
1411
1446
  - `moreLabel: string = 'Load more'` (attribute `more-label`)
1412
1447
  - `emptyHeading: string = 'No data'` (attribute `empty-heading`)
@@ -1417,17 +1452,22 @@ of `rows` — this component only renders and emits intents.
1417
1452
  reveal-button's label while `priority`-hidden columns are hidden)
1418
1453
  - `hideColumnsLabel: string = 'Show fewer columns'` (attribute `hide-columns-label` — the same
1419
1454
  button's label once they've been revealed)
1455
+ - `showAllColumns: boolean = false` (attribute `show-all-columns`, reflected) — forces responsive
1456
+ priority columns visible and is updated by the built-in reveal button
1420
1457
 
1421
1458
  **Events:** `lyra-sort` (`detail: { key }`, fired on sortable-header activation), `lyra-row-click`
1422
1459
  (`detail: { row }`), `lyra-load-more` (fired on the "load more" button), `lyra-columns-hidden-change`
1423
- (`detail: { hidden: boolean }`, fired only on a real `columnsHidden` transition)
1460
+ (`detail: { hidden: boolean }`, fired only on a real `columnsHidden` transition),
1461
+ `lyra-columns-revealed` (`detail: { revealed: boolean }`), and `lyra-row-expand-toggle`
1462
+ (`detail: { row, key }`; the table does not mutate `expandedKeys`)
1424
1463
 
1425
1464
  **Slots:** none — content comes entirely from `columns`/`rows`.
1426
1465
 
1427
1466
  **CSS parts:** `base`, `table`, `head`, `header-cell`, `row`, `cell`, `more-button`, `sort-icon` (a
1428
1467
  chevron indicator shown on the active sortable header, rotated per `sortDir`), `reveal-columns-button`
1429
1468
  (shown only when `columnsHidden` is true), `foot` (the `<tfoot>`, only rendered when at least one
1430
- column defines `footer`), `footer-row` (the single footer row), `footer-cell` (a single footer cell)
1469
+ column defines `footer`), `footer-row`, `footer-cell`, `expand-toggle-cell`, `row-expand-toggle`,
1470
+ `row-expand-icon`, `expanded-row`, `expanded-cell`
1431
1471
 
1432
1472
  **Themeable custom properties:** `--lyra-table-max-height` (default `none`; controls the scrollable
1433
1473
  body's `max-block-size`).
@@ -1510,6 +1550,9 @@ from its built-in default is treated as an explicit per-instance wording overrid
1510
1550
  **Events:** `lyra-page-change` (`detail: { page: number }`, bubbles and composes, non-cancelable) —
1511
1551
  emitted for a valid, different requested page. The host applies `event.detail.page` back to `page`
1512
1552
  after routing, fetching, or any other policy decision.
1553
+ The internal page input's `focus` and `blur` are also bridged as bubbling, composed host events.
1554
+
1555
+ **Methods:** `focus(options?)` and `blur()` forward to the numeric page input.
1513
1556
 
1514
1557
  **Slots:** none.
1515
1558
 
@@ -1625,8 +1668,12 @@ immediately) or multi-format (click opens a small menu).
1625
1668
  not toggle it automatically
1626
1669
  - `label: string = 'Export'` — trigger button text; also feeds the format-choice menu's `aria-label`
1627
1670
  as `` `${label} format` `` so assistive tech gets an accessible name for the menu
1671
+ - `accessibleLabel: string = ''` (attribute `aria-label`) — overrides the trigger's accessible
1672
+ name and feeds the localized format-menu name without changing the visible label
1628
1673
  - `open: boolean = false` (reflected)
1629
1674
 
1675
+ **Methods:** `focus(options?)` and `blur()` forward to the native trigger button.
1676
+
1630
1677
  **Events:** `lyra-export` (`detail: { format: string }`, **cancelable** — call `preventDefault()` to
1631
1678
  substitute your own server-generated download instead of the built-in client-side one),
1632
1679
  `lyra-export-complete` (`detail: { format: 'csv' | 'json' }`, fires only after a non-cancelled
@@ -1684,6 +1731,9 @@ downloadBlob(content: string, filename: string, mime: string): void // trig
1684
1731
  jump to the first/last item once open, Escape closes it and returns focus to the trigger button,
1685
1732
  and a completed export also returns focus to the trigger — not just Escape/click-outside as
1686
1733
  before.
1734
+ - the positioned menu is constrained to the inline/block space reported by the positioner, wraps
1735
+ long localized format labels/descriptions, scrolls when necessary, and disables its transition
1736
+ under reduced motion.
1687
1737
 
1688
1738
  ---
1689
1739
 
@@ -1697,6 +1747,13 @@ buttons, this has no code/JSON content model to adopt just to reuse the copy aff
1697
1747
 
1698
1748
  **Properties:**
1699
1749
  - `value: string = ''` — the plain text to copy.
1750
+ - `accessibleLabel: string | null = null` (attribute `aria-label`) — overrides the localized
1751
+ Copy/Copied accessible name without changing the icon
1752
+ - `disabled: boolean = false` (reflected)
1753
+ - `feedbackDuration: number = 1500` (attribute `feedback-duration`) — milliseconds before the
1754
+ copied checkmark returns to the copy icon; finite values are clamped at zero
1755
+
1756
+ **Methods:** `focus(options?)` and `blur()` forward to the native button.
1700
1757
 
1701
1758
  **Events:** `lyra-copy` (`detail: { text: string }`) — fires on activation, always with the current
1702
1759
  `value`, regardless of whether the OS clipboard write actually succeeded (same convention as
@@ -2112,10 +2169,11 @@ Steps an index through `[0, length)` on a fixed interval — play/pause for time
2112
2169
  change-tracking sees it and auto-pauses on `hidden = true`)
2113
2170
 
2114
2171
  **Methods:** `play()`, `pause()`, `toggle()`, `next()`, `previous()`, `goTo(index: number)` — all
2115
- idempotent/clamped; `length <= 1` is a no-op degenerate case.
2172
+ idempotent/clamped; `length <= 1` is a no-op degenerate case. `focus(options?)` and `blur()` forward
2173
+ to the play button.
2116
2174
 
2117
2175
  **Events:** `lyra-play`, `lyra-pause` (no detail), `lyra-step` (`detail: { index }`, fired on every
2118
- tick and manual step)
2176
+ tick and manual step); internal `focus`/`blur` are bridged as bubbling, composed host events.
2119
2177
 
2120
2178
  **Slots:** none.
2121
2179
 
@@ -2242,6 +2300,14 @@ click, or Enter/Space on the focused cell, fires `lyra-cell-click`.
2242
2300
  `6` Saturday) for a row that would otherwise render a label and, when it returns a string, uses it
2243
2301
  instead of the built-in `Intl.DateTimeFormat`-derived short weekday name. Unset (the default)
2244
2302
  reproduces today's exact locale-derived output.
2303
+ - `monthLabelText?: (jsMonth: number, year: number) => string | undefined` (attribute: false,
2304
+ calendar mode only) — the month-axis analogue of `weekdayLabelText`: receives the real JS month
2305
+ index (`0` January .. `11` December) and full year for a month boundary that would otherwise
2306
+ render a label, and, when it returns a string, uses it instead of the built-in
2307
+ `Intl.DateTimeFormat`-derived short month name. Unset (the default) reproduces today's exact
2308
+ locale-derived output. Lets month labels track the same locale signal (e.g. an app's own i18n
2309
+ store) as `weekdayLabelText` and the component's other localizable strings, instead of always
2310
+ following the browser/OS-language default.
2245
2311
  - `colorSteps?: string[]` (attribute: false) — a discrete array (≥2 entries) of CSS colors used as
2246
2312
  exact ramp steps instead of linearly interpolating between `--lyra-heatmap-scale-lo`/`-hi`;
2247
2313
  governs both `mode`s and both `scale` values, discretizing whichever scale would otherwise
@@ -2599,6 +2665,12 @@ Chart.js wrapper every other `lyra-*-chart` tag subclasses; supports both a simp
2599
2665
  - `config?: Partial<ChartConfiguration>` (attribute: false) — deep-merged over the generated
2600
2666
  config; any nested key wins without clobbering sibling generated keys. This is the raw Chart.js
2601
2667
  escape hatch, so a caller-supplied `config.type` is passed through rather than normalized.
2668
+ - `accessibleLabel: string = ''` (attribute `accessible-label`) — canvas name override; a host
2669
+ `aria-label` has highest precedence
2670
+ - `accessibleDescription: string = ''` (attribute `accessible-description`) — overrides the
2671
+ localized data/trend summary
2672
+ - `showDataTable: boolean = false` (attribute `show-data-table`) — makes the always-available
2673
+ accessible data table visible rather than screen-reader-only
2602
2674
 
2603
2675
  **Methods:** `resetZoom()` (reset any active zoom/pan to the original view), `refreshTheme()`
2604
2676
  (forces a redraw so the `--lyra-chart-*` tokens below are re-read from the current computed style —
@@ -2642,9 +2714,8 @@ subset actually used.
2642
2714
  ```
2643
2715
 
2644
2716
  **Known gotchas:**
2645
- - `type` at the `lyra-chart` (core) level is completely unchecked `buildConfig()` passes it
2646
- straight to Chart.js as-is, so `<lyra-chart type="pie">` already works today with no subclass
2647
- needed. Each typed subclass below locks its *own* `type` via a real prototype accessor (see the
2717
+ - supported `type` values are normalized before reaching Chart.js; unknown runtime attribute or
2718
+ property values fall back to `line`. Each typed subclass below locks its *own* `type` via a real prototype accessor (see the
2648
2719
  typed-subclasses section) — a genuine runtime lock, not just a compile-time default.
2649
2720
  - no global theme-broadcast event exists to auto-retheme an already-drawn chart on a theme switch —
2650
2721
  a consumer flipping something upstream (e.g. a `data-theme` attribute) that doesn't otherwise
@@ -2678,6 +2749,9 @@ subset actually used.
2678
2749
  changed since the last draw (e.g. an unrelated property/state update, or a bare `requestUpdate()`).
2679
2750
  `refreshTheme()` calls `draw()` directly and is unaffected by either gate — it always redraws, since
2680
2751
  a theme change isn't reflected in any tracked property.
2752
+ - Chart.js receives `effectiveLocale`; generated summary values use the same locale. Cartesian y/y2
2753
+ axes swap logical sides under RTL, and host `aria-label` is forwarded to the canvas and data-table
2754
+ caption.
2681
2755
 
2682
2756
  ---
2683
2757
 
@@ -2746,11 +2820,18 @@ passthrough). Not a subclass of `LyraChart`.
2746
2820
  column in a stacked chart. Empty (the default) reproduces the exact existing output: no bar
2747
2821
  carries `data-selected`. This component takes no opinion on what the highlight looks like, only
2748
2822
  which bars it applies to — style it via `::part(bar)[data-selected]`.
2823
+ - `minBarHeight?: number` (attribute `min-bar-height`) — optional minimum visible bar height for
2824
+ small non-zero values
2825
+ - `accessibleLabel?: string` (attribute `accessible-label`) — SVG accessible-name override; a host
2826
+ `aria-label` wins
2749
2827
 
2750
2828
  **Events:** `lyra-point-click` — fired when a bar/point is activated (click, or Enter/Space while
2751
2829
  focused). `detail: { datasetIndex: number, index: number, label: string | undefined, value: number
2752
2830
  | null }` — same shape as `lyra-chart`'s `lyra-point-click`.
2753
2831
 
2832
+ The axis gutter/title and y-axis labels mirror to logical start under RTL. Built-in mark summaries
2833
+ are complete localized templates and format values with `effectiveLocale`.
2834
+
2754
2835
  **Performance:** rendering is `IntersectionObserver`-gated and content-signature-memoized — `render()`
2755
2836
  skips recomputing the grid/marks (and reuses the previous `TemplateResult`) while the host is scrolled
2756
2837
  off-screen, or when none of the content-affecting properties (`type`, `labels`, `datasets`, `legend`,
@@ -2880,6 +2961,13 @@ browser). Does **not** extend `LyraChart` — a deliberately bespoke API.
2880
2961
  - `height: string = '280px'`
2881
2962
  - `yLabel: string = ''` (attribute `y-label`)
2882
2963
  - `beginAtZero: boolean = true` (attribute `begin-at-zero`)
2964
+ - `accessibleLabel: string = ''` (attribute `accessible-label`) — canvas name override; host
2965
+ `aria-label` wins
2966
+ - `accessibleDescription: string = ''` (attribute `accessible-description`) — overrides the
2967
+ localized five-number summary
2968
+ - `showDataTable: boolean = false` (attribute `show-data-table`) — reveals the accessible data table
2969
+
2970
+ **Methods:** `refreshTheme()` re-reads canvas theme custom properties after an ancestor theme change.
2883
2971
 
2884
2972
  **Events:** none.
2885
2973
 
@@ -2903,9 +2991,11 @@ independently of the base `chart-loader.ts`).
2903
2991
  ```
2904
2992
 
2905
2993
  **Known gotchas:**
2906
- - no raw `config` passthrough (unlike every other chart tag) limited to
2907
- `labels`/`boxes`/`legend`/`height`/`yLabel`/`beginAtZero`; can't reach the underlying
2994
+ - no raw `config` passthrough limited to the properties above; can't reach the underlying
2908
2995
  controller's own options (`itemRadius`, `outlierRadius`, `coef`).
2996
+ - Chart.js receives `effectiveLocale`; generated numeric summaries use it, the y axis moves to
2997
+ logical start in RTL, canvas tooltip/axis colors are token-driven, and animation is disabled
2998
+ under reduced motion.
2909
2999
  - The peer-dependency-missing failure path (`.catch()` → warn + resolve `null`) is untested —
2910
3000
  verify it manually if shipping without the peer installed.
2911
3001
 
@@ -3030,8 +3120,11 @@ parsing (that's left entirely to the host).
3030
3120
  **before** (and takes precedence over) `allowedMimeTypes`
3031
3121
  - `maxFileSize: number = 0` (attribute `max-file-size` — bytes; `0` disables the check)
3032
3122
  - `label: string = 'Drop files here or click to browse'`
3123
+ - `accessibleLabel: string = ''` (attribute `aria-label`) — overrides `label` as the internal
3124
+ dropzone/button accessible name without changing visible copy
3033
3125
 
3034
- **Methods:** `openPicker()` programmatically opens the native file dialog.
3126
+ **Methods:** `openPicker()` programmatically opens the native file dialog; `focus(options?)`
3127
+ forwards to the interactive dropzone.
3035
3128
 
3036
3129
  **Events:** `lyra-files` (`detail: { files: File[], rejected: RejectedFile[] }`, fired on both drop
3037
3130
  and manual file-picker selection) — `RejectedFile = { file: File; reason: 'type' | 'count' | 'size'
@@ -3445,7 +3538,7 @@ keyboard.
3445
3538
 
3446
3539
  A boolean form control. `role="checkbox"` with an `aria-checked` that can also be `"mixed"`, and a
3447
3540
  visual box/checkmark. Structurally the same idea as `<lyra-switch>` (form-associated via
3448
- `ElementInternals`, click and Space/Enter both toggle) but with checkbox semantics.
3541
+ `ElementInternals`, click and Space toggle) but with checkbox semantics.
3449
3542
 
3450
3543
  **Properties:**
3451
3544
  - `checked: boolean = false` (reflected)
@@ -3458,8 +3551,11 @@ visual box/checkmark. Structurally the same idea as `<lyra-switch>` (form-associ
3458
3551
  - `value: string = 'on'` — only contributed to form submission while `checked` (a native checkbox
3459
3552
  submits nothing at all, not even an empty string, while unchecked)
3460
3553
 
3461
- **Events:** `lyra-change` (`detail: { checked: boolean }`) fired on a user toggle (click or
3462
- Space/Enter); not fired for a programmatic `.checked` assignment.
3554
+ **Events:** user toggles emit bubbling/composed `input`, then `change`, then the compatibility
3555
+ `lyra-change` alias (`detail: { checked: boolean }`). Programmatic `.checked` assignments are
3556
+ silent. Internal `focus`/`blur` are re-dispatched as bubbling, composed host events.
3557
+
3558
+ **Methods:** `focus(options?)` and `blur()` forward to the internal checkbox control.
3463
3559
 
3464
3560
  **Slots:** default — label text, rendered next to the box. Clicking it toggles the checkbox, the
3465
3561
  same as clicking a native checkbox's associated `<label>`. If left empty, set `aria-label` on the
@@ -3785,8 +3881,9 @@ produced HTML in a single pass (no second DOM walk after insertion).
3785
3881
  the page already finished loading); falls back to the normal async path (with its brief
3786
3882
  plain-text-fallback first paint) when the cache isn't warm yet. `false` (the default) is
3787
3883
  byte-identical to always taking the async path
3788
- - `streaming: boolean = false` (reflected) — reserved hint for a host-provided streaming renderer;
3789
- setting it has no rendering effect, but lets a consumer target `lyra-markdown[streaming]` in CSS
3884
+ - `streaming: boolean = false` (reflected) — marks the host `aria-busy="true"` while partial Markdown
3885
+ is still arriving and lets consumers target `lyra-markdown[streaming]`; busy state also remains
3886
+ true while parser dependencies are loading
3790
3887
 
3791
3888
  **Events:** `lyra-link-click` (`detail: { href: string, internal: true }`, fired — with the click
3792
3889
  prevented — when a rendered link's `href` starts with `internal-link-prefix`; ordinary external
@@ -4030,7 +4127,7 @@ decorative; `label` is the entire accessible content, nothing narrates individua
4030
4127
  A compact inline pill representing one tool/function call an agent made mid-conversation, e.g.
4031
4128
  `web_search: Searching web…` with a `running` spinner. First-party invention (no Web Awesome
4032
4129
  equivalent). It owns no detail surface of its own — activating it (click or Enter/Space while
4033
- focused) only fires `lyra-tool-chip-select`; a consumer wires that to opening a
4130
+ focused) fires `lyra-tool-call-chip-select`; a consumer wires that to opening a
4034
4131
  `<lyra-tool-result-dialog>` (or anything else) at the call site, keeping the chip reusable wherever
4035
4132
  a compact call summary is useful, with or without a detail surface behind it.
4036
4133
 
@@ -4047,10 +4144,11 @@ a compact call summary is useful, with or without a detail surface behind it.
4047
4144
  - `icon: string = ''` — literal icon hint (e.g. an emoji) rendered when the `icon` slot is empty;
4048
4145
  ignored once anything is assigned to `slot="icon"`
4049
4146
  - `callId: string = ''` (attribute `call-id`) — unique identifier for this invocation, echoed back
4050
- in `lyra-tool-chip-select`'s detail so a listener can correlate the click with the call it fired for
4147
+ in `lyra-tool-call-chip-select`'s detail so a listener can correlate the click with the call it fired for
4051
4148
 
4052
- **Events:** `lyra-tool-chip-select` (`detail: { name: string; callId: string }`) — fired on click or
4053
- Enter/Space activation of the pill.
4149
+ **Events:** `lyra-tool-call-chip-select` (`detail: { name: string; callId: string }`) — fired on
4150
+ click or Enter/Space activation of the pill. The deprecated `lyra-tool-chip-select` alias is fired
4151
+ alongside it for one minor compatibility cycle.
4054
4152
 
4055
4153
  **Slots:** default (rich tooltip/detail content — e.g. the tool's raw arguments or a short preview —
4056
4154
  shown in a floating tooltip on hover/focus; nothing renders at all, no hover affordance, when this
@@ -4080,7 +4178,7 @@ rules, not part of the public theming API); shared tokens referenced: `--lyra-co
4080
4178
  summary="Searching web…"
4081
4179
  duration-ms="820"
4082
4180
  call-id="call_123"
4083
- @lyra-tool-chip-select=${(e) => openDetail(e.detail.callId)}
4181
+ @lyra-tool-call-chip-select=${(e) => openDetail(e.detail.callId)}
4084
4182
  >
4085
4183
  <pre slot="icon" style="display:none"></pre>
4086
4184
  <code>{"query": "lyra ui components"}</code>
@@ -4271,6 +4369,8 @@ overlay stack.
4271
4369
  **Properties:**
4272
4370
  - `open: boolean = false` (reflected) — whether the dialog is open; set this (or call `close()`) —
4273
4371
  there is no separate `show()`/`hide()` pair
4372
+ - `accessibleLabel: string | null = null` (attribute `aria-label`) — directly names the internal
4373
+ dialog panel; otherwise the tool-name title supplies `aria-labelledby`
4274
4374
  - `toolName: string = ''` (attribute `tool-name`) — the tool's name, rendered prominently in the
4275
4375
  header
4276
4376
  - `status: 'pending'|'running'|'success'|'error'|'denied' = 'pending'` (reflected) — drives the
@@ -4280,12 +4380,12 @@ overlay stack.
4280
4380
  - `maximized: boolean = false` (reflected) — near-fullscreen presentation of the same open dialog
4281
4381
 
4282
4382
  **Methods:** `close(reason: ToolResultDialogCloseReason = 'api'): void` — closes the dialog (no-op if
4283
- already closed), emits `lyra-dialog-close` with `reason`, and returns focus to whatever had it before
4383
+ already closed), emits `lyra-close` with `reason`, and returns focus to whatever had it before
4284
4384
  the dialog opened. Built-in triggers call this with `'escape'`/`'backdrop'`/`'close-button'`; a
4285
4385
  consumer's own close affordance (e.g. a footer action button) should call it directly with its own
4286
4386
  reason string so every dismissal path funnels through the same event.
4287
4387
 
4288
- **Events:** `lyra-dialog-close` (`detail: ToolResultDialogCloseReason` — `'escape'|'backdrop'|
4388
+ **Events:** `lyra-close` (`detail: ToolResultDialogCloseReason` — `'escape'|'backdrop'|
4289
4389
  'close-button'|'api'|string`) fired exactly once per dismissal; `lyra-maximize-change` (`detail:
4290
4390
  boolean`, the new `maximized` state) fired when the header's maximize/restore toggle is clicked.
4291
4391
 
@@ -4300,7 +4400,8 @@ tool name/status/duration), `tool-name`, `status`, `duration`, `header-actions`,
4300
4400
  **Themeable custom properties:** `--lyra-tool-result-dialog-overlay-color` (default `rgb(0 0 0 /
4301
4401
  0.5)` — the backdrop scrim color; component-specific since no shared overlay token exists),
4302
4402
  `--lyra-tool-result-dialog-maximized-inset` (default `var(--lyra-space-l)` — inset applied to the
4303
- panel while `[maximized]`, overridable e.g. to leave a persistent app rail visible), plus shared
4403
+ panel while `[maximized]`, overridable e.g. to leave a persistent app rail visible), and
4404
+ `--lyra-tool-result-dialog-spin` (default `1s linear`, stopped under reduced motion), plus shared
4304
4405
  tokens `--lyra-color-surface/-border/-text-quiet/-brand/-brand-quiet/-success/-success-quiet/
4305
4406
  -danger/-danger-quiet/-warning/-warning-quiet`, `--lyra-space-*`, `--lyra-radius`, `--lyra-shadow`,
4306
4407
  `--lyra-icon-button-size`, `--lyra-focus-ring-*`, `--lyra-transition-base`.
@@ -4313,7 +4414,7 @@ tokens `--lyra-color-surface/-border/-text-quiet/-brand/-brand-quiet/-success/-s
4313
4414
  status="success"
4314
4415
  duration-ms="1240"
4315
4416
  ?open=${dialogOpen}
4316
- @lyra-dialog-close=${(e) => (dialogOpen = false)}
4417
+ @lyra-close=${(e) => (dialogOpen = false)}
4317
4418
  @lyra-maximize-change=${(e) => console.log('maximized:', e.detail)}
4318
4419
  >
4319
4420
  <lyra-tabs slot="body">
@@ -4344,7 +4445,7 @@ state, so no additional scroll-lock/focus-trap bookkeeping is needed for that tr
4344
4445
  panel template so a slotted `<lyra-tabs>` (or any other light-DOM-scanning child) sees real
4345
4446
  projected content rather than a forwarding `<slot>`, while still sharing the overlay stack
4346
4447
  - `close()` is a no-op when `open` is already `false` — calling it twice in a row only fires
4347
- `lyra-dialog-close` once
4448
+ `lyra-close` once
4348
4449
  - the `maximize`/`close` buttons are always the first elements in the Tab order while open,
4349
4450
  regardless of visual position, followed by `body` then `footer` content
4350
4451
 
@@ -4374,14 +4475,24 @@ reveals the invalid state, and `form.reset()` clears the touched presentation.
4374
4475
  built-in button's icon/label (send vs. stop) and whether Enter still submits
4375
4476
  - `submitOnEnter: boolean = true` (reflected, attribute `submit-on-enter`) — when `false`, Enter
4376
4477
  always inserts a newline instead of submitting
4478
+ - `stoppable: boolean = true` (reflected) — when false, busy states keep a disabled Send button
4479
+ instead of exposing a Stop action
4480
+ - `accessibleLabel: string | null = null` (attribute `aria-label`) — names the internal textarea;
4481
+ wins over placeholder and the localized composer label
4377
4482
  - `spellcheck: boolean = true` — forwarded to the internal `<textarea>`
4378
4483
  - `autocapitalize: string = ''` — forwarded to the internal `<textarea>`; empty omits the attribute
4379
4484
  - `autoCorrect: string = ''` (attribute `autocorrect`) — forwarded to the internal `<textarea>`
4380
4485
  (Safari/WebKit-specific); empty omits the attribute. Named `autoCorrect`, not `autocorrect`, only
4381
4486
  to dodge a `lib.dom.d.ts` collision with `HTMLElement`'s own `boolean`-typed `autocorrect` IDL
4382
4487
  member; the host attribute is explicitly mapped to plain `autocorrect`.
4488
+ - `wrap: 'hard' | 'soft' | 'off' = 'soft'`, `autocomplete: string = ''`, `inputMode: string = ''`
4489
+ (attribute `inputmode`), and `enterKeyHint: string = ''` (attribute `enterkeyhint`) — forwarded to
4490
+ the native textarea
4491
+ - `selectionStart`, `selectionEnd`, and `selectionDirection` — native selection getters/setters
4383
4492
 
4384
- **Methods (own):** none beyond the inherited `checkValidity()`/`reportValidity()`.
4493
+ **Methods (own):** `focus(options?)`, `blur()`, `select()`, `setSelectionRange()`, and
4494
+ `setRangeText()` forward to the textarea; `setRangeText()` synchronizes reactive/form value and
4495
+ auto-sizing. `checkValidity()`/`reportValidity()` remain inherited.
4385
4496
 
4386
4497
  **Events:**
4387
4498
  - `lyra-input` (`detail: { value }`) — fired on every user-driven edit of the textarea, not a
@@ -4496,12 +4607,12 @@ wins when both are present.
4496
4607
  attachment, leaving only the thumbnail. Has no effect for a non-image chip, or when `compact` is
4497
4608
  unset. `false` (the default) reproduces the chip's exact existing output.
4498
4609
  - `removeLabel: string = 'Remove'` (attribute `remove-label`) — verb used in the remove button's
4499
- `aria-label`, interpolated as `` `${removeLabel} ${displayName}` ``; override for i18n/locale
4610
+ accessible name; the default routes through the complete localized `removeWithContext` template
4500
4611
  - `retryLabel: string = 'Retry'` (attribute `retry-label`) — verb used in the retry button's
4501
- `aria-label`, interpolated as `` `${retryLabel} ${displayName}` ``; override for i18n/locale
4612
+ accessible name; the default routes through the complete localized attachment template
4502
4613
  - `uploadingLabel: string = 'Uploading'` (attribute `uploading-label`) — verb used in the visible
4503
- uploading status text, rendered as `` `${uploadingLabel} ${percent}%` `` once progress is a
4504
- meaningful number, else `` `${uploadingLabel}…` ``; override for i18n/locale
4614
+ uploading status; the untouched default uses complete localized messages for progress,
4615
+ indeterminate state, and filename context so translators can reorder every value
4505
4616
  - `uploadFailedLabel: string = 'Upload failed'` (attribute `upload-failed-label`) — visible status
4506
4617
  text shown for `status="error"`; override for i18n/locale
4507
4618
 
@@ -4526,7 +4637,8 @@ generated internal id is used as a last resort.
4526
4637
  `done` → success/success-quiet/transparent); `--lyra-attachment-chip-compact-thumbnail-size` (default
4527
4638
  `1.75rem`), `--lyra-attachment-chip-compact-font-size` (default `var(--lyra-font-size-xs)`),
4528
4639
  `--lyra-attachment-chip-compact-gap` (default `0.25rem`) — govern the chip's thumbnail size, text
4529
- size, and internal gap while `compact` is set; plus shared tokens `--lyra-space-xs`, `--lyra-space-s`,
4640
+ size, and internal gap while `compact` is set; `--lyra-attachment-chip-spinner-duration` (default
4641
+ `0.8s`) controls the indeterminate rotation and stops under reduced motion; plus shared tokens `--lyra-space-xs`, `--lyra-space-s`,
4530
4642
  `--lyra-radius`, `--lyra-color-text`, `--lyra-color-danger`, `--lyra-icon-button-size`,
4531
4643
  `--lyra-transition-fast`, `--lyra-transition-base`, `--lyra-focus-ring-width`,
4532
4644
  `--lyra-focus-ring-color`, `--lyra-focus-ring-offset`.
@@ -5287,7 +5399,8 @@ anything about `<lyra-source-card>`, it only carries the id through its event de
5287
5399
  echoed back verbatim in both events; never read or validated by this component.
5288
5400
  - `href: string = ''` — optional direct link target for the citation's source, carried into
5289
5401
  `lyra-citation-open`'s detail as-is; this component never navigates.
5290
- - `label: string = ''` — overrides the computed accessible name (`"Citation {index}[, {status}]"`).
5402
+ - `label: string = ''` — overrides the computed accessible name. The built-in citation/status
5403
+ summary is a complete localized template; a host `aria-label` has highest precedence.
5291
5404
 
5292
5405
  **Events:**
5293
5406
  - `lyra-citation-activate` (`detail: { sourceId: string; index: number }`) — fires on click, or on
@@ -5301,6 +5414,8 @@ anything about `<lyra-source-card>`, it only carries the id through its event de
5301
5414
  **Slots:** default — rich preview/tooltip content (e.g. a filename + excerpt), shown in a floating
5302
5415
  popover on hover/focus. This is *not* the badge's visible content (the badge always renders
5303
5416
  `[index]`); nothing renders at all (no hover affordance) when this slot is empty.
5417
+ When populated, the button carries `aria-describedby` referencing the same-shadow-tree popover,
5418
+ which owns `role="tooltip"` whether currently shown or hidden.
5304
5419
 
5305
5420
  **CSS parts:** `base` (the clickable `<button>`), `bracket` (each of the two literal `[`/`]` glyphs),
5306
5421
  `index` (the citation number), `popover` (the floating preview panel, only meaningful while open).
@@ -5412,7 +5527,8 @@ while collapsed).
5412
5527
  expand/collapse, which only ever hides/shows the *set* of cards, never a single card's own content.
5413
5528
  - `lyra-open` (`detail: { sourceId: string; href?: string }`) — the title was activated. This
5414
5529
  component never navigates on its own (a controlled component, the same convention
5415
- `<lyra-tool-call-chip>`'s `lyra-tool-chip-select` follows); a listener decides what "open" means.
5530
+ `<lyra-tool-call-chip>`'s `lyra-tool-call-chip-select` follows); a listener decides what "open"
5531
+ means.
5416
5532
 
5417
5533
  **Slots:** `excerpt` (a short preview; when left empty, the `excerpt` part collapses away entirely —
5418
5534
  its wrapper is `hidden`, not just visually empty), `full` (the complete source text/chunk, hidden
@@ -6192,6 +6308,8 @@ and it's what every instance renders at zero extra bytes until shiki resolves.
6192
6308
  `"json"`); when unset, or when shiki doesn't recognize it, the code renders as plain unhighlighted
6193
6309
  text regardless of whether shiki itself is available
6194
6310
  - `filename: string = ''` — shown in the header, when set
6311
+ - `accessibleLabel: string = ''` (attribute `aria-label`) — names the internal focusable code-body
6312
+ region; otherwise a localized filename/language description is generated
6195
6313
  - `collapsible: boolean = false` (reflected) — shows the collapse/expand chevron button
6196
6314
  - `collapsed: boolean = false` (reflected) — only has a visible effect while `collapsible` is also
6197
6315
  true
@@ -6302,6 +6420,8 @@ toggle, the loading-skeleton behavior while the fine-grained highlighter resolve
6302
6420
  key in `languages`, the code renders as plain unhighlighted text — this component has no
6303
6421
  default/full-table highlighter to fall back to.
6304
6422
  - `filename: string = ''` — shown in the header, when set.
6423
+ - `accessibleLabel: string = ''` (attribute `aria-label`) — names the internal focusable code-body
6424
+ region; otherwise a localized filename/language description is generated.
6305
6425
  - `collapsible: boolean = false` (reflected) — shows the collapse/expand chevron button.
6306
6426
  - `collapsed: boolean = false` (reflected) — only has a visible effect while `collapsible` is also
6307
6427
  true.
@@ -6871,9 +6991,9 @@ children are the chips (the same shape `<lyra-split>`'s panels / `<lyra-source-l
6871
6991
  no `.items` array prop).
6872
6992
 
6873
6993
  **Properties:**
6874
- - `maxVisible?: number` (attribute `max-visible`) — maximum number of direct children shown before
6875
- the rest collapse behind a "+N" indicator; unset (the default) means no limit, every child is
6876
- always shown
6994
+ - `maxVisible?: number` (attribute `max-visible`) — maximum number of assigned children shown before
6995
+ the rest collapse behind a "+N" indicator; flattened slot-forwarded children count the same as
6996
+ direct children. Unset means no limit
6877
6997
 
6878
6998
  **Events:** `lyra-overflow-toggle` (`detail: { expanded }` — the overflow indicator was activated,
6879
6999
  revealing or re-collapsing the excess children; fires only from that click, i.e. only when
@@ -7032,6 +7152,9 @@ used" summary.
7032
7152
  - `label: string = ''` — overall accessible caption, e.g. `"128K context window"`. Also rendered
7033
7153
  visually (`[part="label"]`) when set.
7034
7154
 
7155
+ Accessible summaries, segment tooltips, and ring titles format quantities using `effectiveLocale`.
7156
+ A host `aria-label` overrides the generated meter summary and is preserved across reactive updates.
7157
+
7035
7158
  **Events:** none.
7036
7159
 
7037
7160
  **Slots:** none.
@@ -7228,6 +7351,8 @@ fallback simply omits `[part="download-link"]` entirely.
7228
7351
  `<img>`/the anchor.
7229
7352
  - `mimeType: string = ''` (attribute `mime-type`) — drives format dispatch (see above).
7230
7353
  - `filename: string = ''` — shown in the header and used as the download link's suggested filename.
7354
+ - `alt?: string` — image description. When omitted, the filename/localized image-preview fallback
7355
+ is used; an explicit empty string keeps a decorative preview's `alt=""` intact.
7231
7356
  - `status: 'idle' | 'converting' | 'ready' | 'error' = 'idle'` (reflected) — host-owned lifecycle
7232
7357
  state. `"converting"` shows the spinner regardless of `mimeType`/`src`; `"error"` shows
7233
7358
  `errorMessage` regardless of either. `"idle"`/`"ready"` both resume normal format dispatch — a host
@@ -7262,8 +7387,8 @@ above; excludes `data:` even though the other two sinks allow it)
7262
7387
  **Themeable custom properties:** `--lyra-document-preview-max-height` (default `none`) — the
7263
7388
  consumer-tunable scroll cap on `[part="body"]`, set from `max-height`; `none` means the preview grows
7264
7389
  with its content until a caller opts in. `--lyra-document-preview-font` (default `ui-monospace,
7265
- SFMono-Regular, Menlo, Consolas, monospace`) no shared `--wa-*`/`--lyra-*` monospace token exists yet
7266
- (the same gap `lyra-json-viewer`'s own `--lyra-json-viewer-font` documents). Plus shared tokens
7390
+ SFMono-Regular, Menlo, Consolas, monospace`) and `--lyra-document-preview-spin-duration` (default
7391
+ `0.8s`, stopped under reduced motion). Plus shared tokens
7267
7392
  `--lyra-color-border`, `--lyra-radius`, `--lyra-color-surface`, `--lyra-space-s/-m/-l/-xs`,
7268
7393
  `--lyra-color-text`, `--lyra-color-text-quiet`, `--lyra-color-danger`, `--lyra-color-brand`,
7269
7394
  `--lyra-color-on-brand`, `--lyra-focus-ring-width/-color/-offset`, `--lyra-transition-fast`.
@@ -7304,6 +7429,8 @@ available, the region becomes a standard `role="progressbar"` instead, self-desc
7304
7429
  - The component's own text/JSON `fetch(src)` is a *different* async operation from the host-driven
7305
7430
  `status="converting"` conversion. A failed fetch fires `lyra-render-error` and renders
7306
7431
  `[part="error"]` on its own; it never sets `status="error"` itself.
7432
+ - changing `src` aborts the superseded text fetch as well as ignoring any stale completion; removing
7433
+ the component aborts its active request.
7307
7434
  - `progress` is only ever consulted for the host-driven `"converting"` state — this component's own
7308
7435
  in-flight text fetch always renders the indeterminate spinner, with no numeric-progress path.
7309
7436
  - The `unsupported` slot's initial presence is detected once, before the first render, by scanning
@@ -7340,6 +7467,8 @@ final.
7340
7467
  filename, and folded into the accessible name.
7341
7468
  - `alt: string = ''` — alt text for the image case (and reused as a video label fallback). Falls
7342
7469
  back to `filename`, then a generic per-kind description.
7470
+ - `accessibleLabel: string = ''` (attribute `aria-label`) — overrides the localized action name on
7471
+ the actual button/link without replacing image alt text or the video control's own label
7343
7472
  - `maxHeight: string = ''` (attribute `max-height`) — a CSS length (e.g. `"16rem"`); once set,
7344
7473
  overrides the `--lyra-media-card-max-height` custom property for this instance only (applied
7345
7474
  inline on `[part="base"]`, so it reliably wins over a `:host{}`-declared default from outside the
@@ -7638,6 +7767,8 @@ user-menu affordance.
7638
7767
  - `src?: string` — image URL; takes priority over `initials` when set and loads successfully, falling
7639
7768
  back to `initials` on a load error.
7640
7769
  - `alt: string = ''` — image alt text; set alongside `src` for accessibility.
7770
+ - host `aria-label` — overrides `alt` as the image/fallback accessible name without changing the
7771
+ visible initials or image
7641
7772
  - `size: 'sm' | 'md' | 'lg' = 'md'` (reflected).
7642
7773
  - `shape: 'circle' | 'square' = 'circle'` (reflected).
7643
7774
  - `tone: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral'` (reflected) — recolors
@@ -7666,13 +7797,10 @@ var(--lyra-color-border))`, swapped per `tone`), `--lyra-avatar-color` (default
7666
7797
  ```
7667
7798
 
7668
7799
  **Known gotchas:**
7669
- - an image load failure falls back to `initials` automatically (an `error` listener flips internal
7670
- state) there's no manual reset/retry method; reassigning `src` (even to the same value)
7671
- re-attempts the load.
7672
- - the initials fallback is `aria-hidden="true"` whenever `alt` is set, regardless of whether an image
7673
- is actually showing — so if `src`/`alt` are both set but the image fails to load, the rendered
7674
- initials text is still hidden from assistive tech, leaving the avatar with no accessible name of
7675
- its own unless the surrounding context supplies one.
7800
+ - an image load failure falls back to `initials` automatically. Changing `src` clears the failure
7801
+ state so the replacement URL gets its own load attempt.
7802
+ - when `alt` or host `aria-label` supplies a name, the base preserves that name through the
7803
+ initials fallback while hiding duplicate initials text from assistive technology.
7676
7804
 
7677
7805
  ---
7678
7806