@aceshooting/lyra-ui 2.10.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 (256) hide show
  1. package/custom-elements.json +2188 -63
  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.class.d.ts +5 -1
  161. package/dist/components/input/input.class.d.ts.map +1 -1
  162. package/dist/components/input/input.class.js +7 -1
  163. package/dist/components/input/input.class.js.map +1 -1
  164. package/dist/components/input/input.styles.d.ts.map +1 -1
  165. package/dist/components/input/input.styles.js +29 -3
  166. package/dist/components/input/input.styles.js.map +1 -1
  167. package/dist/components/json-viewer/json-viewer.class.js +1 -1
  168. package/dist/components/json-viewer/json-viewer.class.js.map +1 -1
  169. package/dist/components/json-viewer/json-viewer.styles.d.ts.map +1 -1
  170. package/dist/components/json-viewer/json-viewer.styles.js +7 -0
  171. package/dist/components/json-viewer/json-viewer.styles.js.map +1 -1
  172. package/dist/components/map/map.class.d.ts +3 -5
  173. package/dist/components/map/map.class.d.ts.map +1 -1
  174. package/dist/components/map/map.class.js +8 -6
  175. package/dist/components/map/map.class.js.map +1 -1
  176. package/dist/components/markdown/markdown.class.d.ts +5 -5
  177. package/dist/components/markdown/markdown.class.d.ts.map +1 -1
  178. package/dist/components/markdown/markdown.class.js +6 -6
  179. package/dist/components/markdown/markdown.class.js.map +1 -1
  180. package/dist/components/markdown/markdown.styles.d.ts.map +1 -1
  181. package/dist/components/markdown/markdown.styles.js +11 -4
  182. package/dist/components/markdown/markdown.styles.js.map +1 -1
  183. package/dist/components/media-card/media-card.class.d.ts +12 -1
  184. package/dist/components/media-card/media-card.class.d.ts.map +1 -1
  185. package/dist/components/media-card/media-card.class.js +27 -7
  186. package/dist/components/media-card/media-card.class.js.map +1 -1
  187. package/dist/components/mention-popover/mention-popover.styles.d.ts.map +1 -1
  188. package/dist/components/mention-popover/mention-popover.styles.js +2 -0
  189. package/dist/components/mention-popover/mention-popover.styles.js.map +1 -1
  190. package/dist/components/pagination/pagination.class.d.ts +11 -0
  191. package/dist/components/pagination/pagination.class.d.ts.map +1 -1
  192. package/dist/components/pagination/pagination.class.js +28 -1
  193. package/dist/components/pagination/pagination.class.js.map +1 -1
  194. package/dist/components/phone-input/phone-input.class.d.ts +16 -2
  195. package/dist/components/phone-input/phone-input.class.d.ts.map +1 -1
  196. package/dist/components/phone-input/phone-input.class.js +43 -2
  197. package/dist/components/phone-input/phone-input.class.js.map +1 -1
  198. package/dist/components/playback/playback.class.d.ts +11 -0
  199. package/dist/components/playback/playback.class.d.ts.map +1 -1
  200. package/dist/components/playback/playback.class.js +26 -1
  201. package/dist/components/playback/playback.class.js.map +1 -1
  202. package/dist/components/poll-status/poll-status.styles.d.ts.map +1 -1
  203. package/dist/components/poll-status/poll-status.styles.js +4 -0
  204. package/dist/components/poll-status/poll-status.styles.js.map +1 -1
  205. package/dist/components/segmented/segmented.styles.d.ts.map +1 -1
  206. package/dist/components/segmented/segmented.styles.js +3 -0
  207. package/dist/components/segmented/segmented.styles.js.map +1 -1
  208. package/dist/components/select/select.class.d.ts +10 -0
  209. package/dist/components/select/select.class.d.ts.map +1 -1
  210. package/dist/components/select/select.class.js +22 -2
  211. package/dist/components/select/select.class.js.map +1 -1
  212. package/dist/components/skeleton/skeleton.class.d.ts +5 -0
  213. package/dist/components/skeleton/skeleton.class.d.ts.map +1 -1
  214. package/dist/components/skeleton/skeleton.class.js +17 -2
  215. package/dist/components/skeleton/skeleton.class.js.map +1 -1
  216. package/dist/components/skeleton/skeleton.styles.js +2 -2
  217. package/dist/components/sparkline/sparkline.class.d.ts +3 -1
  218. package/dist/components/sparkline/sparkline.class.d.ts.map +1 -1
  219. package/dist/components/sparkline/sparkline.class.js +24 -8
  220. package/dist/components/sparkline/sparkline.class.js.map +1 -1
  221. package/dist/components/stepper/stepper.styles.d.ts.map +1 -1
  222. package/dist/components/stepper/stepper.styles.js +4 -0
  223. package/dist/components/stepper/stepper.styles.js.map +1 -1
  224. package/dist/components/table/table.class.d.ts +47 -0
  225. package/dist/components/table/table.class.d.ts.map +1 -1
  226. package/dist/components/table/table.class.js +95 -19
  227. package/dist/components/table/table.class.js.map +1 -1
  228. package/dist/components/table/table.styles.d.ts.map +1 -1
  229. package/dist/components/table/table.styles.js +39 -0
  230. package/dist/components/table/table.styles.js.map +1 -1
  231. package/dist/components/tool-call-chip/tool-call-chip.class.d.ts +8 -1
  232. package/dist/components/tool-call-chip/tool-call-chip.class.d.ts.map +1 -1
  233. package/dist/components/tool-call-chip/tool-call-chip.class.js +19 -16
  234. package/dist/components/tool-call-chip/tool-call-chip.class.js.map +1 -1
  235. package/dist/components/tool-call-chip/tool-call-chip.styles.d.ts.map +1 -1
  236. package/dist/components/tool-call-chip/tool-call-chip.styles.js +3 -2
  237. package/dist/components/tool-call-chip/tool-call-chip.styles.js.map +1 -1
  238. package/dist/components/tool-result-dialog/tool-result-dialog.class.d.ts +12 -1
  239. package/dist/components/tool-result-dialog/tool-result-dialog.class.d.ts.map +1 -1
  240. package/dist/components/tool-result-dialog/tool-result-dialog.class.js +25 -11
  241. package/dist/components/tool-result-dialog/tool-result-dialog.class.js.map +1 -1
  242. package/dist/components/tool-result-dialog/tool-result-dialog.styles.d.ts.map +1 -1
  243. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +3 -1
  244. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js.map +1 -1
  245. package/dist/internal/localization.d.ts +1 -1
  246. package/dist/internal/localization.d.ts.map +1 -1
  247. package/dist/internal/localization.js +21 -0
  248. package/dist/internal/localization.js.map +1 -1
  249. package/dist/internal/tokens.styles.d.ts.map +1 -1
  250. package/dist/internal/tokens.styles.js +17 -0
  251. package/dist/internal/tokens.styles.js.map +1 -1
  252. package/dist/lyra.d.ts +5 -5
  253. package/dist/lyra.d.ts.map +1 -1
  254. package/dist/lyra.js.map +1 -1
  255. package/llms-full.txt +211 -78
  256. 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
 
@@ -754,10 +777,12 @@ unmodified; disabled while `disabled` or `loading`).
754
777
 
755
778
  A single-line plain-text input primitive, the `lyra-*` equivalent of a plain `wa-input`,
756
779
  form-associated via the same `FormAssociated` mixin as `lyra-textarea`. Ships the same opt-in
757
- `label`/`hint`/`errorText` form-control chrome as `lyra-textarea`/`lyra-select`.
780
+ `label`/`hint`/`errorText` form-control chrome as `lyra-textarea`/`lyra-select`, and the same
781
+ `size` scale as `lyra-select`/`lyra-combobox`.
758
782
 
759
783
  **Properties:**
760
784
  - `type: 'text' | 'password' | 'email' | 'number' = 'text'`
785
+ - `size: 'xs' | 's' | 'm' | 'l' | 'xl' = 'm'` (reflected)
761
786
  - `value: string = ''` (from `FormAssociated`)
762
787
  - `placeholder: string = ''`
763
788
  - `label: string = ''`
@@ -778,13 +803,16 @@ composed from the internal native input's own `blur`/`focus`).
778
803
  **CSS parts:** `form-control`, `form-control-label`, `input-wrapper`, `input`, `password-toggle`
779
804
  (present only when `type="password"`), `hint`, `error`.
780
805
 
781
- **Themeable custom properties:** shared tokens only.
806
+ **Themeable custom properties:** `--lyra-input-padding-block`, `--lyra-input-padding-inline`,
807
+ `--lyra-input-font-size` — all three auto-swapped per `size` (`xs`…`xl`), the same pattern
808
+ `lyra-select`'s `--lyra-select-trigger-padding`/`--lyra-select-font-size` use.
782
809
 
783
810
  **Optional peer deps:** none.
784
811
 
785
812
  ```html
786
813
  <lyra-input type="password" label="Password"></lyra-input>
787
814
  <lyra-input type="email" label="Email" required></lyra-input>
815
+ <lyra-input size="s" placeholder="Compact"></lyra-input>
788
816
  ```
789
817
 
790
818
  **Known gotchas:**
@@ -846,8 +874,9 @@ interface PhoneNumberAdapter {
846
874
  - `label: string = ''`, `hint: string = ''`, `errorText: string = ''` (attribute `error-text`) —
847
875
  visible form-field chrome; each has a matching named slot.
848
876
  - `placeholder: string = ''` — forwarded to the native telephone input.
849
- - host `aria-label` — forwarded to the internal telephone input. Name precedence is `phoneLabel`,
850
- 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`.
851
880
  - `phoneLabel: string = ''` (attribute `phone-label`) — explicit accessible-name override for the
852
881
  native telephone input.
853
882
  - `countryLabel: string = 'Select'` (attribute `country-label`) — country-selector accessible name;
@@ -862,6 +891,8 @@ interface PhoneNumberAdapter {
862
891
  - readonly `input: HTMLInputElement | undefined` — the internal native telephone input.
863
892
  - readonly `inputValue: string` — editable formatted/partial text, which remains available even when
864
893
  canonical `value` is `''`.
894
+ - `selectionStart`, `selectionEnd`, and `selectionDirection` — native selection getters/setters
895
+ forwarded to the telephone input
865
896
  - readonly `phoneStatus: PhoneNumberStatus` — current parse state. The host also reflects it through
866
897
  `data-phone-status`.
867
898
  - readonly `form`, `labels`, `validity`, `validationMessage`, `willValidate`, and
@@ -873,7 +904,9 @@ text remains in `inputValue`/the native input so validation never makes a number
873
904
  but its canonical submitted `value` is blank. Native validation feedback is anchored to the
874
905
  telephone input, not the adjacent country selector.
875
906
 
876
- **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.
877
910
  `setFormValue(value)`, `checkValidity()`, and `reportValidity()` come from `FormAssociated`.
878
911
  `form.reset()` restores the original declarative `value` and the default country.
879
912
 
@@ -1056,6 +1089,8 @@ Zero-dependency inline SVG trend chart (mirrors `<wa-sparkline>`).
1056
1089
  - `type: 'line' | 'bar' | 'area' = 'line'`
1057
1090
  - `min?: number` (defaults to data minimum)
1058
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
1059
1094
 
1060
1095
  **Events:** none.
1061
1096
 
@@ -1076,9 +1111,9 @@ the reviewed family (pure CSS cascade, no JS/`getComputedStyle` bridging needed)
1076
1111
  ```
1077
1112
 
1078
1113
  **Known gotchas:**
1079
- - Auto-sets `role="img"` + a descriptive `aria-label` ("Trend of N values, last X" / "No data" when
1080
- empty) good default, but still just a single summary sentence with no tabular fallback; fine for
1081
- 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.
1082
1117
  - flat data (every value equal, so the auto-computed range spans zero) now renders a centered
1083
1118
  midline/mid-height bars instead of collapsing every point to the bottom edge, and a single-value
1084
1119
  series renders a visible flat line (a zero-length path was previously invisible). **Every** `type`
@@ -1108,6 +1143,8 @@ Country/language flag image. Flag artwork ships in a **separate, optional peer p
1108
1143
  alongside `src` since there's no `country`/`language` to derive a fallback `alt` from.)
1109
1144
  - `label?: string` (accessible name / `alt` text — **defaults to a localized, human-readable region
1110
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
1111
1148
  - `round: boolean = false` (reflected — circular crop)
1112
1149
  - `variant?: 'compact' | 'standard' | 'detailed'` (attribute `variant`, not reflected — picks a
1113
1150
  fidelity tier for the ~65 codes whose source art embeds a coat of arms/seal/emblem; every other
@@ -1127,9 +1164,8 @@ Country/language flag image. Flag artwork ships in a **separate, optional peer p
1127
1164
  **CSS parts:** `image`
1128
1165
 
1129
1166
  **Themeable custom properties:** `--lyra-flag-radius` (default `calc(var(--lyra-radius) * 0.33)` —
1130
- ≈2px at the library's default `--lyra-radius` of `0.375rem`; scales with `--lyra-radius` unless
1131
- overridden directly — non-`round` corner radius); also consumes `--lyra-color-border` (the inset
1132
- 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.
1133
1169
 
1134
1170
  **Optional peer deps:** `@aceshooting/lyra-flags` — required for the component to actually render an
1135
1171
  image when `country` or `language` is used. Import `components/flag/flag-peer.js` once to opt into
@@ -1167,8 +1203,8 @@ import '@aceshooting/lyra-ui/components/flag/flag-peer.js';
1167
1203
  - Rendering is async even when the peer *is* installed: `src` resolves after an `import()` +
1168
1204
  resolver call, so there's a brief loading-skeleton window on first paint/attribute change — don't
1169
1205
  assume the `<img>` exists synchronously right after setting `country`/`language`.
1170
- - if `label` is omitted, the accessible name (`alt`) falls back to a localized region name via
1171
- `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
1172
1208
  a bare code — for `language="en"` that's derived from `"GB"` (the mapped country), not `"EN"` (the
1173
1209
  language tag itself). Falls back further to the bare uppercase code if `Intl.DisplayNames` throws
1174
1210
  for an unrecognized region or isn't available. You can still pass an explicit `label` (e.g.
@@ -1260,6 +1296,9 @@ Loading placeholder (`text`/`circle`/`rect` shapes, `pulse`/`sheen` effects).
1260
1296
  - `label: string = 'Loading…'` — accessible name for this instance's own `role="status"` (rendered as
1261
1297
  visually-hidden text inside `[part="base"]`); override with a description of what's actually
1262
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
1263
1302
 
1264
1303
  **Events:** none.
1265
1304
 
@@ -1268,7 +1307,8 @@ Loading placeholder (`text`/`circle`/`rect` shapes, `pulse`/`sheen` effects).
1268
1307
  **CSS parts:** `base`
1269
1308
 
1270
1309
  **Themeable custom properties:** `--lyra-skeleton-w`, `--lyra-skeleton-h` (set/cleared by the
1271
- `width`/`height` properties; default `100%` / `1em`).
1310
+ `width`/`height` properties; default `100%` / `1em`) and shared `--lyra-transition-ambient` for
1311
+ the pulse/sheen timing.
1272
1312
 
1273
1313
  **Optional peer deps:** none.
1274
1314
 
@@ -1278,14 +1318,8 @@ Loading placeholder (`text`/`circle`/`rect` shapes, `pulse`/`sheen` effects).
1278
1318
  ```
1279
1319
 
1280
1320
  **Known gotchas:**
1281
- - every instance is an independent, simultaneously-firing `role="status"` live region (set via
1282
- `willUpdate`) with its own visually-hidden `label` text (default `"Loading…"`). A realistic loading
1283
- state (e.g. a 10×5 skeleton table = 50 instances) mounts 50 separate live regions at nearly the same
1284
- tick — expect screen readers to announce the label dozens of times, not once, even if every
1285
- instance shares the same default `label`. A more specific per-instance `label` doesn't fix the
1286
- fan-out by itself; there's still no grouping primitive to dedupe it — if it matters, wrap your own
1287
- single `role="status"` region around the set of skeletons and mark the individual ones
1288
- `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.
1289
1323
  - no `lines`/`count` shorthand for "N lines of skeleton text" — stamp out N elements
1290
1324
  yourself.
1291
1325
  - Respects `prefers-reduced-motion` (both effects) — safe to leave as-is for that concern.
@@ -1370,14 +1404,15 @@ Presentational, sort/select-aware data table. **The host owns actual sorting/fil
1370
1404
  of `rows` — this component only renders and emits intents.
1371
1405
 
1372
1406
  **Properties:**
1373
- - `columns: TableColumn<T>[] = []` (attribute: false) — `{ key, label, sortable?, align?:
1374
- '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 }` —
1375
1410
  `priority` progressively hides that column via a `@container` query as `[part='base']` narrows
1376
1411
  (`'low'` hides first, under a ~900px container width; `'medium'` next, under ~640px; both
1377
1412
  breakpoints are fixed in `table.styles.ts`, not themeable tokens), reversible via
1378
- `[part='reveal-columns-button']`; `sticky` pins that column's header cell/cells to the inline-start
1379
- edge (`position: sticky`) while the table scrolls horizontally — multiple `sticky` columns stack
1380
- 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
1381
1416
  `--lyra-table-sticky-offset`) instead of overlapping at the same edge; `footer` renders a
1382
1417
  sticky-bottom footer cell for that column, computed from every currently-rendered row (post-sort,
1383
1418
  pre-pagination) — e.g. a column total — omit it for a column with no footer value, and a
@@ -1402,6 +1437,11 @@ of `rows` — this component only renders and emits intents.
1402
1437
  when omitted, which is only safe while `rows` never reorders — set it whenever `rows` can be
1403
1438
  sorted/filtered/re-ordered across renders, or selection/click can silently attach to the wrong row
1404
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`
1405
1445
  - `hasMore: boolean = false` (attribute `has-more`, reflected)
1406
1446
  - `moreLabel: string = 'Load more'` (attribute `more-label`)
1407
1447
  - `emptyHeading: string = 'No data'` (attribute `empty-heading`)
@@ -1412,17 +1452,22 @@ of `rows` — this component only renders and emits intents.
1412
1452
  reveal-button's label while `priority`-hidden columns are hidden)
1413
1453
  - `hideColumnsLabel: string = 'Show fewer columns'` (attribute `hide-columns-label` — the same
1414
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
1415
1457
 
1416
1458
  **Events:** `lyra-sort` (`detail: { key }`, fired on sortable-header activation), `lyra-row-click`
1417
1459
  (`detail: { row }`), `lyra-load-more` (fired on the "load more" button), `lyra-columns-hidden-change`
1418
- (`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`)
1419
1463
 
1420
1464
  **Slots:** none — content comes entirely from `columns`/`rows`.
1421
1465
 
1422
1466
  **CSS parts:** `base`, `table`, `head`, `header-cell`, `row`, `cell`, `more-button`, `sort-icon` (a
1423
1467
  chevron indicator shown on the active sortable header, rotated per `sortDir`), `reveal-columns-button`
1424
1468
  (shown only when `columnsHidden` is true), `foot` (the `<tfoot>`, only rendered when at least one
1425
- 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`
1426
1471
 
1427
1472
  **Themeable custom properties:** `--lyra-table-max-height` (default `none`; controls the scrollable
1428
1473
  body's `max-block-size`).
@@ -1505,6 +1550,9 @@ from its built-in default is treated as an explicit per-instance wording overrid
1505
1550
  **Events:** `lyra-page-change` (`detail: { page: number }`, bubbles and composes, non-cancelable) —
1506
1551
  emitted for a valid, different requested page. The host applies `event.detail.page` back to `page`
1507
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.
1508
1556
 
1509
1557
  **Slots:** none.
1510
1558
 
@@ -1620,8 +1668,12 @@ immediately) or multi-format (click opens a small menu).
1620
1668
  not toggle it automatically
1621
1669
  - `label: string = 'Export'` — trigger button text; also feeds the format-choice menu's `aria-label`
1622
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
1623
1673
  - `open: boolean = false` (reflected)
1624
1674
 
1675
+ **Methods:** `focus(options?)` and `blur()` forward to the native trigger button.
1676
+
1625
1677
  **Events:** `lyra-export` (`detail: { format: string }`, **cancelable** — call `preventDefault()` to
1626
1678
  substitute your own server-generated download instead of the built-in client-side one),
1627
1679
  `lyra-export-complete` (`detail: { format: 'csv' | 'json' }`, fires only after a non-cancelled
@@ -1679,6 +1731,9 @@ downloadBlob(content: string, filename: string, mime: string): void // trig
1679
1731
  jump to the first/last item once open, Escape closes it and returns focus to the trigger button,
1680
1732
  and a completed export also returns focus to the trigger — not just Escape/click-outside as
1681
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.
1682
1737
 
1683
1738
  ---
1684
1739
 
@@ -1692,6 +1747,13 @@ buttons, this has no code/JSON content model to adopt just to reuse the copy aff
1692
1747
 
1693
1748
  **Properties:**
1694
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.
1695
1757
 
1696
1758
  **Events:** `lyra-copy` (`detail: { text: string }`) — fires on activation, always with the current
1697
1759
  `value`, regardless of whether the OS clipboard write actually succeeded (same convention as
@@ -2107,10 +2169,11 @@ Steps an index through `[0, length)` on a fixed interval — play/pause for time
2107
2169
  change-tracking sees it and auto-pauses on `hidden = true`)
2108
2170
 
2109
2171
  **Methods:** `play()`, `pause()`, `toggle()`, `next()`, `previous()`, `goTo(index: number)` — all
2110
- 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.
2111
2174
 
2112
2175
  **Events:** `lyra-play`, `lyra-pause` (no detail), `lyra-step` (`detail: { index }`, fired on every
2113
- tick and manual step)
2176
+ tick and manual step); internal `focus`/`blur` are bridged as bubbling, composed host events.
2114
2177
 
2115
2178
  **Slots:** none.
2116
2179
 
@@ -2237,6 +2300,14 @@ click, or Enter/Space on the focused cell, fires `lyra-cell-click`.
2237
2300
  `6` Saturday) for a row that would otherwise render a label and, when it returns a string, uses it
2238
2301
  instead of the built-in `Intl.DateTimeFormat`-derived short weekday name. Unset (the default)
2239
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.
2240
2311
  - `colorSteps?: string[]` (attribute: false) — a discrete array (≥2 entries) of CSS colors used as
2241
2312
  exact ramp steps instead of linearly interpolating between `--lyra-heatmap-scale-lo`/`-hi`;
2242
2313
  governs both `mode`s and both `scale` values, discretizing whichever scale would otherwise
@@ -2594,6 +2665,12 @@ Chart.js wrapper every other `lyra-*-chart` tag subclasses; supports both a simp
2594
2665
  - `config?: Partial<ChartConfiguration>` (attribute: false) — deep-merged over the generated
2595
2666
  config; any nested key wins without clobbering sibling generated keys. This is the raw Chart.js
2596
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
2597
2674
 
2598
2675
  **Methods:** `resetZoom()` (reset any active zoom/pan to the original view), `refreshTheme()`
2599
2676
  (forces a redraw so the `--lyra-chart-*` tokens below are re-read from the current computed style —
@@ -2637,9 +2714,8 @@ subset actually used.
2637
2714
  ```
2638
2715
 
2639
2716
  **Known gotchas:**
2640
- - `type` at the `lyra-chart` (core) level is completely unchecked `buildConfig()` passes it
2641
- straight to Chart.js as-is, so `<lyra-chart type="pie">` already works today with no subclass
2642
- 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
2643
2719
  typed-subclasses section) — a genuine runtime lock, not just a compile-time default.
2644
2720
  - no global theme-broadcast event exists to auto-retheme an already-drawn chart on a theme switch —
2645
2721
  a consumer flipping something upstream (e.g. a `data-theme` attribute) that doesn't otherwise
@@ -2673,6 +2749,9 @@ subset actually used.
2673
2749
  changed since the last draw (e.g. an unrelated property/state update, or a bare `requestUpdate()`).
2674
2750
  `refreshTheme()` calls `draw()` directly and is unaffected by either gate — it always redraws, since
2675
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.
2676
2755
 
2677
2756
  ---
2678
2757
 
@@ -2741,11 +2820,18 @@ passthrough). Not a subclass of `LyraChart`.
2741
2820
  column in a stacked chart. Empty (the default) reproduces the exact existing output: no bar
2742
2821
  carries `data-selected`. This component takes no opinion on what the highlight looks like, only
2743
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
2744
2827
 
2745
2828
  **Events:** `lyra-point-click` — fired when a bar/point is activated (click, or Enter/Space while
2746
2829
  focused). `detail: { datasetIndex: number, index: number, label: string | undefined, value: number
2747
2830
  | null }` — same shape as `lyra-chart`'s `lyra-point-click`.
2748
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
+
2749
2835
  **Performance:** rendering is `IntersectionObserver`-gated and content-signature-memoized — `render()`
2750
2836
  skips recomputing the grid/marks (and reuses the previous `TemplateResult`) while the host is scrolled
2751
2837
  off-screen, or when none of the content-affecting properties (`type`, `labels`, `datasets`, `legend`,
@@ -2875,6 +2961,13 @@ browser). Does **not** extend `LyraChart` — a deliberately bespoke API.
2875
2961
  - `height: string = '280px'`
2876
2962
  - `yLabel: string = ''` (attribute `y-label`)
2877
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.
2878
2971
 
2879
2972
  **Events:** none.
2880
2973
 
@@ -2898,9 +2991,11 @@ independently of the base `chart-loader.ts`).
2898
2991
  ```
2899
2992
 
2900
2993
  **Known gotchas:**
2901
- - no raw `config` passthrough (unlike every other chart tag) limited to
2902
- `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
2903
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.
2904
2999
  - The peer-dependency-missing failure path (`.catch()` → warn + resolve `null`) is untested —
2905
3000
  verify it manually if shipping without the peer installed.
2906
3001
 
@@ -3025,8 +3120,11 @@ parsing (that's left entirely to the host).
3025
3120
  **before** (and takes precedence over) `allowedMimeTypes`
3026
3121
  - `maxFileSize: number = 0` (attribute `max-file-size` — bytes; `0` disables the check)
3027
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
3028
3125
 
3029
- **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.
3030
3128
 
3031
3129
  **Events:** `lyra-files` (`detail: { files: File[], rejected: RejectedFile[] }`, fired on both drop
3032
3130
  and manual file-picker selection) — `RejectedFile = { file: File; reason: 'type' | 'count' | 'size'
@@ -3440,7 +3538,7 @@ keyboard.
3440
3538
 
3441
3539
  A boolean form control. `role="checkbox"` with an `aria-checked` that can also be `"mixed"`, and a
3442
3540
  visual box/checkmark. Structurally the same idea as `<lyra-switch>` (form-associated via
3443
- `ElementInternals`, click and Space/Enter both toggle) but with checkbox semantics.
3541
+ `ElementInternals`, click and Space toggle) but with checkbox semantics.
3444
3542
 
3445
3543
  **Properties:**
3446
3544
  - `checked: boolean = false` (reflected)
@@ -3453,8 +3551,11 @@ visual box/checkmark. Structurally the same idea as `<lyra-switch>` (form-associ
3453
3551
  - `value: string = 'on'` — only contributed to form submission while `checked` (a native checkbox
3454
3552
  submits nothing at all, not even an empty string, while unchecked)
3455
3553
 
3456
- **Events:** `lyra-change` (`detail: { checked: boolean }`) fired on a user toggle (click or
3457
- 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.
3458
3559
 
3459
3560
  **Slots:** default — label text, rendered next to the box. Clicking it toggles the checkbox, the
3460
3561
  same as clicking a native checkbox's associated `<label>`. If left empty, set `aria-label` on the
@@ -3780,8 +3881,9 @@ produced HTML in a single pass (no second DOM walk after insertion).
3780
3881
  the page already finished loading); falls back to the normal async path (with its brief
3781
3882
  plain-text-fallback first paint) when the cache isn't warm yet. `false` (the default) is
3782
3883
  byte-identical to always taking the async path
3783
- - `streaming: boolean = false` (reflected) — reserved hint for a host-provided streaming renderer;
3784
- 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
3785
3887
 
3786
3888
  **Events:** `lyra-link-click` (`detail: { href: string, internal: true }`, fired — with the click
3787
3889
  prevented — when a rendered link's `href` starts with `internal-link-prefix`; ordinary external
@@ -4025,7 +4127,7 @@ decorative; `label` is the entire accessible content, nothing narrates individua
4025
4127
  A compact inline pill representing one tool/function call an agent made mid-conversation, e.g.
4026
4128
  `web_search: Searching web…` with a `running` spinner. First-party invention (no Web Awesome
4027
4129
  equivalent). It owns no detail surface of its own — activating it (click or Enter/Space while
4028
- 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
4029
4131
  `<lyra-tool-result-dialog>` (or anything else) at the call site, keeping the chip reusable wherever
4030
4132
  a compact call summary is useful, with or without a detail surface behind it.
4031
4133
 
@@ -4042,10 +4144,11 @@ a compact call summary is useful, with or without a detail surface behind it.
4042
4144
  - `icon: string = ''` — literal icon hint (e.g. an emoji) rendered when the `icon` slot is empty;
4043
4145
  ignored once anything is assigned to `slot="icon"`
4044
4146
  - `callId: string = ''` (attribute `call-id`) — unique identifier for this invocation, echoed back
4045
- 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
4046
4148
 
4047
- **Events:** `lyra-tool-chip-select` (`detail: { name: string; callId: string }`) — fired on click or
4048
- 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.
4049
4152
 
4050
4153
  **Slots:** default (rich tooltip/detail content — e.g. the tool's raw arguments or a short preview —
4051
4154
  shown in a floating tooltip on hover/focus; nothing renders at all, no hover affordance, when this
@@ -4075,7 +4178,7 @@ rules, not part of the public theming API); shared tokens referenced: `--lyra-co
4075
4178
  summary="Searching web…"
4076
4179
  duration-ms="820"
4077
4180
  call-id="call_123"
4078
- @lyra-tool-chip-select=${(e) => openDetail(e.detail.callId)}
4181
+ @lyra-tool-call-chip-select=${(e) => openDetail(e.detail.callId)}
4079
4182
  >
4080
4183
  <pre slot="icon" style="display:none"></pre>
4081
4184
  <code>{"query": "lyra ui components"}</code>
@@ -4266,6 +4369,8 @@ overlay stack.
4266
4369
  **Properties:**
4267
4370
  - `open: boolean = false` (reflected) — whether the dialog is open; set this (or call `close()`) —
4268
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`
4269
4374
  - `toolName: string = ''` (attribute `tool-name`) — the tool's name, rendered prominently in the
4270
4375
  header
4271
4376
  - `status: 'pending'|'running'|'success'|'error'|'denied' = 'pending'` (reflected) — drives the
@@ -4275,12 +4380,12 @@ overlay stack.
4275
4380
  - `maximized: boolean = false` (reflected) — near-fullscreen presentation of the same open dialog
4276
4381
 
4277
4382
  **Methods:** `close(reason: ToolResultDialogCloseReason = 'api'): void` — closes the dialog (no-op if
4278
- 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
4279
4384
  the dialog opened. Built-in triggers call this with `'escape'`/`'backdrop'`/`'close-button'`; a
4280
4385
  consumer's own close affordance (e.g. a footer action button) should call it directly with its own
4281
4386
  reason string so every dismissal path funnels through the same event.
4282
4387
 
4283
- **Events:** `lyra-dialog-close` (`detail: ToolResultDialogCloseReason` — `'escape'|'backdrop'|
4388
+ **Events:** `lyra-close` (`detail: ToolResultDialogCloseReason` — `'escape'|'backdrop'|
4284
4389
  'close-button'|'api'|string`) fired exactly once per dismissal; `lyra-maximize-change` (`detail:
4285
4390
  boolean`, the new `maximized` state) fired when the header's maximize/restore toggle is clicked.
4286
4391
 
@@ -4295,7 +4400,8 @@ tool name/status/duration), `tool-name`, `status`, `duration`, `header-actions`,
4295
4400
  **Themeable custom properties:** `--lyra-tool-result-dialog-overlay-color` (default `rgb(0 0 0 /
4296
4401
  0.5)` — the backdrop scrim color; component-specific since no shared overlay token exists),
4297
4402
  `--lyra-tool-result-dialog-maximized-inset` (default `var(--lyra-space-l)` — inset applied to the
4298
- 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
4299
4405
  tokens `--lyra-color-surface/-border/-text-quiet/-brand/-brand-quiet/-success/-success-quiet/
4300
4406
  -danger/-danger-quiet/-warning/-warning-quiet`, `--lyra-space-*`, `--lyra-radius`, `--lyra-shadow`,
4301
4407
  `--lyra-icon-button-size`, `--lyra-focus-ring-*`, `--lyra-transition-base`.
@@ -4308,7 +4414,7 @@ tokens `--lyra-color-surface/-border/-text-quiet/-brand/-brand-quiet/-success/-s
4308
4414
  status="success"
4309
4415
  duration-ms="1240"
4310
4416
  ?open=${dialogOpen}
4311
- @lyra-dialog-close=${(e) => (dialogOpen = false)}
4417
+ @lyra-close=${(e) => (dialogOpen = false)}
4312
4418
  @lyra-maximize-change=${(e) => console.log('maximized:', e.detail)}
4313
4419
  >
4314
4420
  <lyra-tabs slot="body">
@@ -4339,7 +4445,7 @@ state, so no additional scroll-lock/focus-trap bookkeeping is needed for that tr
4339
4445
  panel template so a slotted `<lyra-tabs>` (or any other light-DOM-scanning child) sees real
4340
4446
  projected content rather than a forwarding `<slot>`, while still sharing the overlay stack
4341
4447
  - `close()` is a no-op when `open` is already `false` — calling it twice in a row only fires
4342
- `lyra-dialog-close` once
4448
+ `lyra-close` once
4343
4449
  - the `maximize`/`close` buttons are always the first elements in the Tab order while open,
4344
4450
  regardless of visual position, followed by `body` then `footer` content
4345
4451
 
@@ -4369,14 +4475,24 @@ reveals the invalid state, and `form.reset()` clears the touched presentation.
4369
4475
  built-in button's icon/label (send vs. stop) and whether Enter still submits
4370
4476
  - `submitOnEnter: boolean = true` (reflected, attribute `submit-on-enter`) — when `false`, Enter
4371
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
4372
4482
  - `spellcheck: boolean = true` — forwarded to the internal `<textarea>`
4373
4483
  - `autocapitalize: string = ''` — forwarded to the internal `<textarea>`; empty omits the attribute
4374
4484
  - `autoCorrect: string = ''` (attribute `autocorrect`) — forwarded to the internal `<textarea>`
4375
4485
  (Safari/WebKit-specific); empty omits the attribute. Named `autoCorrect`, not `autocorrect`, only
4376
4486
  to dodge a `lib.dom.d.ts` collision with `HTMLElement`'s own `boolean`-typed `autocorrect` IDL
4377
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
4378
4492
 
4379
- **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.
4380
4496
 
4381
4497
  **Events:**
4382
4498
  - `lyra-input` (`detail: { value }`) — fired on every user-driven edit of the textarea, not a
@@ -4491,12 +4607,12 @@ wins when both are present.
4491
4607
  attachment, leaving only the thumbnail. Has no effect for a non-image chip, or when `compact` is
4492
4608
  unset. `false` (the default) reproduces the chip's exact existing output.
4493
4609
  - `removeLabel: string = 'Remove'` (attribute `remove-label`) — verb used in the remove button's
4494
- `aria-label`, interpolated as `` `${removeLabel} ${displayName}` ``; override for i18n/locale
4610
+ accessible name; the default routes through the complete localized `removeWithContext` template
4495
4611
  - `retryLabel: string = 'Retry'` (attribute `retry-label`) — verb used in the retry button's
4496
- `aria-label`, interpolated as `` `${retryLabel} ${displayName}` ``; override for i18n/locale
4612
+ accessible name; the default routes through the complete localized attachment template
4497
4613
  - `uploadingLabel: string = 'Uploading'` (attribute `uploading-label`) — verb used in the visible
4498
- uploading status text, rendered as `` `${uploadingLabel} ${percent}%` `` once progress is a
4499
- 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
4500
4616
  - `uploadFailedLabel: string = 'Upload failed'` (attribute `upload-failed-label`) — visible status
4501
4617
  text shown for `status="error"`; override for i18n/locale
4502
4618
 
@@ -4521,7 +4637,8 @@ generated internal id is used as a last resort.
4521
4637
  `done` → success/success-quiet/transparent); `--lyra-attachment-chip-compact-thumbnail-size` (default
4522
4638
  `1.75rem`), `--lyra-attachment-chip-compact-font-size` (default `var(--lyra-font-size-xs)`),
4523
4639
  `--lyra-attachment-chip-compact-gap` (default `0.25rem`) — govern the chip's thumbnail size, text
4524
- 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`,
4525
4642
  `--lyra-radius`, `--lyra-color-text`, `--lyra-color-danger`, `--lyra-icon-button-size`,
4526
4643
  `--lyra-transition-fast`, `--lyra-transition-base`, `--lyra-focus-ring-width`,
4527
4644
  `--lyra-focus-ring-color`, `--lyra-focus-ring-offset`.
@@ -5282,7 +5399,8 @@ anything about `<lyra-source-card>`, it only carries the id through its event de
5282
5399
  echoed back verbatim in both events; never read or validated by this component.
5283
5400
  - `href: string = ''` — optional direct link target for the citation's source, carried into
5284
5401
  `lyra-citation-open`'s detail as-is; this component never navigates.
5285
- - `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.
5286
5404
 
5287
5405
  **Events:**
5288
5406
  - `lyra-citation-activate` (`detail: { sourceId: string; index: number }`) — fires on click, or on
@@ -5296,6 +5414,8 @@ anything about `<lyra-source-card>`, it only carries the id through its event de
5296
5414
  **Slots:** default — rich preview/tooltip content (e.g. a filename + excerpt), shown in a floating
5297
5415
  popover on hover/focus. This is *not* the badge's visible content (the badge always renders
5298
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.
5299
5419
 
5300
5420
  **CSS parts:** `base` (the clickable `<button>`), `bracket` (each of the two literal `[`/`]` glyphs),
5301
5421
  `index` (the citation number), `popover` (the floating preview panel, only meaningful while open).
@@ -5407,7 +5527,8 @@ while collapsed).
5407
5527
  expand/collapse, which only ever hides/shows the *set* of cards, never a single card's own content.
5408
5528
  - `lyra-open` (`detail: { sourceId: string; href?: string }`) — the title was activated. This
5409
5529
  component never navigates on its own (a controlled component, the same convention
5410
- `<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.
5411
5532
 
5412
5533
  **Slots:** `excerpt` (a short preview; when left empty, the `excerpt` part collapses away entirely —
5413
5534
  its wrapper is `hidden`, not just visually empty), `full` (the complete source text/chunk, hidden
@@ -6187,6 +6308,8 @@ and it's what every instance renders at zero extra bytes until shiki resolves.
6187
6308
  `"json"`); when unset, or when shiki doesn't recognize it, the code renders as plain unhighlighted
6188
6309
  text regardless of whether shiki itself is available
6189
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
6190
6313
  - `collapsible: boolean = false` (reflected) — shows the collapse/expand chevron button
6191
6314
  - `collapsed: boolean = false` (reflected) — only has a visible effect while `collapsible` is also
6192
6315
  true
@@ -6297,6 +6420,8 @@ toggle, the loading-skeleton behavior while the fine-grained highlighter resolve
6297
6420
  key in `languages`, the code renders as plain unhighlighted text — this component has no
6298
6421
  default/full-table highlighter to fall back to.
6299
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.
6300
6425
  - `collapsible: boolean = false` (reflected) — shows the collapse/expand chevron button.
6301
6426
  - `collapsed: boolean = false` (reflected) — only has a visible effect while `collapsible` is also
6302
6427
  true.
@@ -6866,9 +6991,9 @@ children are the chips (the same shape `<lyra-split>`'s panels / `<lyra-source-l
6866
6991
  no `.items` array prop).
6867
6992
 
6868
6993
  **Properties:**
6869
- - `maxVisible?: number` (attribute `max-visible`) — maximum number of direct children shown before
6870
- the rest collapse behind a "+N" indicator; unset (the default) means no limit, every child is
6871
- 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
6872
6997
 
6873
6998
  **Events:** `lyra-overflow-toggle` (`detail: { expanded }` — the overflow indicator was activated,
6874
6999
  revealing or re-collapsing the excess children; fires only from that click, i.e. only when
@@ -7027,6 +7152,9 @@ used" summary.
7027
7152
  - `label: string = ''` — overall accessible caption, e.g. `"128K context window"`. Also rendered
7028
7153
  visually (`[part="label"]`) when set.
7029
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
+
7030
7158
  **Events:** none.
7031
7159
 
7032
7160
  **Slots:** none.
@@ -7223,6 +7351,8 @@ fallback simply omits `[part="download-link"]` entirely.
7223
7351
  `<img>`/the anchor.
7224
7352
  - `mimeType: string = ''` (attribute `mime-type`) — drives format dispatch (see above).
7225
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.
7226
7356
  - `status: 'idle' | 'converting' | 'ready' | 'error' = 'idle'` (reflected) — host-owned lifecycle
7227
7357
  state. `"converting"` shows the spinner regardless of `mimeType`/`src`; `"error"` shows
7228
7358
  `errorMessage` regardless of either. `"idle"`/`"ready"` both resume normal format dispatch — a host
@@ -7257,8 +7387,8 @@ above; excludes `data:` even though the other two sinks allow it)
7257
7387
  **Themeable custom properties:** `--lyra-document-preview-max-height` (default `none`) — the
7258
7388
  consumer-tunable scroll cap on `[part="body"]`, set from `max-height`; `none` means the preview grows
7259
7389
  with its content until a caller opts in. `--lyra-document-preview-font` (default `ui-monospace,
7260
- SFMono-Regular, Menlo, Consolas, monospace`) no shared `--wa-*`/`--lyra-*` monospace token exists yet
7261
- (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
7262
7392
  `--lyra-color-border`, `--lyra-radius`, `--lyra-color-surface`, `--lyra-space-s/-m/-l/-xs`,
7263
7393
  `--lyra-color-text`, `--lyra-color-text-quiet`, `--lyra-color-danger`, `--lyra-color-brand`,
7264
7394
  `--lyra-color-on-brand`, `--lyra-focus-ring-width/-color/-offset`, `--lyra-transition-fast`.
@@ -7299,6 +7429,8 @@ available, the region becomes a standard `role="progressbar"` instead, self-desc
7299
7429
  - The component's own text/JSON `fetch(src)` is a *different* async operation from the host-driven
7300
7430
  `status="converting"` conversion. A failed fetch fires `lyra-render-error` and renders
7301
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.
7302
7434
  - `progress` is only ever consulted for the host-driven `"converting"` state — this component's own
7303
7435
  in-flight text fetch always renders the indeterminate spinner, with no numeric-progress path.
7304
7436
  - The `unsupported` slot's initial presence is detected once, before the first render, by scanning
@@ -7335,6 +7467,8 @@ final.
7335
7467
  filename, and folded into the accessible name.
7336
7468
  - `alt: string = ''` — alt text for the image case (and reused as a video label fallback). Falls
7337
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
7338
7472
  - `maxHeight: string = ''` (attribute `max-height`) — a CSS length (e.g. `"16rem"`); once set,
7339
7473
  overrides the `--lyra-media-card-max-height` custom property for this instance only (applied
7340
7474
  inline on `[part="base"]`, so it reliably wins over a `:host{}`-declared default from outside the
@@ -7633,6 +7767,8 @@ user-menu affordance.
7633
7767
  - `src?: string` — image URL; takes priority over `initials` when set and loads successfully, falling
7634
7768
  back to `initials` on a load error.
7635
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
7636
7772
  - `size: 'sm' | 'md' | 'lg' = 'md'` (reflected).
7637
7773
  - `shape: 'circle' | 'square' = 'circle'` (reflected).
7638
7774
  - `tone: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral'` (reflected) — recolors
@@ -7661,13 +7797,10 @@ var(--lyra-color-border))`, swapped per `tone`), `--lyra-avatar-color` (default
7661
7797
  ```
7662
7798
 
7663
7799
  **Known gotchas:**
7664
- - an image load failure falls back to `initials` automatically (an `error` listener flips internal
7665
- state) there's no manual reset/retry method; reassigning `src` (even to the same value)
7666
- re-attempts the load.
7667
- - the initials fallback is `aria-hidden="true"` whenever `alt` is set, regardless of whether an image
7668
- is actually showing — so if `src`/`alt` are both set but the image fails to load, the rendered
7669
- initials text is still hidden from assistive tech, leaving the avatar with no accessible name of
7670
- 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.
7671
7804
 
7672
7805
  ---
7673
7806