@aceshooting/lyra-ui 16.0.0 → 17.0.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 (296) hide show
  1. package/CHANGELOG.md +504 -0
  2. package/custom-elements.json +1 -1
  3. package/dist/cli/migration-contract.json +1 -1
  4. package/dist/components/agent-tools/browser-frame/browser-frame.class.d.ts +3 -3
  5. package/dist/components/agent-tools/browser-frame/browser-frame.class.js +2 -2
  6. package/dist/components/agent-tools/compare-panel/compare-panel.class.d.ts +2 -2
  7. package/dist/components/agent-tools/compare-panel/compare-panel.class.js +3 -3
  8. package/dist/components/agent-tools/confirm-bar/confirm-bar.class.d.ts +37 -13
  9. package/dist/components/agent-tools/confirm-bar/confirm-bar.class.js +2 -2
  10. package/dist/components/agent-tools/task-list/task-list.class.js +2 -2
  11. package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.d.ts +4 -0
  12. package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.js +2 -2
  13. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.d.ts +3 -3
  14. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.js +1 -1
  15. package/dist/components/charts/chart/chart.class.d.ts +117 -17
  16. package/dist/components/charts/chart/chart.class.js +3 -3
  17. package/dist/components/charts/chart/histogram-bin.d.ts +5 -1
  18. package/dist/components/charts/chart/histogram-bin.js +1 -1
  19. package/dist/components/charts/chart/lite-chart.class.d.ts +9 -0
  20. package/dist/components/conversation/code-block/code-block.styles.js +1 -1
  21. package/dist/components/conversation/message-actions/message-actions.styles.js +1 -1
  22. package/dist/components/conversation/model-select/model-select.class.d.ts +13 -4
  23. package/dist/components/conversation/model-select/model-select.class.js +2 -1
  24. package/dist/components/conversation/model-select/model-select.styles.js +1 -1
  25. package/dist/components/conversation/streaming-text/streaming-text-base.class.d.ts +40 -2
  26. package/dist/components/conversation/streaming-text/streaming-text-base.class.js +2 -2
  27. package/dist/components/conversation/streaming-text/streaming-text-core.class.d.ts +5 -3
  28. package/dist/components/conversation/streaming-text/streaming-text-core.class.js +10 -0
  29. package/dist/components/conversation/streaming-text/streaming-text.class.d.ts +9 -3
  30. package/dist/components/conversation/streaming-text/streaming-text.class.js +10 -0
  31. package/dist/components/conversation/suggestion-chips/suggestion-chips.class.d.ts +30 -2
  32. package/dist/components/conversation/suggestion-chips/suggestion-chips.class.js +4 -3
  33. package/dist/components/conversation/suggestion-chips/suggestion-chips.styles.js +1 -1
  34. package/dist/components/conversation/transcript-feed/transcript-feed.class.js +1 -1
  35. package/dist/components/conversation/usage-badge/usage-badge-overlay-runtime.js +1 -1
  36. package/dist/components/conversation/usage-badge/usage-badge.class.d.ts +4 -0
  37. package/dist/components/conversation/voice-picker/voice-picker.class.d.ts +16 -4
  38. package/dist/components/conversation/voice-picker/voice-picker.class.js +2 -1
  39. package/dist/components/conversation/voice-picker/voice-picker.styles.js +1 -1
  40. package/dist/components/data/context-meter/context-meter.class.d.ts +23 -4
  41. package/dist/components/data/context-meter/context-meter.class.js +10 -7
  42. package/dist/components/data/context-meter/context-meter.styles.js +1 -1
  43. package/dist/components/data/data-grid/data-grid.class.d.ts +5 -2
  44. package/dist/components/data/data-grid/data-grid.class.js +1 -1
  45. package/dist/components/data/flow-canvas/flow-canvas.class.d.ts +32 -5
  46. package/dist/components/data/flow-canvas/flow-canvas.class.js +3 -1
  47. package/dist/components/data/flow-canvas/flow-canvas.styles.js +1 -1
  48. package/dist/components/data/flow-canvas/flow-model.js +1 -1
  49. package/dist/components/data/flow-canvas/flow-types.d.ts +10 -1
  50. package/dist/components/data/gauge/gauge.class.d.ts +15 -2
  51. package/dist/components/data/gauge/gauge.class.js +20 -20
  52. package/dist/components/data/gauge/gauge.styles.js +1 -1
  53. package/dist/components/data/graph-query-builder/graph-query-builder.class.d.ts +14 -5
  54. package/dist/components/data/graph-query-builder/graph-query-builder.class.js +2 -2
  55. package/dist/components/data/sequence-strip/sequence-strip.class.d.ts +28 -2
  56. package/dist/components/data/sequence-strip/sequence-strip.class.js +3 -2
  57. package/dist/components/data/sequence-strip/sequence-strip.styles.js +1 -1
  58. package/dist/components/data/table/table.class.d.ts +155 -30
  59. package/dist/components/data/table/table.class.js +6 -4
  60. package/dist/components/data/table/table.styles.js +1 -1
  61. package/dist/components/data/timeline/timeline-item.class.d.ts +9 -1
  62. package/dist/components/data/timeline/timeline-item.class.js +2 -2
  63. package/dist/components/data/word-cloud/word-cloud.class.js +1 -1
  64. package/dist/components/data/word-cloud/word-cloud.styles.js +1 -1
  65. package/dist/components/forms/button/button.class.d.ts +30 -1
  66. package/dist/components/forms/button/button.class.js +2 -2
  67. package/dist/components/forms/checkbox/checkbox.class.d.ts +8 -6
  68. package/dist/components/forms/checkbox/checkbox.class.js +2 -2
  69. package/dist/components/forms/checkbox-group/checkbox-group.class.d.ts +7 -5
  70. package/dist/components/forms/checkbox-group/checkbox-group.class.js +1 -1
  71. package/dist/components/forms/color-picker/color-picker.class.d.ts +16 -2
  72. package/dist/components/forms/color-picker/color-picker.class.js +2 -2
  73. package/dist/components/forms/color-picker/color-picker.styles.js +1 -1
  74. package/dist/components/forms/combobox/combobox.class.d.ts +43 -8
  75. package/dist/components/forms/combobox/combobox.class.js +2 -2
  76. package/dist/components/forms/date-picker/date-input.class.d.ts +4 -0
  77. package/dist/components/forms/date-picker/date-input.class.js +1 -1
  78. package/dist/components/forms/icon-button/icon-button.class.d.ts +20 -3
  79. package/dist/components/forms/icon-button/icon-button.class.js +1 -1
  80. package/dist/components/forms/icon-button/icon-button.styles.js +1 -1
  81. package/dist/components/forms/input/input.class.d.ts +5 -2
  82. package/dist/components/forms/input/input.class.js +1 -1
  83. package/dist/components/forms/input/time-input.class.d.ts +4 -0
  84. package/dist/components/forms/input/time-input.class.js +1 -1
  85. package/dist/components/forms/locale-picker/locale-picker.class.d.ts +11 -5
  86. package/dist/components/forms/locale-picker/locale-picker.class.js +1 -1
  87. package/dist/components/forms/otp-input/otp-input.class.d.ts +7 -2
  88. package/dist/components/forms/otp-input/otp-input.class.js +2 -2
  89. package/dist/components/forms/radio/radio-button.class.d.ts +2 -1
  90. package/dist/components/forms/radio/radio-group.class.d.ts +9 -4
  91. package/dist/components/forms/radio/radio-group.class.js +1 -1
  92. package/dist/components/forms/radio/radio.class.d.ts +13 -7
  93. package/dist/components/forms/radio/radio.class.js +1 -1
  94. package/dist/components/forms/rubric-form/rubric-form.class.d.ts +16 -6
  95. package/dist/components/forms/rubric-form/rubric-form.class.js +2 -2
  96. package/dist/components/forms/select/select.class.d.ts +19 -8
  97. package/dist/components/forms/select/select.class.js +2 -2
  98. package/dist/components/forms/slider/slider.class.d.ts +4 -2
  99. package/dist/components/forms/slider/slider.class.js +1 -1
  100. package/dist/components/forms/switch/switch.class.d.ts +8 -6
  101. package/dist/components/forms/switch/switch.class.js +1 -1
  102. package/dist/components/forms/textarea/textarea.class.d.ts +5 -3
  103. package/dist/components/forms/textarea/textarea.class.js +1 -1
  104. package/dist/components/forms/time-range/time-range.class.d.ts +12 -7
  105. package/dist/components/forms/time-range/time-range.class.js +1 -1
  106. package/dist/components/forms/time-range/time-range.styles.js +1 -1
  107. package/dist/components/forms/token-input/token-input.class.d.ts +6 -4
  108. package/dist/components/forms/token-input/token-input.class.js +1 -1
  109. package/dist/components/layout/app-rail/app-rail-item.class.d.ts +109 -4
  110. package/dist/components/layout/app-rail/app-rail-item.class.js +34 -29
  111. package/dist/components/layout/app-rail/app-rail-item.styles.js +1 -1
  112. package/dist/components/layout/app-rail/app-rail.class.d.ts +25 -3
  113. package/dist/components/layout/app-rail/app-rail.styles.js +1 -1
  114. package/dist/components/layout/app-rail-group/app-rail-group.class.d.ts +2 -2
  115. package/dist/components/layout/app-rail-group/app-rail-group.class.js +2 -2
  116. package/dist/components/layout/carousel/carousel.class.d.ts +1 -1
  117. package/dist/components/layout/carousel/carousel.class.js +1 -1
  118. package/dist/components/layout/details/accordion.class.d.ts +2 -2
  119. package/dist/components/layout/details/accordion.class.js +2 -2
  120. package/dist/components/layout/filter-bar/filter-bar-register.d.ts +1 -0
  121. package/dist/components/layout/filter-bar/filter-bar-register.js +1 -0
  122. package/dist/components/layout/filter-bar/filter-bar.class.d.ts +85 -10
  123. package/dist/components/layout/filter-bar/filter-bar.class.js +7 -4
  124. package/dist/components/layout/menu/menu-item.class.d.ts +3 -3
  125. package/dist/components/layout/menu/menu-item.class.js +3 -3
  126. package/dist/components/layout/menu/menu.class.d.ts +5 -1
  127. package/dist/components/layout/menu/menu.class.js +2 -2
  128. package/dist/components/layout/reorder-list/reorder-item.styles.js +1 -1
  129. package/dist/components/layout/virtual-list/virtual-list.class.js +1 -1
  130. package/dist/components/media/attachment-trigger/attachment-trigger.styles.js +1 -1
  131. package/dist/components/media/avatar-group/avatar-group.class.d.ts +12 -1
  132. package/dist/components/media/avatar-group/avatar-group.class.js +2 -2
  133. package/dist/components/media/drop-zone/drop-zone.class.d.ts +32 -11
  134. package/dist/components/media/drop-zone/drop-zone.class.js +2 -2
  135. package/dist/components/media/file-input/file-input.class.d.ts +40 -19
  136. package/dist/components/media/file-input/file-input.class.js +2 -2
  137. package/dist/components/overlays/callout/callout.styles.js +1 -1
  138. package/dist/components/overlays/dialog/dialog.styles.js +1 -1
  139. package/dist/components/overlays/overlay/dropdown.class.d.ts +13 -3
  140. package/dist/components/overlays/overlay/dropdown.class.js +2 -2
  141. package/dist/components/overlays/overlay/popover.class.d.ts +12 -3
  142. package/dist/components/overlays/overlay/popover.class.js +2 -2
  143. package/dist/components/overlays/rating/rating.class.d.ts +9 -7
  144. package/dist/components/overlays/rating/rating.class.js +1 -1
  145. package/dist/components/retrieval/citation-badge/citation-badge.class.d.ts +5 -1
  146. package/dist/components/retrieval/citation-badge/citation-badge.class.js +1 -1
  147. package/dist/components/retrieval/embedding-explorer/embedding-explorer.styles.js +1 -1
  148. package/dist/components/retrieval/entity-chip/entity-chip.class.d.ts +5 -1
  149. package/dist/components/retrieval/entity-chip/entity-chip.class.js +1 -1
  150. package/dist/components/retrieval/graph-legend/graph-legend.styles.js +1 -1
  151. package/dist/components/retrieval/retrieval-value-format.js +1 -1
  152. package/dist/components/retrieval/source-list/source-list.styles.js +1 -1
  153. package/dist/components/utility/copy-button/copy-button.class.d.ts +23 -11
  154. package/dist/components/utility/copy-button/copy-button.class.js +2 -2
  155. package/dist/components/utility/copy-button/copy-button.styles.js +1 -1
  156. package/dist/components/utility/diff-view/diff-view.styles.js +1 -1
  157. package/dist/components/utility/export-button/export-button.class.d.ts +4 -0
  158. package/dist/components/utility/export-button/export-button.class.js +1 -1
  159. package/dist/components/utility/json-viewer/json-viewer.styles.js +1 -1
  160. package/dist/components/utility/known-date/known-date.class.js +1 -1
  161. package/dist/components/utility/mention-popover/mention-popover.class.d.ts +38 -3
  162. package/dist/components/utility/mention-popover/mention-popover.class.js +2 -1
  163. package/dist/components/utility/mention-popover/mention-popover.styles.js +1 -1
  164. package/dist/components/utility/poll-status/poll-status.styles.js +1 -1
  165. package/dist/components/utility/tour/tour.class.d.ts +4 -0
  166. package/dist/components/utility/tour/tour.class.js +1 -1
  167. package/dist/components/utility/tour/tour.styles.js +1 -1
  168. package/dist/components/viewers/document-preview/document-preview.class.js +2 -2
  169. package/dist/components/viewers/docx-viewer/docx-viewer.class.js +2 -2
  170. package/dist/components/viewers/ebook-viewer/ebook-viewer.class.js +2 -2
  171. package/dist/components/viewers/highlight-layer/highlight-layer.class.js +2 -2
  172. package/dist/components/viewers/notebook-viewer/notebook-viewer.class.js +2 -2
  173. package/dist/components/viewers/pdf-viewer/pdf-viewer.class.js +2 -2
  174. package/dist/components/viewers/pptx-viewer/pptx-viewer.class.js +2 -2
  175. package/dist/components/viewers/xml-viewer/xml-viewer.class.js +2 -2
  176. package/dist/custom-elements-jsx.d.ts +2 -2
  177. package/dist/events.d.ts +13 -12
  178. package/dist/internal/aggregate-file-limits.d.ts +33 -0
  179. package/dist/internal/aggregate-file-limits.js +1 -0
  180. package/dist/internal/catalog-picker.d.ts +15 -2
  181. package/dist/internal/catalog-picker.js +1 -1
  182. package/dist/internal/debounce-controller.d.ts +14 -0
  183. package/dist/internal/debounce-controller.js +1 -1
  184. package/dist/internal/default-strings.generated.d.ts +1 -1
  185. package/dist/internal/default-strings.generated.js +2 -2
  186. package/dist/internal/focus-navigation.d.ts +45 -0
  187. package/dist/internal/focus-navigation.js +1 -1
  188. package/dist/internal/form-associated.js +1 -1
  189. package/dist/internal/initial-slot-collection.d.ts +30 -0
  190. package/dist/internal/initial-slot-collection.js +1 -0
  191. package/dist/internal/intl-cache.js +1 -1
  192. package/dist/internal/invalid-event-alias.d.ts +46 -0
  193. package/dist/internal/invalid-event-alias.js +1 -1
  194. package/dist/internal/localization-runtime.d.ts +24 -0
  195. package/dist/internal/localization-runtime.js +1 -1
  196. package/dist/internal/localization-types.d.ts +1 -1
  197. package/dist/internal/localization.js +1 -1
  198. package/dist/internal/package-metadata.d.ts +1 -1
  199. package/dist/internal/package-metadata.js +1 -1
  200. package/dist/internal/positioning-strategy.d.ts +3 -1
  201. package/dist/internal/state-part.d.ts +49 -0
  202. package/dist/internal/state-part.js +1 -0
  203. package/dist/internal/variants.styles.js +1 -1
  204. package/dist/lyra.d.ts +1 -1
  205. package/dist/svelte.d.ts +2 -2
  206. package/dist/testing/index.d.ts +1 -1
  207. package/dist/testing/index.js +1 -1
  208. package/dist/testing/lyra-tag-event-map.d.ts +2 -2
  209. package/dist/testing/lyra-tag-event-map.js +1 -1
  210. package/dist/testing/wait-for-mount.d.ts +46 -0
  211. package/dist/testing/wait-for-mount.js +1 -0
  212. package/dist/theme/theme-bootstrap.js +1 -1
  213. package/dist/theme/theme.d.ts +11 -2
  214. package/dist/theme/theme.js +1 -1
  215. package/dist/translations/ar/layout.js +1 -1
  216. package/dist/translations/de/layout.js +1 -1
  217. package/dist/translations/es/layout.js +1 -1
  218. package/dist/translations/fa/layout.js +1 -1
  219. package/dist/translations/fr/layout.js +1 -1
  220. package/dist/translations/he/layout.js +1 -1
  221. package/dist/translations/it/layout.js +1 -1
  222. package/dist/translations/ja/layout.js +1 -1
  223. package/dist/translations/pt-BR/layout.js +1 -1
  224. package/dist/translations/ru/layout.js +1 -1
  225. package/dist/translations/zh-CN/layout.js +1 -1
  226. package/dist/utilities/format.d.ts +17 -0
  227. package/dist/utilities/format.js +1 -1
  228. package/dist/vue.d.ts +2 -2
  229. package/llms/components/lr-app-rail-group.md +87 -10
  230. package/llms/components/lr-app-rail-item.md +88 -11
  231. package/llms/components/lr-app-rail.md +88 -11
  232. package/llms/components/lr-attachment-trigger.md +21 -0
  233. package/llms/components/lr-bar-chart.md +3 -2
  234. package/llms/components/lr-bubble-chart.md +3 -2
  235. package/llms/components/lr-callout.md +10 -0
  236. package/llms/components/lr-chart.md +43 -12
  237. package/llms/components/lr-citation-badge.md +7 -1
  238. package/llms/components/lr-code-block.md +21 -0
  239. package/llms/components/lr-color-picker.md +12 -7
  240. package/llms/components/lr-combobox.md +13 -1
  241. package/llms/components/lr-confirm-bar.md +36 -7
  242. package/llms/components/lr-context-meter.md +17 -4
  243. package/llms/components/lr-date-input.md +7 -1
  244. package/llms/components/lr-date-picker.md +6 -0
  245. package/llms/components/lr-dialog.md +21 -0
  246. package/llms/components/lr-doughnut-chart.md +3 -2
  247. package/llms/components/lr-drawer.md +10 -0
  248. package/llms/components/lr-drop-zone.md +16 -7
  249. package/llms/components/lr-dropdown-item.md +7 -0
  250. package/llms/components/lr-entity-chip.md +7 -1
  251. package/llms/components/lr-export-button.md +7 -1
  252. package/llms/components/lr-file-input.md +21 -10
  253. package/llms/components/lr-filter-bar.md +91 -15
  254. package/llms/components/lr-flow-canvas.md +16 -9
  255. package/llms/components/lr-gauge.md +22 -2
  256. package/llms/components/lr-histogram.md +7 -2
  257. package/llms/components/lr-icon-button.md +15 -7
  258. package/llms/components/lr-input.md +3 -1
  259. package/llms/components/lr-line-chart.md +3 -2
  260. package/llms/components/lr-lite-chart.md +13 -0
  261. package/llms/components/lr-locale-picker.md +7 -1
  262. package/llms/components/lr-mention-popover.md +16 -3
  263. package/llms/components/lr-menu-item.md +7 -0
  264. package/llms/components/lr-menu.md +8 -1
  265. package/llms/components/lr-message-actions.md +10 -0
  266. package/llms/components/lr-model-select.md +8 -3
  267. package/llms/components/lr-native-time-input.md +8 -1
  268. package/llms/components/lr-number-input.md +8 -1
  269. package/llms/components/lr-option.md +12 -0
  270. package/llms/components/lr-otp-input.md +6 -0
  271. package/llms/components/lr-pie-chart.md +3 -2
  272. package/llms/components/lr-polar-area-chart.md +3 -2
  273. package/llms/components/lr-prompt-input.md +2 -2
  274. package/llms/components/lr-radar-chart.md +3 -2
  275. package/llms/components/lr-reorder-item.md +12 -0
  276. package/llms/components/lr-reorder-list.md +12 -0
  277. package/llms/components/lr-scatter-chart.md +3 -2
  278. package/llms/components/lr-sequence-strip.md +10 -4
  279. package/llms/components/lr-streaming-text-core.md +21 -8
  280. package/llms/components/lr-streaming-text.md +34 -4
  281. package/llms/components/lr-suggestion-chips.md +8 -4
  282. package/llms/components/lr-table.md +47 -10
  283. package/llms/components/lr-textarea.md +1 -1
  284. package/llms/components/lr-time-input.md +7 -1
  285. package/llms/components/lr-tool-call-chip.md +7 -1
  286. package/llms/components/lr-tour.md +7 -1
  287. package/llms/components/lr-usage-badge.md +7 -1
  288. package/llms/components/lr-voice-picker.md +7 -3
  289. package/llms/shared.md +169 -16
  290. package/llms/tokens.md +17 -1
  291. package/llms-full.txt +941 -147
  292. package/package.json +16 -2
  293. package/registrations.json +1 -1
  294. package/vscode-css-data.json +1 -1
  295. package/vscode-html-data.json +1 -1
  296. package/web-types.json +1 -1
package/llms-full.txt CHANGED
@@ -229,8 +229,9 @@ The entry points, then:
229
229
  `@aceshooting/lyra-ui/translations/<locale>.js` (the eleven shipped message catalogs),
230
230
  `@aceshooting/lyra-ui/events` (the global typed-event map — types only, no runtime),
231
231
  `@aceshooting/lyra-ui/ai` (provider-neutral data types), `@aceshooting/lyra-ui/testing`
232
- (happy-dom shims, `createLyraEvent()` for building a validated test event, plus a small set of
233
- interaction drivers that go through a component's own real activation path),
232
+ (happy-dom shims, `createLyraEvent()` for building a validated test event, a small set of
233
+ interaction drivers that go through a component's own real activation path, and
234
+ `waitForLyraElement()`/`waitForToast()` for awaiting a lazily registered mount),
234
235
  `@aceshooting/lyra-ui/utilities/*` (the curated shared helpers, all documented below).
235
236
 
236
237
  ### Registration-free component helpers
@@ -1418,9 +1419,50 @@ per-response nonce — a static HTML entry, for example — where the documented
1418
1419
  nonce/hash guidance above does not apply. Serving it same-origin (copy it into your build output,
1419
1420
  or configure your bundler/static host to do so) needs no hash at all; hashing it for an even
1420
1421
  stricter policy uses the same CSP `script-src` hash mechanism browsers already apply to any
1421
- external script resource. It only ever carries the default storage key (`'lyra-theme'`) — an
1422
- application-owned key from `createLyraThemeBootstrap({ storageKey })` still has to be inlined,
1423
- since a static file cannot take a call-time argument.
1422
+ external script resource.
1423
+
1424
+ **Configuring the static asset from its own `<script>` tag.** `theme-bootstrap.js` must be loaded
1425
+ as a plain classic script — never `type="module"` and never `async` — because it reads its own
1426
+ configuration synchronously through `document.currentScript` while it runs, and that property is
1427
+ `null` for both of those loading modes (as well as for anything scheduled after the script has
1428
+ already finished executing). Two optional attributes on that same `<script>` tag override the
1429
+ defaults without regenerating the file:
1430
+
1431
+ ```html
1432
+ <head>
1433
+ <script
1434
+ src="/vendor/theme-bootstrap.js"
1435
+ data-lr-theme-storage-key="my-app-theme"
1436
+ data-lr-theme-attributes="data-lr-theme data-theme"
1437
+ ></script>
1438
+ <link rel="stylesheet" href="/theme.css" />
1439
+ </head>
1440
+ ```
1441
+
1442
+ - `data-lr-theme-storage-key` — the `localStorage` key to read, in place of the default
1443
+ `'lyra-theme'`. Equivalent to `createLyraThemeBootstrap({ storageKey })`'s argument, but
1444
+ resolved by the static file itself at parse time rather than baked in ahead of time. This is
1445
+ what lets an application with its own pre-existing storage key use the static asset instead of
1446
+ inlining a per-app copy.
1447
+ - `data-lr-theme-attributes` — a space-separated list of attribute names to set on
1448
+ `<html>` in place of the default `data-lr-theme data-theme` pair, replacing that list entirely
1449
+ rather than adding to it.
1450
+
1451
+ Both attributes are optional and independently validated; an absent, empty, oversized, or
1452
+ malformed value falls back to the built-in default rather than throwing, so a `<script>` tag with
1453
+ neither attribute — every existing deployment — behaves exactly as before. `data-lr-theme-storage-key`
1454
+ must be a non-empty string of at most 200 characters (its content is otherwise unrestricted — it is
1455
+ only ever used as an opaque `localStorage` key, never written to the DOM). `data-lr-theme-attributes`
1456
+ must parse to one to eight tokens, each unique and each matching `data-[a-z0-9]+(-[a-z0-9]+)*` —
1457
+ which rejects an event-handler name (`onload`), a native attribute (`style`, `class`, `id`), any
1458
+ token containing whitespace, a quote, `=`, or a control character, an empty list, and a duplicated
1459
+ token — because these attribute names reach `setAttribute()`/`removeAttribute()` on the document
1460
+ root. A `document.currentScript` of `null` (module/async misuse, or a script tag re-read after it
1461
+ finished running) is treated the same as no configuration at all.
1462
+
1463
+ An application-owned key from `createLyraThemeBootstrap({ storageKey })` can still be inlined as
1464
+ documented above; the static file's own script-tag attributes are the alternative for a strict-CSP
1465
+ deployment that cannot inline that call.
1424
1466
 
1425
1467
  **Migrating from 15.x.** `accent` used to be exactly an absolute CSS color or `null`; that shape
1426
1468
  still works unchanged (`setLyraTheme({ accent: '#7c3aed' })` keeps deriving only the brand ramp).
@@ -2162,6 +2204,83 @@ happy-dom/jsdom environment, not only a real browser.
2162
2204
  Scope: one driver per interaction named above. Not a general "drive any component" toolkit —
2163
2205
  render the real component and interact with it directly for anything else.
2164
2206
 
2207
+ ## Awaiting a lazily registered mount: `waitForLyraElement()` and `waitForToast()`
2208
+
2209
+ An imperative API can register its elements lazily -- `toast()` dynamically `import()`s
2210
+ `<lr-toast>`/`<lr-toast-item>` on first call (a deliberate bundle-size trade: importing the package
2211
+ root, or even `toast()` itself, never pulls the element classes into an eagerly loaded bundle). A
2212
+ fire-and-forget `toast(...)` call -- the normal application pattern, since a component should not
2213
+ block its own flow on a toast -- therefore leaves the document empty for at least one microtask
2214
+ after the call returns. `@aceshooting/lyra-ui/testing` exports `waitForLyraElement()` for this shape
2215
+ in general, plus `waitForToast()` as the named convenience for `toast()` specifically:
2216
+
2217
+ ```ts
2218
+ import { waitForToast } from '@aceshooting/lyra-ui/testing';
2219
+
2220
+ toast('Saved'); // fire-and-forget; toast.class.js/toast-item.class.js may still be importing
2221
+ const item = await waitForToast('Saved'); // resolves once a matching <lr-toast-item> mounts
2222
+ expect(item.textContent?.trim()).to.equal('Saved');
2223
+ ```
2224
+
2225
+ `waitForToast(match?, options?)` resolves once a `<lr-toast-item>` is connected and upgraded. A
2226
+ string `match` compares against the item's trimmed `textContent` (what `toast('Saved')` sets
2227
+ verbatim); pass a predicate — `(item: LyraToastItem) => boolean` — for anything else (a substring,
2228
+ an icon/action check, a specific variant); omitting `match` resolves the first toast item to mount.
2229
+
2230
+ The underlying `waitForLyraElement<T>(selector, options?)` is generic over any element reachable
2231
+ from `options.root` (`document` by default): it resolves once an element matching `selector` is
2232
+ both connected and upgraded — registered with a constructor the element is actually an instance of
2233
+ — filtered further by an optional `options.match: (element: T) => boolean`. An element already
2234
+ present in markup before its class registers (the SSR/hydration case) is not a match until it
2235
+ upgrades. Both resolve via `MutationObserver` (new elements arriving) and
2236
+ `customElements.whenDefined()` (an already-connected-but-undefined element finishing registration)
2237
+ rather than polling on a timer, and both reject with an Error describing the selector, the timeout,
2238
+ and how many non-matching candidates were found — after a bounded `options.timeoutMs` (2000ms
2239
+ default). Every underlying API is standard DOM/HTML with no `@web/test-runner`/CDP dependency, so
2240
+ both also run under a downstream suite's own happy-dom environment, not only a real browser.
2241
+
2242
+ Scope: awaiting a lazy mount reachable from a root you already have a handle to. Not a replacement
2243
+ for `updateComplete` (a mounted element may still have a pending render) or for the interaction
2244
+ drivers above (already-mounted components' own activation paths). `toast()` is currently the only
2245
+ imperative `lyra-ui` API that registers its elements through a dynamic `import()`; `confirm()`
2246
+ registers `<lr-dialog>` synchronously (a static import plus an idempotent `defineElement()` call) and
2247
+ mounts its transient dialog before returning, so it has no equivalent gap.
2248
+
2249
+ ## happy-dom's custom-property resolver and host-to-part token forwarding
2250
+
2251
+ In 16.0.0, seven built-in controls that each compose a real
2252
+ `<lr-icon-button>` for their icon-only action — `<lr-copy-button>`, `<lr-dialog>` (whose close
2253
+ button is inherited by `<lr-drawer>`), `<lr-reorder-item>`, `<lr-message-actions>`,
2254
+ `<lr-attachment-trigger>`, `<lr-code-block>` (shared by `<lr-code-block-core>`), and `<lr-callout>`
2255
+ — captured the composed control's public `--lr-icon-button-*` tokens on their own `:host` and
2256
+ forwarded that private token back onto the SAME public token name on the `[part]` rendering the
2257
+ composed control, so that an ancestor theme override still reached the composed child instead of
2258
+ being shadowed by the component's own default. That was legal under the CSS Custom Properties spec
2259
+ — `:host` and `[part]` resolve on different elements, so a real browser resolves the host
2260
+ declaration to a concrete value first and the part substitutes that, and per-element cycle detection
2261
+ never fired — but **happy-dom does not model that element boundary**. Its `CSSComputedStyle` merges
2262
+ ancestor and own-element custom properties into a single flat map with no notion of which element
2263
+ declared what, and (at least through 20.14.5, the newest release at time of writing)
2264
+ `CSSVariableFormatter.resolveVariables` substitutes into that map recursively with no visited set
2265
+ and no depth cap — so the capture-and-forward pair resolved into each other forever, throwing an
2266
+ unhandled `RangeError: Maximum call stack size exceeded` from `CSSVariableFormatter.resolveVariables`
2267
+ on every render of any of the seven components. Every test still reported as passing — there was no
2268
+ failing assertion to point at — but the runner counted the unhandled errors and exited non-zero
2269
+ anyway, which read as unrelated flakiness rather than a CSS issue.
2270
+
2271
+ **Current versions are unaffected.** `<lr-icon-button>` now carries a private
2272
+ `--_lr-icon-button-<token>-default` fallback tier for every paint token (background, color, border,
2273
+ and their hover/active variants — the same shape its corner radius already used via
2274
+ `--_lr-icon-button-radius-default`), and each composing component sets its own default directly on
2275
+ that private tier rather than re-declaring the public token name. `<lr-icon-button>`'s own
2276
+ stylesheet still checks the public token first, so an ancestor override reaches a composed control
2277
+ exactly as before, but no descendant declares a public `--lr-icon-button-*` token from a private
2278
+ token that was itself derived from that same public token — so no resolver, scoped or flattened,
2279
+ ever sees a cycle. A project still hitting the `RangeError` above should upgrade
2280
+ `@aceshooting/lyra-ui`; the workarounds that version range needed (patching or upgrading the DOM
2281
+ implementation to cycle-aware/depth-limited custom-property resolution, or running the affected
2282
+ suites against a real browser engine) are no longer necessary once it does.
2283
+
2165
2284
  ## Accessibility contract
2166
2285
 
2167
2286
  Semantic roles live on the shadow-DOM element that owns them, with explicit false states for
@@ -2213,18 +2332,36 @@ those four kinds must walk the declaration's own `superclass.name`/`superclass.m
2213
2332
  `modules[].declarations[]` itself, or read `web-types.json`/`vscode-html-data.json` instead, which
2214
2333
  are already fully resolved.
2215
2334
 
2216
- **Which tags a per-tag entry registers (`registrations.json`).** A stable per-tag entry
2217
- (`@aceshooting/lyra-ui/components/lr-<name>.js`) can, at import time, define more than one custom
2218
- element: importing `lr-table.js` also registers `<lr-empty>`, `<lr-pagination>`, `<lr-skeleton>` and
2219
- `<lr-spinner>`, because `lr-table`'s registration entry imports those composed children's own
2220
- registration entries before defining `<lr-table>` itself. `custom-elements.json` declares one
2221
- custom element per family source module, with no field for a stable per-tag entry specifier and
2222
- none for the extra tags importing it registers as a side effect. For that, read the generated
2223
- `@aceshooting/lyra-ui/registrations.json` instead: `{ schemaVersion: 1, entries: [{ tag, entry,
2224
- registrationModule, registers }] }`, where `registers` is every `lr-*` tag importing `entry`
2225
- defines, derived from the same transitive-import analysis
2335
+ **Which tags an entry registers, and which message keys it can reach (`registrations.json`).** A
2336
+ stable per-tag entry (`@aceshooting/lyra-ui/components/lr-<name>.js`) can, at import time, define
2337
+ more than one custom element: importing `lr-table.js` also registers `<lr-empty>`,
2338
+ `<lr-pagination>`, `<lr-skeleton>` and `<lr-spinner>`, because `lr-table`'s registration entry
2339
+ imports those composed children's own registration entries before defining `<lr-table>` itself.
2340
+ `custom-elements.json` declares one custom element per family source module, with no field for a
2341
+ stable per-tag entry specifier and none for the extra tags importing it registers as a side effect.
2342
+ For that, read the generated `@aceshooting/lyra-ui/registrations.json` instead (`schemaVersion: 1`):
2343
+ `{ entries: [{ tag, entry, registrationModule, distModule, registers, localeKeys }],
2344
+ integrations: [{ entry, registrationModule, distModule, registers, localeKeys }] }`. Every
2345
+ `entries` row describes the stable per-tag alias above and always carries `tag`. `integrations`
2346
+ lists the published integration-bridge specifiers, which install an integration — an optional-peer
2347
+ resolver, a lazy document-format registrar — without being any single component's own alias, so
2348
+ they carry no `tag`: `components/media/flag/flag-peer.js`,
2349
+ `components/viewers/archive-viewer/archive-viewer-register.js` and
2350
+ `components/viewers/ebook-viewer/ebook-viewer-register.js`, the three imports a per-tag alias cannot
2351
+ stand in for. They are a separate array rather than tag-less rows mixed into `entries`, so a reader
2352
+ that keys `entries` by `tag` keeps working; `integrations`, `distModule` and `localeKeys` are all
2353
+ additive, which is why the schema version is unchanged. `registrationModule` is the `src/` path used
2354
+ internally; `distModule` is that same module's own published deep specifier (e.g.
2355
+ `./components/data/table/table.js`) so a caller holding either a per-tag alias or a deep import can
2356
+ resolve the other without reading `src/` or walking `dist/` — for an integration bridge,
2357
+ `distModule` equals `entry`, since there is no separate alias. `registers` is every `lr-*` tag
2358
+ importing `entry` defines, direct or transitive, derived from the same transitive-import analysis
2226
2359
  `scripts/check-component-dependencies.mjs` already performs against the real registration graph
2227
- (not a second hand-maintained list) and regenerated by `pnpm run registration-graph`.
2360
+ (not a second hand-maintained list). `localeKeys` is every `LyraMessageKey` the registered tags can
2361
+ reach — including a key reached only through an indirect lookup table (e.g. `lr-attachment-trigger`'s
2362
+ `{ triggerKey: 'attachmentTriggerFiles' }`-shaped map), because it reuses
2363
+ `generate-default-string-slices.mjs`'s own reachability walk rather than a literal-`localize()`-only
2364
+ scan. All of it is regenerated by `pnpm run registration-graph`.
2228
2365
 
2229
2366
  ## Independence and migration
2230
2367
 
@@ -2479,6 +2616,11 @@ inlineSize: number; blockSize: number }> }`.
2479
2616
  element: interpolating into a message template, populating a text-only property on another
2480
2617
  component (a stat tile's value, a chart tick label, a badge's cost text), building a search
2481
2618
  predicate, or composing an accessibility announcement.
2619
+ An omitted `locale` (or the explicit `'auto'` sentinel) on any of the four resolves to the page's
2620
+ active `setLyraLocale()` locale, exactly like a rendered `<lr-*>` component with no closer
2621
+ `locale`/`lang` override — not a hardcoded `'en'`. It falls back to `'en'` only once no active
2622
+ locale has ever been set, so an app that never calls `setLyraLocale()` sees no change. An
2623
+ explicit BCP-47 tag always stays authoritative over the active locale.
2482
2624
  `formatNumber()` and `formatBytes()` accept a `bigint` or a decimal/integer string, not just a
2483
2625
  `number`, for exact-precision input (large ids, monetary amounts, exact byte counts) — a plain
2484
2626
  `number` is a float64 and cannot exactly represent an integer beyond `Number.MAX_SAFE_INTEGER` or
@@ -4167,6 +4309,17 @@ These named interfaces and helper signatures are available to typed integrations
4167
4309
  `activateStep(/* public names: stepper, target */): unknown`
4168
4310
  See "Driving a component's real activation path: interaction drivers" above for the full contract.
4169
4311
 
4312
+ - **`testing-wait-for-mount-contracts`** — Shared utility contracts.
4313
+ `waitForLyraElement(/* public names: selector, options */): unknown`
4314
+ `WaitForLyraElementOptions {
4315
+ root: unknown;
4316
+ match: (element: unknown) => unknown;
4317
+ timeoutMs: unknown;
4318
+ }`
4319
+ `waitForToast(/* public names: match, options */): unknown`
4320
+ See "Awaiting a lazily registered mount: `waitForLyraElement()` and `waitForToast()`" above for the
4321
+ full contract.
4322
+
4170
4323
  - **`theme-gemstones-data-contracts`** — Shared utility contracts.
4171
4324
  `GemstoneAccent {
4172
4325
  key: unknown;
@@ -4763,6 +4916,18 @@ An async `source` row can carry the same two fields (`start`, `end`) alongside i
4763
4916
  that window instead, since the value is not yet known to be unmatched at all
4764
4917
  - `appearance: 'filled' | 'outlined' | 'filled-outlined' = 'outlined'` (reflected)
4765
4918
  - `placement: 'top' | 'bottom' = 'bottom'` (reflected; flip/shift can still keep the listbox in view)
4919
+ - `positioningStrategy: PlaceStrategy = 'fixed'` (attribute `positioning-strategy`, reflected) —
4920
+ the CSS positioning scheme the listbox is laid out with, spelled the same as on `lr-select`,
4921
+ `lr-popover`, `lr-dropdown`, `lr-tooltip` and `lr-color-picker`. `fixed` is this control's
4922
+ default and what it has always rendered: it positions against the viewport and escapes most
4923
+ clipping ancestors, which suits a typeahead list that usually sits inside a scrollable region.
4924
+ `absolute` positions against the nearest containing block and scrolls with it. An unsupported
4925
+ value resolves to the default. Like `placement`, a change takes effect the next time the listbox
4926
+ opens. When the instance sets nothing, the cascading `--lr-positioning-strategy` custom property
4927
+ (`absolute`/`fixed`, set on `:root`, a theme, or one clipping ancestor) is honoured ahead of the
4928
+ default; an explicit instance value always wins. There is deliberately no `hoist` alias here:
4929
+ unlike on `lr-select`, where it is Shoelace's established spelling, it would be a boolean
4930
+ defaulting to `true`, so its attribute could only ever express the value the control already has
4766
4931
  - `clearable: boolean = false` (reflected) — displays the clear button while there is something to
4767
4932
  clear on **either** axis this control owns: a committed selection, or _visible_ filter text. See
4768
4933
  "the clear button covers two axes" below
@@ -6028,6 +6193,12 @@ state hooks are `--lr-date-input-action-hover-color`, `--lr-date-input-action-ho
6028
6193
  `--lr-date-input-action-active-radius` for the pressed state. They inherit from theme ancestors;
6029
6194
  direct values on `lr-date-input` win without retuning library-wide tokens.
6030
6195
 
6196
+ `--lr-positioning-strategy` (16.0.0) — the calendar popup reads this same cascading
6197
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
6198
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
6199
+ property on `<lr-date-input>`; set the custom property on `:root`, a theme, or one clipping
6200
+ ancestor to change every unset date input beneath it.
6201
+
6031
6202
  **Optional peer deps:** none.
6032
6203
 
6033
6204
  ```html
@@ -6213,7 +6384,7 @@ disabled state.
6213
6384
  | `enterKeyHint` | `enterkeyhint` | `string` | `''` | Virtual-keyboard Enter-key hint forwarded to the native `<textarea>`. |
6214
6385
  | `minlength` | `minlength` | `number \| undefined` | `undefined` | Minimum text length; forwarded to the native `<textarea>` and reported as `validity.tooShort`. |
6215
6386
  | `maxlength` | `maxlength` | `number \| undefined` | `undefined` | Maximum text length; forwarded to the native `<textarea>` (which also stops typing past it) and reported as `validity.tooLong`. |
6216
- | `debounce` | `debounce` | `number \| undefined` | `undefined` | How long (ms) to wait after the last keystroke before emitting one `lr-input-settled`, while `input`/`lr-input` keep firing per keystroke as before. Omitted, `0`, or non-finite means no debounce: `lr-input-settled` never fires. A pending debounce is flushed immediately by `change`/Enter/blur and cancelled with no stray settle by disconnection and a programmatic `value` write. Shares its `DebounceController` primitive with `lr-filter-bar`'s own per-filter `debounce` and with `lr-input`'s identical property. |
6387
+ | `debounce` | `debounce` | `number \| undefined` | `undefined` | How long (ms) to wait after the last keystroke before emitting one `lr-input-settled`, while `input`/`lr-input` keep firing per keystroke as before. Omitted, `0`, or non-finite means no debounce: `lr-input-settled` never fires. A pending debounce is flushed immediately by `change`/Enter/blur and cancelled with no stray settle by disconnection and by a programmatic `value` write that changes the value. A write of the value already held leaves it pending, so a framework binding that writes the just-typed value back on each render (the controlled-input pattern) still settles. Shares its `DebounceController` primitive with `lr-filter-bar`'s own per-filter `debounce` and with `lr-input`'s identical property. |
6217
6388
  | `name` | `name` | `string` | `''` | Form field name. |
6218
6389
  | `disabled` | `disabled` | `boolean` | `false` | Disables the control. |
6219
6390
  | `required` | `required` | `boolean` | `false` | Participates in native constraint validation. |
@@ -6875,16 +7046,24 @@ DOM while at least one top-level slotted element needs the bare-geometry fallbac
6875
7046
  **Themeable custom properties:** `--lr-icon-button-size` (default `2.5rem`) is the **minimum**
6876
7047
  tappable inline and block size of the native button — a floor, not a fixed size. Content larger
6877
7048
  than it grows the button and keeps its own aspect ratio; a small glyph pads out to it. It is a
6878
- library-wide token (declared on `:root` by the token layer, and the shared minimum tappable size
7049
+ library-wide token (declared on every `lr-*` host by the shared token layer, and the shared minimum tappable size
6879
7050
  that several other components size their icon-only controls against), so overriding
6880
7051
  `--lr-theme-icon-button-size` globally resizes all of them together. Keep the resolved value at or
6881
- above 24px — see `llms/shared.md`. Lowering the floor for a dense action row (directly via
6882
- `--lr-icon-button-size`, or via `--lr-theme-icon-button-size` on an ancestor to reach a
7052
+ above 24px — see `llms/shared.md`. **`--lr-icon-button-size` is element-scoped, unlike every other
7053
+ token in this section:** the shared token layer re-declares it on every `lr-*` host's own `:host`,
7054
+ so a rule that sets `--lr-icon-button-size` on an ancestor wrapper is reset the moment it crosses
7055
+ into any intervening `lr-*` component and never reaches a `<lr-icon-button>` composed inside it
7056
+ (e.g. one slotted through `<lr-popover>`). The only two levers that actually reach it are: setting
7057
+ `--lr-icon-button-size` directly on the icon button element itself, where no intervening component
7058
+ sits between the rule and the property; or setting `--lr-theme-icon-button-size` on an ancestor,
7059
+ which the shared layer reads through `var()` at every level and which therefore reaches a
6883
7060
  `<lr-icon-button>` composed inside another component, e.g. `<lr-copy-button>`/
6884
- `<lr-message-actions>`) is safe even below 24px: a coarse-pointer/no-hover media rule floors the
6885
- RENDERED hit area back at 2.75rem/44px regardless of how far the override lowered it, so the
6886
- control stays comfortably tappable the moment the pointer reaching it is a finger rather than a
6887
- mouse. `--lr-icon-button-radius` (default `--lr-radius`) is the
7061
+ `<lr-message-actions>`. Lowering the floor for a dense action row through either lever is safe even
7062
+ below 24px: a coarse-pointer/no-hover media rule floors the RENDERED hit area back at 2.75rem/44px
7063
+ regardless of how far the override lowered it, so the control stays comfortably tappable the moment
7064
+ the pointer reaching it is a finger rather than a mouse. `--lr-icon-button-radius` (default
7065
+ `--lr-radius`) is not re-declared anywhere in the shared layer, so — like every other token below —
7066
+ it inherits normally from an ancestor even through an intervening component; it is the
6888
7067
  `[part='button']` corner radius, retunable without a `::part(button)` rule — the same
6889
7068
  `--lr-button-radius` pattern; `lr-icon-button` has no `size` tiers, so there is no per-tier gap
6890
7069
  counterpart to it. The internal control sets `font: inherit`, so an `em`-sized slotted glyph takes
@@ -7063,7 +7242,9 @@ writes remain valid and read back as booleans. Markup uses `autocorrect="on"` /
7063
7242
  before. Omitted, `0`, or a non-finite value means no debounce at all: `lr-input-settled` never
7064
7243
  fires. A pending debounce is flushed immediately by `change`/Enter/blur (so a blur never drops
7065
7244
  the last keystroke) and cancelled with no stray settle by disconnection, the built-in clear
7066
- button, and a programmatic `value` write. Shares its `DebounceController` primitive with
7245
+ button, and a programmatic `value` write that changes the value. A write of the value already
7246
+ held leaves it pending, so a framework binding that writes the just-typed value back on each
7247
+ render (the controlled-input pattern) still settles. Shares its `DebounceController` primitive with
7067
7248
  `lr-filter-bar`'s own per-filter `debounce` and with `lr-textarea`'s identical property
7068
7249
  - `name`/`disabled`/`required` (from `FormAssociated`)
7069
7250
 
@@ -7421,7 +7602,14 @@ action-height ladder as `lr-input` instead of remaining at the default tier for
7421
7602
  identical meaning. This component changes the mapped defaults to `appearance='outlined'`,
7422
7603
  `inputMode='numeric'`, and `step=1`. `clearable` (and its `with-clear` spelling),
7423
7604
  `passwordVisible` (`password-visible`), and `minlength`/`maxlength`/`pattern` are inherited but
7424
- inert — see gotchas.
7605
+ inert — see gotchas. Also inherited from `lr-input`, with identical meaning:
7606
+ `defaultValue: string = ''` (attribute `value`, reflected) — the reset value; and
7607
+ `customError: string | null = null` (attribute `custom-error`, reflected) — a consumer-supplied
7608
+ validation message. `getForm()` returns the browser-resolved form owner, including an external
7609
+ owner selected by `form`; `setCustomValidity(message)` sets or clears `customError` without
7610
+ discarding intrinsic validity; `resetValidity()` clears only that consumer layer and recomputes
7611
+ the current intrinsic constraints, leaving `value`/`defaultValue` and prior interaction state
7612
+ unchanged.
7425
7613
 
7426
7614
  Stepper switches:
7427
7615
 
@@ -7687,6 +7875,12 @@ mode the raised tone is already distinct from the page, so this panel never had
7687
7875
  reads-as-a-hole problem the family exists to fix. Setting `--lr-overlay-surface` still repaints it
7688
7876
  along with every other popup.
7689
7877
 
7878
+ `--lr-positioning-strategy` (16.0.0) — the `popup` panel reads this same cascading
7879
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
7880
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
7881
+ property on `<lr-time-input>`; set the custom property on `:root`, a theme, or one clipping
7882
+ ancestor to change every unset time input beneath it.
7883
+
7690
7884
  ```html
7691
7885
  <lr-time-input
7692
7886
  label="Start time"
@@ -7725,7 +7919,14 @@ properties apply. `step` is native seconds; `showPicker()`, `stepUp()`, and `ste
7725
7919
  native-wrapper behavior. The control row carries `base input-wrapper time-input` part tokens on one
7726
7920
  node. Its native picker UI and AM/PM presentation are browser-owned and intentionally unstyled.
7727
7921
  The inherited `--lr-input-*` theme inputs therefore remain configurable from an ancestor theme
7728
- wrapper without being shadowed by the subclass.
7922
+ wrapper without being shadowed by the subclass. Among those inherited properties and methods:
7923
+ `defaultValue: string = ''` (attribute `value`, reflected) is the reset value, and
7924
+ `customError: string | null = null` (attribute `custom-error`, reflected) is a consumer-supplied
7925
+ validation message. `getForm()` returns the browser-resolved form owner, including an external
7926
+ owner selected by `form`; `setCustomValidity(message)` sets or clears `customError` without
7927
+ discarding intrinsic validity; `resetValidity()` clears only that consumer layer and recomputes
7928
+ the current intrinsic constraints, leaving `value`/`defaultValue` and prior interaction state
7929
+ unchanged.
7729
7930
 
7730
7931
  **Events:** native-style `input` and `change`; bubbling, composed `focus` and `blur` bridges; the
7731
7932
  `lr-input` / `lr-change` aliases with `{ value }`;
@@ -9479,6 +9680,12 @@ The exact-320px RTL story covers an eight-cell row and an unbroken localized lab
9479
9680
  horizontal reachability for every cell.
9480
9681
  The internal role token `--lr-otp-input-segment-size` supplies that `2.5em` default and can be
9481
9682
  retuned through `--lr-theme-otp-input-segment-size` when the `--segment-size` override is absent.
9683
+ Like `--lr-icon-button-size`, `--lr-otp-input-segment-size` is element-scoped: the shared token
9684
+ layer re-declares it on every `lr-*` host, so a rule that sets it on an ancestor wrapper is reset at
9685
+ the first intervening `lr-*` component and never reaches a nested `<lr-otp-input>`. Set it directly
9686
+ on the element, or set `--lr-theme-otp-input-segment-size` on an ancestor to resize every OTP input
9687
+ in the subtree at once — the retained per-cell hooks below are not re-declared anywhere in the
9688
+ shared layer and inherit normally.
9482
9689
 
9483
9690
  The retained per-cell hooks are `--lr-otp-input-segment-fill` (default `transparent`),
9484
9691
  `--lr-otp-input-segment-border-color` (default `var(--lr-color-border)`), and
@@ -10086,12 +10293,15 @@ and:
10086
10293
  applies to the whole string, function names included (`RGB(255, 0, 0)`)
10087
10294
  - `swatches: string | string[] | LyraColorPickerSwatch[] = ''` — a predefined palette, given as a
10088
10295
  `;`-separated string, an array of colour strings, or an array of
10089
- `{ color: string; label?: string }` objects. Any colour the picker can parse is accepted; blank
10090
- entries are dropped. An entry that is _not_ parseable is kept in the list and still renders a
10091
- swatch — it just paints no colour (the bare checkerboard) and clicking it does nothing, so filter
10092
- the palette yourself if that matters. `label` becomes the swatch's accessible name; a missing,
10093
- empty, or whitespace-only label falls back to announcing the raw colour string. The palette
10094
- container renders only while the normalized list is non-empty
10296
+ `{ color: string; label?: string; disabled?: boolean }` objects. Any colour the picker can parse
10297
+ is accepted; blank entries are dropped. An entry that is _not_ parseable is kept in the list and
10298
+ still renders a swatch — it just paints no colour (the bare checkerboard) and clicking it does
10299
+ nothing, so filter the palette yourself if that matters. `label` becomes the swatch's accessible
10300
+ name; a missing, empty, or whitespace-only label falls back to announcing the raw colour string.
10301
+ `disabled` marks that one swatch non-actionable, independent of the whole control's own
10302
+ `disabled`: it renders a genuinely disabled `<button>` (no tab stop, no hover/press affordance)
10303
+ and clicking it commits nothing; omitted or `false` renders the swatch exactly as before this
10304
+ field existed. The palette container renders only while the normalized list is non-empty
10095
10305
  - `withoutFormatToggle: boolean = false` (attribute `without-format-toggle`) — removes the button
10096
10306
  that cycles between formats. `noFormatToggle` (`no-format-toggle`) is the Shoelace spelling and
10097
10307
  reaches the same behavior; either one wins
@@ -10275,6 +10485,8 @@ of authoring `positioning-strategy`/`hoist` on each instance.
10275
10485
  `var(--lr-color-brand)`.
10276
10486
  - `--lr-color-picker-selected-check-color` — Checkmark on the selected palette swatch. Default:
10277
10487
  `var(--lr-color-surface)`.
10488
+ - `--lr-color-picker-swatch-disabled-opacity` — Opacity of a palette swatch whose own entry sets
10489
+ `disabled`. Default: `0.5`.
10278
10490
 
10279
10491
  ```html
10280
10492
  <lr-color-picker
@@ -10745,6 +10957,12 @@ this listbox together with every other floating surface. `--lr-overlay-radius` r
10745
10957
  only as the middle arm of this component's own `--lr-locale-picker-radius`, which still wins when
10746
10958
  set: a component-scoped override outranks the shared family, never the other way round.
10747
10959
 
10960
+ `--lr-positioning-strategy` (16.0.0) — the listbox reads this same cascading `absolute`/`fixed`
10961
+ override documented on `<lr-popover>` when it is (re)positioned, falling back to its own `fixed`
10962
+ default when nothing is set. There is no per-instance `positioning-strategy` property on
10963
+ `<lr-locale-picker>`; set the custom property on `:root`, a theme, or one clipping ancestor to
10964
+ change every unset locale picker beneath it.
10965
+
10748
10966
  **Optional peer deps:** none directly — each row's `<lr-flag>` degrades to an empty render (no
10749
10967
  peer warning duplication; `lr-flag` itself already logs one) when the optional
10750
10968
  `@aceshooting/lyra-flags` package isn't installed and `showFlags` is left on.
@@ -10829,6 +11047,7 @@ These named interfaces and helper signatures are available to typed integrations
10829
11047
  `LyraColorPickerSwatch {
10830
11048
  color: string;
10831
11049
  label?: string;
11050
+ disabled?: boolean;
10832
11051
  }`
10833
11052
 
10834
11053
  - **`components-forms-combobox-combobox-contracts`** — Supporting data types and helpers for this component family.
@@ -11678,9 +11897,11 @@ unchanged.
11678
11897
  headerCell?, width?, minWidth?, maxWidth?,
11679
11898
  resizable?, sortable?, sortValue?, defaultSortDir?: 'asc'|'desc', align?: 'start'|'end',
11680
11899
  priority?: 'medium'|'low',
11681
- sticky?: 'start'|'end', editTrigger?: 'double-click'|'always', editValue?, editType?: 'text'|'number'|'select',
11900
+ sticky?: 'start'|'end', editTrigger?: 'double-click'|'always', editValue?, editLabel?: (row) => string,
11901
+ editType?: 'text'|'number'|'select',
11682
11902
  editOptions?: { value: string; label: string }[], footer?, cellStyle?, heatValue?,
11683
- cell: (row) => unknown }` —
11903
+ cell: (row) => unknown }` — `cell` is required for every `editTrigger` except `'always'`, whose
11904
+ persistent editor renders unconditionally so the table's render path never falls back to it —
11684
11905
  `sortValue(row) => string | number | null | undefined` supplies the comparable value backing
11685
11906
  client-mode sorting for that column: a finite number sorts numerically, a string sorts through an
11686
11907
  `Intl.Collator` built from the component's effective locale with `numeric: true` (so `item2`
@@ -11720,13 +11941,15 @@ cell: (row) => unknown }` —
11720
11941
  own ramp-token convention; `cellStyle` is applied directly to the generated `<td>` via `styleMap` — e.g. a computed heat-tint
11721
11942
  background a `cell()`-returned inner element can't paint into the cell's own padding — omit it for
11722
11943
  no per-cell style override (the default, unchanged output);
11723
- `editTrigger: 'double-click'` opens a native editor on that cell's double-click (one cell at a
11724
- time), while `'always'` renders a persistent editor in every body cell from first paint, for a
11944
+ `editTrigger: 'double-click'` opens a native editor on that cell's double-click, `F2`, or `Enter`
11945
+ (one cell at a time), while `'always'` renders a persistent editor in every body cell from first paint, for a
11725
11946
  settings/rate-style column meant to be typed straight into — while `editValue` supplies the editor
11726
11947
  value and `editType` selects `'text'`, `'number'`, or `'select'` (a native `<select>` populated
11727
11948
  from `editOptions: { value: string; label: string }[]`, one `<option>` per entry in order; a
11728
11949
  `'select'` column with no `editOptions` renders an empty, valueless `<select>` instead of
11729
- throwing)
11950
+ throwing); `editLabel(row) => string`, read once per row exactly like `editValue`/`cellTitle`,
11951
+ overrides that editor's accessible name — omit it and every editor in the column shares the same
11952
+ interpolated `tableEditCell` name instead (see the accessibility note under `editTrigger` below)
11730
11953
  `cellTitle(row) => string | undefined` is the `title` analogue of `cellStyle`, applied directly to
11731
11954
  the generated `<td>` — e.g. the untruncated text behind an ellipsized cell, or a formatted
11732
11955
  timestamp behind a relative one;
@@ -11748,8 +11971,21 @@ cell: (row) => unknown }` —
11748
11971
  Enter commits and closes, Escape cancels and closes, and blur-after-change commits. `'always'`
11749
11972
  renders an editor in
11750
11973
  every body cell of that column, permanently:
11751
- - **Focus model.** Each editor is a plain tab stop — no `tabindex` of its own exactly like the
11752
- existing row-expand toggle, and stays _outside_ the header/row roving-tabindex model. Tab walks
11974
+ - **Keyboard entry (`'double-click'` columns).** The resting (not-currently-editing) cell of a
11975
+ `'double-click'` column is its own roving-focus stop — `tabindex="-1"`, carrying `[data-editable]`
11976
+ — reachable once the row itself has focus: ArrowRight (ArrowLeft under RTL) enters at the first
11977
+ editable cell in the row and steps forward through any further ones; ArrowLeft (ArrowRight under
11978
+ RTL) steps back and, from the first editable cell, returns focus to the row. None of this is a Tab
11979
+ stop — a table with a `'double-click'` column gains no new entry in the page's Tab order, only a
11980
+ new arrow-reachable one — and a table with no `editTrigger` column at all renders no `tabindex`/
11981
+ `[data-editable]` anywhere. `F2` or `Enter` on the focused cell opens its editor; `Enter` on the
11982
+ row itself (no cell focused) still only activates the row. `editCell(rowKey, columnKey)` (see
11983
+ Methods above) is the same open action as a public method. Closing the editor, by commit or by
11984
+ cancel, returns focus to the cell that opened it.
11985
+ - **Focus model (`'always'` columns).** Each editor is a plain tab stop — no `tabindex` of its own
11986
+ — exactly like the
11987
+ existing row-expand toggle, and stays _outside_ the header/row/cell roving-tabindex model. Tab
11988
+ walks
11753
11989
  down the column; arrow keys still navigate the grid from a row's own roving stop, and act as
11754
11990
  ordinary caret movement once focus is inside a field. Non-editable columns are unaffected.
11755
11991
  - **Value binding.** A persistent `'text'`/`'number'` editor binds its `value` as a **content
@@ -11768,8 +12004,14 @@ cell: (row) => unknown }` —
11768
12004
  `<input>` (the typed value rides along) and the table restores focus to the same logical cell
11769
12005
  afterwards. If the focused row leaves the rendered page entirely (pagination, filtering), focus
11770
12006
  is simply lost rather than yanked to whichever unrelated row now sits in that position.
11771
- - Each editor keeps its own interpolated `tableEditCell` accessible name (`Edit {column}`), so a
11772
- column of otherwise-identical inputs is still individually named to a screen reader.
12007
+ - **Accessible name.** Each editor's name is `columns[].editLabel(row)` when the column defines
12008
+ it, or otherwise the interpolated `tableEditCell` string (`Edit {column}`) identical for every
12009
+ row in that column, since the default has no row context. That default is adequate for
12010
+ `'double-click'`, where at most one editor is ever open, but not for `'always'`: every row's
12011
+ editor there is a permanent, individually focusable Tab stop, so leaving `editLabel` unset on an
12012
+ `'always'` column exposes as many identically named controls as there are rows (e.g. fifty "Edit
12013
+ Status" comboboxes), failing WCAG 2.4.6 and 1.3.1. Define `editLabel` for any `'always'` column
12014
+ to give each row's editor its own name.
11773
12015
  - `hasHiddenPriorityColumns: boolean = false` (attribute `has-hidden-priority-columns`, reflected) —
11774
12016
  computed/read-only and true only while a priority column is actually hidden. It becomes false
11775
12017
  when `priorityColumnsVisible` reveals the columns. Measured via a `ResizeObserver` on
@@ -11907,6 +12149,14 @@ cell: (row) => unknown }` —
11907
12149
  rendered panel anyway, `expandedContentElement(rowKey)` (below) resolves that `<td>`;
11908
12150
  `rowElement(rowKey)` does not, because the panel is a sibling `<tr>` rather than part of the row
11909
12151
  - `canExpand?: (row: T) => boolean` (attribute: false) — optional per-row gate for expansion
12152
+ - `rowExpandLabel?: (row: T, expanded: boolean) => string | undefined` (attribute: false) —
12153
+ accessible name for one row's expand/collapse chevron, read once per render for that row,
12154
+ exactly like a column's `editLabel`/`cellTitle`; consumer-owned text used verbatim, never
12155
+ passed through localization. Omit it and every chevron shares the same localized
12156
+ `expand`/`collapse` name, which carries no row context — fine for a handful of rows, but each
12157
+ chevron is its own Tab stop, so a long table otherwise announces the same two names over and
12158
+ over with no way to tell the rows apart. There is no default row context to derive one from
12159
+ here: this component has no row-header notion (`rowKey` is an opaque identity, not a label)
11910
12160
  - `expansionMode: 'none'|'single'|'multiple' = 'none'` (attribute `expansion-mode`, reflected) —
11911
12161
  mirrors `selectionMode` member for member, for expansion. The default `'none'` keeps
11912
12162
  `expandedRowKeys` fully consumer-controlled: an activation only reports `lr-row-expand-toggle`.
@@ -12013,8 +12263,14 @@ cell: (row) => unknown }` —
12013
12263
  - `expandedContentElement(rowKey)` — the rendered `[part='expanded-cell']` holding that row's
12014
12264
  `expandedContent(row)` output, or `null` when the row is not currently rendered, is not expanded,
12015
12265
  or the table sets no `expandedContent`
12016
-
12017
- All three exist for code that has to reach content a `cell(row)`/`expandedContent(row)` callback
12266
+ - `editCell(rowKey, columnKey)` — opens the inline editor at that row/column pair, exactly as a
12267
+ double-click, `F2`, or `Enter` on the cell's own focus stop would (see `columns[].editTrigger`
12268
+ below) — the entry point for a consumer's own key binding or menu action. A no-op for an unknown
12269
+ row key, an unknown column key, or a column with no `editTrigger`. For an `editTrigger: 'always'`
12270
+ column (already open from first paint) it moves focus into that editor instead of opening
12271
+ anything.
12272
+
12273
+ The first three exist for code that has to reach content a `cell(row)`/`expandedContent(row)` callback
12018
12274
  rendered into this component's shadow root — measuring it, scrolling it into view, or applying a
12019
12275
  style `::part()` cannot express, since only pseudo-classes may follow a part selector. One method per
12020
12276
  callback, and the split is not cosmetic: the expansion panel is a **sibling** `<tr part='expanded-row'>`
@@ -12640,6 +12896,12 @@ explicitly empty labels remain empty and later labels render normally.
12640
12896
  - `valueText?: string` (attribute `value-text` — overrides both the visible text and the host's
12641
12897
  `aria-valuetext`; an empty string is treated the same as unset and falls back to the numeric
12642
12898
  `value` while removing `aria-valuetext`)
12899
+ - `showValue: boolean = true` (attribute `show-value`, not reflected) — whether the decorative
12900
+ `part="value"` caption renders at all; `show-value="false"` omits it the same way an empty
12901
+ `label` already omits `part="label"`. `aria-valuenow`/`aria-valuetext` and the host's accessible
12902
+ name are unaffected either way, since the caption itself is always `aria-hidden`. Mirrors
12903
+ `<lr-progress-bar>`'s/`<lr-progress-ring>`'s own `showValue` name and meaning; the default here
12904
+ is `true` (a gauge's whole purpose is showing the reading it announces) where theirs is `false`.
12643
12905
  - `variant: LyraProgressVariant = 'brand'` (reflected) — the same shared semantic-tone vocabulary
12644
12906
  `<lr-progress-bar>` uses (`'neutral'|'brand'|'success'|'warning'|'danger'`). The fallback color
12645
12907
  whenever `thresholds` is empty or matches nothing.
@@ -12656,7 +12918,8 @@ explicitly empty labels remain empty and later labels render normally.
12656
12918
 
12657
12919
  **Slots:** none.
12658
12920
 
12659
- **CSS parts:** `base` (the `<svg>`), `track`, `fill`, `value`, `label`
12921
+ **CSS parts:** `base` (the `<svg>`), `track`, `fill`, `value` (rendered only while `showValue` is
12922
+ true), `label` (rendered only while `label` is non-empty)
12660
12923
 
12661
12924
  **Themeable custom properties:** `--lr-gauge-fill` (fill stroke; overrides `variant`/`thresholds`
12662
12925
  entirely and falls back to the effective variant's shared semantic token —
@@ -12673,6 +12936,15 @@ entirely and falls back to the effective variant's shared semantic token —
12673
12936
  style="--lr-gauge-fill: var(--lr-color-success)"
12674
12937
  ></lr-gauge>
12675
12938
  <lr-gauge shape="linear" value="0.4" max="1" value-text="72°F"></lr-gauge>
12939
+ <!-- compact dashboard meter: a slim, captionless, thresholded row -->
12940
+ <lr-gauge
12941
+ shape="linear"
12942
+ size="xs"
12943
+ show-value="false"
12944
+ aria-label="Spend"
12945
+ value="84"
12946
+ max="100"
12947
+ ></lr-gauge>
12676
12948
  <!-- automatic threshold coloring: same rule, opposite direction -->
12677
12949
  <lr-gauge id="cpu" value="82" label="CPU"></lr-gauge>
12678
12950
  <script>
@@ -12716,7 +12988,11 @@ entirely and falls back to the effective variant's shared semantic token —
12716
12988
  - no documented component-specific sizing custom property. The host box is fixed em values
12717
12989
  (`8em` radial/ring, `12em`/`1.5em` linear) against the host font size, so `size` is the supported
12718
12990
  way to step it; for a dimension off the ladder, set plain CSS `width`/`height` (or `font-size`)
12719
- on the element instead.
12991
+ on the element instead. The value/label captions are `em`-sized against that same host font-size,
12992
+ so they shrink right along with the frame at a smaller tier or a smaller host `font-size` —
12993
+ combine a small tier (or a small host `font-size`) with `show-value="false"` for a slim,
12994
+ thresholded dashboard meter, matching `<lr-progress-bar size="xs">`'s footprint but with
12995
+ `role="meter"` and one `thresholds` array instead of a hand-written ratio-to-variant mapping.
12720
12996
  - Divide-by-zero guarded, and radial/linear share one component via the `shape`
12721
12997
  attribute.
12722
12998
  - non-finite `value` text remains blank unless `valueText` supplies a truthful fallback; that
@@ -13550,13 +13826,18 @@ numeric disclosure.
13550
13826
  **Properties:**
13551
13827
 
13552
13828
  - `items: readonly SequenceStripItem[] = []` (attribute: false) — `{ readonly id, readonly
13553
- categoryId, readonly marker?, readonly label? }`;
13829
+ categoryId, readonly marker?, readonly label?, readonly disabled? }`;
13554
13830
  `marker` renders a small bottom marker on that cell independent of the category color (e.g. a
13555
13831
  subagent-dispatched turn); `label` is per-item hover/focus tooltip text _and_ that cell's own
13556
13832
  `role="listitem"` accessible name, falling back to the matching category's own nonblank `label`,
13557
13833
  then localized `sequenceStripUnnamedCategory` (`"Unnamed category"` in the built-in English
13558
13834
  catalog) when unset — it is not read by `[part="base"]`'s auto-generated `aria-label`, which
13559
- summarizes by category/count only
13835
+ summarizes by category/count only. `disabled` marks the item non-actionable:
13836
+ `aria-disabled="true"` replaces the selected/active affordances of the cell that represents it,
13837
+ activating it (click or Enter/Space) emits nothing, and roving Left/Right/Home/End navigation —
13838
+ including the default resting tab stop — steps past it. Above the 200-cell cap, a range cell's
13839
+ disabled state follows its own activated item, the range's first. Omitted or `false` renders the
13840
+ item exactly as before this field existed
13560
13841
  - `categories: readonly SequenceStripCategory[] = []` (attribute: false) — `{ readonly id,
13561
13842
  readonly color, readonly label? }`; `color`
13562
13843
  is the cell background for every item whose `categoryId` matches `id`; invalid CSS colors,
@@ -13632,7 +13913,8 @@ block-size), `--lr-sequence-strip-marker-color` (default `var(--lr-color-text)`
13632
13913
  (default `0.625rem` — a legend swatch's inline- and block-size, category and marker rows alike), and
13633
13914
  `--lr-sequence-strip-legend-marker-bg` (default `var(--lr-color-surface-raised)` — the neutral chip
13634
13915
  background behind the marker legend row's bar; it stands in for "any cell", so it deliberately
13635
- matches no category color); the tooltip also consumes shared tokens
13916
+ matches no category color), and `--lr-sequence-strip-disabled-opacity` (default `var(--lr-opacity-disabled)` opacity of
13917
+ a cell whose activated item sets `disabled`); the tooltip also consumes shared tokens
13636
13918
  `--lr-color-surface`, `--lr-color-text`, `--lr-font-size-xs`, `--lr-radius`, and `--lr-shadow`, and
13637
13919
  the legend consumes `--lr-space-2xs`, `--lr-space-xs`, `--lr-space-s`, `--lr-font-size-xs`,
13638
13920
  `--lr-color-text-quiet`, and `--lr-radius-xs`.
@@ -14058,14 +14340,19 @@ import type {
14058
14340
  **Properties:**
14059
14341
 
14060
14342
  - `nodes: readonly FlowNode[] = []` (attribute: false) — each record has readonly `id`, optional
14061
- `type`, `position`, `data`, `accessibleLabel`, `inputs`, and `outputs`. A missing `position` opts
14062
- into layered layout. String `data.label` and `data.description` feed the declarative fallback
14063
- card. Assignment takes a detached, deeply frozen snapshot of plain arrays/records, omitting blank
14064
- ids and later duplicates first-wins before layout, focus, selection, gestures, companion
14065
- snapshots, and events. At most the first 10,000 source nodes are retained, with finite nested
14066
- depth/entry budgets; reassign `nodes` after changes. Replacing the model cancels node-drag and
14067
- connect gestures whose ids belonged to the old model and silently prunes selected ids that no
14068
- longer exist.
14343
+ `type`, `position`, `data`, `accessibleLabel`, `inputs`, `outputs`, and `disabled`. A missing
14344
+ `position` opts into layered layout. String `data.label` and `data.description` feed the
14345
+ declarative fallback card. Assignment takes a detached, deeply frozen snapshot of plain
14346
+ arrays/records, omitting blank ids and later duplicates first-wins before layout, focus,
14347
+ selection, gestures, companion snapshots, and events. At most the first 10,000 source nodes are
14348
+ retained, with finite nested depth/entry budgets; reassign `nodes` after changes. Replacing the
14349
+ model cancels node-drag and connect gestures whose ids belonged to the old model and silently
14350
+ prunes selected ids that no longer exist. `disabled` marks a node non-actionable: it keeps its
14351
+ position and card content but cannot be selected/activated by click or keyboard, roving-tabindex
14352
+ navigation (arrow keys, Home/End) steps past it, it cannot be dragged even while
14353
+ `nodes-draggable`, and it is excluded from starting or receiving a new connection while
14354
+ `connectable` (an edge already touching it is left alone). Omitted or `false` renders the node
14355
+ exactly as before this field existed.
14069
14356
  - `edges: readonly FlowEdge[] = []` (attribute: false) — readonly `id`, `source`, `target`, optional
14070
14357
  handle ids, optional drawn `label`, and optional `tone: LyraVariant`. The canonical brand value is
14071
14358
  `brand`; the former `accent` value and `FlowEdgeTone` alias are not part of this contract. Blank
@@ -14231,6 +14518,8 @@ four above. Set it to `transparent` to opt out of the hover treatment.
14231
14518
  - `part="edge-hit-area"` — The transparent wide pointer target behind an edge.
14232
14519
  - `part="node-control"` — The visually hidden, roving selection button for a node.
14233
14520
  - `--lr-flow-canvas-node-selected-outline-color` — Outline color of a selected node. Default: `var(--lr-color-brand)`.
14521
+ - `--lr-flow-canvas-node-disabled-opacity` — Opacity of a node whose `FlowNode` entry sets
14522
+ `disabled`. Default: `var(--lr-opacity-disabled)`.
14234
14523
 
14235
14524
  ---
14236
14525
 
@@ -14549,9 +14838,13 @@ used" summary.
14549
14838
  **Properties:**
14550
14839
 
14551
14840
  - `segments: ContextMeterSegment[] = []` (attribute: false, JS-only) — `{ label: string; value:
14552
- number; tone?: 'brand' | 'success' | 'warning' | 'danger' | 'neutral'; color?: string }[]`. `value` is an _absolute_
14841
+ number; tone?: 'brand' | 'success' | 'warning' | 'danger' | 'neutral'; color?: string; disabled?:
14842
+ boolean }[]`. `value` is an _absolute_
14553
14843
  quantity measured against `total`, never a pre-computed percentage.
14554
14844
  `color`, when supplied, is a sanitized arbitrary CSS color that takes precedence over `tone`.
14845
+ `disabled`, when set, marks that band non-actionable while `interactive` is set: its control
14846
+ renders genuinely disabled (no tab stop, no hover/press affordance) and activating it emits no
14847
+ `lr-segment-activate`.
14555
14848
  - `total: number = 0` — the full capacity segments are measured against (e.g. a model's context
14556
14849
  window size).
14557
14850
  - `shape: ContextMeterShape = 'bar'` (`'bar' | 'ring'`, reflected) — the v9 geometry name;
@@ -14618,7 +14911,14 @@ color hook as `segment`) and `legend-label`, plus `legend-value` and `legend-per
14618
14911
  matching `legendDisplay` settings. While `interactive` is set, `segment` and `legend-item` are
14619
14912
  `<button>`s (a `role="button"` arc under `shape="ring"`) and a selected one carries a second part
14620
14913
  token — `segment-selected` / `legend-item-selected` — because nothing but a pseudo-class may follow
14621
- `::part()`, so the state has to live in the part name
14914
+ `::part()`, so the state has to live in the part name. Two further state tokens join them, and they
14915
+ compose: `segment-empty` / `legend-item-empty` on a band whose `value` is 0, and
14916
+ `segment-disabled` / `legend-item-disabled` on a band whose `segments` entry sets `disabled`. The
14917
+ empty pair is DERIVED and carries no built-in treatment — it is the hook for your own "nothing in
14918
+ this bucket" styling, and a zero band stays actionable. The disabled pair is DECLARED: that control
14919
+ renders genuinely disabled (no tab stop, no hover or press affordance) and activating it emits no
14920
+ `lr-segment-activate`. Inertness is never inferred from a zero value, because a zero band is
14921
+ legitimately clickable in a budget meter
14622
14922
 
14623
14923
  **Themeable custom properties:** `--lr-context-meter-segment-color` is set per segment when its
14624
14924
  `color` field is supplied, and is read by both `segment` and its matching `legend-swatch` so the
@@ -14639,7 +14939,9 @@ selected band stays visibly selected exactly while it is being pointed at or foc
14639
14939
  ring stays intact. `--lr-context-meter-selected-arc-stroke` (default `16`, in this component's
14640
14940
  `0 0 100 100` viewBox units) is the stroke width of a selected `ring`-shape arc: every arc shares
14641
14941
  one bounding box, so a selected arc reports itself by thickening in place rather than by an outline
14642
- that would trace the whole ring identically for every selection. Otherwise the component consumes shared tokens
14942
+ that would trace the whole ring identically for every selection.
14943
+ `--lr-context-meter-disabled-opacity` (default `var(--lr-opacity-disabled)`) dims a band or legend row whose entry sets
14944
+ `disabled`; the band keeps its own colour, since that colour is the datum. Otherwise the component consumes shared tokens
14643
14945
  `--lr-space-xs`, `--lr-color-text-quiet`, `--lr-font`, `--lr-radius`, `--lr-color-border`,
14644
14946
  `--lr-color-brand`, `--lr-color-success`, `--lr-color-warning`, `--lr-color-danger`,
14645
14947
  `--lr-transition-base`.
@@ -15259,6 +15561,7 @@ These named interfaces and helper signatures are available to typed integrations
15259
15561
  value: number;
15260
15562
  tone?: ContextMeterTone;
15261
15563
  color?: string;
15564
+ disabled?: boolean;
15262
15565
  }`
15263
15566
  Import: `@aceshooting/lyra-ui/components/data/context-meter/context-meter.class.js`.
15264
15567
  `LyraContextMeterSegmentActivateDetail {
@@ -15557,6 +15860,7 @@ These named interfaces and helper signatures are available to typed integrations
15557
15860
  readonly accessibleLabel?: string;
15558
15861
  readonly inputs?: readonly FlowHandle[];
15559
15862
  readonly outputs?: readonly FlowHandle[];
15863
+ readonly disabled?: boolean;
15560
15864
  }`
15561
15865
  Import: `@aceshooting/lyra-ui/components/data/flow-canvas/flow-types.js`.
15562
15866
  `FlowRunDecoration {
@@ -15752,6 +16056,7 @@ These named interfaces and helper signatures are available to typed integrations
15752
16056
  readonly categoryId: string;
15753
16057
  readonly marker?: boolean;
15754
16058
  readonly label?: string;
16059
+ readonly disabled?: boolean;
15755
16060
  }`
15756
16061
 
15757
16062
  - **`components-data-stat-stat-contracts`** — Supporting data types and helpers for this component family.
@@ -15784,6 +16089,7 @@ These named interfaces and helper signatures are available to typed integrations
15784
16089
  heatValue?(row: T): number | null | undefined;
15785
16090
  editTrigger?: TableColumnEditTrigger;
15786
16091
  editValue?: (row: T) => string | number;
16092
+ editLabel?: (row: T) => string;
15787
16093
  editType?: 'text' | 'number' | 'select';
15788
16094
  editOptions?: TableColumnEditOption[];
15789
16095
  cell: (row: T) => unknown;
@@ -17540,6 +17846,18 @@ rotation and activation, while background, radius, hover/press mixes, focus ring
17540
17846
  come from `--lr-icon-button-*`, and the component's own `--lr-reorder-item-move-button-*` hooks still
17541
17847
  win over those defaults), `content` (default-slot wrapper).
17542
17848
 
17849
+ **Border reaches the composed move controls the same way background/color/radius do.** This
17850
+ component paints no resting border on either move control, so it relays no
17851
+ `--_lr-icon-button-border-default` into their private fallback tier — but that absence is not a
17852
+ gap. The public `--lr-icon-button-border` (and its `-hover`/`-active` variants) is the FIRST arm
17853
+ of the token chain, resolved by ordinary custom-property inheritance regardless of whether this
17854
+ component relays a default for that same property, so setting it on either move control or an
17855
+ ancestor reaches it exactly as the background/color/radius tokens do. A component with no resting
17856
+ border simply has no default to relay, which is different from border theming being broken. Size
17857
+ remains the one exception that does not cross this way: use `--lr-theme-icon-button-size`, never
17858
+ `--lr-icon-button-size` — every `LyraElement` re-declares the latter on its own `:host`, so it
17859
+ never reaches a composed child (see `llms/tokens.md`).
17860
+
17543
17861
  **Themeable custom properties:** `--lr-reorder-item-gap` (default `var(--lr-space-xs)`) — gap
17544
17862
  between the move buttons and the row content. The move-button interaction paints are independent,
17545
17863
  inherited inline fallbacks: `--lr-reorder-item-move-button-hover-bg` (default
@@ -18240,9 +18558,18 @@ width), `--lr-app-rail-overlay-color` (default `var(--lr-color-overlay)` — the
18240
18558
  color; component-specific since no shared token exists), `--lr-app-rail-panel-inset-block-start`
18241
18559
  (default `0`, applied to both `[part="panel"]` and `[part="backdrop"]` — raise it to leave room for
18242
18560
  a fixed app bar/status area above the drawer instead of the panel/scrim starting flush with the
18243
- viewport top), `--lr-app-rail-panel-radius` (default `0` — corner radius of `[part="panel"]`; pairs
18244
- naturally with a nonzero `--lr-app-rail-panel-inset-block-start`, which exposes the panel's top
18245
- corners), `--lr-app-rail-panel-overflow-block` (default `auto`) and
18561
+ viewport top), `--lr-app-rail-panel-radius` (default `0` — uniform corner radius of `[part="panel"]`;
18562
+ pairs naturally with a nonzero `--lr-app-rail-panel-inset-block-start`, which exposes the panel's top
18563
+ corners). Four direction-aware per-corner tokens each default to `--lr-app-rail-panel-radius`, so
18564
+ setting only the uniform token still rounds all four corners exactly as before:
18565
+ `--lr-app-rail-panel-radius-start-start` and `--lr-app-rail-panel-radius-end-start` (logical
18566
+ `border-start-start-radius`/`border-end-start-radius` — the two corners at the panel's own flush
18567
+ inline-start edge, since the drawer always sits flush against `inset-inline-start: 0`) and
18568
+ `--lr-app-rail-panel-radius-start-end`/`--lr-app-rail-panel-radius-end-end` (logical
18569
+ `border-start-end-radius`/`border-end-end-radius` — the two corners away from that flush edge, the
18570
+ pair a flush-against-one-edge drawer typically rounds). All four are logical, so which physical
18571
+ corner each one paints swaps under `dir="rtl"` with no second consumer rule.
18572
+ `--lr-app-rail-panel-overflow-block` (default `auto`) and
18246
18573
  `--lr-app-rail-panel-overflow-inline` (default `clip`) — `[part="panel"]`'s logical overflow axes;
18247
18574
  either non-`visible` value clips a `position: fixed` popup opened by a slotted/nav-item control
18248
18575
  (e.g. a slotted `<lr-select>`/`<lr-menu>`) whenever its rendered box extends past the panel,
@@ -18258,7 +18585,10 @@ docked rail chrome). `--lr-app-rail-header-padding` and `--lr-app-rail-footer-pa
18258
18585
  `var(--lr-space-m)`) retune `[part="header"]`/`[part="footer"]`'s padding independently.
18259
18586
  `--lr-app-rail-header-min-block-size` (default `auto`, the property's own initial value, so unset
18260
18587
  reproduces today's exact height) reserves a minimum height for `[part="header"]`, for content that
18261
- mounts or resizes asynchronously. Plus shared
18588
+ mounts or resizes asynchronously. `--lr-app-rail-nav-padding` and `--lr-app-rail-nav-gap` (default
18589
+ `var(--lr-space-s)`/`var(--lr-space-xs)`, the values this rule hard-coded before either token
18590
+ existed) retune `[part="nav"]`'s own padding and inter-item gap — the rail's vertical rhythm,
18591
+ previously reachable only through `::part(nav)`. Plus shared
18262
18592
  tokens (`--lr-color-border`,
18263
18593
  `--lr-color-surface`, `--lr-color-text`, `--lr-color-brand`, `--lr-color-brand-quiet`,
18264
18594
  `--lr-space-*`, `--lr-radius`, `--lr-shadow`, `--lr-icon-button-size`,
@@ -18391,10 +18721,22 @@ removing the label from the accessibility tree.
18391
18721
  `<lr-app-rail>` as the viewport narrows) hides it from view. No effect outside icon-only mode,
18392
18722
  since the label is already visible there. `false` (the default) reproduces the exact existing
18393
18723
  output.
18724
+ - `expanded: boolean = false` (reflected) — whether this item's own `children` are shown. `false`
18725
+ reproduces exactly what an item without this property rendered before this feature existed.
18726
+ Driven through the same request/commit pair as `<lr-app-rail-group>`'s `open`, see Events below.
18394
18727
 
18395
18728
  A host `aria-label` is copied to the rendered native link or button by attribute presence,
18396
18729
  including an explicitly empty value; without it, the default slot supplies the native name. The
18397
- same precedence supplies the tooltip text when that opt-in flyout is visible.
18730
+ same precedence supplies the tooltip text when that opt-in flyout is visible, and the disclosure's
18731
+ interpolated `{label}` (see Events below).
18732
+
18733
+ **Events:** `lr-toggle-request` — cancelable, emitted before `expanded` changes from the built-in
18734
+ disclosure (`detail: { open }` — the field is named `open`, matching `<lr-app-rail-group>`'s
18735
+ identical event name and detail shape exactly). Call `preventDefault()` to keep the current state,
18736
+ or assign `expanded` from the listener to resolve it yourself; a write during the dispatch
18737
+ suppresses the default commit even when it assigns the value the property already held. Not
18738
+ emitted for a direct `expanded` write. `lr-toggle` — non-cancelable, emitted after `expanded` is
18739
+ written, never for a vetoed or listener-resolved request (`detail: { open }`).
18398
18740
 
18399
18741
  **Methods:** `click(): void` activates the internal native link or button; it is a no-op while
18400
18742
  `disabled`.
@@ -18417,6 +18759,28 @@ names the native control, which remains the sole action).
18417
18759
  control keeps its own click, keyboard activation and focus order instead of being swallowed.
18418
18760
  Unlike `meta` it stays visible in `icon-only` mode, where it shares the narrow rail's width with
18419
18761
  the icon.
18762
+ - `children` slot — nested `<lr-app-rail-item>`s disclosed beneath this item (the
18763
+ treeitem-with-link pattern: the row itself navigates, a separate disclosure expands its own
18764
+ child rows). Slotting anything into it grows a built-in `[part="toggle"]` disclosure button as a
18765
+ SIBLING of the item's own link/button, never nested inside it, so the link keeps navigating on
18766
+ its own and the disclosure keeps toggling on its own — clicking one never triggers the other.
18767
+ Leaving `children` empty renders neither the disclosure nor `[part="children"]` at all: an item
18768
+ authored without any `children` content renders byte-identically to one authored before this
18769
+ slot existed. The disclosure carries `aria-expanded` (both states) and `aria-controls` pointing
18770
+ at `[part="children"]`'s id, and a localized accessible name interpolating this item's own label
18771
+ (`Expand {label}`/`Collapse {label}` in the default locale — no literal fallback, so a
18772
+ `registerLyraLocale()` translation or a `.strings` override always reaches it). `<lr-app-rail-group>`
18773
+ cannot express this pattern: its collapsible heading *is* the toggle, so a navigable link cannot
18774
+ live inside it without nesting an interactive element inside a button.
18775
+
18776
+ `icon-only` forwards from this item onto every `<lr-app-rail-item>` it directly owns through
18777
+ `children` — including ones appended later — exactly how `<lr-app-rail-group>` forwards onto the
18778
+ items and nested groups it owns. The disclosure itself never changes shape between
18779
+ presentations: it is always a fixed icon-button-sized square beside `[part="base"]`, reusing the
18780
+ same hover/active/focus tokens as the link/button (`--lr-app-rail-item-hover-bg` etc.) rather than
18781
+ a second disclosure-only set. There is no ancestor-current treatment — `<lr-app-rail-group>` has
18782
+ no equivalent concept for a group containing the current item, so none is invented here either; a
18783
+ current descendant stays perceivable only through its own `current` property.
18420
18784
 
18421
18785
  Both wrappers (`[part="meta"]`, `[part="end"]`) are hidden while empty, so an item using neither
18422
18786
  renders exactly as before. Note that while the mobile overlay is open, a click anywhere in the
@@ -18425,10 +18789,16 @@ nav-slot behaviour, not new to these slots.
18425
18789
 
18426
18790
  **CSS parts:** `base`, `icon`, `label`, `current-indicator` (a decorative inline indicator rendered
18427
18791
  only while the item is `current`/`aria-current="page"`, mirroring `<lr-conversation-item>`'s
18428
- shipped `active-indicator` part), `tooltip` (the hover/focus label flyout, only rendered while
18429
- `tooltip` is set, the item is `icon-only`, and it is hovered or focused), `meta` (the wrapper around
18430
- the `meta` slot, hidden while empty) and `end` (the wrapper around the `end` slot, hidden while
18431
- empty).
18792
+ shipped `active-indicator` part suppressed by default while `icon-only`, see the current-ring
18793
+ tokens below), `tooltip` (the hover/focus label flyout, only rendered while `tooltip` is set, the
18794
+ item is `icon-only`, and it is hovered or focused), `meta` (the wrapper around the `meta` slot,
18795
+ hidden while empty), `end` (the wrapper around the `end` slot, hidden while empty), `toggle` (the
18796
+ `children` disclosure, rendered only while something is slotted into `children`; a sibling of
18797
+ `base`, never nested inside it), `toggle-icon` (the wrapper around the disclosure chevron,
18798
+ direction-aware through this wrapper's own `transform` — mirrors `<lr-app-rail-group>`'s own
18799
+ `[part="toggle-icon"]`) and `children` (the wrapper around the `children` slot, rendered only
18800
+ alongside `toggle`; hidden — but present, so `aria-controls` keeps resolving — while `expanded` is
18801
+ `false`).
18432
18802
 
18433
18803
  **Themeable custom properties:** `--lr-app-rail-item-current-bg` (default
18434
18804
  `var(--lr-color-brand-quiet)`), `--lr-app-rail-item-current-color` (default
@@ -18447,6 +18817,16 @@ before. `--lr-app-rail-item-current-font-weight` mirrors `<lr-stepper>`'s
18447
18817
  `--lr-app-rail-item-current-indicator-width` (default `var(--lr-size-2px)`), and
18448
18818
  `--lr-app-rail-item-current-indicator-inset-inline` (default `0 auto`; set `auto 0` to place the
18449
18819
  indicator at the inline-end edge instead) theme `[part="current-indicator"]`.
18820
+ `--lr-app-rail-item-current-indicator-display` (no default; unset resolves to `none` while
18821
+ `icon-only`) restores the indicator bar in icon-only presentation — a full-height edge bar reads
18822
+ as a rendering glitch on the square icon-only tile, so it is suppressed there by default; full
18823
+ presentation is unaffected either way, since its own `[part="current-indicator"]` rule declares no
18824
+ `display` at all. `--lr-app-rail-item-current-ring` (no default; unset resolves to `none` in full
18825
+ presentation and an inset ring in icon-only presentation) sets `box-shadow` on `[part="base"]`
18826
+ while current: unset, icon-only gets an inset ring automatically — the non-color-only signal
18827
+ (WCAG 1.4.1) that replaces the bar suppressed there, since full presentation already conveys
18828
+ current state through the indicator bar and `--lr-app-rail-item-current-font-weight`. Setting this
18829
+ token explicitly applies the same value in both presentations.
18450
18830
  Ordinary interaction states are independently inheritable through
18451
18831
  `--lr-app-rail-item-hover-bg`, `--lr-app-rail-item-hover-color`,
18452
18832
  `--lr-app-rail-item-active-bg`, and `--lr-app-rail-item-active-color`, again retaining the former
@@ -18464,7 +18844,22 @@ floor-clamped since the icon is decorative, not itself a pointer target), and
18464
18844
  is retuned while family/weight/line-height stay inherited) retune the row's geometry.
18465
18845
  While `icon-only`, `[part="base"]` resolves to a square hit target matching the icon-button
18466
18846
  footprint used elsewhere in this library (`aspect-ratio: 1` against its already floor-clamped
18467
- block size) instead of stretching across the rail's icon column.
18847
+ block size) instead of stretching across the rail's icon column. `--lr-app-rail-item-icon-only-size`
18848
+ (no default) sizes that square directly — both `inline-size` and `block-size`, and the row's own
18849
+ `min-block-size` floor — independent of `--lr-app-rail-item-min-block-size`, so a taller expanded
18850
+ row and an icon-only square pinned to `--lr-icon-button-size` can coexist. Unset, the square is
18851
+ still derived via `aspect-ratio: 1` against the row's block size exactly as before.
18852
+
18853
+ **`--lr-positioning-strategy`** (16.0.0) — the icon-only flyout tooltip reads this same cascading
18854
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
18855
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
18856
+ property on `<lr-app-rail-item>`; set the custom property on `:root`, a theme, or one clipping
18857
+ ancestor to change every unset rail item's flyout beneath it.
18858
+
18859
+ `--lr-app-rail-item-indent` (default `var(--lr-space-l)`) sets `[part="children"]`'s
18860
+ `padding-inline-start`. Applied once per nesting level — a doubly-nested `children` list compounds
18861
+ two insets automatically, since each level's own `[part="children"]` applies the token again.
18862
+ Logical, so it mirrors under `dir="rtl"` with no separate rule.
18468
18863
 
18469
18864
  **Optional peer deps:** none.
18470
18865
 
@@ -18791,6 +19186,13 @@ an out-of-syntax value falls back cleanly instead of invalidating the whole decl
18791
19186
  without `CSS.registerProperty` degrades to "use `100%`, not `none`".) A menu contained by
18792
19187
  `<lr-dropdown>` sizes from its dropdown and is unaffected by both names.
18793
19188
 
19189
+ **`--lr-positioning-strategy`** (16.0.0) — the private submenu surface reads this same cascading
19190
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
19191
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
19192
+ property on `<lr-menu>`; set the custom property on `:root`, a theme, or one clipping ancestor to
19193
+ change every unset submenu beneath it. A menu contained by `<lr-dropdown>` is positioned by the
19194
+ dropdown instead and is unaffected.
19195
+
18794
19196
  **Methods:** no menu-specific public overlay methods. Use `<lr-dropdown>`'s `show()`/`hide()` and
18795
19197
  `open` state for an overlay. Menu-item submenu methods remain public because they drive a row's
18796
19198
  nested disclosure.
@@ -19974,6 +20376,38 @@ omitted independently, while supplied empty strings remain valid. A custom defin
19974
20376
  adapter and a callable `render`; a rejected definition does not reserve its filter ID. Valid
19975
20377
  siblings remain available. Exceptions thrown by an admitted trusted renderer still propagate.
19976
20378
 
20379
+ **Lean registration entry.** `components/layout/filter-bar/filter-bar.js` (the default entry)
20380
+ eagerly imports every composed control this bar could possibly render — `<lr-select>`,
20381
+ `<lr-combobox>`, `<lr-dropdown>` + `<lr-dropdown-item>` (the `'checkbox-menu'` branch),
20382
+ `<lr-date-input>`, `<lr-input>`, `<lr-chip>`/`<lr-chip-group>` (the active-filter row), and
20383
+ `<lr-button>`/`<lr-spinner>` (the reset action and the loading status) — because `filters` is a
20384
+ runtime value it cannot inspect ahead of time. A bar that only ever declares `'select'`/`'text'`
20385
+ filters still pays for `<lr-combobox>` and `<lr-date-input>` through that entry: a measured ~69.5 kB
20386
+ gzip more than importing only what it uses. A consumer who knows their own filter `type`s ahead of
20387
+ time can import `components/layout/filter-bar/filter-bar-register.js` instead, which registers
20388
+ `<lr-filter-bar>` and nothing else, then import each composed control's own registration entry for
20389
+ the filter `type`s actually declared:
20390
+
20391
+ | Filter `type` | Registration entry |
20392
+ | --- | --- |
20393
+ | `'select'` | `components/forms/select/select.js` |
20394
+ | `'combobox'` | `components/forms/combobox/combobox.js` |
20395
+ | `'checkbox-menu'` | `components/overlays/overlay/dropdown.js` **and** `components/layout/menu/dropdown-item.js` |
20396
+ | `'date'` / `'date-range'` | `components/forms/date-picker/date-input.js` |
20397
+ | `'text'` | `components/forms/input/input.js` |
20398
+
20399
+ Two more are unconditional regardless of which filter `type`s are declared: `<lr-button>` renders
20400
+ the reset action on every bar, and `<lr-chip>`/`<lr-chip-group>` render the active-filter row
20401
+ whenever any filter has a value (further gated by `activeFiltersDisplay`, but never provably absent
20402
+ for a generic bar) — `components/forms/button/button.js` and `components/overlays/chip/chip.js` +
20403
+ `components/overlays/chip/chip-group.js`. `<lr-spinner>`
20404
+ (`components/overlays/spinner/spinner.js`) is the one built-in dependency the lean entry omits even
20405
+ though every bar could use it: `loading` is a plain boolean any consumer can leave unset entirely,
20406
+ unlike a filter `type`, which `filters` always names outright — import it too if the bar ever sets
20407
+ `loading`. A filter definition whose `type` has no matching import above renders no usable control
20408
+ until something else registers it, the same trade `icon-button-register.js` documents for
20409
+ `<lr-icon-button>`'s own `icon`/`src` attribute.
20410
+
19977
20411
  **Properties:**
19978
20412
 
19979
20413
  - `filters: readonly LyraFilterBarFilterDefinition[] = []` (attribute: false) — filter schema in
@@ -19998,8 +20432,20 @@ siblings remain available. Exceptions thrown by an admitted trusted renderer sti
19998
20432
  - `loading: boolean = false` (reflected) — shows the status spinner and disables reset while leaving
19999
20433
  filters editable.
20000
20434
  - `hasActiveFilters: boolean` (read-only) — whether any configured filter currently has a value.
20435
+ Drives the reset button's own disabled state; unaffected by `activeFiltersDisplay`.
20001
20436
  - `invalidFilterIds: readonly string[]` (read-only) — immutable ids of required filters whose
20002
20437
  values are unset.
20438
+ - `activeFiltersDisplay: 'all' | 'changed' | 'hidden' = 'all'` (reflected, attribute
20439
+ `active-filters-display`) — which currently-active filters render as removable chips in the row
20440
+ below the fields. `'all'` (the default, and this component's only behavior before this property
20441
+ existed) shows one chip per non-empty filter, including one sitting at its own `defaultValue`.
20442
+ `'changed'` shows a chip only for a filter whose value differs from its own `defaultValue` — so a
20443
+ bar whose defaults narrow the view on load does not claim the user narrowed it — and a filter with
20444
+ no declared `defaultValue` counts as changed as soon as it has any value at all. `'hidden'` never
20445
+ renders the row. Array values compare against `defaultValue` positionally (same length, same entry
20446
+ at each index), matching this component's only other array-equality precedent (a custom adapter's
20447
+ own `clearValue` comparison); a `'date-range'` value is a single composed string, so it compares
20448
+ like any other string. Removing a chip always clears that filter, unaffected by this property.
20003
20449
 
20004
20450
  The composed reset action uses `lr-button`'s default `m` size tier, matching the default rendered
20005
20451
  height of adjacent select, combobox, input, and date fields instead of introducing a shorter action
@@ -20028,12 +20474,13 @@ action) rendered inside `controls`, next to the reset button. Hidden and claimin
20028
20474
  space while nothing is slotted.
20029
20475
 
20030
20476
  **CSS parts:** `base`, `controls`, `field`, `field-<filterId>`, `end`, `filter-control`,
20031
- `filter-control-label`, `filter-control-field`, `filter-control-input`, `filter-control-start`,
20032
- `filter-control-end`, `filter-control-listbox`, `filter-control-option`, `filter-control-tags`,
20033
- `filter-control-tag`, `filter-control-tag-label`, `filter-control-clear-button`,
20034
- `filter-control-expand-button`, `filter-control-expand-icon`, `filter-control-popup`,
20035
- `filter-control-error`, `filter-control-hint`, `active-filters`, `chips`, `chip`, `reset-button`,
20036
- `status`.
20477
+ `filter-control-label`, `filter-control-label-group`, `filter-control-field`,
20478
+ `filter-control-input`, `filter-control-start`, `filter-control-end`, `filter-control-listbox`,
20479
+ `filter-control-option`, `filter-control-tags`, `filter-control-tag`, `filter-control-tag-label`,
20480
+ `filter-control-tag-remove-button`, `filter-control-tag-remove-button-base`,
20481
+ `filter-control-clear-button`, `filter-control-expand-button`, `filter-control-expand-icon`,
20482
+ `filter-control-popup`, `filter-control-error`, `filter-control-hint`, `active-filters`, `chips`,
20483
+ `chip`, `reset-button`, `status`.
20037
20484
 
20038
20485
  The `filter-control-*` parts are semantic aliases forwarded from each built-in control's shadow
20039
20486
  surface. `filter-control-field` consistently reaches the select trigger, combobox container, or
@@ -20041,9 +20488,23 @@ text/date input wrapper; `filter-control-input` reaches the corresponding displa
20041
20488
  Listbox/option aliases apply to select and combobox filters, `filter-control-tags`/
20042
20489
  `filter-control-tag`/`filter-control-tag-label` apply to a `multiple` combobox filter's selected-tag
20043
20490
  chips (`filter-control-tag-label` is capped by that control's own `--tag-max-size`), and
20044
- expand-button/popup apply to date filters. This lets a consumer theme the composed tier from
20491
+ expand-button/popup apply to date filters. `filter-control-tag-remove-button`/
20492
+ `filter-control-tag-remove-button-base` reach a selected tag's own remove button and its inner icon
20493
+ wrapper — the same reach a standalone `lr-combobox`/`lr-select` consumer already has, now available
20494
+ from `lr-filter-bar` too, for a consumer re-skinning filter tags as pills who needs the remove
20495
+ target inside one to be stylable. This lets a consumer theme the composed tier from
20045
20496
  `lr-filter-bar::part(...)` without depending on the built-in control type selected by a filter
20046
20497
  definition. Custom renderers retain ownership of their own part forwarding.
20498
+
20499
+ A `multiple` `'combobox'` filter collapses past its own `max-options-visible` (3 by default, an
20500
+ `<lr-combobox>` property this component does not forward) into a localized "+N" overflow indicator,
20501
+ the same substance as `lr-select`'s own `multiple`-mode overflow chip. The one remaining difference:
20502
+ `lr-select`'s overflow chip carries a second, distinguishing `tag-overflow` part
20503
+ (`part="tag tag-overflow tag__base"`) so a consumer can style just that chip; `lr-combobox`'s
20504
+ overflow chip carries only the plain `tag` part, with no equivalent token to forward as
20505
+ `filter-control-tag-overflow`. Adding one is `<lr-combobox>`'s own surface to grow, not something
20506
+ `lr-filter-bar`'s `exportparts` can manufacture for a part its composed child never renders — noted
20507
+ here as a known, deliberate gap rather than silently undocumented.
20047
20508
  On a `'checkbox-menu'` filter, `filter-control-field` is the trigger button's own frame — the
20048
20509
  element inside `<lr-button>` that draws the border, background and radius, not the chrome-less
20049
20510
  button host, so a `::part(filter-control-field) { border-color: … }` rule works there exactly as it
@@ -20052,7 +20513,19 @@ a definition `icon` lands), `filter-control-input` is its selection summary, `fi
20052
20513
  is the trigger's own label text (not a stacked label above the control), `filter-control-listbox` is
20053
20514
  the dropdown's popup surface, `filter-control-option` is one `role="menuitemcheckbox"` row, and
20054
20515
  `filter-control-error` is the revealed required message — rendered by the bar itself, because the
20055
- composed dropdown has no error chrome of its own.
20516
+ composed dropdown has no error chrome of its own. The trigger also renders a `with-caret` disclosure
20517
+ chevron, matching `lr-select`'s own — forwarded as `filter-control-expand-icon`, the same name a
20518
+ select/combobox/date-input filter's own chevron already uses, so one consumer rule styles every
20519
+ filter type's expand icon. `filter-control-label-group` reaches the trigger's own label wrapper —
20520
+ the flex row this component lays `filter-control-label` and `filter-control-input` out in, which
20521
+ also grows to fill the stretched trigger (via `with-caret`) so its content starts at the leading
20522
+ edge instead of centring; no other filter type renders this part, since every other type's label and
20523
+ input are two independent elements with no shared wrapper of their own. This component does not
20524
+ render a stacked label above a `'checkbox-menu'` field the way every other built-in type does:
20525
+ every other type's stacked label is rendered by the composed control itself, and there is no
20526
+ equivalent shared "stacked label" template inside `<lr-filter-bar>` for this branch to reuse without
20527
+ inventing a new one, so `labelVisibility` keeps its narrower meaning here (whether the trigger's own
20528
+ baked-in label text is visible or screen-reader-only).
20056
20529
 
20057
20530
  `field` wraps one filter's composed control and its validation spacer inside `controls`; its
20058
20531
  flex-basis is themeable via `--lr-filter-bar-field-basis` (default `var(--lr-size-12rem)`).
@@ -20070,12 +20543,17 @@ alone, exactly as before this part existed, rather than risking a `part` attribu
20070
20543
  space-separated token list fabricates an unrelated second token.
20071
20544
 
20072
20545
  A `'select'`, `'combobox'` or `'checkbox-menu'` filter's required `options` entries are
20073
- `LyraFilterBarOption { value, label, icon?, searchText? }`. `searchText` is extra text the option
20074
- also matches on, forwarded verbatim to `<lr-option>`'s own `search-text`, so a row can keep a short
20075
- visible `label` ("Urgent") while still matching a long canonical key ("SEV-1 production outage").
20076
- It affects a `'combobox'` filter only: the attribute is written on every choice type's `<lr-option>`,
20077
- but `<lr-select>`'s listbox type-ahead matches the option's `label` alone and never reads it, and a
20078
- `'checkbox-menu'` has no text entry to match against.
20546
+ `LyraFilterBarOption { value, label, icon?, searchText?, disabled? }`. `searchText` is extra text
20547
+ the option also matches on, forwarded verbatim to `<lr-option>`'s own `search-text`, so a row can
20548
+ keep a short visible `label` ("Urgent") while still matching a long canonical key ("SEV-1
20549
+ production outage"). It affects a `'combobox'` filter only: the attribute is written on every
20550
+ choice type's `<lr-option>`, but `<lr-select>`'s listbox type-ahead matches the option's `label`
20551
+ alone and never reads it, and a `'checkbox-menu'` has no text entry to match against. `disabled`
20552
+ marks the option non-actionable: forwarded to `<lr-option disabled>` for `'select'`/`'combobox'`
20553
+ and to the composed `<lr-dropdown-item disabled>` for `'checkbox-menu'`, so the row renders
20554
+ genuinely disabled (no tab/roving stop, no hover/press affordance) and arrow-key navigation already
20555
+ steps past it, since that is the composed control's own existing `disabled` behavior. Omitted or
20556
+ `false` renders the option exactly as before this field existed.
20079
20557
  `icon` is optional Lit content — a status dot, a type glyph, a flag — rendered into the composed
20080
20558
  `<lr-option>`'s own `start` slot as inert, `aria-hidden` chrome, so it never joins the option's
20081
20559
  accessible name:
@@ -20507,6 +20985,12 @@ These named interfaces and helper signatures are available to typed integrations
20507
20985
  open: boolean;
20508
20986
  }`
20509
20987
 
20988
+ - **`components-layout-app-rail-item-app-rail-item-contracts`** — Supporting data types and helpers for this component family.
20989
+ Import: `@aceshooting/lyra-ui/components/layout/app-rail/app-rail-item.class.js`.
20990
+ `LyraAppRailItemToggleDetail {
20991
+ open: boolean;
20992
+ }`
20993
+
20510
20994
  - **`components-layout-command-palette-command-palette-contracts`** — Supporting data types and helpers for this component family.
20511
20995
  Import: `@aceshooting/lyra-ui/components/layout/command-palette/command-palette.class.js`.
20512
20996
  `LyraCommand {
@@ -20819,6 +21303,7 @@ These named interfaces and helper signatures are available to typed integrations
20819
21303
  readonly label: string;
20820
21304
  readonly icon?: unknown;
20821
21305
  readonly searchText?: string;
21306
+ readonly disabled?: boolean;
20822
21307
  }`
20823
21308
  Import: `@aceshooting/lyra-ui/components/layout/filter-bar/filter-bar.class.js`.
20824
21309
  `LyraFilterBarResetDetail {
@@ -21618,6 +22103,16 @@ controls, rendered before the built-in close button), `footer` — all inherited
21618
22103
  Names grouped together are aliases on the same functional node; `close-button__control` is the
21619
22104
  composed `<lr-icon-button>`'s own native `<button>`, inherited from `lr-dialog` as of 16.0.0.
21620
22105
 
22106
+ **Migrating a pre-16.0.0 `::part()` rule.** This component's icon-only action is a composed
22107
+ `<lr-icon-button>`, so the part naming that action now names the composed child's HOST, which
22108
+ paints nothing. A `border`, `background` or `border-radius` set on it is silently dead — only
22109
+ `color` still appears to work, because it inherits, which makes such a rule look half-alive rather
22110
+ than broken. Set `--lr-icon-button-background`/`-color`/`-border`/`-radius` (and their
22111
+ `-hover`/`-active` variants) on this element or an ancestor instead: the composed control reads
22112
+ those public tokens ahead of any default this component supplies. For SIZE use
22113
+ `--lr-theme-icon-button-size`, not `--lr-icon-button-size` — every `LyraElement` re-declares the
22114
+ latter on its own `:host`, so it never reaches a composed child (see `llms/tokens.md`).
22115
+
21621
22116
  **Themeable custom properties:** mapped `--size` controls the active axis. For start/end drawers,
21622
22117
  the inherited `--width` and `--lr-dialog-width` remain compatibility fallbacks when neither
21623
22118
  `--size` nor `--lr-drawer-width` is set, and `--lr-dialog-max-width` remains an effective cap,
@@ -21842,6 +22337,27 @@ focusable control _inside_ the body, and the body itself is used only when there
21842
22337
  focus. So a dialog full of form controls behaves exactly as before, and a dialog full of text is now
21843
22338
  scrollable with the arrow keys, Page Up/Down and Home/End once Tab reaches it.
21844
22339
 
22340
+ **Migrating a pre-16.0.0 `::part()` rule.** This component's icon-only action is a composed
22341
+ `<lr-icon-button>`, so the part naming that action now names the composed child's HOST, which
22342
+ paints nothing. A `border`, `background` or `border-radius` set on it is silently dead — only
22343
+ `color` still appears to work, because it inherits, which makes such a rule look half-alive rather
22344
+ than broken. Set `--lr-icon-button-background`/`-color`/`-border`/`-radius` (and their
22345
+ `-hover`/`-active` variants) on this element or an ancestor instead: the composed control reads
22346
+ those public tokens ahead of any default this component supplies. For SIZE use
22347
+ `--lr-theme-icon-button-size`, not `--lr-icon-button-size` — every `LyraElement` re-declares the
22348
+ latter on its own `:host`, so it never reaches a composed child (see `llms/tokens.md`).
22349
+
22350
+ **Border reaches the composed close control the same way background/color/radius do.** This
22351
+ component paints no resting border of its own, so it relays no `--_lr-icon-button-border-default`
22352
+ into the close control's private fallback tier — but that absence is not a gap. The public
22353
+ `--lr-icon-button-border` (and its `-hover`/`-active` variants) is the FIRST arm of the token
22354
+ chain, resolved by ordinary custom-property inheritance regardless of whether this component
22355
+ relays a default for that same property, so setting it on this element or an ancestor reaches the
22356
+ close control exactly as the background/color/radius tokens do. A component with no resting
22357
+ border simply has no default to relay, which is different from border theming being broken. Size
22358
+ remains the one exception that does not cross this way: use `--lr-theme-icon-button-size`, never
22359
+ `--lr-icon-button-size`, as noted above.
22360
+
21845
22361
  **Themeable custom properties:** mapped aliases are `--backdrop-filter`, `--width`, `--spacing`,
21846
22362
  `--header-spacing`, `--body-spacing`, `--footer-spacing`, `--show-duration`, and
21847
22363
  `--hide-duration`. The individual region properties override `--spacing`; mapped properties in
@@ -23613,6 +24129,16 @@ The surface chrome lives on the custom-element host, not inside `base`. Ordinary
23613
24129
  work directly and take normal author precedence. `inline` removes the host's border, background,
23614
24130
  and padding.
23615
24131
 
24132
+ **Migrating a pre-16.0.0 `::part()` rule.** This component's icon-only action is a composed
24133
+ `<lr-icon-button>`, so the part naming that action now names the composed child's HOST, which
24134
+ paints nothing. A `border`, `background` or `border-radius` set on it is silently dead — only
24135
+ `color` still appears to work, because it inherits, which makes such a rule look half-alive rather
24136
+ than broken. Set `--lr-icon-button-background`/`-color`/`-border`/`-radius` (and their
24137
+ `-hover`/`-active` variants) on this element or an ancestor instead: the composed control reads
24138
+ those public tokens ahead of any default this component supplies. For SIZE use
24139
+ `--lr-theme-icon-button-size`, not `--lr-icon-button-size` — every `LyraElement` re-declares the
24140
+ latter on its own `:host`, so it never reaches a composed child (see `llms/tokens.md`).
24141
+
23616
24142
  **Themeable custom properties:** `--lr-callout-background`, `--lr-callout-color`, and
23617
24143
  `--lr-callout-border` read the inherited generic semantic quiet/loud slots, with brand quiet/loud
23618
24144
  as their standalone fallback. An explicit `variant` maps all generic slots locally; leaving it
@@ -24055,6 +24581,12 @@ The menu popup is a floating surface and paints from the **shared overlay-surfac
24055
24581
  declared on `:host`, so one declaration on `:root` — or on any ancestor, to scope it — retints this
24056
24582
  surface together with every other floating surface in the library. `--lr-overlay-radius` (default `var(--lr-radius)`) is the matching corner radius.
24057
24583
 
24584
+ `--lr-positioning-strategy` (16.0.0) — the format menu reads this same cascading `absolute`/`fixed`
24585
+ override documented on `<lr-popover>` when it is (re)positioned, falling back to its own `fixed`
24586
+ default when nothing is set. There is no per-instance `positioning-strategy` property on
24587
+ `<lr-export-button>`; set the custom property on `:root`, a theme, or one clipping ancestor to
24588
+ change every unset export button beneath it.
24589
+
24058
24590
  **Optional peer deps:** none.
24059
24591
 
24060
24592
  ```html
@@ -24832,6 +25364,11 @@ preserving null readback; an explicitly empty query remains empty.
24832
25364
  pre-`query`-filtering. Assignment takes a shallow frozen snapshot. Runtime rows without a string
24833
25365
  `label` remain in that diagnostic snapshot but are omitted from filtering/rendering before the
24834
25366
  built-in or custom predicate runs, so one malformed provider row cannot take down valid siblings.
25367
+ An entry's `disabled` marks that row non-actionable: `aria-disabled="true"` replaces its
25368
+ selected/active affordances, activating it (click, or Enter/Tab while highlighted) commits
25369
+ nothing and emits no `lr-mention-select`, and ArrowDown/ArrowUp highlighting -- including the
25370
+ default pre-highlighted first row -- steps past it instead of landing on it. Omitted or `false`
25371
+ renders the row exactly as before this field existed.
24835
25372
  - `query: string = ''` — the text typed since the trigger character; drives the built-in filtering
24836
25373
  (see `filter`).
24837
25374
  - `open: boolean = false` (reflected)
@@ -24876,7 +25413,7 @@ preserving null readback; an explicitly empty query remains empty.
24876
25413
  disconnect/adoption, a newer transfer, or failed ownership resolves `false` without moving focus.
24877
25414
 
24878
25415
  **Exported types:** `LyraMentionItem { suggestionId: string; label: string; description?: string;
24879
- icon?: string }`; `LyraMentionFilter = (item: LyraMentionItem, query: string) => boolean`;
25416
+ icon?: string; disabled?: boolean }`; `LyraMentionFilter = (item: LyraMentionItem, query: string) => boolean`;
24880
25417
  `LyraMentionFocusOptions { ownsFocus?: () => boolean }`;
24881
25418
  `LyraMentionSelectDetail { suggestionId: string; index: number; label: string }`.
24882
25419
 
@@ -24897,7 +25434,9 @@ renders `open="false"` on first paint)
24897
25434
  `var(--lr-color-brand-quiet)`) — background of the hovered or `[data-active]`
24898
25435
  (keyboard-highlighted) suggestion row. Component-scoped indirection over the shared
24899
25436
  `--lr-color-brand-quiet` token, so a consumer can retheme just this highlighted/active row without
24900
- repainting every other component that reuses the same shared token. Plus shared tokens —
25437
+ repainting every other component that reuses the same shared token.
25438
+ `--lr-mention-popover-option-disabled-opacity` (default `0.5`) — opacity of a row whose `items`
25439
+ entry sets `disabled`. Plus shared tokens —
24901
25440
  `--lr-space-xs`/`-s`/`-m` (popup padding,
24902
25441
  row padding/gap), `--lr-radius`
24903
25442
  (row corners — the popup's own corner is the overlay family's, below),
@@ -24914,6 +25453,12 @@ The popup is a floating surface and paints from the **shared overlay-surface fam
24914
25453
  declared on `:host`, so one declaration on `:root` — or on any ancestor, to scope it — retints this
24915
25454
  surface together with every other floating surface in the library. `--lr-overlay-radius` (default `var(--lr-radius)`) is the matching corner radius.
24916
25455
 
25456
+ `--lr-positioning-strategy` (16.0.0) — the popup reads this same cascading `absolute`/`fixed`
25457
+ override documented on `<lr-popover>` when it is (re)positioned, falling back to its own `fixed`
25458
+ default when nothing is set. There is no per-instance `positioning-strategy` property on
25459
+ `<lr-mention-popover>`; set the custom property on `:root`, a theme, or one clipping ancestor to
25460
+ change every unset mention popover beneath it.
25461
+
24917
25462
  **Optional peer deps:** none.
24918
25463
 
24919
25464
  ```html
@@ -25894,6 +26439,12 @@ shared ceiling that keeps any floating surface inside a narrow viewport. `lr-tou
25894
26439
  retuning `--lr-theme-popover-viewport-clamp` once at `:root` narrows or widens all three together
25895
26440
  rather than per component.
25896
26441
 
26442
+ `--lr-positioning-strategy` (16.0.0) — the step popover reads this same cascading `absolute`/`fixed`
26443
+ override documented on `<lr-popover>` when a step is (re)positioned, falling back to its own `fixed`
26444
+ default when nothing is set. There is no per-instance `positioning-strategy` property on `<lr-tour>`;
26445
+ set the custom property on `:root`, a theme, or one clipping ancestor to change every unset tour
26446
+ beneath it.
26447
+
25897
26448
  **Known gotchas:**
25898
26449
 
25899
26450
  - By default the spotlighted target is **non-interactive**: it stays visible and announceable (not
@@ -26007,6 +26558,7 @@ These named interfaces and helper signatures are available to typed integrations
26007
26558
  readonly label: string;
26008
26559
  readonly description?: string;
26009
26560
  readonly icon?: string;
26561
+ readonly disabled?: boolean;
26010
26562
  }`
26011
26563
  Import: `@aceshooting/lyra-ui/components/utility/mention-popover/mention-popover.class.js`.
26012
26564
  `LyraMentionSelectDetail {
@@ -27002,16 +27554,25 @@ reimplemented.
27002
27554
  - `maxFileSize: number = 0` (attribute `max-file-size` — bytes; `0` disables the check), `maxFiles:
27003
27555
  number = 0` (attribute `max-files`), `maxTotalSize: number = 0` (attribute `max-total-size`) —
27004
27556
  identical contract and invalid-override fail-safe fallback to `lr-file-input`'s own three limits.
27005
- Since this component retains nothing between drops, `maxFiles`/`maxTotalSize` always cover only
27006
- the current drop (there is no persisted count/total to add).
27557
+ Since this component retains nothing of its own between drops, `maxFiles`/`maxTotalSize` would
27558
+ otherwise always cover only the current drop `heldFileCount`/`heldTotalSize` below are what let
27559
+ a cumulative cap span separate drops.
27560
+ - `heldFileCount: number = 0` (attribute `held-file-count`) and `heldTotalSize: number = 0`
27561
+ (attribute `held-total-size`) — externally held baseline added to the running count/byte-total
27562
+ `maxFiles`/`maxTotalSize` evaluate against, identical contract to `lr-file-input`'s own
27563
+ `heldFileCount`/`heldTotalSize`: `0` (the default) means "nothing held" and reproduces prior
27564
+ behavior exactly, and a negative, `NaN`, or `Infinity` override is normalized to `0` via
27565
+ `finiteCount` rather than corrupting every later comparison.
27007
27566
  - `readonly dragging: boolean` — `true` during an active drag session
27008
27567
 
27009
27568
  **Events:** `lr-files` (`detail: LyraDropZoneFilesDetail`, with fresh frozen readonly `files` and
27010
- `rejected` arrays and frozen rejected-file records, fired on drop; immutable `File` objects retain
27011
- identity) typed as `LyraDropZoneFilesEvent`, so `event.target`/`event.currentTarget` are
27012
- `LyraDropZone` without a cast. `LyraDropZoneRejectedFile = { readonly file: File; readonly reason:
27013
- 'type' | 'count' | 'size' | 'directory' | 'read' | 'limit' | 'maxFiles' | 'maxTotalSize' }`, the
27014
- same reason vocabulary as `lr-file-input`'s `LyraFileInputRejectedFile`.
27569
+ `rejected` arrays and frozen rejected-file records, plus `remainingFiles`/`remainingTotalSize`
27570
+ reporting the allowance still left under `maxFiles`/`maxTotalSize` after this drop (`null` while
27571
+ that limit is unset), fired on drop; immutable `File` objects retain identity) typed as
27572
+ `LyraDropZoneFilesEvent`, so `event.target`/`event.currentTarget` are `LyraDropZone` without a
27573
+ cast. `LyraDropZoneRejectedFile = { readonly file: File; readonly reason: 'type' | 'count' | 'size'
27574
+ | 'directory' | 'read' | 'limit' | 'maxFiles' | 'maxTotalSize' }`, the same reason vocabulary as
27575
+ `lr-file-input`'s `LyraFileInputRejectedFile`.
27015
27576
 
27016
27577
  **Slots:** the default slot is the wrapped region, rendered as ordinary light DOM; `overlay`
27017
27578
  overrides the localized accept/reject overlay text.
@@ -27112,14 +27673,23 @@ enabled buttons retain pointer feedback.
27112
27673
  update them by assigning a new collection.
27113
27674
  - `maxFileSize: number = 0` (attribute `max-file-size` — bytes; `0` disables the check)
27114
27675
  - `maxFiles: number = 0` (attribute `max-files`) — largest total file count accepted, counting
27115
- retained files plus the current batch; `0` disables the check. An excess file in the batch is
27116
- rejected with reason `'maxFiles'`, in the same `[part="rejection"]` shape as `maxFileSize`. While
27117
- `nonRetaining` is set, the count covers only the current batch (there is no externally-held count
27118
- to add).
27676
+ retained files (unless `nonRetaining`) plus `heldFileCount` plus the current batch; `0` disables
27677
+ the check. An excess file in the batch is rejected with reason `'maxFiles'`, in the same
27678
+ `[part="rejection"]` shape as `maxFileSize`.
27119
27679
  - `maxTotalSize: number = 0` (attribute `max-total-size`) — largest combined byte size accepted,
27120
- summing retained files plus the current batch; `0` disables the check. Same rejection-UI shape and
27121
- fail-safe invalid-override behavior as `maxFileSize` (see gotchas). Same `nonRetaining` batch-only
27122
- scoping as `maxFiles`.
27680
+ summing retained files (unless `nonRetaining`) plus `heldTotalSize` plus the current batch; `0`
27681
+ disables the check. Same rejection-UI shape and fail-safe invalid-override behavior as
27682
+ `maxFileSize` (see gotchas).
27683
+ - `heldFileCount: number = 0` (attribute `held-file-count`) — externally held file count added to
27684
+ the running count `maxFiles` evaluates against, in both retaining and `nonRetaining` modes — the
27685
+ numeric counterpart of `valuePresent`, for a cumulative cap (e.g. a server-backed upload limit)
27686
+ that spans separate picker sessions rather than resetting to what this control alone can see. `0`
27687
+ (the default) means "nothing held" and reproduces prior behavior exactly. A negative, `NaN`, or
27688
+ `Infinity` override is normalized to `0` via `finiteCount` rather than corrupting every later
27689
+ comparison or permanently blocking every future file.
27690
+ - `heldTotalSize: number = 0` (attribute `held-total-size`) — externally held byte total added to
27691
+ the running size `maxTotalSize` evaluates against, in both retaining and `nonRetaining` modes.
27692
+ Same contract, default, and invalid-input normalization as `heldFileCount`.
27123
27693
  - `nonRetaining: boolean = false` (reflected, attribute `non-retaining`) — opt-in mode where an
27124
27694
  accepted selection still fires `lr-files`/`input`/`change` but is never written to `files` or
27125
27695
  rendered as a built-in `[part="file"]` row. For a host that persists files elsewhere and renders
@@ -27198,9 +27768,11 @@ enabled buttons retain pointer feedback.
27198
27768
  host `change`; programmatic `files` writes are silent (both still fire while `nonRetaining` is set,
27199
27769
  even though `files` itself is not written in that mode). `lr-files` (`detail:
27200
27770
  LyraFileInputFilesDetail`, with fresh frozen readonly `files` and `rejected` arrays and frozen
27201
- rejected-file records, fired on both drop and manual file-picker selection; immutable `File` objects
27202
- retain identity) typed as `LyraFileInputFilesEvent`, so `event.target`/`event.currentTarget` are
27203
- `LyraFileInput` without a cast. `LyraFileInputRejectedFile = { readonly file: File; readonly reason:
27771
+ rejected-file records, plus `remainingFiles`/`remainingTotalSize` reporting the allowance still left
27772
+ under `maxFiles`/`maxTotalSize` after this batch (`null` while that limit is unset), fired on both
27773
+ drop and manual file-picker selection; immutable `File` objects retain identity) typed as
27774
+ `LyraFileInputFilesEvent`, so `event.target`/`event.currentTarget` are `LyraFileInput` without a
27775
+ cast. `LyraFileInputRejectedFile = { readonly file: File; readonly reason:
27204
27776
  'type' | 'count' | 'size' | 'directory' | 'read' | 'limit' | 'maxFiles' | 'maxTotalSize' }`: `'type'`
27205
27777
  from `accept`/`allowedMimeTypes`/`forbiddenMimeTypes`, `'count'` when a single-file input
27206
27778
  (`multiple` unset) receives more than one file (in which case _all_ files are rejected, none
@@ -28074,6 +28646,27 @@ painted surface sits one boundary deeper),
28074
28646
  hidden via CSS by default, exposed as a part only so a consumer can override that with
28075
28647
  `::part(hidden-input)` in the unlikely case their integration needs to).
28076
28648
 
28649
+ **Migrating a pre-16.0.0 `::part()` rule.** This component's icon-only action is a composed
28650
+ `<lr-icon-button>`, so the part naming that action now names the composed child's HOST, which
28651
+ paints nothing. A `border`, `background` or `border-radius` set on it is silently dead — only
28652
+ `color` still appears to work, because it inherits, which makes such a rule look half-alive rather
28653
+ than broken. Set `--lr-icon-button-background`/`-color`/`-border`/`-radius` (and their
28654
+ `-hover`/`-active` variants) on this element or an ancestor instead: the composed control reads
28655
+ those public tokens ahead of any default this component supplies. For SIZE use
28656
+ `--lr-theme-icon-button-size`, not `--lr-icon-button-size` — every `LyraElement` re-declares the
28657
+ latter on its own `:host`, so it never reaches a composed child (see `llms/tokens.md`).
28658
+
28659
+ **An ancestor's public border wins over this component's own relayed default, not just its
28660
+ absence.** Unlike most composing components, the `outlined`/`filled-outlined` appearances here DO
28661
+ relay a non-zero `--_lr-icon-button-border-default` (a themed edge) into the trigger's private
28662
+ fallback tier. That does not change the resolution order: `--lr-icon-button-border` (and its
28663
+ `-hover`/`-active` variants) is still the FIRST arm of the token chain, read by the composed
28664
+ trigger ahead of whatever this component relays, so setting it on this element or an ancestor
28665
+ overrides the outlined edge exactly as it overrides the `plain`/`filled`/`accent` appearances'
28666
+ zero default. The private relay is only this component's own default opinion, never a gate the
28667
+ public token must pass through. Size remains the one exception that does not cross this way: use
28668
+ `--lr-theme-icon-button-size`, never `--lr-icon-button-size`, as noted above.
28669
+
28077
28670
  **Themeable custom properties:** shared tokens only — `--lr-space-xs`, `--lr-color-text`/
28078
28671
  `-text-quiet`, `--lr-icon-button-size`, `--lr-focus-ring-*`, `--lr-opacity-disabled`,
28079
28672
  `--lr-radius`, `--lr-transition-fast`.
@@ -29205,6 +29798,8 @@ These named interfaces and helper signatures are available to typed integrations
29205
29798
  `LyraDropZoneFilesDetail {
29206
29799
  readonly files: readonly File[];
29207
29800
  readonly rejected: readonly LyraDropZoneRejectedFile[];
29801
+ readonly remainingFiles: number | null;
29802
+ readonly remainingTotalSize: number | null;
29208
29803
  }`
29209
29804
  Import: `@aceshooting/lyra-ui/components/media/drop-zone/drop-zone.class.js`.
29210
29805
  `LyraDropZoneFilesEvent extends CustomEvent<LyraDropZoneFilesDetail> {
@@ -29253,6 +29848,8 @@ These named interfaces and helper signatures are available to typed integrations
29253
29848
  `LyraFileInputFilesDetail {
29254
29849
  readonly files: readonly File[];
29255
29850
  readonly rejected: readonly LyraFileInputRejectedFile[];
29851
+ readonly remainingFiles: number | null;
29852
+ readonly remainingTotalSize: number | null;
29256
29853
  }`
29257
29854
  Import: `@aceshooting/lyra-ui/components/media/file-input/file-input.class.js`.
29258
29855
  `LyraFileInputObjectValidator {
@@ -29725,8 +30322,14 @@ structured points retain their y-value formatting.
29725
30322
  - `labels: readonly string[] = []` (attribute: false)
29726
30323
  - `datasets: readonly LyraChartSeries[] = []` (attribute: false) — `LyraChartSeries { readonly
29727
30324
  label: string; readonly data?: readonly (number|null)[]; readonly points?: readonly
29728
- LyraChartPoint[]; readonly color?: string|readonly string[]; ... }`. The deprecated `Series` and
29729
- `ChartPoint` names were removed in 9.0.0 — import `LyraChartSeries`/`LyraChartPoint` instead.
30325
+ LyraChartPoint[]; readonly color?: string|readonly string[]; readonly stack?: string; ... }`. The
30326
+ deprecated `Series` and `ChartPoint` names were removed in 9.0.0 — import
30327
+ `LyraChartSeries`/`LyraChartPoint` instead.
30328
+ - `stack` is a Chart.js dataset `stack` group id: series sharing one `stack` value on the same
30329
+ (stacked) axis accumulate into one stack; a different id starts an independent stack Chart.js
30330
+ draws side by side with the first on that axis. Omitted series share one implicit group, so
30331
+ every chart written before `stack` existed sums exactly as it always did. Only meaningful on an
30332
+ axis that is actually stacked — see `stacked`/`stackedAxes` below.
29730
30333
  `LyraChartPoint { readonly x: number; readonly
29731
30334
  y: number; readonly r?: number; readonly label?: string }`: `r` is the bubble
29732
30335
  radius, and the optional per-point `label` is retained by events, CSV export, keyboard
@@ -29821,6 +30424,16 @@ structured points retain their y-value formatting.
29821
30424
  and the stack's own `axis`, but no `datasetIndex` and no `seriesLabel` — naming the topmost
29822
30425
  series would make a unit-switching formatter render that one series' unit for a cross-series
29823
30426
  number. `lr-lite-chart`'s total cells drop the same two fields.
30427
+ - `tooltipTitleFormatter?: LyraChartTooltipGroupFormatter` (attribute: false) — tooltip title
30428
+ formatter (e.g. a scatter point's own name). `LyraChartTooltipGroupFormatter = (items:
30429
+ readonly LyraChartFormatterContext[]) => string`: unlike `formatter`, which runs once per item,
30430
+ this runs once per tooltip render and receives every hovered item's context at once (one entry
30431
+ per dataset the tooltip covers, each in the same shape `formatter`'s `'tooltip'` surface already
30432
+ produces). Unset (the default) leaves Chart.js's own default title — the shared category label.
30433
+ - `tooltipFooterFormatter?: LyraChartTooltipGroupFormatter` (attribute: false) — tooltip footer
30434
+ formatter (e.g. a category's stack total under the items), in the same shape and calling
30435
+ convention as `tooltipTitleFormatter`. Unset (the default) leaves Chart.js's own default: no
30436
+ footer.
29824
30437
  - `area: boolean = false` — chart-wide default for whether line-type series fill the region under
29825
30438
  their line; a series's own `fill` overrides it, rendered with a translucent version of its color
29826
30439
  - `zoom: boolean = false` — wheel/drag/pinch zoom on the `x` axis only (pan disabled, and the zoom
@@ -29835,6 +30448,14 @@ structured points retain their y-value formatting.
29835
30448
  - `stacked: boolean = false` — stacks the `x`/`y`(/`y2`) scale entries `buildScales()` returns; only
29836
30449
  meaningful for `bar`/`line` types (scatter/bubble's linear `x` scale and the radial `r` scale used
29837
30450
  by radar/polar-area are out of scope)
30451
+ - `stackedAxes?: Partial<Record<'y' | 'y2', boolean>>` (attribute: false) — per-value-axis override
30452
+ of `stacked`, keyed by `'y'`/`'y2'`. An axis absent from this record — including every axis when
30453
+ the whole property is unset — falls back to `stacked`, so a chart that never sets this renders
30454
+ byte-identically to before. Lets a `stacked` bar series on the primary axis sit next to an
30455
+ unstacked overlay series on `y2` (via `LyraChartSeries.axis: 'y2'`): e.g. `stacked` plus
30456
+ `stackedAxes: { y2: false }`. The shared categorical axis (`x` for a vertical bar/line, or `y`
30457
+ under a horizontal `indexAxis`) has no entry of its own — it always mirrors the resolved `'y'`
30458
+ value, matching Chart.js's own paired index/value-scale stacking contract.
29838
30459
  - `withoutAnimation: boolean = false` (attribute `without-animation`, reflected) — disables Chart.js
29839
30460
  construction animation; reduced-motion preference also disables it regardless of this value
29840
30461
  - `withoutTooltip: boolean = false` (attribute `without-tooltip`, reflected) — disables the
@@ -29847,14 +30468,20 @@ structured points retain their y-value formatting.
29847
30468
  `feature-warning` plus assertive announcement explains the nonfatal limitation. The screen-reader
29848
30469
  equivalent is the always-present accessible data table (`show-data-table` makes it visible) —
29849
30470
  labels are a purely visual, canvas-only addition and add no new a11y surface.
29850
- - `stackTotals: boolean = false` (attribute `stack-totals`) — with `stacked` (bar/line only), draws
29851
- the per-category stack total above each stack, via the same `chartjs-plugin-datalabels` peer.
29852
- Null/undefined points are skipped; a category whose every value is null shows no total (not
29853
- `0`). The generated accessible table receives the same formatted total column; a dual-axis stack
29854
- receives separately labelled primary- and secondary-axis total columns. The table totals do not
29855
- depend on the optional visual-label peer being installed. If that peer is unavailable, the chart
29856
- retains its core rendering and generated table totals while a localized nonfatal warning explains
29857
- that the canvas labels cannot be drawn.
30471
+ - `stackTotals: boolean = false` (attribute `stack-totals`) — on an actually-stacked axis (`stacked`
30472
+ or `stackedAxes`, bar/line only), draws the per-category stack total above each stack, via the
30473
+ same `chartjs-plugin-datalabels` peer. Computed per `LyraChartSeries.stack` group as well as per
30474
+ axis: two stack groups sharing one axis each get their own total, drawn above their own topmost
30475
+ dataset, and a dataset on an axis that isn't stacked (e.g. an unstacked `stackedAxes` overlay)
30476
+ never gets one. Null/undefined points are skipped; a category whose every value is null shows no
30477
+ total (not `0`). The generated accessible table receives one formatted total column per stacked
30478
+ axis (a dual-axis stack gets separately labelled primary- and secondary-axis columns); with
30479
+ multiple stack groups on one axis, that column still totals only the implicit group of series
30480
+ that never set their own `stack` id — a per-group breakdown is available programmatically but not
30481
+ yet surfaced as extra table columns. The table totals do not depend on the optional visual-label
30482
+ peer being installed. If that peer is unavailable, the chart retains its core rendering and
30483
+ generated table totals while a localized nonfatal warning explains that the canvas labels cannot
30484
+ be drawn.
29858
30485
  - `config?: LyraChartConfiguration` (attribute: false) — peer-neutral configuration structurally
29859
30486
  compatible with Chart.js's `ChartConfiguration`, deep-merged over the generated
29860
30487
  config; any nested key wins without clobbering sibling generated keys. This is the raw Chart.js
@@ -30175,8 +30802,9 @@ announced. In particular, unavailable data labels do not remove generated table
30175
30802
  pending. Independently, `updated()` only reaches
30176
30803
  Chart.js when at least one of `type`, `labels`, `datasets`, `description`, `grid`, `axes`, `compact`, `indexAxis`,
30177
30804
  `label`, `hiddenDatasets`, `legendPosition`, `min`, `max`, `plugins`, the internal resolved auto legend
30178
- position, `valueFormatter`, `formatter`, `area`, `height`, `xLabel`, `yLabel`, `y2Label`, `beginAtZero`,
30179
- `stacked`, any `without*` control, `dataLabels`, `stackTotals`, `config`, the parsed
30805
+ position, `valueFormatter`, `formatter`, `tooltipTitleFormatter`, `tooltipFooterFormatter`, `area`,
30806
+ `height`, `xLabel`, `yLabel`, `y2Label`, `beginAtZero`,
30807
+ `stacked`, `stackedAxes`, any `without*` control, `dataLabels`, `stackTotals`, `config`, the parsed
30180
30808
  slotted config, `zoom`, `locale`, `strings`, or the internal loading state actually changed in
30181
30809
  that update (so an
30182
30810
  unrelated property/state update, or a bare `requestUpdate()`, draws nothing). Resize callbacks
@@ -30200,6 +30828,19 @@ tooltips (native SVG `<title>`, no positioning JS) — not a full `lr-chart` rep
30200
30828
  zoom/pan, no pie/doughnut/radar/scatter/bubble types, no horizontal/dual-y-axis, no raw-config
30201
30829
  passthrough). Not a subclass of `LyraChart`.
30202
30830
 
30831
+ Deliberate omissions, assessed and not implemented: `lr-chart`'s per-series `LyraChartSeries.stack`
30832
+ group and per-axis `stackedAxes` have no `lr-lite-chart` counterpart. `stacked` here is already
30833
+ chart-wide only (see below) and this component has exactly one value scale — no `y2` — so "an
30834
+ unstacked overlay on a second axis," the motivating case for `stackedAxes`, has no equivalent
30835
+ shape to express. A per-series stack-group id would also need the hand-rolled SVG bar-geometry
30836
+ pass (linear/sqrt/log stack compression, `minBarHeight`) to track independent running offsets per
30837
+ group instead of one per category, which is a materially larger, higher-risk change than this
30838
+ component's existing single-stack model. `tooltipTitleFormatter`/`tooltipFooterFormatter` are
30839
+ similarly absent: this component's hover tooltip is a native SVG `<title>` on each mark — one
30840
+ self-contained string per mark, generated by `pointText` — not a Chart.js-style multi-item tooltip
30841
+ with separate title/body/footer regions for several datasets sharing a hovered category, so there
30842
+ is no "every item in the tooltip" surface to hook a title or footer formatter onto.
30843
+
30203
30844
  **Properties:**
30204
30845
  - `type: LyraLiteChartType = 'bar'` — `'bar' | 'line'`
30205
30846
  - `labels: readonly string[] = []` (attribute: false)
@@ -30518,9 +31159,10 @@ of every entry in these lists.**
30518
31159
  **Properties:** `description`, `grid`, `axes`, `compact`, `indexAxis` (`index-axis`), `label`, `hiddenDatasets`, `legendPosition`
30519
31160
  (`legend-position`), `hiddenDatums`, `legendMode` (`legend-mode`), `legendDisplay` (`legend-display`),
30520
31161
  `max`, `min`, `plugins`, `scaleType` (`scale-type`), `annotations`,
30521
- `stacked`, `withoutAnimation` (`without-animation`),
31162
+ `stacked`, `stackedAxes`, `withoutAnimation` (`without-animation`),
30522
31163
  `withoutLegend` (`without-legend`), `withoutTooltip` (`without-tooltip`), `xLabel` (`x-label`),
30523
- `yLabel` (`y-label`), plus additive `labels`, `datasets`, `valueFormatter`, `formatter`, `area`, `zoom`,
31164
+ `yLabel` (`y-label`), plus additive `labels`, `datasets`, `valueFormatter`, `formatter`,
31165
+ `tooltipTitleFormatter`, `tooltipFooterFormatter`, `area`, `zoom`,
30524
31166
  `height`, `y2Label` (`y2-label`), `beginAtZero` (`begin-at-zero`), `dataLabels`
30525
31167
  (`data-labels`), `stackTotals` (`stack-totals`), `config`, `showDataTable`
30526
31168
  (`show-data-table`), `dataTableToggle` (`data-table-toggle`), `chartArea` (readonly), and `chart`.
@@ -30607,9 +31249,10 @@ Bins `values` into `bins` equal-width buckets and renders as a bar chart (extend
30607
31249
  (`index-axis`), `hiddenDatasets`, `hiddenDatums`, `legendPosition` (`legend-position`),
30608
31250
  `legendMode` (`legend-mode`), `legendDisplay` (`legend-display`), `max`, `min`, `plugins`,
30609
31251
  `withoutAnimation` (`without-animation`), `withoutLegend` (`without-legend`), `withoutTooltip`
30610
- (`without-tooltip`), `valueFormatter`, `formatter`, `area`, `zoom`, `config`, `height`, `xLabel` (`x-label`),
31252
+ (`without-tooltip`), `valueFormatter`, `formatter`, `tooltipTitleFormatter`,
31253
+ `tooltipFooterFormatter`, `area`, `zoom`, `config`, `height`, `xLabel` (`x-label`),
30611
31254
  `yLabel` (`y-label`), `y2Label` (`y2-label`), `beginAtZero` (`begin-at-zero`),
30612
- `stacked`, `dataLabels` (`data-labels`), `stackTotals` (`stack-totals`), `showDataTable`
31255
+ `stacked`, `stackedAxes`, `dataLabels` (`data-labels`), `stackTotals` (`stack-totals`), `showDataTable`
30613
31256
  (`show-data-table`), `dataTableToggle` (`data-table-toggle`), `chartArea` (readonly).
30614
31257
 
30615
31258
  **Methods:** `resetZoom()`, `refreshTheme()`, and `renderChart()` are inherited; `appendSamples(values,
@@ -30673,6 +31316,10 @@ their semantics, defaults, and gotchas.
30673
31316
  - `values`/`bins`/`seriesLabel` changes join the inherited connected-and-visible redraw path. There is no
30674
31317
  second post-update refresh, so a same-tick disconnect cannot recreate Chart.js on a detached
30675
31318
  canvas and off-screen sample updates do not repaint it.
31319
+ - calling `binValues()` directly (not through `<lr-histogram>`, which always passes its own
31320
+ resolved `effectiveLocale`) with an omitted `locale` (or `'auto'`) now resolves to the page's
31321
+ active `setLyraLocale()` locale instead of a hardcoded `'en'`, matching `utilities/format.ts`'s
31322
+ helpers; an app that never calls `setLyraLocale()` sees no change, and an explicit tag still wins.
30676
31323
 
30677
31324
  ---
30678
31325
 
@@ -31060,6 +31707,7 @@ These named interfaces and helper signatures are available to typed integrations
31060
31707
  hidden?: boolean;
31061
31708
  axis?: string;
31062
31709
  yAxisID?: string;
31710
+ stack?: string;
31063
31711
  noTooltip?: boolean;
31064
31712
  fill?: unknown;
31065
31713
  backgroundColor?: unknown;
@@ -31142,6 +31790,7 @@ These named interfaces and helper signatures are available to typed integrations
31142
31790
  readonly dash?: boolean;
31143
31791
  readonly noTooltip?: boolean;
31144
31792
  readonly axis?: 'y' | 'y2';
31793
+ readonly stack?: string;
31145
31794
  readonly pointColors?: readonly string[];
31146
31795
  readonly pointRadius?: number | readonly number[];
31147
31796
  readonly segmentColors?: readonly string[];
@@ -35130,7 +35779,11 @@ focus move.
35130
35779
 
35131
35780
  **Exported types:**
35132
35781
 
35133
- - `LyraCatalogEntry { id: string; label: string }` — the shared minimum row vocabulary.
35782
+ - `LyraCatalogEntry { id: string; label: string; disabled?: boolean }` — the shared minimum row
35783
+ vocabulary. `disabled` marks a row non-actionable: `aria-disabled="true"` replaces its
35784
+ selected/active affordances, activating it (click or keyboard) commits nothing and changes no
35785
+ state, and arrow-key/Home/End active-descendant navigation steps past it instead of landing on
35786
+ it. Omitted or `false` renders the row exactly as before this field existed.
35134
35787
  - `LyraCatalog<T extends LyraCatalogEntry = LyraCatalogEntry> = readonly string[] | readonly T[]`
35135
35788
  — a homogeneous catalog shared by model-select, voice-picker, and composed controls. String
35136
35789
  shorthand uses the same string for both id and label; readonly tuples/arrays are accepted. Ids
@@ -35324,7 +35977,8 @@ use, not on `:host`, so it isn't tied to `size`. The selected row
35324
35977
  `--lr-model-select-option-selected-border` and `--lr-model-select-option-selected-color` (both
35325
35978
  `var(--lr-color-brand)`), and `--lr-model-select-option-selected-font-weight`
35326
35979
  (`var(--lr-font-weight-semibold)`), all inline `var()` fallbacks so the selected row is rethemeable
35327
- without hijacking `--lr-color-brand`. `--lr-model-select-max-inline-size` (default
35980
+ without hijacking `--lr-color-brand`. `--lr-model-select-option-disabled-opacity` (default `0.5`)
35981
+ — opacity of an option row whose catalog entry sets `disabled`. `--lr-model-select-max-inline-size` (default
35328
35982
  `var(--lr-size-24rem)`) publishes the host's own width ceiling, which was previously a hard-wired
35329
35983
  literal: set a length to retune it, or `none` to let the control fill its container the way
35330
35984
  `lr-select` does. Like every other name here it is read as a `var()` fallback and never declared on
@@ -35399,6 +36053,32 @@ not a delta — this component does no accumulation or ordering of its own.
35399
36053
  `<lr-code-block>`/`<lr-markdown>` support. Unset leaves the composed element's own default
35400
36054
  untouched.
35401
36055
 
36056
+ The rest of `<lr-markdown>`'s configuration surface forwards verbatim too, each defaulting to
36057
+ exactly `<lr-markdown>`'s own default so leaving it unset renders identically to before these
36058
+ properties existed:
36059
+
36060
+ - `tabSize: number = 4` (attribute `tab-size`) — forwarded to the composed `<lr-markdown>`'s own
36061
+ `tabSize`.
36062
+ - `htmlMode: 'sanitize' | 'escape' | 'trusted' = 'sanitize'` (attribute `html-mode`) — forwarded to
36063
+ the composed `<lr-markdown>`'s own `htmlMode`.
36064
+ - `gfm: boolean = true` — forwarded to the composed `<lr-markdown>`'s own `gfm`.
36065
+ - `linkTarget: string | null = '_blank'` (attribute `link-target`) — forwarded to the composed
36066
+ `<lr-markdown>`'s own `linkTarget`; the composed element always applies its own
36067
+ `rel="noopener noreferrer"` guard whenever a `target` is emitted, including a forwarded
36068
+ non-default value, and never a bare `opener`.
36069
+ - `internalLinkPrefix: string = ''` (attribute `internal-link-prefix`) — forwarded to the composed
36070
+ `<lr-markdown>`'s own `internalLinkPrefix`.
36071
+ - `headingOffset: number = 0` (attribute `heading-offset`) — forwarded to the composed
36072
+ `<lr-markdown>`'s own `headingOffset`.
36073
+ - `highlightCode: boolean = true` (attribute `highlight-code`) — forwarded to the composed
36074
+ `<lr-markdown>`'s own `highlightCode`.
36075
+ - `headingAnchors: boolean = false` (attribute `heading-anchors`) — forwarded to the composed
36076
+ `<lr-markdown>`'s own `headingAnchors`.
36077
+ - `math: boolean = false` — forwarded to the composed `<lr-markdown>`'s own `math`; the transitive
36078
+ `katex` peer is requested only once this is set.
36079
+ - `maxHeight: string = ''` (attribute `max-height`) — forwarded to the composed `<lr-markdown>`'s
36080
+ own `maxHeight`.
36081
+
35402
36082
  **Exported helper:** `looksLikeMarkdown(text: string): boolean` — runs a fixed, ordered list of
35403
36083
  lightweight regexes (ATX heading, fenced code block, `**bold**`, `_italic_`, inline code, bullet
35404
36084
  list item, numbered list item, `[text](url)` link, blockquote) against the whole string and returns
@@ -35435,8 +36115,9 @@ does not register it separately), so its optional-peer module graph includes `ma
35435
36115
  stay on the peer-free plain-text path; Markdown rendering lazy-loads `marked` plus the default
35436
36116
  `dompurify` sanitizer and falls back to readable plain text if either is unavailable. Fenced code
35437
36117
  can additionally use `shiki`, whose absence only leaves code unhighlighted. The composed Markdown
35438
- implementation contains the opt-in `katex` loader, but this wrapper does not enable its `math`
35439
- property and therefore never requests `katex` itself.
36118
+ implementation contains the opt-in `katex` loader; this wrapper forwards its own `math` property
36119
+ (default `false`) to the composed element verbatim, so `katex` is requested only once a consumer
36120
+ sets `math` here.
35440
36121
 
35441
36122
  ```html
35442
36123
  <lr-streaming-text id="out" coalesce-ms="80" streaming></lr-streaming-text>
@@ -35461,8 +36142,11 @@ never be left stranded mid-window, and a stream restarting on a reused element c
35461
36142
  showing the previous stream's stale final content for the length of the window.
35462
36143
 
35463
36144
  Rendering itself is never reimplemented here: Markdown mode composes `<lr-markdown>` directly,
35464
- forwarding this component's own `streaming` through as that component's `streaming` hint prop and
35465
- `languages` verbatim; plain-text mode renders into a `white-space: pre-wrap` span instead. The
36145
+ forwarding this component's own `streaming` through as that component's `streaming` hint prop,
36146
+ `languages` verbatim, and the rest of `<lr-markdown>`'s configuration surface verbatim too
36147
+ (`tabSize`, `htmlMode`, `gfm`, `linkTarget`, `internalLinkPrefix`, `headingOffset`,
36148
+ `highlightCode`, `headingAnchors`, `math`, `maxHeight` — see **Properties** above); plain-text mode
36149
+ renders into a `white-space: pre-wrap` span instead. The
35466
36150
  blinking cursor degrades
35467
36151
  to a static, always-visible bar under `prefers-reduced-motion: reduce`. In plain-text mode it sits
35468
36152
  inline at the tail of the final character; in Markdown mode it renders as its own trailing block
@@ -35490,13 +36174,15 @@ happens to end with.
35490
36174
  A build-lean `<lr-streaming-text>` variant for a consumer whose fenced-code `languages` map already
35491
36175
  covers every language it will ever stream, or who never renders fenced code at all. Every
35492
36176
  capability — token coalescing, `contentMode` auto-detection, the blinking cursor, the
35493
- `lr-content-settled` event, the `languages` property is identical to `<lr-streaming-text>`; only
35494
- which Markdown element Markdown mode composes differs: this variant renders `<lr-markdown-core>`
35495
- (`../markdown/markdown-core.js`) instead of `<lr-markdown>`, so importing this entry point instead
35496
- of `streaming-text.js` never references `<lr-markdown>`'s ~200-language dynamic-import table at
35497
- all. A fenced code block whose language isn't a key in `languages` always renders the plain-text
35498
- fallback there is no default/full-table highlighter here to fall back to, mirroring
35499
- `<lr-markdown-core>`'s own contract.
36177
+ `lr-content-settled` event, the `languages` property, and the full forwarded Markdown configuration
36178
+ surface (`tabSize`, `htmlMode`, `gfm`, `linkTarget`, `internalLinkPrefix`, `headingOffset`,
36179
+ `highlightCode`, `headingAnchors`, `math`, `maxHeight`) is identical to `<lr-streaming-text>`;
36180
+ only which Markdown element Markdown mode composes differs: this variant renders
36181
+ `<lr-markdown-core>` (`../markdown/markdown-core.js`) instead of `<lr-markdown>`, so importing this
36182
+ entry point instead of `streaming-text.js` never references `<lr-markdown>`'s ~200-language
36183
+ dynamic-import table at all. A fenced code block whose language isn't a key in `languages` always
36184
+ renders the plain-text fallback — there is no default/full-table highlighter here to fall back to,
36185
+ mirroring `<lr-markdown-core>`'s own contract.
35500
36186
 
35501
36187
  **Properties:** `content: string = ''` — the full current text so far, identical contract to
35502
36188
  `<lr-streaming-text>`'s own; `streaming: boolean = false` (reflected); `coalesceMs: number = 50`
@@ -35505,7 +36191,18 @@ fallback — there is no default/full-table highlighter here to fall back to, mi
35505
36191
  `content-mode`, reflected) — `auto`
35506
36192
  uses `looksLikeMarkdown`, `plain`/`markdown` force their named paths; `languages?:
35507
36193
  Readonly<Record<string, ShikiLanguageInput>>` (property only) — forwarded verbatim to the composed
35508
- `<lr-markdown-core>`'s own `languages` instead of `<lr-markdown>`'s.
36194
+ `<lr-markdown-core>`'s own `languages` instead of `<lr-markdown>`'s (defaulting the composed
36195
+ element's own `languages` to `{}` when unset, unlike the full variant's `undefined`). The rest of
36196
+ `<lr-markdown-core>`'s configuration surface forwards verbatim too, sharing the same properties,
36197
+ attribute names, and defaults described under `<lr-streaming-text>`'s own **Properties** above:
36198
+ `tabSize: number = 4` (attribute `tab-size`); `htmlMode: 'sanitize' | 'escape' | 'trusted' =
36199
+ 'sanitize'` (attribute `html-mode`); `gfm: boolean = true`; `linkTarget: string | null = '_blank'`
36200
+ (attribute `link-target`, still guarded by the composed element's own
36201
+ `rel="noopener noreferrer"` whenever a `target` is emitted); `internalLinkPrefix: string = ''`
36202
+ (attribute `internal-link-prefix`); `headingOffset: number = 0` (attribute `heading-offset`);
36203
+ `highlightCode: boolean = true` (attribute `highlight-code`); `headingAnchors: boolean = false`
36204
+ (attribute `heading-anchors`); `math: boolean = false`; `maxHeight: string = ''` (attribute
36205
+ `max-height`).
35509
36206
 
35510
36207
  **Exported helper:** `looksLikeMarkdown(text: string): boolean` — the same standalone heuristic
35511
36208
  `<lr-streaming-text>` exports and documents, in `llms/components/lr-streaming-text.md`; both tags
@@ -35765,6 +36462,27 @@ header gap — a rule that sets `display` on it must qualify itself with `:not([
35765
36462
  `line-button` (a gutter line-number button, only rendered while `activatableLines` and `lineNumbers`
35766
36463
  are both set)
35767
36464
 
36465
+ **Migrating a pre-16.0.0 `::part()` rule.** This component's icon-only action is a composed
36466
+ `<lr-icon-button>`, so the part naming that action now names the composed child's HOST, which
36467
+ paints nothing. A `border`, `background` or `border-radius` set on it is silently dead — only
36468
+ `color` still appears to work, because it inherits, which makes such a rule look half-alive rather
36469
+ than broken. Set `--lr-icon-button-background`/`-color`/`-border`/`-radius` (and their
36470
+ `-hover`/`-active` variants) on this element or an ancestor instead: the composed control reads
36471
+ those public tokens ahead of any default this component supplies. For SIZE use
36472
+ `--lr-theme-icon-button-size`, not `--lr-icon-button-size` — every `LyraElement` re-declares the
36473
+ latter on its own `:host`, so it never reaches a composed child (see `llms/tokens.md`).
36474
+
36475
+ **Border reaches the composed copy control the same way background/color/radius do.** This
36476
+ component paints no resting border of its own, so it relays no `--_lr-icon-button-border-default`
36477
+ into the copy control's private fallback tier — but that absence is not a gap. The public
36478
+ `--lr-icon-button-border` (and its `-hover`/`-active` variants) is the FIRST arm of the token
36479
+ chain, resolved by ordinary custom-property inheritance regardless of whether this component
36480
+ relays a default for that same property, so setting it on this element or an ancestor reaches the
36481
+ copy control exactly as the background/color/radius tokens do. A component with no resting
36482
+ border simply has no default to relay, which is different from border theming being broken. Size
36483
+ remains the one exception that does not cross this way: use `--lr-theme-icon-button-size`, never
36484
+ `--lr-icon-button-size`, as noted above.
36485
+
35768
36486
  **Themeable custom properties:** `--lr-code-block-max-height` (default `none` — an independently
35769
36487
  settable scroll cap; a `max-height` attribute writes the same property inline on `body` and wins),
35770
36488
  `--lr-code-block-font` (default
@@ -36260,6 +36978,16 @@ or an ancestor, or reach a built-in's composed native control directly through
36260
36978
  media rule then floors the rendered hit area at 2.75rem/44px regardless of how far a dense-row
36261
36979
  override lowered it, so the shrink is safe on a touch device.
36262
36980
 
36981
+ **Migrating a pre-16.0.0 `::part()` rule.** This component's icon-only actions are composed
36982
+ `<lr-icon-button>`s, so a part naming one of them now names the composed child's HOST, which paints
36983
+ nothing. A `border`, `background` or `border-radius` set on it is silently dead — only `color` still
36984
+ appears to work, because it inherits, which makes such a rule look half-alive rather than broken.
36985
+ Set `--lr-icon-button-background`/`-color`/`-border`/`-radius` (and their `-hover`/`-active`
36986
+ variants) on this element or an ancestor instead: the composed control reads those public tokens
36987
+ ahead of any default this component supplies. For SIZE use `--lr-theme-icon-button-size`, not
36988
+ `--lr-icon-button-size` — every `LyraElement` re-declares the latter on its own `:host`, so it never
36989
+ reaches a composed child (see `llms/tokens.md`).
36990
+
36263
36991
  ## `lr-message-feedback`
36264
36992
 
36265
36993
  Thumbs up/down for one assistant message, with an optional inline detail step (categorical reason
@@ -36597,12 +37325,15 @@ identifier disappears, focus repairs to the nearest surviving occurrence without
36597
37325
  external focus move.
36598
37326
 
36599
37327
  **Properties:** `suggestions: readonly LyraChatSuggestion[] = []` (attribute: false) —
36600
- `LyraChatSuggestion { suggestionId: string; label: string; icon?: string; detail?: string }`
37328
+ `LyraChatSuggestion { suggestionId: string; label: string; icon?: string; detail?: string; disabled?: boolean }`
36601
37329
  (exported here). Identifiers must be nonempty and unique; invalid/later duplicates are omitted with
36602
37330
  the first valid occurrence winning. The input is clone-owned, bounded, and frozen; reassign a new
36603
37331
  array after changing the sequence or a row. `icon` is an optional
36604
37332
  peer-neutral literal hint (for example, an emoji), rendered decoratively before the text, and
36605
- `detail` is an optional secondary line. Empty renders nothing at all. `wrap: boolean = false`
37333
+ `detail` is an optional secondary line. `disabled` marks a suggestion non-actionable: its chip
37334
+ renders a genuinely disabled `<button>` (no roving tab stop, no hover/press affordance), activating
37335
+ it emits nothing, and arrow-key/Home/End roving navigation steps past it. Empty renders nothing at
37336
+ all. `wrap: boolean = false`
36606
37337
  (reflected) — wraps into multiple rows instead of a single horizontally scrollable line. `label?:
36607
37338
  string` — accessible name for the group. Omitting it uses the localized `suggestionsLabel`; an
36608
37339
  explicit empty string intentionally leaves the group unnamed.
@@ -36621,7 +37352,8 @@ cannot do (once the chips wrap, the row fills the available inline size and each
36621
37352
  start). `--lr-suggestion-chips-hover-bg` (default `var(--lr-color-brand-quiet)`) — a `chip`'s
36622
37353
  background on hover. `--lr-suggestion-chips-hover-border` (default `var(--lr-color-brand)`) — a
36623
37354
  `chip`'s border color on hover. All three are declared as `var()` fallbacks at the point of use, not
36624
- on `:host`. Plus shared tokens `--lr-space-xs/-m/-2xs`,
37355
+ on `:host`. `--lr-suggestion-chips-disabled-opacity` (default `0.5`) — opacity of a chip whose
37356
+ suggestion sets `disabled`. Plus shared tokens `--lr-space-xs/-m/-2xs`,
36625
37357
  `--lr-color-border/-surface/-text/-text-quiet`, `--lr-radius-pill`, `--lr-font-size-xs`,
36626
37358
  `--lr-focus-ring-width/-color/-offset`.
36627
37359
 
@@ -37019,6 +37751,12 @@ family** (16.0.0): `--lr-overlay-surface` (default `var(--lr-color-surface-overl
37019
37751
  ancestor, to scope it — retints this surface together with every other floating surface in the
37020
37752
  library. `--lr-overlay-radius` (default `var(--lr-radius)`) is the matching corner radius.
37021
37753
 
37754
+ `--lr-positioning-strategy` (16.0.0) — the breakdown tooltip reads this same cascading
37755
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
37756
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
37757
+ property on `<lr-usage-badge>`; set the custom property on `:root`, a theme, or one clipping
37758
+ ancestor to change every unset usage badge beneath it.
37759
+
37022
37760
  ```html
37023
37761
  <lr-chat-message message-role="assistant" status="sent">
37024
37762
  <lr-usage-badge
@@ -37262,8 +38000,11 @@ popup. Ordinary keyboard behavior resumes after composition.
37262
38000
  **Exported types:** `LyraVoiceCatalogEntry extends LyraCatalogEntry { language?: string;
37263
38001
  description?: string; previewUrl?: string }` — `language`/`description` render as a quiet
37264
38002
  `[part="option-meta"]` second line. Voice catalogs use the shared
37265
- `LyraCatalog<LyraVoiceCatalogEntry>` homogeneous readonly union documented under `lr-model-select`.
37266
- The public `size` property uses `LyraSize`, including the long-form aliases.
38003
+ `LyraCatalog<LyraVoiceCatalogEntry>` homogeneous readonly union documented under `lr-model-select`,
38004
+ including the shared `disabled` field: a disabled voice row cannot be selected by click or keyboard
38005
+ and is stepped over by arrow-key/Home/End navigation, but its own `[part="option-preview"]` stays
38006
+ independently clickable, since previewing a voice is a separate affordance from selecting it. The
38007
+ public `size` property uses `LyraSize`, including the long-form aliases.
37267
38008
  `LyraVoicePickerSelectionDirection = 'forward' | 'backward' | 'none'` is the native
37268
38009
  selection direction exposed in free-text mode.
37269
38010
 
@@ -37423,6 +38164,7 @@ trigger), `expand-icon`, `empty`, `hint`, `error`.
37423
38164
  - `--lr-voice-picker-option-selected-font-weight` — Selected option label weight. Default: `var(--lr-font-weight-semibold)`.
37424
38165
  - `--lr-voice-picker-option-synthetic-border-style` — Synthetic stale-value row border style. Default: `dashed`.
37425
38166
  - `--lr-voice-picker-option-synthetic-border-color` — Synthetic stale-value row border color. Default: `var(--lr-color-border)`.
38167
+ - `--lr-voice-picker-option-disabled-opacity` — Opacity of an option row whose catalog entry sets `disabled`. Default: `0.5`.
37426
38168
  - `--lr-voice-picker-option-synthetic-font-style` — Synthetic stale-value option-label font style. Default: `italic`.
37427
38169
  - `--lr-voice-picker-preview-hover-bg` — Preview hover fill. Default: `var(--lr-color-brand-quiet)`.
37428
38170
  - `--lr-voice-picker-preview-hover-color` — Preview hover icon. Default: `var(--lr-color-brand)`.
@@ -37685,8 +38427,8 @@ Every array-valued property above is a clone-owned, bounded, frozen readonly sna
37685
38427
  nested source children and queued attachments. Mutating a previously assigned collection has no
37686
38428
  effect; create and reassign a new array after changes.
37687
38429
 
37688
- `LyraPromptSuggestion` extends `LyraMentionItem { suggestionId, label, description?, icon? }` with
37689
- optional `insertText` (defaults to `label`). The selected occurrence's original, pre-filter `index`
38430
+ `LyraPromptSuggestion` extends `LyraMentionItem { suggestionId, label, description?, icon?, disabled? }`
38431
+ with optional `insertText` (defaults to `label`). The selected occurrence's original, pre-filter `index`
37690
38432
  is preserved in the event detail. `LyraPromptInputAttachment` replaces `DocumentRef.id` with
37691
38433
  `attachmentId` and adds `file?`, `bytes?`, `status?: 'pending' | 'uploading' | 'error' | 'success'`,
37692
38434
  and numeric `progress?`.
@@ -38203,6 +38945,7 @@ These named interfaces and helper signatures are available to typed integrations
38203
38945
  // Inherited from LyraCatalogEntry.
38204
38946
  id: string;
38205
38947
  label: string;
38948
+ disabled?: boolean;
38206
38949
  }`
38207
38950
 
38208
38951
  - **`components-conversation-model-settings-panel-model-settings-panel-contracts`** — Supporting data types and helpers for this component family.
@@ -38235,6 +38978,7 @@ These named interfaces and helper signatures are available to typed integrations
38235
38978
  readonly label: string;
38236
38979
  readonly description?: string;
38237
38980
  readonly icon?: string;
38981
+ readonly disabled?: boolean;
38238
38982
  }`
38239
38983
 
38240
38984
  - **`components-conversation-prompt-queue-prompt-queue-contracts`** — Supporting data types and helpers for this component family.
@@ -38275,6 +39019,7 @@ These named interfaces and helper signatures are available to typed integrations
38275
39019
  label: string;
38276
39020
  icon?: string;
38277
39021
  detail?: string;
39022
+ disabled?: boolean;
38278
39023
  }`
38279
39024
 
38280
39025
  - **`components-conversation-transcript-feed-transcript-feed-contracts`** — Supporting data types and helpers for this component family.
@@ -38296,6 +39041,7 @@ These named interfaces and helper signatures are available to typed integrations
38296
39041
  // Inherited from LyraCatalogEntry.
38297
39042
  id: string;
38298
39043
  label: string;
39044
+ disabled?: boolean;
38299
39045
  }`
38300
39046
 
38301
39047
  - **`internal-catalog-picker-contracts`** — Shared utility contracts.
@@ -38303,6 +39049,7 @@ These named interfaces and helper signatures are available to typed integrations
38303
39049
  `LyraCatalogEntry {
38304
39050
  id: string;
38305
39051
  label: string;
39052
+ disabled?: boolean;
38306
39053
  }`
38307
39054
 
38308
39055
  # Agent tooling, tool calls & evaluation (`components/agent-tools/`)
@@ -38413,6 +39160,12 @@ The anchored detail tooltip is a floating surface and paints from the **shared o
38413
39160
  declared on `:host`, so one declaration on `:root` — or on any ancestor, to scope it — retints this
38414
39161
  surface together with every other floating surface in the library. `--lr-overlay-radius` (default `var(--lr-radius)`) is the matching corner radius.
38415
39162
 
39163
+ `--lr-positioning-strategy` (16.0.0) — the detail tooltip reads this same cascading
39164
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
39165
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
39166
+ property on `<lr-tool-call-chip>`; set the custom property on `:root`, a theme, or one clipping
39167
+ ancestor to change every unset chip beneath it.
39168
+
38416
39169
  **Optional peer deps:** none.
38417
39170
 
38418
39171
  ```html
@@ -40486,13 +41239,21 @@ real overlays use.
40486
41239
  `returnFocusTo: ConfirmBarReturnFocusTarget = null` (attribute: false) — where focus goes once a
40487
41240
  decision lands, instead of parking on `[part="status"]`.
40488
41241
  `ConfirmBarReturnFocusTarget = HTMLElement | null | (() => HTMLElement | null)`; the thunk form is
40489
- resolved at handoff time, because a host that swaps a focused control out for this bar often
40490
- re-creates that control on the way back. It applies to every path that reaches a decision, a
40491
- `pending` decision finalized externally included. A named target that is missing, detached, `inert`,
40492
- or otherwise refuses focus falls back to `[part="status"]` rather than to `<body>` an `inert`
40493
- element refuses `focus()` silently. Left unset, the handoff is byte-identical to the shipped one.
40494
- The pending state is deliberately *not* affected: while a decision is awaiting resolution, focus
40495
- still parks on `[part="status"]`, because that is not the return journey yet.
41242
+ called at handoff time, because a host that swaps a focused control out for this bar often
41243
+ re-creates that control on the way back and, because every supported host framework re-renders
41244
+ asynchronously relative to that synchronous handoff, the control frequently does not exist yet at
41245
+ that first call. When the first call does not yet name a live, focusable element, the same handoff
41246
+ calls the thunk again once the host has had a real chance to react (its own re-render committed),
41247
+ and moves focus there if it has since appeared and nothing else has claimed focus in the meantime —
41248
+ this is what makes the swap-a-trigger-for-this-bar case actually work, rather than only working when
41249
+ the host happens to re-create its control before the decision lands. A plain element value is
41250
+ resolved once, synchronously, and never retried: it names something that either already exists or
41251
+ never will. It applies to every path that reaches a decision, a `pending` decision finalized
41252
+ externally included. A named target that is missing, detached, `inert`, or otherwise refuses focus
41253
+ falls back to `[part="status"]` rather than to `<body>` — an `inert` element refuses `focus()`
41254
+ silently. Left unset, the handoff is byte-identical to the shipped one. The pending state is
41255
+ deliberately *not* affected: while a decision is awaiting resolution, focus still parks on
41256
+ `[part="status"]`, because that is not the return journey yet.
40496
41257
 
40497
41258
  **Slots:** default — supplementary body content between the heading and the actions (e.g. a
40498
41259
  `lr-diff-view`). `footer` — extra content at the start of the action row.
@@ -40618,6 +41379,27 @@ bar.addEventListener("lr-approve", (e) => {
40618
41379
  });
40619
41380
  ```
40620
41381
 
41382
+ A host that reveals this bar in place of a control it just hid — the `returnFocusTo` motivating
41383
+ case — does not need to order that swap relative to the line above. A reactive host's own re-render
41384
+ (replacing this bar with its trigger again) runs on its own update cycle, which lands asynchronously
41385
+ either way, so `returnFocusTo`'s thunk is written to be called twice: once immediately, in case the
41386
+ control already exists, and once more after the host has had a chance to react if the first call
41387
+ found nothing yet:
41388
+
41389
+ ```ts
41390
+ bar.returnFocusTo = () => document.querySelector('[data-action="delete"]');
41391
+ bar.addEventListener("lr-approve", (e) => {
41392
+ e.preventDefault();
41393
+ runApproval(e.detail.args)
41394
+ .then(() => {
41395
+ bar.decision = "approved"; // the host's own state clear can happen before or after this
41396
+ })
41397
+ .catch(() => {
41398
+ bar.pending = null;
41399
+ });
41400
+ });
41401
+ ```
41402
+
40621
41403
  ## `lr-browser-frame`
40622
41404
 
40623
41405
  Presentational "agent computer" viewport: a screenshot/frame stream (or slotted live media), a
@@ -42857,6 +43639,12 @@ The anchored detail popover is a floating surface and paints from the **shared o
42857
43639
  declared on `:host`, so one declaration on `:root` — or on any ancestor, to scope it — retints this
42858
43640
  surface together with every other floating surface in the library. `--lr-overlay-radius` (default `var(--lr-radius)`) is the matching corner radius.
42859
43641
 
43642
+ `--lr-positioning-strategy` (16.0.0) — the preview popover reads this same cascading
43643
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
43644
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
43645
+ property on `<lr-entity-chip>`; set the custom property on `:root`, a theme, or one clipping
43646
+ ancestor to change every unset entity chip beneath it.
43647
+
42860
43648
  **Optional peer deps:** none.
42861
43649
 
42862
43650
  ```html
@@ -43483,6 +44271,12 @@ The anchored source-preview popover is a floating surface and paints from the **
43483
44271
  declared on `:host`, so one declaration on `:root` — or on any ancestor, to scope it — retints this
43484
44272
  surface together with every other floating surface in the library. `--lr-overlay-radius` (default `var(--lr-radius)`) is the matching corner radius.
43485
44273
 
44274
+ `--lr-positioning-strategy` (16.0.0) — the source-preview popover reads this same cascading
44275
+ `absolute`/`fixed` override documented on `<lr-popover>` when it is (re)positioned, falling back to
44276
+ its own `fixed` default when nothing is set. There is no per-instance `positioning-strategy`
44277
+ property on `<lr-citation-badge>`; set the custom property on `:root`, a theme, or one clipping
44278
+ ancestor to change every unset citation badge beneath it.
44279
+
43486
44280
  **Optional peer deps:** none.
43487
44281
 
43488
44282
  ```html