@aceshooting/lyra-ui 9.1.1 → 10.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (578) hide show
  1. package/CHANGELOG.md +597 -0
  2. package/custom-elements.json +1 -1
  3. package/dist/cli/migrate-wa.mjs +52 -0
  4. package/dist/cli/migration-contract.json +1 -1
  5. package/dist/components/agent-tools/activity-feed/activity-feed.class.js +1 -1
  6. package/dist/components/agent-tools/activity-feed/activity-feed.styles.js +0 -16
  7. package/dist/components/agent-tools/agent-eval-dashboard/agent-eval-dashboard.class.js +1 -1
  8. package/dist/components/agent-tools/agent-eval-dashboard/agent-eval-dashboard.styles.js +7 -5
  9. package/dist/components/agent-tools/agent-run/agent-run.class.js +2 -2
  10. package/dist/components/agent-tools/agent-run/agent-run.styles.js +0 -13
  11. package/dist/components/agent-tools/agent-trace/agent-trace.styles.js +7 -4
  12. package/dist/components/agent-tools/approval-queue/approval-queue.styles.js +7 -5
  13. package/dist/components/agent-tools/artifact-panel/artifact-panel.styles.js +0 -3
  14. package/dist/components/agent-tools/browser-frame/browser-frame.styles.js +3 -5
  15. package/dist/components/agent-tools/commit-card/commit-card.styles.js +0 -10
  16. package/dist/components/agent-tools/compare-panel/compare-panel.styles.js +11 -6
  17. package/dist/components/agent-tools/confirm-bar/confirm-bar.styles.js +0 -46
  18. package/dist/components/agent-tools/eval-dataset/eval-dataset.styles.js +0 -7
  19. package/dist/components/agent-tools/evaluation-run/evaluation-run.class.js +2 -2
  20. package/dist/components/agent-tools/prompt-studio/prompt-studio.styles.js +0 -15
  21. package/dist/components/agent-tools/result-card/result-card.styles.js +0 -7
  22. package/dist/components/agent-tools/result-card/result-field.styles.js +0 -5
  23. package/dist/components/agent-tools/schema-viewer/schema-viewer.styles.js +0 -3
  24. package/dist/components/agent-tools/span-waterfall/span-waterfall.styles.js +0 -15
  25. package/dist/components/agent-tools/stack-trace/stack-trace.styles.js +0 -20
  26. package/dist/components/agent-tools/subagent-panel/subagent-panel.class.js +2 -2
  27. package/dist/components/agent-tools/subagent-panel/subagent-panel.styles.js +0 -3
  28. package/dist/components/agent-tools/task-list/task-list.styles.js +0 -15
  29. package/dist/components/agent-tools/terminal/terminal.class.d.ts +11 -6
  30. package/dist/components/agent-tools/terminal/terminal.class.js +4 -4
  31. package/dist/components/agent-tools/terminal/terminal.styles.js +0 -46
  32. package/dist/components/agent-tools/test-results/test-results.class.js +2 -2
  33. package/dist/components/agent-tools/test-results/test-results.styles.js +0 -5
  34. package/dist/components/agent-tools/thinking-panel/thinking-panel.styles.js +0 -41
  35. package/dist/components/agent-tools/tool-approval-dialog/tool-approval-dialog.styles.js +0 -41
  36. package/dist/components/agent-tools/tool-call-chip/tool-call-chip.styles.js +0 -30
  37. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.js +6 -6
  38. package/dist/components/agent-tools/tool-param-form/tool-param-form.styles.js +0 -5
  39. package/dist/components/agent-tools/tool-result-dialog/tool-result-dialog.styles.js +0 -20
  40. package/dist/components/agent-tools/tool-result-view/tool-result-view.styles.js +0 -4
  41. package/dist/components/agent-tools/tool-select-dialog/tool-select-dialog.styles.js +0 -21
  42. package/dist/components/agent-tools/trace-tree/trace-tree.styles.js +7 -31
  43. package/dist/components/charts/chart/box-plot.styles.js +0 -20
  44. package/dist/components/charts/chart/chart-colors.d.ts +1 -1
  45. package/dist/components/charts/chart/chart-colors.js +1 -1
  46. package/dist/components/charts/chart/chart-core-loader.d.ts +1 -0
  47. package/dist/components/charts/chart/chart-core-loader.js +1 -1
  48. package/dist/components/charts/chart/chart-feature-loader.d.ts +35 -0
  49. package/dist/components/charts/chart/chart-feature-loader.js +1 -1
  50. package/dist/components/charts/chart/chart.class.d.ts +93 -0
  51. package/dist/components/charts/chart/chart.class.js +3 -3
  52. package/dist/components/charts/chart/chart.styles.js +0 -27
  53. package/dist/components/charts/chart/lite-chart.class.d.ts +20 -1
  54. package/dist/components/charts/chart/lite-chart.class.js +4 -4
  55. package/dist/components/charts/chart/lite-chart.styles.js +0 -27
  56. package/dist/components/conversation/agent-workspace/agent-workspace.class.d.ts +20 -0
  57. package/dist/components/conversation/agent-workspace/agent-workspace.class.js +3 -1
  58. package/dist/components/conversation/agent-workspace/agent-workspace.styles.js +3 -0
  59. package/dist/components/conversation/audio-visualizer/audio-visualizer.styles.js +0 -7
  60. package/dist/components/conversation/branch-picker/branch-picker.styles.js +0 -3
  61. package/dist/components/conversation/chat-composer/chat-composer.styles.js +0 -51
  62. package/dist/components/conversation/chat-message/chat-message.styles.js +7 -35
  63. package/dist/components/conversation/chat-viewport/chat-viewport.class.js +1 -1
  64. package/dist/components/conversation/chat-viewport/chat-viewport.styles.js +0 -33
  65. package/dist/components/conversation/checkpoint/checkpoint.class.js +1 -1
  66. package/dist/components/conversation/checkpoint/checkpoint.styles.js +0 -3
  67. package/dist/components/conversation/code-block/code-block-shared.d.ts +5 -2
  68. package/dist/components/conversation/code-block/code-block.class.js +1 -1
  69. package/dist/components/conversation/code-block/code-block.styles.js +4 -95
  70. package/dist/components/conversation/code-block/code-loader.d.ts +11 -0
  71. package/dist/components/conversation/code-block/code-loader.js +1 -1
  72. package/dist/components/conversation/code-block/shiki-types.d.ts +12 -0
  73. package/dist/components/conversation/code-block/shiki-types.js +1 -1
  74. package/dist/components/conversation/conversation-item/conversation-item.styles.js +8 -54
  75. package/dist/components/conversation/generation-metrics/generation-metrics.class.js +2 -2
  76. package/dist/components/conversation/generation-metrics/generation-metrics.styles.js +0 -17
  77. package/dist/components/conversation/markdown/markdown-base.class.js +1 -1
  78. package/dist/components/conversation/markdown/markdown.styles.js +0 -41
  79. package/dist/components/conversation/message-actions/message-actions.styles.js +0 -3
  80. package/dist/components/conversation/message-feedback/message-feedback.styles.js +0 -35
  81. package/dist/components/conversation/message-parts/message-parts.class.d.ts +1 -1
  82. package/dist/components/conversation/message-parts/message-parts.styles.js +0 -5
  83. package/dist/components/conversation/model-select/model-select.class.js +3 -3
  84. package/dist/components/conversation/model-select/model-select.styles.js +12 -47
  85. package/dist/components/conversation/model-settings-panel/model-settings-panel.styles.js +0 -6
  86. package/dist/components/conversation/prompt-input/prompt-input.class.d.ts +3 -0
  87. package/dist/components/conversation/prompt-input/prompt-input.styles.js +0 -10
  88. package/dist/components/conversation/push-to-talk/push-to-talk.styles.js +0 -8
  89. package/dist/components/conversation/selection-toolbar/selection-toolbar.styles.js +1 -11
  90. package/dist/components/conversation/stream-status/stream-status.styles.js +0 -16
  91. package/dist/components/conversation/streaming-text/streaming-text.styles.js +0 -15
  92. package/dist/components/conversation/suggestion-chips/suggestion-chips.styles.js +0 -5
  93. package/dist/components/conversation/thread-list/thread-list.styles.js +0 -23
  94. package/dist/components/conversation/transcript-feed/transcript-feed.class.d.ts +16 -4
  95. package/dist/components/conversation/transcript-feed/transcript-feed.class.js +1 -1
  96. package/dist/components/conversation/transcript-feed/transcript-feed.styles.js +0 -1
  97. package/dist/components/conversation/typing-indicator/typing-indicator.styles.js +0 -23
  98. package/dist/components/conversation/usage-badge/usage-badge.styles.js +0 -3
  99. package/dist/components/conversation/voice-picker/voice-picker.class.js +3 -3
  100. package/dist/components/conversation/voice-picker/voice-picker.styles.js +9 -29
  101. package/dist/components/conversation/widget-renderer/resolve.d.ts +2 -0
  102. package/dist/components/conversation/widget-renderer/resolve.js +1 -1
  103. package/dist/components/data/calendar/calendar.class.d.ts +15 -2
  104. package/dist/components/data/calendar/calendar.class.js +2 -2
  105. package/dist/components/data/calendar/calendar.styles.js +2 -28
  106. package/dist/components/data/condition-builder/condition-builder.class.d.ts +10 -6
  107. package/dist/components/data/condition-builder/condition-builder.class.js +2 -2
  108. package/dist/components/data/condition-builder/condition-builder.styles.js +0 -6
  109. package/dist/components/data/context-meter/context-meter.styles.js +0 -24
  110. package/dist/components/data/data-grid/data-grid.class.js +3 -3
  111. package/dist/components/data/data-grid/data-grid.styles.js +0 -22
  112. package/dist/components/data/document-library/document-library.class.js +2 -2
  113. package/dist/components/data/document-library/document-library.styles.js +0 -4
  114. package/dist/components/data/env-list/env-list.class.js +1 -1
  115. package/dist/components/data/env-list/env-list.styles.js +7 -4
  116. package/dist/components/data/file-tree/file-tree.class.d.ts +12 -0
  117. package/dist/components/data/flow-canvas/flow-canvas.styles.js +12 -19
  118. package/dist/components/data/flow-controls/flow-controls.class.js +2 -2
  119. package/dist/components/data/flow-controls/flow-controls.styles.js +3 -36
  120. package/dist/components/data/flow-minimap/flow-minimap.class.js +1 -1
  121. package/dist/components/data/flow-minimap/flow-minimap.styles.js +0 -9
  122. package/dist/components/data/flow-node/flow-node.styles.js +0 -23
  123. package/dist/components/data/flow-run-status/flow-run-status.class.js +1 -1
  124. package/dist/components/data/flow-run-status/flow-run-status.styles.js +0 -7
  125. package/dist/components/data/graph-query-builder/graph-query-builder.class.d.ts +0 -7
  126. package/dist/components/data/graph-query-builder/graph-query-builder.class.js +1 -1
  127. package/dist/components/data/graph-query-builder/graph-query-builder.styles.js +0 -10
  128. package/dist/components/data/heatmap/heatmap-scale.d.ts +20 -0
  129. package/dist/components/data/heatmap/heatmap-scale.js +1 -1
  130. package/dist/components/data/heatmap/heatmap.class.d.ts +84 -1
  131. package/dist/components/data/heatmap/heatmap.class.js +2 -2
  132. package/dist/components/data/heatmap/heatmap.styles.js +0 -54
  133. package/dist/components/data/pagination/pagination.styles.js +23 -46
  134. package/dist/components/data/sequence-strip/sequence-strip.class.d.ts +34 -1
  135. package/dist/components/data/sequence-strip/sequence-strip.class.js +5 -2
  136. package/dist/components/data/sequence-strip/sequence-strip.styles.js +14 -20
  137. package/dist/components/data/sparkline/sparkline.class.js +1 -1
  138. package/dist/components/data/stat/stat.styles.js +0 -67
  139. package/dist/components/data/table/table.class.d.ts +42 -3
  140. package/dist/components/data/table/table.class.js +4 -4
  141. package/dist/components/data/table/table.styles.js +20 -91
  142. package/dist/components/data/timeline/timeline-item.styles.js +0 -30
  143. package/dist/components/data/timeline/timeline.class.d.ts +89 -1
  144. package/dist/components/data/timeline/timeline.class.js +2 -2
  145. package/dist/components/data/timeline/timeline.styles.js +111 -31
  146. package/dist/components/data/tree/tree-item.styles.js +1 -28
  147. package/dist/components/data/tree/tree.class.js +2 -2
  148. package/dist/components/data/tree/tree.styles.js +0 -6
  149. package/dist/components/data/word-cloud/word-cloud.styles.js +0 -5
  150. package/dist/components/forms/button/button.class.js +1 -1
  151. package/dist/components/forms/button/button.styles.js +0 -105
  152. package/dist/components/forms/checkbox/checkbox.class.d.ts +3 -0
  153. package/dist/components/forms/checkbox/checkbox.class.js +1 -1
  154. package/dist/components/forms/checkbox/checkbox.styles.js +0 -39
  155. package/dist/components/forms/checkbox-group/checkbox-group.class.d.ts +21 -2
  156. package/dist/components/forms/checkbox-group/checkbox-group.class.js +1 -1
  157. package/dist/components/forms/checkbox-group/checkbox-group.styles.js +0 -18
  158. package/dist/components/forms/code-editor/code-editor.styles.js +0 -30
  159. package/dist/components/forms/color-picker/color-picker.class.js +2 -2
  160. package/dist/components/forms/color-picker/color-picker.styles.js +0 -69
  161. package/dist/components/forms/combobox/combobox.class.js +2 -2
  162. package/dist/components/forms/combobox/combobox.styles.js +22 -111
  163. package/dist/components/forms/combobox/option.styles.js +7 -1
  164. package/dist/components/forms/date-picker/date-input.class.js +1 -1
  165. package/dist/components/forms/date-picker/date-input.styles.js +12 -67
  166. package/dist/components/forms/date-picker/date-picker.class.d.ts +1 -0
  167. package/dist/components/forms/date-picker/date-picker.class.js +22 -20
  168. package/dist/components/forms/date-picker/date-picker.styles.js +36 -29
  169. package/dist/components/forms/emoji-picker/emoji-data-loader.d.ts +6 -3
  170. package/dist/components/forms/emoji-picker/emoji-data-loader.js +1 -1
  171. package/dist/components/forms/emoji-picker/emoji-picker.class.d.ts +8 -1
  172. package/dist/components/forms/emoji-picker/emoji-picker.class.js +1 -1
  173. package/dist/components/forms/emoji-picker/emoji-picker.styles.js +3 -41
  174. package/dist/components/forms/icon-button/icon-button.class.js +1 -1
  175. package/dist/components/forms/icon-button/icon-button.styles.js +0 -16
  176. package/dist/components/forms/input/input.styles.js +0 -54
  177. package/dist/components/forms/input/number-input.styles.d.ts +4 -5
  178. package/dist/components/forms/input/number-input.styles.js +0 -11
  179. package/dist/components/forms/input/time-input-shared.d.ts +11 -0
  180. package/dist/components/forms/input/time-input-shared.js +1 -1
  181. package/dist/components/forms/input/time-input.class.d.ts +11 -2
  182. package/dist/components/forms/input/time-input.class.js +1 -1
  183. package/dist/components/forms/input/time-input.styles.js +0 -6
  184. package/dist/components/forms/locale-picker/locale-picker.class.js +2 -2
  185. package/dist/components/forms/locale-picker/locale-picker.styles.js +1 -26
  186. package/dist/components/forms/otp-input/otp-input.class.js +3 -3
  187. package/dist/components/forms/otp-input/otp-input.styles.js +0 -16
  188. package/dist/components/forms/phone-input/phone-input.class.d.ts +9 -1
  189. package/dist/components/forms/phone-input/phone-input.class.js +2 -2
  190. package/dist/components/forms/phone-input/phone-input.styles.js +0 -37
  191. package/dist/components/forms/radio/radio-button.styles.js +1 -30
  192. package/dist/components/forms/radio/radio-group.styles.js +0 -4
  193. package/dist/components/forms/radio/radio.styles.js +0 -44
  194. package/dist/components/forms/rubric-form/rubric-form.styles.js +0 -5
  195. package/dist/components/forms/select/select.class.js +1 -1
  196. package/dist/components/forms/select/select.styles.js +14 -114
  197. package/dist/components/forms/slider/slider.styles.js +0 -55
  198. package/dist/components/forms/swatch-picker/swatch-picker.class.d.ts +0 -11
  199. package/dist/components/forms/swatch-picker/swatch-picker.class.js +2 -2
  200. package/dist/components/forms/swatch-picker/swatch-picker.styles.js +0 -77
  201. package/dist/components/forms/switch/switch.class.d.ts +3 -0
  202. package/dist/components/forms/switch/switch.class.js +1 -1
  203. package/dist/components/forms/switch/switch.styles.js +0 -37
  204. package/dist/components/forms/textarea/textarea.styles.js +0 -28
  205. package/dist/components/forms/time-range/time-range.styles.js +12 -84
  206. package/dist/components/forms/token-input/token-input.class.d.ts +23 -9
  207. package/dist/components/forms/token-input/token-input.class.js +1 -1
  208. package/dist/components/forms/token-input/token-input.styles.js +1 -54
  209. package/dist/components/layout/app-rail/app-rail-item.class.js +2 -2
  210. package/dist/components/layout/app-rail/app-rail-item.styles.js +0 -13
  211. package/dist/components/layout/app-rail/app-rail.class.d.ts +5 -0
  212. package/dist/components/layout/app-rail/app-rail.class.js +1 -1
  213. package/dist/components/layout/app-rail/app-rail.styles.js +0 -46
  214. package/dist/components/layout/button-group/button-group.styles.js +0 -6
  215. package/dist/components/layout/card/card.class.d.ts +12 -0
  216. package/dist/components/layout/card/card.styles.js +3 -11
  217. package/dist/components/layout/carousel/carousel.styles.js +0 -1
  218. package/dist/components/layout/command-palette/command-palette.class.d.ts +8 -0
  219. package/dist/components/layout/command-palette/command-palette.class.js +3 -1
  220. package/dist/components/layout/command-palette/command-palette.styles.js +1 -13
  221. package/dist/components/layout/control-group/control-group.styles.js +0 -7
  222. package/dist/components/layout/dashboard-grid/dashboard-grid.styles.js +6 -25
  223. package/dist/components/layout/details/accordion.class.d.ts +13 -0
  224. package/dist/components/layout/details/accordion.class.js +1 -1
  225. package/dist/components/layout/details/details.class.js +1 -1
  226. package/dist/components/layout/details/details.styles.js +0 -12
  227. package/dist/components/layout/dock-panel/dock-panel.styles.js +0 -45
  228. package/dist/components/layout/drilldown-panel/drilldown-panel.class.d.ts +2 -0
  229. package/dist/components/layout/drilldown-panel/drilldown-panel.class.js +2 -2
  230. package/dist/components/layout/drilldown-panel/drilldown-panel.styles.js +0 -4
  231. package/dist/components/layout/filter-bar/filter-bar.class.js +1 -1
  232. package/dist/components/layout/filter-bar/filter-bar.styles.js +0 -9
  233. package/dist/components/layout/menu/menu-item.class.d.ts +5 -0
  234. package/dist/components/layout/menu/menu-item.class.js +1 -1
  235. package/dist/components/layout/menu/menu-item.styles.js +0 -49
  236. package/dist/components/layout/menu/menu-label.styles.js +0 -2
  237. package/dist/components/layout/menu/menu.styles.js +0 -18
  238. package/dist/components/layout/multi-split/multi-split.styles.js +0 -63
  239. package/dist/components/layout/page/page.class.d.ts +4 -0
  240. package/dist/components/layout/page/page.class.js +1 -1
  241. package/dist/components/layout/reorder-list/reorder-item.styles.js +0 -4
  242. package/dist/components/layout/responsive-panel/responsive-panel.styles.js +0 -27
  243. package/dist/components/layout/scroller/scroller.styles.js +0 -20
  244. package/dist/components/layout/segmented/segmented.class.d.ts +7 -1
  245. package/dist/components/layout/segmented/segmented.class.js +1 -1
  246. package/dist/components/layout/segmented/segmented.styles.js +69 -37
  247. package/dist/components/layout/split-panel/split-panel.styles.js +1 -7
  248. package/dist/components/layout/stepper/stepper.class.d.ts +8 -1
  249. package/dist/components/layout/stepper/stepper.class.js +1 -1
  250. package/dist/components/layout/stepper/stepper.styles.js +140 -41
  251. package/dist/components/layout/tab-group/tab-group.class.d.ts +4 -1
  252. package/dist/components/layout/tab-group/tab-group.styles.js +9 -75
  253. package/dist/components/layout/tab-group/tab.styles.js +0 -2
  254. package/dist/components/layout/virtual-list/virtual-list.class.d.ts +4 -4
  255. package/dist/components/layout/virtual-list/virtual-list.class.js +1 -1
  256. package/dist/components/layout/virtual-list/virtual-list.styles.js +0 -68
  257. package/dist/components/layout/widget/widget.class.d.ts +5 -1
  258. package/dist/components/layout/widget/widget.class.js +1 -1
  259. package/dist/components/layout/widget/widget.styles.js +97 -40
  260. package/dist/components/media/animated-image/animated-image.class.d.ts +3 -0
  261. package/dist/components/media/animated-image/animated-image.class.js +1 -1
  262. package/dist/components/media/animated-image/animated-image.styles.js +0 -28
  263. package/dist/components/media/attachment-chip/attachment-chip.class.d.ts +1 -1
  264. package/dist/components/media/attachment-chip/attachment-chip.class.js +1 -1
  265. package/dist/components/media/attachment-chip/attachment-chip.styles.js +0 -31
  266. package/dist/components/media/attachment-trigger/attachment-trigger.class.js +3 -3
  267. package/dist/components/media/attachment-trigger/attachment-trigger.styles.js +0 -40
  268. package/dist/components/media/av-player/av-player.class.d.ts +5 -6
  269. package/dist/components/media/av-player/av-player.class.js +1 -1
  270. package/dist/components/media/av-player/av-player.styles.js +0 -45
  271. package/dist/components/media/avatar/avatar.styles.js +3 -16
  272. package/dist/components/media/file-icon/file-icon.class.d.ts +1 -2
  273. package/dist/components/media/file-icon/file-icon.class.js +1 -1
  274. package/dist/components/media/file-input/file-input.class.d.ts +12 -0
  275. package/dist/components/media/file-input/file-input.styles.js +3 -24
  276. package/dist/components/media/flag/flag.class.d.ts +20 -0
  277. package/dist/components/media/flag/flag.class.js +4 -2
  278. package/dist/components/media/flag/flag.styles.js +7 -1
  279. package/dist/components/media/flag/language-map.d.ts +10 -0
  280. package/dist/components/media/flag/language-map.js +1 -1
  281. package/dist/components/media/image-comparer/image-comparer.styles.js +4 -33
  282. package/dist/components/media/image-viewer/image-viewer.class.js +0 -2
  283. package/dist/components/media/image-viewer/image-viewer.styles.js +7 -27
  284. package/dist/components/media/lightbox/lightbox.class.js +0 -2
  285. package/dist/components/media/lightbox/lightbox.styles.js +0 -21
  286. package/dist/components/media/map/map-loader.d.ts +19 -1
  287. package/dist/components/media/map/map-loader.js +1 -1
  288. package/dist/components/media/map/map.class.d.ts +141 -1
  289. package/dist/components/media/map/map.class.js +15 -3
  290. package/dist/components/media/map/map.styles.js +20 -17
  291. package/dist/components/media/media-card/media-card.class.d.ts +14 -3
  292. package/dist/components/media/media-card/media-card.class.js +1 -1
  293. package/dist/components/media/media-card/media-card.styles.js +2 -28
  294. package/dist/components/media/pan-zoom/pan-zoom.styles.js +0 -3
  295. package/dist/components/media/qr-code/qr-code.class.d.ts +3 -2
  296. package/dist/components/media/qr-code/qr-code.class.js +2 -2
  297. package/dist/components/media/qr-code/qr-code.styles.js +0 -3
  298. package/dist/components/media/sequence-playback/sequence-playback.class.d.ts +2 -0
  299. package/dist/components/media/sequence-playback/sequence-playback.class.js +2 -1
  300. package/dist/components/media/sequence-playback/sequence-playback.styles.js +0 -19
  301. package/dist/components/media/video/video.class.d.ts +23 -2
  302. package/dist/components/media/video/video.class.js +3 -3
  303. package/dist/components/media/video/video.styles.js +4 -2
  304. package/dist/components/media/zoomable-frame/zoomable-frame.class.d.ts +3 -2
  305. package/dist/components/media/zoomable-frame/zoomable-frame.class.js +2 -2
  306. package/dist/components/media/zoomable-frame/zoomable-frame.styles.js +0 -5
  307. package/dist/components/overlays/alert/alert.styles.js +4 -2
  308. package/dist/components/overlays/badge/badge.styles.js +4 -48
  309. package/dist/components/overlays/badge/tag.styles.js +0 -14
  310. package/dist/components/overlays/callout/callout.styles.js +0 -11
  311. package/dist/components/overlays/chip/chip-group.styles.js +0 -18
  312. package/dist/components/overlays/chip/chip.styles.js +6 -69
  313. package/dist/components/overlays/dialog/confirm.d.ts +1 -4
  314. package/dist/components/overlays/dialog/confirm.js +1 -1
  315. package/dist/components/overlays/dialog/dialog.class.d.ts +12 -9
  316. package/dist/components/overlays/dialog/dialog.class.js +1 -1
  317. package/dist/components/overlays/dialog/dialog.styles.js +0 -43
  318. package/dist/components/overlays/drawer/drawer.class.d.ts +2 -2
  319. package/dist/components/overlays/drawer/drawer.styles.js +0 -9
  320. package/dist/components/overlays/empty/empty.styles.js +0 -12
  321. package/dist/components/overlays/kbd/kbd.styles.js +0 -8
  322. package/dist/components/overlays/overlay/dropdown.class.d.ts +1 -6
  323. package/dist/components/overlays/overlay/dropdown.class.js +2 -2
  324. package/dist/components/overlays/overlay/overlay.styles.js +0 -28
  325. package/dist/components/overlays/overlay/popover.class.d.ts +9 -1
  326. package/dist/components/overlays/overlay/popover.class.js +2 -2
  327. package/dist/components/overlays/overlay/tooltip.class.d.ts +10 -0
  328. package/dist/components/overlays/overlay/tooltip.class.js +1 -1
  329. package/dist/components/overlays/popup/popup.class.d.ts +1 -0
  330. package/dist/components/overlays/popup/popup.class.js +1 -1
  331. package/dist/components/overlays/popup/popup.styles.js +0 -15
  332. package/dist/components/overlays/progress/progress-ring.class.d.ts +9 -1
  333. package/dist/components/overlays/progress/progress-ring.class.js +3 -3
  334. package/dist/components/overlays/progress/progress.styles.js +0 -21
  335. package/dist/components/overlays/rating/rating.styles.js +0 -25
  336. package/dist/components/overlays/skeleton/skeleton.styles.js +0 -4
  337. package/dist/components/overlays/spinner/spinner.styles.js +0 -3
  338. package/dist/components/overlays/toast/toast-item.styles.js +3 -45
  339. package/dist/components/retrieval/chunk-inspector/chunk-inspector.styles.js +0 -35
  340. package/dist/components/retrieval/citation-badge/citation-badge.class.d.ts +2 -2
  341. package/dist/components/retrieval/citation-badge/citation-badge.class.js +3 -3
  342. package/dist/components/retrieval/citation-badge/citation-badge.styles.js +0 -20
  343. package/dist/components/retrieval/claim-evidence/claim-evidence.styles.js +0 -8
  344. package/dist/components/retrieval/community-card/community-card.class.d.ts +1 -0
  345. package/dist/components/retrieval/community-card/community-card.styles.js +0 -6
  346. package/dist/components/retrieval/embedding-explorer/embedding-explorer.styles.js +8 -12
  347. package/dist/components/retrieval/entity-card/entity-card.class.d.ts +4 -3
  348. package/dist/components/retrieval/entity-card/entity-card.class.js +1 -1
  349. package/dist/components/retrieval/entity-card/entity-card.styles.js +0 -12
  350. package/dist/components/retrieval/entity-chip/entity-chip.class.d.ts +10 -4
  351. package/dist/components/retrieval/entity-chip/entity-chip.class.js +3 -3
  352. package/dist/components/retrieval/entity-chip/entity-chip.styles.js +6 -9
  353. package/dist/components/retrieval/entity-dossier/entity-dossier.class.d.ts +19 -5
  354. package/dist/components/retrieval/graph/graph.class.d.ts +5 -0
  355. package/dist/components/retrieval/graph/graph.class.js +1 -1
  356. package/dist/components/retrieval/graph/graph.styles.js +0 -30
  357. package/dist/components/retrieval/graph-legend/graph-legend.styles.js +0 -3
  358. package/dist/components/retrieval/ingestion-queue/ingestion-queue.styles.js +0 -25
  359. package/dist/components/retrieval/knowledge-base-admin/knowledge-base-admin.class.d.ts +2 -0
  360. package/dist/components/retrieval/knowledge-base-admin/knowledge-base-admin.styles.js +0 -7
  361. package/dist/components/retrieval/knowledge-graph-explorer/knowledge-graph-explorer.class.d.ts +20 -6
  362. package/dist/components/retrieval/knowledge-graph-explorer/knowledge-graph-explorer.class.js +2 -2
  363. package/dist/components/retrieval/knowledge-graph-explorer/knowledge-graph-explorer.styles.js +0 -16
  364. package/dist/components/retrieval/mind-map/mind-map.class.d.ts +5 -3
  365. package/dist/components/retrieval/mind-map/mind-map.class.js +1 -1
  366. package/dist/components/retrieval/mind-map/mind-map.styles.js +0 -2
  367. package/dist/components/retrieval/neighbor-list/neighbor-list.class.d.ts +3 -2
  368. package/dist/components/retrieval/neighbor-list/neighbor-list.class.js +1 -1
  369. package/dist/components/retrieval/neighbor-list/neighbor-list.styles.js +0 -30
  370. package/dist/components/retrieval/node-palette/node-palette.styles.js +0 -11
  371. package/dist/components/retrieval/path-strip/path-strip.styles.js +0 -10
  372. package/dist/components/retrieval/provenance-panel/provenance-panel.class.d.ts +12 -3
  373. package/dist/components/retrieval/provenance-panel/provenance-panel.styles.js +0 -2
  374. package/dist/components/retrieval/rag-eval-dashboard/rag-eval-dashboard.class.d.ts +3 -2
  375. package/dist/components/retrieval/rag-eval-dashboard/rag-eval-dashboard.class.js +2 -2
  376. package/dist/components/retrieval/retrieval-results/retrieval-results.styles.js +0 -28
  377. package/dist/components/retrieval/retrieval-search/retrieval-search.styles.js +0 -4
  378. package/dist/components/retrieval/retrieval-trace/retrieval-trace.styles.js +0 -2
  379. package/dist/components/retrieval/source-card/source-card.styles.js +0 -13
  380. package/dist/components/retrieval/source-list/source-list.styles.js +0 -7
  381. package/dist/components/retrieval/source-picker/source-picker.styles.js +0 -7
  382. package/dist/components/utility/copy-button/copy-button.styles.js +0 -10
  383. package/dist/components/utility/diff-view/diff-view.styles.js +0 -14
  384. package/dist/components/utility/export-button/export-button.styles.js +0 -22
  385. package/dist/components/utility/icon/icon.styles.js +0 -6
  386. package/dist/components/utility/json-viewer/json-viewer.styles.js +2 -48
  387. package/dist/components/utility/known-date/known-date.class.d.ts +7 -3
  388. package/dist/components/utility/known-date/known-date.styles.js +10 -51
  389. package/dist/components/utility/live-region/live-region.styles.js +0 -4
  390. package/dist/components/utility/mention-popover/mention-popover.styles.js +0 -25
  391. package/dist/components/utility/poll-status/poll-status.styles.js +0 -4
  392. package/dist/components/utility/random-content/random-content.class.d.ts +22 -0
  393. package/dist/components/utility/random-content/random-content.class.js +3 -2
  394. package/dist/components/utility/random-content/random-content.styles.js +6 -13
  395. package/dist/components/utility/tour/tour.class.d.ts +4 -2
  396. package/dist/components/utility/tour/tour.class.js +3 -3
  397. package/dist/components/utility/tour/tour.styles.js +0 -13
  398. package/dist/components/utility/visually-hidden/visually-hidden.styles.js +0 -5
  399. package/dist/components/viewers/archive-viewer/archive-viewer.class.js +1 -1
  400. package/dist/components/viewers/archive-viewer/archive-viewer.styles.d.ts +2 -2
  401. package/dist/components/viewers/archive-viewer/archive-viewer.styles.js +0 -10
  402. package/dist/components/viewers/csv-viewer/csv-viewer.class.js +1 -1
  403. package/dist/components/viewers/csv-viewer/csv-viewer.styles.js +0 -19
  404. package/dist/components/viewers/dataset-viewer/dataset-viewer.class.js +1 -1
  405. package/dist/components/viewers/dataset-viewer/dataset-viewer.styles.js +0 -15
  406. package/dist/components/viewers/document-compare/document-compare.styles.js +0 -3
  407. package/dist/components/viewers/document-preview/document-preview.styles.js +0 -25
  408. package/dist/components/viewers/document-viewer/document-viewer.class.d.ts +2 -1
  409. package/dist/components/viewers/document-viewer/document-viewer.class.js +1 -1
  410. package/dist/components/viewers/document-viewer/document-viewer.styles.js +0 -5
  411. package/dist/components/viewers/docx-viewer/docx-viewer.styles.js +0 -17
  412. package/dist/components/viewers/ebook-viewer/ebook-viewer.styles.js +0 -4
  413. package/dist/components/viewers/email-viewer/email-viewer.styles.js +0 -7
  414. package/dist/components/viewers/geojson-view/geojson-view.styles.js +0 -5
  415. package/dist/components/viewers/highlight-layer/highlight-layer.styles.js +0 -3
  416. package/dist/components/viewers/notebook-viewer/notebook-viewer.class.js +1 -1
  417. package/dist/components/viewers/notebook-viewer/notebook-viewer.styles.js +0 -38
  418. package/dist/components/viewers/page-rail/page-rail.class.js +1 -1
  419. package/dist/components/viewers/page-rail/page-rail.styles.js +0 -13
  420. package/dist/components/viewers/pdf-viewer/pdf-loader.d.ts +13 -2
  421. package/dist/components/viewers/pdf-viewer/pdf-loader.js +1 -1
  422. package/dist/components/viewers/pdf-viewer/pdf-viewer.class.d.ts +32 -2
  423. package/dist/components/viewers/pdf-viewer/pdf-viewer.class.js +4 -4
  424. package/dist/components/viewers/pdf-viewer/pdf-viewer.styles.js +1 -27
  425. package/dist/components/viewers/pptx-viewer/pptx-viewer.styles.js +0 -3
  426. package/dist/components/viewers/spreadsheet-viewer/spreadsheet-viewer.class.js +1 -1
  427. package/dist/components/viewers/spreadsheet-viewer/spreadsheet-viewer.styles.js +0 -14
  428. package/dist/components/viewers/svg-viewer/svg-viewer.styles.js +0 -7
  429. package/dist/components/viewers/xml-viewer/xml-viewer.styles.js +2 -24
  430. package/dist/custom-elements-jsx.d.ts +56 -37
  431. package/dist/events.d.ts +43 -33
  432. package/dist/internal/agent-status-variants.d.ts +18 -0
  433. package/dist/internal/agent-status-variants.js +1 -0
  434. package/dist/internal/announcer.d.ts +8 -3
  435. package/dist/internal/announcer.js +1 -1
  436. package/dist/internal/autoloader-manifest.js +1 -1
  437. package/dist/internal/canvas-color.d.ts +16 -0
  438. package/dist/internal/canvas-color.js +1 -1
  439. package/dist/internal/catalog-picker.d.ts +0 -1
  440. package/dist/internal/catalog-picker.js +1 -1
  441. package/dist/internal/default-strings.generated.d.ts +1 -0
  442. package/dist/internal/default-strings.generated.js +1 -1
  443. package/dist/internal/dev-mode-attribute-warning.d.ts +27 -4
  444. package/dist/internal/dev-mode-attribute-warning.js +1 -1
  445. package/dist/internal/localization-runtime.js +1 -1
  446. package/dist/internal/localization-types.d.ts +1 -1
  447. package/dist/internal/localization.js +1 -1
  448. package/dist/internal/lyra-element.d.ts +13 -0
  449. package/dist/internal/lyra-element.js +1 -1
  450. package/dist/internal/media-controller.js +1 -1
  451. package/dist/internal/package-metadata.d.ts +1 -1
  452. package/dist/internal/package-metadata.js +1 -1
  453. package/dist/internal/scroll-overflow.d.ts +35 -13
  454. package/dist/internal/scroll-overflow.js +1 -1
  455. package/dist/internal/sizes.styles.js +0 -2
  456. package/dist/internal/specialist-tokens.styles.js +6 -11
  457. package/dist/internal/text-highlights.d.ts +4 -1
  458. package/dist/internal/text-highlights.js +1 -1
  459. package/dist/internal/tokens/palette.styles.js +0 -15
  460. package/dist/internal/tokens.styles.js +19 -113
  461. package/dist/lyra.d.ts +8 -5
  462. package/dist/styles/reservations.css +82 -0
  463. package/dist/svelte.d.ts +56 -37
  464. package/dist/translations/ar.js +1 -1
  465. package/dist/translations/de.js +1 -1
  466. package/dist/translations/es.js +1 -1
  467. package/dist/translations/fa.js +1 -1
  468. package/dist/translations/fr.js +1 -1
  469. package/dist/translations/he.js +1 -1
  470. package/dist/translations/ja.js +1 -1
  471. package/dist/translations/pt-BR.js +1 -1
  472. package/dist/translations/ru.js +1 -1
  473. package/dist/translations/zh-CN.js +1 -1
  474. package/dist/vue.d.ts +56 -37
  475. package/llms/components/lr-accordion-item.md +12 -3
  476. package/llms/components/lr-accordion.md +11 -2
  477. package/llms/components/lr-agent-eval-dashboard.md +1 -1
  478. package/llms/components/lr-agent-trace.md +3 -1
  479. package/llms/components/lr-agent-workspace.md +20 -0
  480. package/llms/components/lr-artifact-panel.md +10 -4
  481. package/llms/components/lr-attachment-chip.md +7 -4
  482. package/llms/components/lr-attachment-trigger.md +7 -4
  483. package/llms/components/lr-av-player.md +3 -1
  484. package/llms/components/lr-avatar.md +6 -6
  485. package/llms/components/lr-bar-chart.md +4 -3
  486. package/llms/components/lr-box-plot.md +1 -1
  487. package/llms/components/lr-browser-frame.md +7 -3
  488. package/llms/components/lr-bubble-chart.md +4 -3
  489. package/llms/components/lr-calendar.md +9 -2
  490. package/llms/components/lr-card.md +24 -0
  491. package/llms/components/lr-chart.md +32 -8
  492. package/llms/components/lr-chat-viewport.md +7 -2
  493. package/llms/components/lr-checkbox-group.md +13 -5
  494. package/llms/components/lr-checkbox.md +5 -2
  495. package/llms/components/lr-checkpoint.md +6 -2
  496. package/llms/components/lr-combobox.md +5 -2
  497. package/llms/components/lr-command-palette.md +4 -1
  498. package/llms/components/lr-confirm-bar.md +7 -3
  499. package/llms/components/lr-context-meter.md +12 -11
  500. package/llms/components/lr-conversation-item.md +7 -4
  501. package/llms/components/lr-details.md +11 -2
  502. package/llms/components/lr-dialog.md +15 -10
  503. package/llms/components/lr-dock-panel.md +7 -10
  504. package/llms/components/lr-document-preview.md +6 -1
  505. package/llms/components/lr-document-viewer.md +3 -2
  506. package/llms/components/lr-doughnut-chart.md +4 -3
  507. package/llms/components/lr-drawer.md +3 -3
  508. package/llms/components/lr-entity-card.md +3 -3
  509. package/llms/components/lr-entity-chip.md +1 -1
  510. package/llms/components/lr-entity-dossier.md +4 -1
  511. package/llms/components/lr-file-input.md +2 -2
  512. package/llms/components/lr-flag.md +20 -5
  513. package/llms/components/lr-heatmap.md +28 -0
  514. package/llms/components/lr-histogram.md +3 -1
  515. package/llms/components/lr-icon.md +1 -1
  516. package/llms/components/lr-json-schema-viewer.md +2 -1
  517. package/llms/components/lr-knowledge-graph-explorer.md +8 -3
  518. package/llms/components/lr-known-date.md +4 -2
  519. package/llms/components/lr-line-chart.md +4 -3
  520. package/llms/components/lr-lite-chart.md +16 -6
  521. package/llms/components/lr-map.md +72 -8
  522. package/llms/components/lr-markdown-core.md +3 -2
  523. package/llms/components/lr-media-card.md +28 -12
  524. package/llms/components/lr-message-parts.md +2 -1
  525. package/llms/components/lr-model-select.md +9 -10
  526. package/llms/components/lr-model-settings-panel.md +9 -9
  527. package/llms/components/lr-neighbor-list.md +1 -1
  528. package/llms/components/lr-notebook-viewer.md +6 -3
  529. package/llms/components/lr-option.md +5 -2
  530. package/llms/components/lr-pdf-viewer.md +62 -2
  531. package/llms/components/lr-pie-chart.md +4 -3
  532. package/llms/components/lr-polar-area-chart.md +4 -3
  533. package/llms/components/lr-popover.md +5 -0
  534. package/llms/components/lr-progress-ring.md +8 -1
  535. package/llms/components/lr-prompt-studio.md +1 -1
  536. package/llms/components/lr-provenance-panel.md +4 -2
  537. package/llms/components/lr-qr-code.md +1 -1
  538. package/llms/components/lr-radar-chart.md +4 -3
  539. package/llms/components/lr-rag-eval-dashboard.md +2 -2
  540. package/llms/components/lr-random-content.md +13 -0
  541. package/llms/components/lr-reorder-item.md +6 -1
  542. package/llms/components/lr-reorder-list.md +6 -1
  543. package/llms/components/lr-responsive-panel.md +11 -7
  544. package/llms/components/lr-scatter-chart.md +4 -3
  545. package/llms/components/lr-sequence-strip.md +16 -2
  546. package/llms/components/lr-slider.md +12 -5
  547. package/llms/components/lr-sparkline.md +1 -1
  548. package/llms/components/lr-suggestion-chips.md +7 -2
  549. package/llms/components/lr-swatch-picker.md +5 -5
  550. package/llms/components/lr-switch.md +5 -2
  551. package/llms/components/lr-table.md +30 -4
  552. package/llms/components/lr-terminal.md +3 -1
  553. package/llms/components/lr-thread-list.md +8 -8
  554. package/llms/components/lr-time-input.md +6 -1
  555. package/llms/components/lr-timeline-item.md +24 -0
  556. package/llms/components/lr-timeline.md +25 -1
  557. package/llms/components/lr-token-input.md +7 -2
  558. package/llms/components/lr-tool-approval-dialog.md +7 -8
  559. package/llms/components/lr-tool-call-chip.md +5 -1
  560. package/llms/components/lr-tool-param-form.md +14 -12
  561. package/llms/components/lr-tool-result-dialog.md +11 -9
  562. package/llms/components/lr-tool-result-view.md +7 -6
  563. package/llms/components/lr-tool-select-dialog.md +18 -16
  564. package/llms/components/lr-trace-tree.md +3 -1
  565. package/llms/components/lr-usage-badge.md +4 -1
  566. package/llms/components/lr-video-playlist.md +1 -1
  567. package/llms/components/lr-virtual-list.md +22 -14
  568. package/llms/components/lr-voice-picker.md +8 -5
  569. package/llms/components/lr-widget-renderer.md +3 -3
  570. package/llms/components/lr-widget.md +1 -1
  571. package/llms/components/lr-word-cloud.md +6 -2
  572. package/llms/peers.md +12 -2
  573. package/llms/shared.md +70 -2
  574. package/llms-full.txt +1143 -285
  575. package/package.json +17 -5
  576. package/vscode-css-data.json +37 -2
  577. package/vscode-html-data.json +401 -44
  578. package/web-types.json +299 -55
package/llms-full.txt CHANGED
@@ -1145,6 +1145,70 @@ canvas consumer's redraw to its normal microtask/render schedule. The optional r
1145
1145
  browser realm; it does not limit invalidation to a subtree. The function is a no-op during server
1146
1146
  rendering and retains no document or stylesheet after the last canvas consumer disconnects.
1147
1147
 
1148
+ ## Preventing layout shift from lazy-upgrading elements (CLS)
1149
+
1150
+ An undefined custom element is an inline box with no intrinsic size, so every `lr-*` in the initial
1151
+ viewport contributes a reflow as its definition loads. Components that additionally defer on an
1152
+ optional peer (`lr-chart`, `lr-map`, `lr-flag`, `lr-flow-canvas`, `lr-knowledge-graph-explorer`)
1153
+ render a skeleton while that peer resolves, which can cost a second shift when the real content
1154
+ replaces it. Each component is individually well-behaved; the aggregate on a first paint is what
1155
+ costs a Lighthouse Cumulative Layout Shift score.
1156
+
1157
+ Lyra ships an optional, opt-in stylesheet that reserves each component's intrinsic footprint before
1158
+ upgrade:
1159
+
1160
+ ```css
1161
+ @import "@aceshooting/lyra-ui/reservations.css";
1162
+ ```
1163
+
1164
+ It styles **only** `:not(:defined)` elements, inside an `@layer lr-reservations`, so it becomes inert
1165
+ the moment a definition upgrades and can never fight a component's own layout. It sets no colors and
1166
+ no `:root` rules.
1167
+
1168
+ **Every reservation is expressed with the same custom property and fallback token the component's
1169
+ own stylesheet uses** — `--lr-chart-height` / `--lr-size-280px` for the chart family,
1170
+ `--lr-flag-aspect-ratio` for `lr-flag`, `--lr-form-control-height` for the field controls, and so
1171
+ on. That is the point of shipping it rather than documenting measured pixel values: a hand-written
1172
+ reservation rots silently the moment a component's default changes, whereas these track it, and
1173
+ theming a component through its documented custom property re-themes its reservation with it.
1174
+
1175
+ Hand-rolling equivalent rules is still fine — the pattern is just:
1176
+
1177
+ ```css
1178
+ lr-chart:not(:defined) {
1179
+ display: block;
1180
+ min-block-size: var(--lr-chart-height, var(--lr-size-280px));
1181
+ }
1182
+ ```
1183
+
1184
+ Two things worth knowing:
1185
+
1186
+ - A per-instance override needs the matching custom property to be set as well, not only the
1187
+ attribute, or the pre-upgrade frame and the upgraded frame will disagree. `<lr-chart height="500px">`
1188
+ should carry `style="--lr-chart-height: 500px"` too if it sits above the fold.
1189
+ - The reservation covers the definition-upgrade shift. A component that then swaps a skeleton for
1190
+ peer-resolved content stays stable as long as the reserved box matches the final footprint, which
1191
+ is why the reservations target each component's *final* default size rather than its skeleton's.
1192
+
1193
+ ## Scope: what this library does not provide
1194
+
1195
+ Lyra is a component library, not an application framework. The following are deliberately out of
1196
+ scope, so they are worth not searching the catalog for:
1197
+
1198
+ - **Client-side routing.** There is no router and no route-outlet component. URL ownership belongs to
1199
+ the application (or its router of choice), because a component library that took it over would
1200
+ conflict with every framework router a consumer might already run. The navigation components are
1201
+ designed to be *driven* by whatever router you use rather than to own the URL themselves:
1202
+ `lr-app-rail-item`, `lr-breadcrumb-item` and `lr-tab-group` all expose their active/selected state
1203
+ as ordinary reflected properties, so binding is a one-way write from your route state plus a click
1204
+ handler that calls your router. Wire it once in your shell component; there is no Lyra-specific
1205
+ pattern to learn.
1206
+ - **Data fetching, caching, and state management.** Components take data as properties and emit
1207
+ events; they never fetch on your behalf, except the documented viewers/`src`-taking components,
1208
+ which are explicit about it.
1209
+ - **Form submission and validation orchestration.** Form-associated controls integrate with the
1210
+ native `<form>`/`ElementInternals` contract; the submission lifecycle stays the application's.
1211
+
1148
1212
  ## Optional native styles and CSS utilities
1149
1213
 
1150
1214
  Lyra ships two independent light-DOM stylesheets. Neither is imported by the root barrel, a family
@@ -1259,7 +1323,10 @@ setLyraLocale("fr"); // page-level selection; see the precedence order below
1259
1323
  ```
1260
1324
 
1261
1325
  ```html
1262
- <lr-toast .strings=${{ close: 'Fermer' }}></lr-toast>
1326
+ <lr-toast></lr-toast>
1327
+ <script type="module">
1328
+ document.querySelector("lr-toast").strings = { close: "Fermer" };
1329
+ </script>
1263
1330
  ```
1264
1331
 
1265
1332
  **Which locale a component ends up using.** Four sources, first answer wins:
@@ -1651,7 +1718,7 @@ control) is a single tab stop using a roving `tabindex`; arrow keys move within
1651
1718
  `Escape` dismisses the topmost dismissible overlay and returns focus to whatever opened it.
1652
1719
  `ArrowLeft`/`ArrowRight` mean previous/next and swap under `dir="rtl"`.
1653
1720
 
1654
- **What that contract is verified by, precisely.** Every one of the 283 components carries at least
1721
+ **What that contract is verified by, precisely.** Every one of the 284 public tags carries at least
1655
1722
  one axe-core assertion in its own directory's tests, in a test that mounts its own tag; contrast
1656
1723
  (4.5:1 text, 3:1 control borders, in both the light and dark palettes), a 40px minimum target size,
1657
1724
  pressed-state coverage for every hoverable part, and `::part()` reachability are separate blocking
@@ -2857,6 +2924,7 @@ These named interfaces and helper signatures are available to typed integrations
2857
2924
 
2858
2925
  - **`internal-canvas-color-contracts`** — Shared utility contracts.
2859
2926
  `resolveCanvasColor(/* public names: scope, color, fallback */): unknown`
2927
+ `resolveCanvasColors(/* public names: scope, colors, fallback */): unknown`
2860
2928
 
2861
2929
  - **`internal-localization-runtime-contracts`** — Shared utility contracts.
2862
2930
  `getLyraLocaleDirection(/* public names: locale */): unknown`
@@ -3842,6 +3910,32 @@ These named interfaces and helper signatures are available to typed integrations
3842
3910
 
3843
3911
  # Form controls & inputs (`components/forms/`)
3844
3912
 
3913
+ ## Breaking changes in 10.0.0
3914
+
3915
+ `<lr-swatch-picker>` drops the three members it carried through 9.x as documented one-major
3916
+ back-compat aliases, each with a like-for-like replacement that has shipped since. The `options`
3917
+ property is now `items` — same frozen owned-snapshot contract, still `attribute: false`, so no
3918
+ markup changes. The `label` property/attribute is now `accessibleLabel` (attribute `aria-label`), or
3919
+ the host `aria-label` directly; this is the one worth grepping for, because an un-updated
3920
+ `<lr-swatch-picker label="Brand colours">` leaves the internal `role="radiogroup"` with no accessible
3921
+ name at all rather than failing loudly. And the exported `SwatchOption` type is now
3922
+ `SwatchPickerItem`. The item shape itself is unchanged, including its own per-item `label` field,
3923
+ which is a different member and stays.
3924
+
3925
+ Also corrected in 10.0.0 — not breaking, but visible. A specificity sweep found rules that were
3926
+ meant to win yet were losing to another rule in the same shadow stylesheet, so their declarations
3927
+ never applied at all. In this family: arrow-keying onto the already-selected option in
3928
+ `<lr-select>` or `<lr-combobox>` produces a visible keyboard highlight again — `[aria-selected="true"]`
3929
+ was written after the active-descendant rule at equal specificity and swallowed it, so the highlight
3930
+ was absent exactly on the row a user is most likely to arrow onto first. `appearance="filled"` has a
3931
+ focus indicator again on `<lr-combobox>` and `<lr-date-input>`, both of which previously had none:
3932
+ the appearance rule out-ranked `:focus-within`, and the only `outline` in the focus rule was
3933
+ `solid transparent`. Both now express appearance as private custom properties, so no `[part]` rule
3934
+ can out-rank another. `<lr-option>` and `<lr-time-range>`'s active preset regain their pointer
3935
+ feedback, and `<lr-token-input>` can now veto all three of its mutations (`lr-add` and
3936
+ `lr-token-edit` became cancelable alongside `lr-remove`, which already was — additive; see that
3937
+ section).
3938
+
3845
3939
  ## Setter-only `null` clearing in 8.0.0
3846
3940
 
3847
3941
  Several mapped string IDLs accept `null` on assignment without widening their read type. This is a
@@ -4260,7 +4354,10 @@ box visibly (nothing is clipped or made unreachable), so leave it unset there.
4260
4354
  plain-text contract even when a separate WA `label` override is present.
4261
4355
 
4262
4356
  **Events:** `lr-option-change` — bubbles when the option's label or selectable data changes so
4263
- its parent `lr-combobox` or `lr-select` can refresh its normalized option rows.
4357
+ its parent `lr-combobox` or `lr-select` can refresh its normalized option rows. It is a private
4358
+ child-to-parent refresh signal, not a picker event: the owning `lr-combobox`/`lr-select` consumes
4359
+ it and stops it, so it never reaches a listener on the picker host (whose own contract is
4360
+ `lr-change`/`lr-input`/`change`/`input`). Listen on the `<lr-option>` itself to observe it.
4264
4361
 
4265
4362
  **Slots:** default (visible label), `start`/`end` (WA adornments), and `prefix`/`suffix` (Shoelace
4266
4363
  aliases). `start` and `prefix` project into one leading wrapper; `end` and `suffix` project into one
@@ -4356,7 +4453,7 @@ synchronous and fires no `input`/`change`/`lr-change` event.
4356
4453
 
4357
4454
  **Additional API surface:**
4358
4455
 
4359
- - `part="tag-label"` — The wrapping/ellipsis-safe selected-tag label.
4456
+ - `part="tag-label"` — The selected-tag label. Kept on one line and truncated with an ellipsis at `--tag-max-size` (default `var(--lr-size-5rem)`), rather than wrapped. Note that `lr-select`'s tag of the same name defaults to `var(--lr-size-12rem)`, so the same `--tag-max-size` value yields a wider tag there.
4360
4457
 
4361
4458
  ---
4362
4459
 
@@ -6197,7 +6294,12 @@ than adding outer padding around the buttons.
6197
6294
  - `value: string` (also accepts a `Date` or `null` when assigned) — strict `HH:mm`, optional
6198
6295
  `:ss`/`.sss`; `Date` reads local clock fields without timezone conversion. Invalid strings and
6199
6296
  `null` normalize to `''`. `valueAsNumber` is milliseconds since midnight (`NaN` while blank),
6200
- and `valueAsDate` applies the clock fields to today's local date (`null` while blank).
6297
+ and `valueAsDate` applies the clock fields to today's local date (`null` while blank). Both are
6298
+ settable, like the native `<input type="time">` properties they mirror: assigning `valueAsNumber`
6299
+ sets `value` from the same scale, and out-of-range or non-finite figures clear the field rather
6300
+ than wrapping into a different time; assigning `valueAsDate` reads the same local clock fields
6301
+ back off the Date, so it round-trips with the getter, and `null`/an invalid Date clears. Both
6302
+ assignments are silent, again like the native properties.
6201
6303
  - `defaultValue`, `name`, `form`, `disabled`, `required`, `customError`, `getForm()`,
6202
6304
  `checkValidity()`, `reportValidity()`, `setCustomValidity()`, and `resetValidity()` use the shared form-control
6203
6305
  contract. Reset restores the current declarative `value` default; `readonly` remains focusable
@@ -6861,9 +6963,10 @@ gemstone?: GemstoneKey }`; a valid CSS `color` is used as the
6861
6963
  the selected glow/shine defaults.
6862
6964
  - `accessibleLabel: string = ''` (attribute `aria-label`) — accessible name copied to the internal
6863
6965
  `role="radiogroup"`; attribute presence wins, including an explicitly empty name.
6864
- - `options` and `SwatchOption` remain compatibility aliases for `items` and `SwatchPickerItem`;
6865
- new code uses the canonical sibling radiogroup vocabulary. The former invisible `label` IDL also
6866
- remains as a compatibility fallback after `aria-label`/`accessibleLabel`.
6966
+ - The 9.x compatibility aliases were removed in 10.0.0: `options` is `items`, the exported
6967
+ `SwatchOption` type is `SwatchPickerItem`, and the former invisible `label` IDL is
6968
+ `accessibleLabel`/`aria-label`. The canonical sibling radiogroup vocabulary is now the only
6969
+ spelling.
6867
6970
  - `disabled: boolean = false` (reflected) — locks the whole picker. Every swatch renders as a real
6868
6971
  `disabled` `<button>`, so it leaves the tab sequence and cannot be activated; arrow/Home/End
6869
6972
  navigation and host `click()` become no-ops; and the swatches dim to `--lr-opacity-disabled` with
@@ -7047,7 +7150,10 @@ leaves the internal role's serialized attribute empty; browsers without the refl
7047
7150
  API keep the string fallback. The relationship tracks host attribute changes and clears when
7048
7151
  unset.
7049
7152
 
7050
- **CSS parts:** `form-control` (outer checkbox/error/hint frame), `base` (compatibility name for the
7153
+ **CSS parts:** `form-control` (outer checkbox/error/hint frame), `row` (the row wrapping the
7154
+ checkbox owner and the label as siblings — the node to size or align when laying out a column of
7155
+ checkboxes, since `base`/`checkbox` below is only the control box and its inline size tracks the box
7156
+ rather than the row), `base` (compatibility name for the
7051
7157
  semantic owner; use `checkbox`), `checkbox` (the interactive `role="checkbox"` owner; it is the
7052
7158
  same node as `base`, while the rich default label is its sibling),
7053
7159
  `box` / `control` (the small square showing the checkmark/indeterminate dash; while active it also
@@ -7212,7 +7318,10 @@ restores the current default before making the control pristine again.
7212
7318
  - `help-text` — Shoelace alias for the same hint surface.
7213
7319
  - `error` — custom error content.
7214
7320
 
7215
- **CSS parts:** `form-control` (the outer wrapper around the switch, error and hint), `base` /
7321
+ **CSS parts:** `form-control` (the outer wrapper around the switch, error and hint), `row` (the row
7322
+ wrapping the switch owner and the label as siblings — the node to size or align when laying out a
7323
+ column of switches, since `base`/`switch` below is only the track box and its inline size tracks the
7324
+ track rather than the row), `base` /
7216
7325
  `switch` / `wrapper` (the semantic interactive `role="switch"` owner; the rich label is its
7217
7326
  sibling), `track` / `control` (the
7218
7327
  pill-shaped background), `thumb` (the circular knob), `label` (wrapper around the default slot),
@@ -7458,6 +7567,7 @@ Mapped aliases are also live: `--thumb-size`, `--thumb-width`, `--thumb-height`,
7458
7567
 
7459
7568
  ```html
7460
7569
  <lr-slider
7570
+ id="temperature-slider"
7461
7571
  name="temperature"
7462
7572
  min="0"
7463
7573
  max="2"
@@ -7466,14 +7576,11 @@ Mapped aliases are also live: `--thumb-size`, `--thumb-width`, `--thumb-height`,
7466
7576
  hint="Higher values make replies more varied."
7467
7577
  with-markers
7468
7578
  with-tooltip
7469
- .valueAsNumber=${0.7}
7470
- .valueFormatter=${(value, handle) => `${value * 100}%`}
7471
- @lr-input=${(e) => setDraftTemperature(e.detail.value)}
7472
- @lr-change=${(e) => commitTemperature(e.detail.value)}
7473
7579
  ></lr-slider>
7474
7580
 
7475
7581
  <!-- Two handles, vertical. A name submits two `price` entries. -->
7476
7582
  <lr-slider
7583
+ id="price-slider"
7477
7584
  range
7478
7585
  name="price"
7479
7586
  orientation="vertical"
@@ -7483,8 +7590,17 @@ Mapped aliases are also live: `--thumb-size`, `--thumb-width`, `--thumb-height`,
7483
7590
  min-value="200"
7484
7591
  max-value="800"
7485
7592
  label="Price"
7486
- @lr-change=${(e) => applyPriceFilter(e.detail.minValue, e.detail.maxValue)}
7487
7593
  ></lr-slider>
7594
+ <script type="module">
7595
+ const temperature = document.getElementById("temperature-slider");
7596
+ temperature.valueAsNumber = 0.7;
7597
+ temperature.valueFormatter = (value, handle) => `${value * 100}%`;
7598
+ temperature.addEventListener("lr-input", (e) => setDraftTemperature(e.detail.value));
7599
+ temperature.addEventListener("lr-change", (e) => commitTemperature(e.detail.value));
7600
+
7601
+ const price = document.getElementById("price-slider");
7602
+ price.addEventListener("lr-change", (e) => applyPriceFilter(e.detail.minValue, e.detail.maxValue));
7603
+ </script>
7488
7604
  ```
7489
7605
 
7490
7606
  An unset `value` starts at numeric `0`, clamped into the configured domain and step grid. A reset
@@ -8041,15 +8157,23 @@ option layout and defaults to `--lr-checkbox-group-option-gap`.
8041
8157
  `--lr-checkbox-group-invalid-border` (default `var(--lr-color-danger)`) independently retints the
8042
8158
  invalid option-collection border without changing other danger-colored surfaces.
8043
8159
 
8044
- **`value` is a readonly defensive read-out of child state, not an input.** The children are the
8045
- single source of truth. An internal sync recomputes `value` on every child toggle, programmatic
8046
- child `checked`/`value`/`disabled` update, `slotchange`, `name`/`required` change, blur, and
8047
- `form.reset()`. Mutating an obtained array cannot mutate the group.
8160
+ **`value` reads as a frozen defensive snapshot of child state, and assigning it mirrors back onto
8161
+ the children.** The children remain the single source of truth. An internal sync recomputes `value`
8162
+ on every child toggle, programmatic child `checked`/`value`/`disabled` update, `slotchange`,
8163
+ `name`/`required` change, blur, and `form.reset()`. Mutating an obtained array cannot mutate the
8164
+ group — assign a new array instead.
8048
8165
  Only a checkbox whose nearest `lr-checkbox-group` ancestor is this group contributes; a nested
8049
8166
  group owns its own descendants and form entries. `connectedCallback()` runs that sync before the
8050
8167
  first render.
8051
8168
 
8052
- - **To preselect**, set `checked` on the children: `<lr-checkbox value="a" checked>`.
8169
+ Assigning checks every child whose `value` (defaulting to `'on'`) appears in the array and unchecks
8170
+ every other one; duplicate entries check that many same-valued children, and values naming no child
8171
+ are ignored. `null`/`undefined` clear the selection. It is controlled input, so it emits no
8172
+ `lr-change` — only user interaction does. An assignment made before the children exist (the shape of
8173
+ a `.value=${...}` binding on first render) is applied once they arrive.
8174
+
8175
+ - **To preselect**, either set `checked` on the children (`<lr-checkbox value="a" checked>`) or
8176
+ assign the group's `value`.
8053
8177
  - **To read the selection**, use this property or the `lr-change` event detail.
8054
8178
  - **Give every child a distinct `value`.** `<lr-checkbox>`'s `value` defaults to `'on'`, so a group
8055
8179
  of undifferentiated children submits several identical `FormData` entries and the submitted data
@@ -8090,11 +8214,16 @@ each list mutation; native events have no detail and both aliases carry a frozen
8090
8214
  Native `FocusEvent` `focus`/`blur` are relayed once from the draft and inline editor, preserving
8091
8215
  `relatedTarget`. `lr-add`
8092
8216
  (`detail: { value, values }`, where `value` is the final added token and `values` is the frozen,
8093
- readonly, complete ordered and deduplicated set of tokens added by that commit),
8217
+ readonly, complete ordered and deduplicated set of tokens added by that commit — cancelable as of
8218
+ 10.0.0; `preventDefault()` keeps the tokens out of `value` and leaves the typed draft text in the
8219
+ input unchanged so the user can correct it, rather than clearing it),
8094
8220
  `lr-remove`
8095
8221
  (`detail: { value, index }` — cancelable; `preventDefault()` keeps the token in `value`
8096
8222
  unchanged), and `lr-token-edit`
8097
- (`detail: { value, previousValue, index }` — an existing token was edited in place and committed).
8223
+ (`detail: { value, previousValue, index }` — an existing token is about to be edited in place
8224
+ cancelable as of 10.0.0; `preventDefault()` keeps the token in `value` unchanged and leaves the
8225
+ inline editor open with the user's edited text intact, rather than closing and discarding it).
8226
+ All three mutators now share one veto contract; previously only `lr-remove` could be vetoed.
8098
8227
  `lr-invalid` (no detail) is emitted once as a bubbling/composed alias when native validity fails.
8099
8228
  **CSS parts:** `form-control`, `form-control-label`, `input-wrapper`, `token`, `token-label` (the
8100
8229
  token's text, doubling as the roving-focus edit trigger — rendered only while `editable`),
@@ -9152,6 +9281,30 @@ These named interfaces and helper signatures are available to typed integrations
9152
9281
 
9153
9282
  # Data display, dashboards & flow canvas (`components/data/`)
9154
9283
 
9284
+ ## Breaking changes in 10.0.0
9285
+
9286
+ `<lr-calendar>`'s `firstDayOfWeek`/`first-day-of-week` drops the bare `0`–`6` integer form and stops
9287
+ defaulting to a hardcoded Monday. The type is now exactly `LyraCalendarFirstDayOfWeek`
9288
+ (`'auto'|'sun'|'mon'|'tue'|'wed'|'thu'|'fri'|'sat'`, default `'auto'`), so there is one way to
9289
+ express a week start instead of two that had to be sanitized and wrapped against each other, and
9290
+ `'auto'` resolves through the same `resolveFirstDayOfWeek()` contract `<lr-date-picker>`/
9291
+ `<lr-date-input>` already use. An unset `<lr-calendar>` and an unset `<lr-date-picker>` on the same
9292
+ page therefore agree at last — Sunday-first under `en-US`, Monday-first under `fr-FR` — where the
9293
+ calendar previously rendered Monday-first everywhere while already formatting its weekday *labels*
9294
+ from the locale. Replace `first-day-of-week="1"` with `first-day-of-week="mon"`: a leftover numeric
9295
+ value is not mapped or clamped, it is simply an unrecognized token and falls through to Sunday. If
9296
+ the locale-independent Monday start was deliberate, keep it by writing `"mon"` explicitly instead of
9297
+ relying on the default. There is no `wa-calendar`, so no upstream mirror is affected.
9298
+
9299
+ Also corrected in 10.0.0 — not breaking, but visible. A specificity sweep found rules that were
9300
+ meant to win yet were losing to another rule in the same shadow stylesheet, so their declarations
9301
+ never applied at all. In this family: `<lr-calendar>`'s today cell has a focus ring again (its
9302
+ `[data-today]` outline was swallowing it, leaving today's cell pixel-identical focused and at rest)
9303
+ and its adjacent-month cells take selection and pointer feedback again; `<lr-table>`'s header cell
9304
+ that is both sticky and sortable, `<lr-pagination>`'s page input, `<lr-sequence-strip>`'s selected
9305
+ cell and `<lr-flow-canvas>`'s selected edge regain hover/press/focus feedback; and
9306
+ `<lr-flow-controls>` honors a `hidden` slotted action button instead of painting it.
9307
+
9155
9308
  ## `lr-sparkline`
9156
9309
 
9157
9310
  Zero-dependency inline SVG trend chart (mirrors `<wa-sparkline>`). Its default allocation is one
@@ -9820,7 +9973,13 @@ cell: (row) => unknown }` —
9820
9973
  - `groupLabel?: (key: string | number, rows: readonly T[]) => unknown` (attribute: false) — custom group
9821
9974
  header content; without it, the group key is rendered as text
9822
9975
  - `expandedContent?: (row: T) => unknown` (attribute: false) — enables a leading expand toggle and
9823
- renders a full-width detail row beneath expanded records
9976
+ renders a full-width detail row beneath expanded records. The returned content renders inside
9977
+ the component's shadow root, behind the `expanded-cell` part — page CSS cannot reach it, and
9978
+ `::part(expanded-cell)` only reaches the wrapping `<td>` itself, not the descendants this
9979
+ callback returns (the same `::part()` limitation a column's `cell(row)` anchors run into, see
9980
+ `--lr-table-cell-link-color` below). Style such content by returning already-styled elements —
9981
+ inline `style`, or elements that reference this table's own `--lr-*` design tokens, which
9982
+ inherit across the shadow boundary like any custom property
9824
9983
  - `canExpand?: (row: T) => boolean` (attribute: false) — optional per-row gate for expansion
9825
9984
  - `expandedRowKeys: ReadonlySet<string | number> = new Set()` (attribute: false) — consumer-controlled
9826
9985
  expanded state bounded to 10,000 keys; malformed and whitespace-only string keys are omitted while valid
@@ -9872,7 +10031,11 @@ sort properties; server mode leaves them controlled. Other events are `lr-row-cl
9872
10031
  (`detail: { row }`), `lr-load-more` (fired on the "load more" button),
9873
10032
  `lr-priority-columns-visibility-change` (frozen readonly `detail: { visible }`), and `lr-row-expand-toggle`
9874
10033
  (`detail: { row, rowKey }`; the table does not mutate `expandedRowKeys`), and
9875
- `lr-selection-change` (frozen readonly `detail: { rowKeys }`) when selection is enabled, `lr-filter-change`
10034
+ `lr-selection-change` (frozen readonly `detail: { rowKeys }`, not cancelable) when selection is
10035
+ enabled — fired both from a row activation and from a `selectionMode` flip to `'single'` that coerces
10036
+ an existing multi-row selection down to one key (skipped on the very first render, since an
10037
+ already-inconsistent initial `selectionMode`/`selectedRowKeys` pairing is a starting state, not a
10038
+ live transition), `lr-filter-change`
9876
10039
  (frozen readonly `detail: { text }`), and `lr-page-change` (frozen readonly `detail: { page }`) from the
9877
10040
  filter/pagination surfaces, and `lr-cell-edit` (`detail: { row, columnKey, value }`) for editable
9878
10041
  columns, and `lr-column-resize` (`detail: { columnKey, width }`, `width` in CSS pixels) on every pointer or
@@ -9921,7 +10084,23 @@ no-rows states return the empty element as the shadow root's own root, with no `
9921
10084
  wrapper around it — `::part(base)` does not apply in those two states, only in the filtered-to-zero
9922
10085
  one — and that `empty` disappears entirely once the `empty` slot is filled.
9923
10086
 
9924
- **Themeable custom properties:** `--lr-table-max-height` (default `none`; controls the scrollable
10087
+ - `scrollMode: 'self' | 'page' = 'self'` (attribute `scroll-mode`, reflected) which element
10088
+ scrolls when the table overflows. `'self'` makes `[part="base"]` the scroll container, which is
10089
+ what pairs with `--lr-table-max-height` and makes the sticky header pin inside the table's own
10090
+ viewport. `'page'` hands scrolling back to the document. Needed because a scroll container clips
10091
+ **both** axes — CSS offers no way to scroll one and not the other — so an *uncapped* table that is
10092
+ still `overflow: auto` becomes a sticky containing block that never scrolls, and its header
10093
+ scrolls away with the page. With `'page'` the header's nearest scrollport is the page, so it pins
10094
+ there; the cost is that a table wider than its host overflows the page instead of scrolling
10095
+ inside itself. Named `scrollMode` rather than `scroll` because a `scroll` property would shadow
10096
+ `Element.prototype.scroll()`
10097
+
10098
+ **Themeable custom properties:** `--lr-table-cell-color` (default `inherit`),
10099
+ `--lr-table-cell-link-color` (default `var(--lr-color-brand)`) and
10100
+ `--lr-table-cell-link-hover-color` — an anchor returned from a column's `cell(row)` renders inside
10101
+ the component's shadow root, where page CSS cannot reach it and `::part()` cannot select past the
10102
+ first compound selector to reach it either, so without these it computes to the UA default link
10103
+ blue; set `revert` for the UA default. `--lr-table-max-height` (default `none`; controls the scrollable
9925
10104
  body's `max-block-size`). `--lr-table-heat-tint-lo` (default `var(--lr-color-brand-quiet)`) and
9926
10105
  `--lr-table-heat-tint-hi` (default `var(--lr-color-brand)`) — the `color-mix()` ramp endpoints
9927
10106
  for heat-tint mode's per-cell background, consulted only on columns/rows that define `heatValue`;
@@ -10431,9 +10610,13 @@ number, color?: string, group?: string }` snapshots; malformed/hostile records a
10431
10610
  marking shortened strings with an ellipsis and disclosing omitted input through `[part="limit"]`.
10432
10611
  The returned sequence and records are frozen; reassign `words` after changes.
10433
10612
  - `minFontSize: number = 12` (attribute `min-font-size`) — px, applied to the lowest-weight word;
10434
- layout clamps positive finite values to at most 512px and uses 1px for invalid/non-positive values
10613
+ a finite value is clamped to `[1, 512]` (so `0`/a negative value floors at `1px`, and an oversized
10614
+ value caps at `512px`); a non-finite value (`NaN`/`Infinity`) falls back to the default `12px`
10615
+ rather than to the `1px` floor
10435
10616
  - `maxFontSize: number = 48` (attribute `max-font-size`) — px, applied to the highest-weight word;
10436
- normalized by the same 1–512px layout bound (reversed min/max bounds are swapped)
10617
+ clamped/defaulted the same way (a non-finite value falls back to `48px`, not to `1px`); a
10618
+ resulting reversed pair (`minFontSize` greater than `maxFontSize`) is swapped rather than
10619
+ inverting the weight-to-size mapping
10437
10620
  - `scale: 'linear'|'sqrt' = 'linear'` — `sqrt` compresses the weight→font-size mapping so one heavy
10438
10621
  word doesn't dwarf the rest, matching `lr-heatmap`'s `scale` property
10439
10622
  - `wordRotation: 'none'|'mixed' = 'none'` (attribute `word-rotation`, reflected) — `mixed` lets
@@ -10580,6 +10763,17 @@ weekdayLabelText?: (jsWeekday:number)=>string|undefined; monthLabelText?:
10580
10763
  measured `clientWidth` on every draw/resize instead of the fixed `cell-size`, so the grid actually
10581
10764
  fills the available width; now applies to calendar mode as well as matrix mode — see gotchas for
10582
10765
  the default, non-`fit-to-width` behavior)
10766
+ - `rowLabelWidth?: number | 'auto'` (attribute `row-label-width`, reflected) — width, in CSS px, of
10767
+ the **matrix** row-label gutter, or `'auto'` to measure the widest label and size the gutter to
10768
+ fit (never below the built-in `60`, never above 40% of the host width, so one long label cannot
10769
+ squeeze out the cells it describes). Unset keeps the built-in `60`, so no existing chart reflows.
10770
+ Independently of this, a label too wide for the resolved gutter is truncated with an ellipsis
10771
+ rather than clipped mid-glyph — clipping read as a rendering fault, truncation reads as "there is
10772
+ more here". `cellText` still carries the full label to the tooltip and the keyboard announcement.
10773
+ A malformed value is ignored rather than collapsing the gutter. Calendar mode is unaffected; it
10774
+ has its own fixed weekday gutter
10775
+ - `colLabelHeight?: number` (attribute `col-label-height`) — height, in CSS px, of the matrix
10776
+ column-label band. Unset keeps the built-in `20`
10583
10777
  - `maxCellSize?: number` (attribute `max-cell-size`) — ceiling, in CSS px, on the cell size
10584
10778
  `fitToWidth` derives from the host width, in **both** modes. Exists because `fitToWidth` divides
10585
10779
  the _whole_ host width across the grid, so a 5-week calendar or a 3-column matrix in a wide pane
@@ -10597,6 +10791,23 @@ weekdayLabelText?: (jsWeekday:number)=>string|undefined; monthLabelText?:
10597
10791
  color ramp via `sqrtStep()` instead of mapping linearly; in calendar mode, the default `'linear'`
10598
10792
  still buckets by quartile (`quartileBucket()`, unchanged), while `'sqrt'` instead compresses via the
10599
10793
  same `sqrtStep()` magnitude compression as matrix mode, so one heavy day doesn't wash out the rest
10794
+ - `domain?: [number, number]` (attribute: false) — pins the color ramp's input domain instead of
10795
+ deriving it from the data's own extremes, so two heatmaps of comparable data can share a scale
10796
+ rather than each normalizing to its own min/max. A reversed pair is normalized; a degenerate or
10797
+ non-finite one falls back to the derived range
10798
+ - `midpoint?: number` — anchors a diverging ramp's neutral color on this value rather than at the
10799
+ middle of the domain, scaling the two halves independently (`lo`→0, `midpoint`→0.5, `hi`→1). A
10800
+ midpoint outside the resolved domain degrades to plain normalization rather than distorting the
10801
+ ramp
10802
+ - **Signed data.** Setting either `domain` or `midpoint` opts the component into signed data, where
10803
+ only a **non-finite** value is no-data. With neither set (the default), a negative value is
10804
+ no-data — matching the long-documented `-1` sentinel, since a matrix of counts has no meaningful
10805
+ negative. Declaring a domain or midpoint is what disambiguates "a real negative" from "the
10806
+ sentinel", so signed datasets render their negative half instead of dropping it. In signed mode a
10807
+ structurally absent matrix cell reads as `NaN` so it stays no-data while a real `-1` beside it
10808
+ renders on the ramp; in default mode an absent cell still resolves to `-1`, keeping `valueAt()`
10809
+ and the `lr-cell-click` payload unchanged. `scale="sqrt"` rejects negatives in both modes — a
10810
+ square root of a negative has no meaning
10600
10811
  - `bucketCount: number = 5` (attribute `bucket-count` — calendar mode only; non-finite values fall
10601
10812
  back to 5, while finite values are floored and clamped to 2–256 before the color-ramp allocation)
10602
10813
  - `annotations: readonly HeatmapAnnotation[] = []` (attribute: false) — `HeatmapAnnotation { row?: number;
@@ -10907,16 +11118,30 @@ readonly color, readonly label? }`; `color`
10907
11118
  per-category only. The marker count is reported as its own clause rather than folded into any
10908
11119
  category's count. Unset (the default) changes nothing: no extra legend row, no extra summary clause
10909
11120
 
11121
+ - `selectedIndex: number = -1` (attribute `selected-index`) — the currently selected item, or `-1`
11122
+ for none. **Controlled:** activating a cell emits `lr-item-activate` and does *not* move the
11123
+ selection itself, so the consumer stays the single source of truth and the strip cannot drift from
11124
+ a playback index it does not own (its natural companion is `lr-sequence-playback`). Mirrors the
11125
+ shape `lr-lite-chart`'s `selectedIndices` and `lr-heatmap`'s `selectedCell` already establish. An
11126
+ out-of-range or non-integer value selects nothing. The selected cell carries `aria-current="true"`
11127
+ and `data-selected`; the selection is drawn as a ring rather than a background change, because a
11128
+ cell's background is data (its category colour) and tinting it would misreport the category
11129
+
10910
11130
  The single-member `orientation: 'horizontal'` property was **removed in 9.0.0**: nothing read it and
10911
11131
  the stylesheet never mentioned it, so the reflected attribute styled nothing. Delete the attribute;
10912
11132
  the strip has always laid out horizontally.
10913
11133
 
10914
- **Events:** none.
11134
+ **Events:** `lr-item-activate` — `detail: { index: number; id: string; item: SequenceStripItem }`,
11135
+ fired when a cell is clicked or activated with Enter/Space on the roving-tabindex focus. Not
11136
+ cancelable: nothing in the component branches on `defaultPrevented`. Bubbles and composed, like every
11137
+ library event.
10915
11138
 
10916
11139
  **Slots:** none.
10917
11140
 
10918
11141
  **CSS parts:** `base` (the root strip, `role="list"`), `cell` (each item's `role="listitem"` cell,
10919
- background-colored by its category and carrying the roving `tabindex`), `marker` (the small bottom
11142
+ background-colored by its category, carrying the roving `tabindex`, and activatable by click or
11143
+ Enter/Space — it has a pointer cursor plus paired hover/press treatments, and `[data-selected]` when
11144
+ it is `selectedIndex`), `marker` (the small bottom
10920
11145
  marker on a cell whose item sets `marker: true`), `tooltip` (the detail tooltip showing the active
10921
11146
  item's label, hidden until a cell is hovered or focused),
10922
11147
  `legend` (the static category key rendered below the strip when `showLegend` is set — `aria-hidden`,
@@ -11851,17 +12076,18 @@ sizes a legend chip on both axes. Otherwise the component consumes shared tokens
11851
12076
  **Optional peer deps:** none.
11852
12077
 
11853
12078
  ```html
11854
- <lr-context-meter
11855
- label="128K context window"
11856
- total="128000"
11857
- .segments=${[
11858
- { label: 'System prompt', value: 2200, tone: 'neutral' },
11859
- { label: 'Conversation history', value: 61000, tone: 'brand' },
11860
- { label: 'Retrieved context', value: 30800, tone: 'warning' },
11861
- ]}
11862
- ></lr-context-meter>
12079
+ <lr-context-meter label="128K context window" total="128000"></lr-context-meter>
11863
12080
 
11864
- <lr-context-meter shape="ring" total="128000" .segments=${segments}></lr-context-meter>
12081
+ <lr-context-meter shape="ring" total="128000"></lr-context-meter>
12082
+ <script type="module">
12083
+ const [meter, ringMeter] = document.querySelectorAll("lr-context-meter");
12084
+ meter.segments = [
12085
+ { label: "System prompt", value: 2200, tone: "neutral" },
12086
+ { label: "Conversation history", value: 61000, tone: "brand" },
12087
+ { label: "Retrieved context", value: 30800, tone: "warning" },
12088
+ ];
12089
+ ringMeter.segments = segments;
12090
+ </script>
11865
12091
  ```
11866
12092
 
11867
12093
  An internal visually-hidden semantic node carries `role="meter"` plus `aria-valuenow`,
@@ -11918,8 +12144,15 @@ title, readonly color?, readonly data? }`; `date` is an ISO `YYYY-MM-DD` string
11918
12144
  - `view: CalendarView = 'month'`, where `CalendarView = 'month' | 'agenda'` (reflected) — agenda
11919
12145
  lists the effective visible month's events, date-sorted. Foreign tokens normalize and reflect to
11920
12146
  `month`
11921
- - `firstDayOfWeek: number = 1` (attribute `first-day-of-week`) — sanitized to a finite integer
11922
- (fallback `1`) and wrapped into `0`–`6`, so a malformed value can't drop days
12147
+ - `firstDayOfWeek: LyraCalendarFirstDayOfWeek = 'auto'` (attribute `first-day-of-week`) — which
12148
+ weekday the grid starts on. **Breaking in 10.0.0:** the default was a hardcoded `1` (Monday)
12149
+ regardless of locale; it now derives from the effective locale through the same
12150
+ `resolveFirstDayOfWeek()` contract `<lr-date-picker>`/`<lr-date-input>` already use, so an unset
12151
+ `<lr-calendar>` renders Sunday-first under `en-US` and Monday-first under `fr-FR` instead of
12152
+ disagreeing with a date picker on the same page. **Also breaking in 10.0.0:** the bare `0`–`6`
12153
+ integer form is gone; the value is now one of the shared weekday-name tokens (`'auto'`, then
12154
+ `'sun'` through `'sat'`), which pins the week start independent of locale. Pass `'mon'` to keep
12155
+ the pre-10.0.0 rendering.
11923
12156
  - `accessibleLabel: string = ''` (attribute `aria-label`) — names the host. The nested calendar
11924
12157
  section retains the localized purpose name rather than duplicating an authored host name; when
11925
12158
  set programmatically without a host attribute, this value names the section
@@ -11971,6 +12204,30 @@ opposite default from `lr-stepper`; `horizontal` makes `[part='base']` a horizon
11971
12204
  (the `role="list"` element is in the shadow root and never inherits a host attribute). Read-only
11972
12205
  `itemCount: number` is the live count of direct default-slot `<lr-timeline-item>` children;
11973
12206
  unrelated slotted elements and text nodes are ignored.
12207
+ `scale: 'flow' | 'time' = 'flow'` (attribute `scale`, type `LyraTimelineScale`) chooses how items
12208
+ are distributed along the main axis. `'flow'` is the default even sequence, where `timestamp` is
12209
+ rendered as text but carries no positional meaning. `'time'` positions each item at its true
12210
+ proportion of the range, so a gap of weeks and a gap of decades stop looking identical. `'time'`
12211
+ needs a definite extent to distribute along — `--lr-timeline-time-extent` (default
12212
+ `var(--lr-size-20rem)`), applied as `block-size` when vertical and `inline-size` when horizontal —
12213
+ because items are absolutely positioned and a percentage against an auto-sized track resolves to
12214
+ zero. `collision: 'overlap' | 'stack' = 'overlap'` (attribute `collision`, type `LyraTimelineCollision`)
12215
+ chooses what `scale="time"` does with items landing on nearly the same position: `'overlap'` leaves
12216
+ them stacked on one another, `'stack'` steps each colliding item one lane along the **cross** axis
12217
+ (indent per lane: `--lr-timeline-collision-offset`, default `var(--lr-space-l)`), which is what a
12218
+ dense chronology needs — items within 1.5% of the axis of each other count as colliding, and an
12219
+ isolated item returns to lane 0 rather than inheriting a preceding run's depth. There is
12220
+ deliberately no `'cluster'` mode: collapsing coincident items into one expandable marker needs a
12221
+ selection model and click events this passive component does not have.
12222
+ `rangeStart` / `rangeEnd` (`Date | string | number`, attribute: false) pin the axis instead of
12223
+ deriving it from the earliest/latest item; a reversed or non-finite pair falls back to the derived
12224
+ range. An item with no parseable `timestamp` (including one supplied only through the `timestamp`
12225
+ slot, which carries no machine-readable instant) keeps document order and is spread evenly, so a
12226
+ partially-timestamped list degrades rather than stacking at the origin. Items sharing an instant
12227
+ overlap rather than being fanned into lanes: lane assignment, brushing, zooming and per-event
12228
+ selection belong to a denser component than this deliberately passive one. Positions are written to
12229
+ each child as a private `--_lr-timeline-item-offset` custom property and removed again on a switch
12230
+ back to `'flow'`, so the component still never alters its children's content or structure.
11974
12231
 
11975
12232
  **`lr-timeline-item` properties:** `timestamp?: Date | string | number` (attribute: false — `Date`
11976
12233
  isn't attribute-serializable; invalid input normalizes to unset and renders no timestamp UI),
@@ -12691,6 +12948,11 @@ These named interfaces and helper signatures are available to typed integrations
12691
12948
  }`
12692
12949
 
12693
12950
  - **`components-data-sequence-strip-sequence-strip-contracts`** — Supporting data types and helpers for this component family.
12951
+ `LyraSequenceStripActivateDetail {
12952
+ index: unknown;
12953
+ id: unknown;
12954
+ item: unknown;
12955
+ }`
12694
12956
  `SequenceStripCategory {
12695
12957
  id: unknown;
12696
12958
  color: unknown;
@@ -12782,6 +13044,23 @@ These named interfaces and helper signatures are available to typed integrations
12782
13044
 
12783
13045
  # Layout, navigation & structure (`components/layout/`)
12784
13046
 
13047
+ ## Breaking changes in 10.0.0
13048
+
13049
+ **`lr-virtual-list`:** the `lr-visible-range-changed` event is removed — listen for
13050
+ `lr-visible-range-change` instead. The detail (`LyraVirtualListRange`), the firing conditions and the
13051
+ gesture are all unchanged; only the name moved. The old spelling was the library's only past-tense
13052
+ `-changed` event among 58 members of the `-change` family, so a convention-driven `lr-${x}-change`
13053
+ listener silently missed it on a component embedded in ten viewers. It is removed outright rather
13054
+ than kept as a dual-emitting alias, because the library has no released consumers and an alias is a
13055
+ permanent tax paid to protect users who do not exist. Rename the listener; nothing else changes.
13056
+
13057
+ Also corrected in 10.0.0 — not breaking, but visible. `<lr-dashboard-grid>`'s cell keeps a focus
13058
+ indicator while it is in a collision or drop state: the collision rule owns the outline channel by
13059
+ design, but the side effect was that the focus ring vanished entirely during exactly the drag or
13060
+ resize a keyboard user most needs it, so the ring is now re-expressed on a second channel. And
13061
+ `<lr-card>` honors a `hidden` slotted media child instead of painting it — the component's own
13062
+ `display` declaration is author-origin and was beating the UA stylesheet's `[hidden] { display: none }`.
13063
+
12785
13064
  ## Breaking changes in 9.0.0
12786
13065
 
12787
13066
  **`lr-app-rail`:** `mode`'s write side is removed: the accessor is now strictly read-only (always resolves to
@@ -14181,11 +14460,16 @@ is pending.
14181
14460
  between rows.
14182
14461
 
14183
14462
  ```html
14184
- <lr-reorder-list label="Form fields" @lr-reorder=${(e) => console.log(e.detail.order)}>
14463
+ <lr-reorder-list label="Form fields">
14185
14464
  <lr-reorder-item value="name">Name</lr-reorder-item>
14186
14465
  <lr-reorder-item value="email">Email</lr-reorder-item>
14187
14466
  <lr-reorder-item value="phone">Phone</lr-reorder-item>
14188
14467
  </lr-reorder-list>
14468
+ <script type="module">
14469
+ document
14470
+ .querySelector("lr-reorder-list")
14471
+ .addEventListener("lr-reorder", (e) => console.log(e.detail.order));
14472
+ </script>
14189
14473
  ```
14190
14474
 
14191
14475
  **Known gotchas:**
@@ -14476,7 +14760,7 @@ progress` style, and gates `lr-load-more` while a consumer's fetch is in flight.
14476
14760
  **Exported types:** `VirtualListRowHeight = number | 'auto'`;
14477
14761
  `VirtualListSource<T> = readonly T[] | VirtualListIndexedSource<T>` and
14478
14762
  `VirtualListIndexedSource<T> { readonly count: number; itemAt(index): T; keyAt?(index): string |
14479
- number; indexOfKey?(key: string | number): number }`; `VirtualListRange { start: number; end: number }` (the `lr-visible-range-changed`
14763
+ number; indexOfKey?(key: string | number): number }`; `VirtualListRange { start: number; end: number }` (the `lr-visible-range-change`
14480
14764
  detail shape); `VirtualListGroup { key: string | number; label?: string; startIndex: number }` — the
14481
14765
  shape consumed by `groups` above; `VirtualListScroll { scrollTop: number; viewportHeight: number }` —
14482
14766
  the `lr-virtual-scroll` detail shape.
@@ -14521,12 +14805,14 @@ math, and any row element can be recycled or removed on the next update.
14521
14805
  **Events:** `lr-load-more` (no detail — fired once per approach to the bottom of the list while
14522
14806
  `has-more` is true and `loading` is false; does not refire on every scroll tick while still near the
14523
14807
  bottom — scrolling back away from the bottom and returning, or `items` growing enough to move the
14524
- window away from the end, re-arms it), `lr-visible-range-changed` (`detail: VirtualListRange`, the
14525
- current visible, non-overscanned item index range — fired only when it actually changes),
14808
+ window away from the end, re-arms it), `lr-visible-range-change` (`detail: VirtualListRange`, the
14809
+ current visible, non-overscanned item index range — fired only when it actually changes; it was
14810
+ spelled `lr-visible-range-changed` before 10.0.0, the only past-tense `-changed` spelling among 58
14811
+ `-change`-family events, so a convention-driven `lr-${x}-change` listener silently missed it),
14526
14812
  `lr-virtual-scroll`
14527
14813
  (`detail: VirtualListScroll` — the scroll container moved; emitted from the same animation frame that
14528
14814
  already coalesces native `scroll` events, so a fling produces at most one per frame and none at all
14529
- when the position did not change. Unlike `lr-visible-range-changed`, which only fires on index-range
14815
+ when the position did not change. Unlike `lr-visible-range-change`, which only fires on index-range
14530
14816
  changes, this reports _sub-row_ movement, which is what scroll-linked layout needs)
14531
14817
 
14532
14818
  **Slots:** none — all content comes from `renderItem`.
@@ -14557,8 +14843,10 @@ activation target.
14557
14843
 
14558
14844
  **Optional peer deps:** none.
14559
14845
 
14560
- ```html
14561
- <lr-virtual-list
14846
+ ```ts
14847
+ import { html } from "lit";
14848
+
14849
+ const view = html`<lr-virtual-list
14562
14850
  .items=${sessions}
14563
14851
  .renderItem=${(item, index) => html`
14564
14852
  <lr-conversation-item
@@ -14573,12 +14861,14 @@ activation target.
14573
14861
  ?has-more=${hasMorePages}
14574
14862
  ?loading=${isLoadingMore}
14575
14863
  @lr-load-more=${() => loadNextPage()}
14576
- @lr-visible-range-changed=${(e) => console.log('visible', e.detail.start, e.detail.end)}
14577
- @lr-virtual-scroll=${(e) => console.log('scroll top', e.detail.scrollTop)}
14578
- ></lr-virtual-list>
14864
+ @lr-visible-range-change=${(e) => console.log("visible", e.detail.start, e.detail.end)}
14865
+ @lr-virtual-scroll=${(e) => console.log("scroll top", e.detail.scrollTop)}
14866
+ ></lr-virtual-list>`;
14579
14867
  ```
14580
14868
 
14581
14869
  ```ts
14870
+ import { html } from "lit";
14871
+
14582
14872
  // No count-sized array: only the current window is read.
14583
14873
  const syntheticRows = {
14584
14874
  count: 100_000,
@@ -14595,15 +14885,17 @@ html`<lr-virtual-list
14595
14885
  ></lr-virtual-list>`;
14596
14886
  ```
14597
14887
 
14598
- ```html
14599
- <!-- Sticky group headers: the header is a real row, so the `groups` entries are position anchors
14600
- only (`label: ''`); the pinned copy remains strictly presentational. -->
14601
- <lr-virtual-list
14888
+ ```ts
14889
+ import { html } from "lit";
14890
+
14891
+ // Sticky group headers: the header is a real row, so the `groups` entries are position anchors
14892
+ // only (`label: ''`); the pinned copy remains strictly presentational.
14893
+ const view = html`<lr-virtual-list
14602
14894
  .items=${rows}
14603
14895
  .groups=${groupStarts /* [{ key: 'Today', label: '', startIndex: 0 }, …] */}
14604
14896
  .renderItem=${(item, index) => (item.isHeader ? headerTemplate(item) : rowTemplate(item))}
14605
14897
  .renderStickyGroup=${(group) => headerTemplate(group)}
14606
- ></lr-virtual-list>
14898
+ ></lr-virtual-list>`;
14607
14899
  ```
14608
14900
 
14609
14901
  Every row is positioned by a `transform: translateY(offset)`, rather than page flow, so only a small
@@ -14959,13 +15251,17 @@ invention (no `wa-*`/`sl-*` counterpart).
14959
15251
  anchors to its block-end edge and does not cover the full height. Has no visual effect while the effective
14960
15252
  presentation resolves to `'inline'`.
14961
15253
  - `label: string = ''` — accessible name for the overlay presentation's `role="dialog"`, used
14962
- verbatim when set. When empty, falls back to the `header` slot's content: a heading element
14963
- (`h1`–`h6` or `[role="heading"]`) among the slotted header content wins if present, otherwise the
14964
- header slot's combined text content is used (mirrors `lr-dialog`'s `detectHeading()` fallback,
14965
- via `aria-label` rather than `aria-labelledby` since the header content is light DOM while
14966
- `[part="panel"]` is in shadow DOM). A panel opened with neither `label` nor header content uses
14967
- the localized `responsivePanel` fallback (`"Panel"` in the default locale), so its dialog is
14968
- never unnamed. Unused in the inline presentation, which has no dialog semantics to name.
15254
+ verbatim when set but a plain `aria-label` attribute on the host wins outright over `label`
15255
+ when both are present, the standard ARIA convention for a consumer that wants full control over
15256
+ the announced name (matching `lr-dialog`'s `accessibleLabel` pattern). When both the host
15257
+ `aria-label` and `label` are empty, this falls back to the `header` slot's content: a heading
15258
+ element (`h1`–`h6` or `[role="heading"]`) among the slotted header content wins if present,
15259
+ otherwise the header slot's combined text content is used (mirrors `lr-dialog`'s
15260
+ `detectHeading()` fallback, via `aria-label` rather than `aria-labelledby` since the header
15261
+ content is light DOM while `[part="panel"]` is in shadow DOM). A panel opened with none of a host
15262
+ `aria-label`, `label`, or header content uses the localized `responsivePanel` fallback (`"Panel"`
15263
+ in the default locale), so its dialog is never unnamed. Unused in the inline presentation, which
15264
+ has no dialog semantics to name.
14969
15265
  - `overlayBreakpoint: string = '768px'` (attribute `overlay-breakpoint`) — CSS length compared with
14970
15266
  the component's allocated inline size in `mode="auto"`; at or below it, the effective presentation
14971
15267
  is `'overlay'`.
@@ -15383,19 +15679,16 @@ being dragged. Plus shared tokens `--lr-color-surface`, `--lr-color-border`, `--
15383
15679
 
15384
15680
  ```html
15385
15681
  <div style="position: relative; block-size: 100vh;">
15386
- <lr-dock-panel
15387
- edge="end"
15388
- extent="320px"
15389
- min-extent="200px"
15390
- max-extent="480px"
15391
- collapsible
15392
- @lr-resize-input=${(e) => updateLayoutPreview(e.detail.extent)}
15393
- @lr-resize-change=${(e) => persistExtent(e.detail.extent)}
15394
- @lr-collapse-change=${(e) => console.log(e.detail.collapsed)}
15395
- >
15682
+ <lr-dock-panel edge="end" extent="320px" min-extent="200px" max-extent="480px" collapsible>
15396
15683
  <div>Sidebar content — a chat thread list, an inspector, anything.</div>
15397
15684
  </lr-dock-panel>
15398
15685
  </div>
15686
+ <script type="module">
15687
+ const panel = document.querySelector("lr-dock-panel");
15688
+ panel.addEventListener("lr-resize-input", (e) => updateLayoutPreview(e.detail.extent));
15689
+ panel.addEventListener("lr-resize-change", (e) => persistExtent(e.detail.extent));
15690
+ panel.addEventListener("lr-collapse-change", (e) => console.log(e.detail.collapsed));
15691
+ </script>
15399
15692
  ```
15400
15693
 
15401
15694
  Pointer-drag-resize admits only a primary pointer using its primary button, then mirrors
@@ -15530,6 +15823,30 @@ former brand and active-mix values when unset.
15530
15823
 
15531
15824
  - every `appearance` renders on the _same_ `[part="base"]` element — there's no separate element per
15532
15825
  variant, so a `::part(base)` override applies uniformly regardless of `appearance`.
15826
+ - **a card clips, it does not scroll — and it never picks a scroll owner for you.** `[part='base']`
15827
+ stretches to the host's allocated block-size and clips its overflow, which is what keeps a
15828
+ full-bleed `media`/`image` child inside the rounded border. In an auto-sized row the card simply
15829
+ grows and nothing is clipped; give it a _definite_ allocation (a fixed grid row, an explicit
15830
+ `block-size`) and body content taller than that allocation is clipped silently, with no
15831
+ scrollbar. Neither upstream card exposes an overflow, block-size, or scroll hook and neither does
15832
+ this one: the public `body` part already carries the whole decision, and a `::part()` rule from
15833
+ your tree wins over the shadow stylesheet regardless of specificity. A fixed-height tile that
15834
+ must hold more content says so itself:
15835
+
15836
+ ```css
15837
+ .tile-grid {
15838
+ display: grid;
15839
+ grid-template-rows: 12rem;
15840
+ }
15841
+ .tile-grid lr-card::part(body) {
15842
+ overflow: auto;
15843
+ overscroll-behavior: contain;
15844
+ }
15845
+ ```
15846
+
15847
+ `overflow` other than `visible` also zeroes the body's automatic minimum size, so that one
15848
+ declaration is enough — the body shrinks into the tile and scrolls, and `max-block-size` /
15849
+ `scrollbar-gutter` stay available on the same rule. The linked (`href`) card behaves identically.
15533
15850
  - slot-presence (`header`/`media`/`image`/`footer`/`actions`/`header-actions`/`footer-actions`) is
15534
15851
  tracked in JS, not via CSS `:empty` (a
15535
15852
  `[part]` wrapper always contains a literal `<slot>` child, so `:empty` never matches) — the same
@@ -15609,7 +15926,10 @@ row also makes it active.
15609
15926
  **Events:** `lr-open`, `lr-close` (both `detail: undefined`, cancelable — fired before the
15610
15927
  mutation, `preventDefault()` keeps the palette in its current open state), `lr-select`
15611
15928
  (`detail: { command }`, fired before the command's own `onSelect` runs and before the palette
15612
- closes).
15929
+ closes), and no-detail `focus`/`blur` events re-dispatched from the host whenever the search input
15930
+ gains or loses focus. The `focus`/`blur` bridge is new in 10.0.0: native `focus`/`blur` neither
15931
+ bubble nor cross the shadow boundary, so a host-level `el.addEventListener('focus', …)` previously
15932
+ never fired at all.
15613
15933
 
15614
15934
  **Slots:** none.
15615
15935
 
@@ -15720,11 +16040,20 @@ the ladder doesn't cover is a two-line override rather than a fork.
15720
16040
 
15721
16041
  **Events:**
15722
16042
 
15723
- - `lr-expand`, `lr-collapse`, `lr-after-expand`, `lr-after-collapse` — accordion group lifecycle.
16043
+ - `lr-expand`, `lr-collapse`, `lr-toggle-request`, `lr-after-expand`, `lr-after-collapse` —
16044
+ accordion group lifecycle.
15724
16045
  - `lr-show`, `lr-hide`, `lr-toggle`, `lr-after-show`, `lr-after-hide` — Details lifecycle only.
15725
16046
 
15726
16047
  On the accordion, `lr-expand` and `lr-collapse` fire before a direct item changes, are cancelable,
15727
- and carry `detail: { item }`. **Changed in 9.0.0:** `item` is now always a `LyraAccordionItem`
16048
+ and carry `detail: { item }`. **New in 10.0.0:** a cancelable `lr-toggle-request`
16049
+ (`detail: { collapsed, item }`) fires alongside the matching directional event for every transition,
16050
+ including sibling auto-collapses in `single`/`single-collapsible` mode and `collapseAll()`. It carries
16051
+ the direction in the detail rather than the event name, matching `<lr-code-block>`/`<lr-chat-message>`'s
16052
+ `lr-toggle-request` convention, plus an `item` reference the single-panel siblings do not need (an
16053
+ accordion's toggling entity is one of several children, so the event target alone cannot identify it).
16054
+ `preventDefault()` on **either** event vetoes the transition — the two are a symmetric veto pair, not
16055
+ a primary and a notification. Note `<lr-thinking-panel>`'s own `lr-toggle-request` spells its detail
16056
+ `{ expanded }` rather than `{ collapsed }`; the two conventions are not fully unified. **Changed in 9.0.0:** `item` is now always a `LyraAccordionItem` —
15728
16057
  it could previously also be a `LyraDetails`. The exported `LyraAccordionPanel` union that spelled
15729
16058
  that has been removed; use `LyraAccordionItem`. An accepted transition finishes with the
15730
16059
  non-cancelable
@@ -16745,6 +17074,35 @@ These named interfaces and helper signatures are available to typed integrations
16745
17074
 
16746
17075
  # Overlays, status & feedback (`components/overlays/`)
16747
17076
 
17077
+ ## Breaking changes in 10.0.0
17078
+
17079
+ **Breaking (event rename, v10):** `lr-dialog`'s close event is now spelled `lr-close`, and
17080
+ `lr-dialog-close` is removed; `lr-drawer`, which inherits the whole dialog lifecycle, loses it too.
17081
+ The detail (`DialogCloseReason`), the cancelability, and the position in the `lr-hide` → close →
17082
+ `lr-after-hide` sequence are all unchanged — only the name moved, onto the plain spelling
17083
+ `lr-tool-select-dialog` and the rest of the library already use. The old name is removed outright
17084
+ rather than dual-emitted, because the library has no released consumers and an alias is a permanent
17085
+ tax paid to protect users who do not exist. Rename the listener. **Breaking (default change, v10):**
17086
+ `lr-progress-ring` gains `showValue`/`show-value`, defaulting to `false`, so a determinate ring no
17087
+ longer renders its percentage unless asked. It used to render it unconditionally with no way to
17088
+ suppress it short of slotting replacement content, while sibling `lr-progress-bar` has had an opt-in
17089
+ `show-value` all along and this reference has always claimed the two share the same value contract;
17090
+ they now actually do. Add `show-value` to keep the percentage. The accessible value is unchanged
17091
+ either way — `aria-valuetext` still carries the locale-formatted percentage — and slotted replacement
17092
+ content still projects with or without the attribute. **Breaking (removal, v10):** `confirm()`'s
17093
+ deprecated `tone` option is removed from `ConfirmOptions`; use `variant` (same `'neutral' | 'danger'`
17094
+ values, same `'neutral'` default). It was documented as a one-major back-compat alias and `variant`
17095
+ already won whenever both were set, so only a caller passing `tone` alone is affected. **New,
17096
+ additive, non-breaking:** `lr-popover` gains `disabled` — both `lr-tooltip` and `lr-popover`'s own
17097
+ subclass `lr-dropdown` had it and the base did not; `lr-dropdown` now inherits it with byte-identical
17098
+ behavior.
17099
+
17100
+ Also corrected in 10.0.0 — not breaking, but visible. `lr-alert` really hides a base that is queued
17101
+ behind the visible toast window (it renders that base `hidden` and `inert`; `inert` is
17102
+ platform-enforced, but `hidden` was doing nothing), and `lr-badge` and `lr-chip` honor a consumer's
17103
+ `hidden` slotted adornment. In each case the component's own author-origin `display` declaration was
17104
+ beating the UA stylesheet's `[hidden] { display: none }` regardless of specificity.
17105
+
16748
17106
  ## Breaking changes in 9.0.0
16749
17107
 
16750
17108
  **Breaking (type-only, v9):** `lr-toast`'s exported `ToastPlacement`, `ToastCreateOptions`, and
@@ -16775,7 +17133,7 @@ boolean, and all three drive the same code path: `el.show()` is indistinguishabl
16775
17133
  `el.open = true`, and `el.hide()` from `el.open = false`. The property, the reflected attribute and
16776
17134
  the two methods can therefore never disagree, and each method is a no-op when the overlay is already
16777
17135
  in the requested state. `lr-dialog` and `lr-drawer` keep `close(reason)` alongside — `hide()` plus
16778
- the reason string that `lr-dialog-close` carries.
17136
+ the reason string that `lr-close` carries.
16779
17137
 
16780
17138
  **Four events, and where the veto sits.**
16781
17139
 
@@ -16799,9 +17157,12 @@ with matching timing _and_ matching cancelability — which also means Lyra 7.x
16799
17157
  relying on the opposite polarity and has to be re-read.
16800
17158
 
16801
17159
  `lr-dialog` and `lr-drawer` also expose cancelable `lr-initial-focus` and `lr-request-close` veto
16802
- points, documented in their sections. Their cancelable `lr-dialog-close` fires **after** `lr-hide`
16803
- and before `lr-after-hide`; it carries the close reason. Vetoing `lr-hide` stops it from firing at
16804
- all.
17160
+ points, documented in their sections. Their cancelable `lr-close` fires **after** `lr-hide` and
17161
+ before `lr-after-hide`; it carries the close reason as `detail: DialogCloseReason`. Vetoing
17162
+ `lr-hide` stops it from firing at all, and `preventDefault()` on `lr-close` itself also vetoes the
17163
+ close. The same name is already used by the `lr-tool-select-dialog`/`lr-tool-result-dialog`/
17164
+ `lr-tool-approval-dialog` trio, which mirrors this identical detail shape, so one listener covers
17165
+ all of them. `lr-drawer` inherits `lr-close` unchanged.
16805
17166
 
16806
17167
  **The top layer.** An open `lr-dialog` or modal `lr-drawer` is promoted into the browser **top layer**
16807
17168
  (through `popover="manual"`) rather than stacked with `z-index`. It therefore escapes every ancestor
@@ -17217,7 +17578,7 @@ A modal panel anchored to one logical edge of the viewport. `LyraDrawer` extends
17217
17578
  inherits the entire dialog contract unchanged: focus trapping, Escape and opt-in backdrop dismissal,
17218
17579
  document scroll locking, browser **top-layer** promotion, overlay stacking, accessible naming, the
17219
17580
  `show()`/`hide()`/`close()` methods and the whole
17220
- `lr-show`/`lr-after-show`/`lr-hide`/`lr-after-hide`/`lr-dialog-close` lifecycle. `contained` switches
17581
+ `lr-show`/`lr-after-show`/`lr-hide`/`lr-after-hide`/`lr-close` lifecycle. `contained` switches
17221
17582
  to an absolute, nonmodal panel inside the nearest containing block; only that mode, `placement`, and
17222
17583
  the slide animation are its own.
17223
17584
 
@@ -17248,8 +17609,8 @@ the slide animation are its own.
17248
17609
  promise settles after the matching `lr-after-*` event.
17249
17610
 
17250
17611
  **Events:** `lr-show` (cancelable), `lr-after-show`, `lr-hide` (cancelable), `lr-after-hide`, and
17251
- `lr-initial-focus` (cancelable), `lr-request-close` (cancelable, detail source), and
17252
- `lr-dialog-close` (`detail: DialogCloseReason`, cancelable) — all inherited unchanged from
17612
+ `lr-initial-focus` (cancelable), `lr-request-close` (cancelable, detail source), and `lr-close`
17613
+ (`detail: DialogCloseReason`, cancelable) — all inherited unchanged from
17253
17614
  `lr-dialog`; see that section for details and veto rules. `lr-after-show` /
17254
17615
  `lr-after-hide` fire once the slide animation has finished, so they are deferred by roughly one
17255
17616
  animation compared with the state flip.
@@ -17376,13 +17737,18 @@ chrome remains visible. The fallback order appears below.
17376
17737
  - `lr-request-close` — cancelable request from a built-in affordance; detail source is
17377
17738
  `'close-button' | 'keyboard' | 'overlay'`. Veto stops the close lifecycle. Direct `close()` and
17378
17739
  `hide()` calls do not emit this request event.
17379
- - `lr-dialog-close` — cancelable, with `detail: DialogCloseReason`; emitted after `lr-hide`
17740
+ - `lr-close` — cancelable, with `detail: DialogCloseReason`; emitted after `lr-hide`. The same name
17741
+ is already used by `<lr-tool-select-dialog>`, `<lr-tool-result-dialog>`, and
17742
+ `<lr-tool-approval-dialog>`, whose own docs describe an identical detail shape, so one listener
17743
+ covers all of them. A listener calling `preventDefault()` vetoes the close. Also fired (with
17744
+ reason `'unmount'`, non-cancelable there) when the dialog is removed from the DOM while still
17745
+ open.
17380
17746
 
17381
17747
  The two `lr-after-*` events are never cancelable.
17382
17748
 
17383
17749
  The open sequence is `lr-show` → `lr-initial-focus` (when focus would move) → `lr-after-show`; the
17384
- direct close sequence is `lr-hide` → `lr-dialog-close` → `lr-after-hide`. A built-in dismissal
17385
- prepends `lr-request-close`. **Both state pre-events fire _before_ the state changes**, so reading
17750
+ direct close sequence is `lr-hide` → `lr-close` → `lr-after-hide`.
17751
+ A built-in dismissal prepends `lr-request-close`. **Both state pre-events fire _before_ the state changes**, so reading
17386
17752
  `el.open` inside an `lr-show`/`lr-hide` handler returns the _old_ value — this is the polarity
17387
17753
  `wa-show`/`wa-hide` already had, and the opposite of what Lyra 7.x's own `lr-show`/`lr-hide` did on
17388
17754
  `lr-popover`/`lr-dropdown`. The `wa-*` → `lr-*` migration table treats the rename as mechanical, and
@@ -17398,8 +17764,8 @@ and easing. Under `prefers-reduced-motion: reduce`, registry timing flattens to
17398
17764
  frame and lifecycle remain intact. Passing `null` skips native interpolation but still emits the
17399
17765
  matching after-event before the method promise resolves. Because dialogs now animate on close too,
17400
17766
  `lr-after-hide` is normally deferred by roughly one animation. A removal while open emits
17401
- `lr-hide`, `lr-dialog-close` (reason `'unmount'`) and `lr-after-hide` in that order, none of them
17402
- cancelable, since the element is already gone.
17767
+ `lr-hide`, `lr-close` (reason `'unmount'`) and `lr-after-hide` in that
17768
+ order, none of them cancelable, since the element is already gone.
17403
17769
 
17404
17770
  **Stacking and the top layer:** an open dialog is promoted into the browser **top layer** (via
17405
17771
  `popover="manual"`), new in 8.0.0. That means it escapes every ancestor stacking context and every
@@ -17488,7 +17854,7 @@ Otherwise shared tokens include `--lr-space-l/-m/-s`, `--lr-color-surface/-borde
17488
17854
  dlg.addEventListener("lr-after-show", () =>
17489
17855
  console.log("enter animation done")
17490
17856
  );
17491
- dlg.addEventListener("lr-dialog-close", (e) =>
17857
+ dlg.addEventListener("lr-close", (e) =>
17492
17858
  console.log("closed:", e.detail)
17493
17859
  );
17494
17860
  dlg.addEventListener("lr-after-hide", () =>
@@ -17571,7 +17937,7 @@ if (ok) deleteConversation();
17571
17937
  ```
17572
17938
 
17573
17939
  `confirm(options: ConfirmOptions): Promise<boolean>` where
17574
- `ConfirmOptions = { title: string; description?: string; confirmLabel?: string /* = 'Confirm' */; cancelLabel?: string /* = 'Cancel' */; variant?: 'neutral' | 'danger' /* = 'neutral' */; tone?: 'neutral' | 'danger' /* @deprecated, use variant */ }`.
17940
+ `ConfirmOptions = { title: string; description?: string; confirmLabel?: string /* = 'Confirm' */; cancelLabel?: string /* = 'Cancel' */; variant?: 'neutral' | 'danger' /* = 'neutral' */ }`.
17575
17941
 
17576
17942
  Resolves `true` only when the confirm button is pressed — Escape, a backdrop click, and the cancel
17577
17943
  button all resolve `false`. It sets `lightDismiss = true` on its transient dialog explicitly, so the
@@ -17582,8 +17948,8 @@ of the call and removes it once settled, rather than reusing a persistent page-l
17582
17948
  stack, each tied to its own returned promise. `title` becomes a direct light-DOM `<h2>`, which per `<lr-dialog>`'s
17583
17949
  own heading-detection also drives the dialog's accessible name; `description`, if provided, becomes
17584
17950
  a direct light-DOM `<p>`. `variant: 'danger'` fills the confirm button with `--lr-color-danger`
17585
- instead of `--lr-color-brand`, for destructive actions. The deprecated `tone` option is a one-major
17586
- back-compat alias for `variant`; `variant` wins when both are set. Confirm/cancel actions deliberately use native
17951
+ instead of `--lr-color-brand`, for destructive actions. The deprecated `tone` option that preceded
17952
+ `variant` was removed in 10.0.0. Confirm/cancel actions deliberately use native
17587
17953
  inline-styled `<button>` elements so this helper does not register or import the broader button
17588
17954
  component; every color value is still a `--lr-*` token reference, never a raw literal. They carry the same interaction
17589
17955
  states as every other control in the library: a hover/pressed fill mixed toward
@@ -17596,7 +17962,7 @@ their `data-lr-confirm-action` attribute.
17596
17962
  **Known gotchas:**
17597
17963
 
17598
17964
  - Every dismissal path (confirm button, cancel button, Escape, backdrop click) funnels through
17599
- `<lr-dialog>`'s own `close()`/`lr-dialog-close` event, so there is exactly one place that
17965
+ `<lr-dialog>`'s own `close()`/`lr-close` event, so there is exactly one place that
17600
17966
  resolves the promise and tears the dialog down — a consumer never needs to (and shouldn't) call
17601
17967
  `.remove()` itself. Because the close event is cancelable, `confirm()` waits through the full
17602
17968
  dispatch and remains pending/mounted when a listener calls `preventDefault()`.
@@ -18084,6 +18450,11 @@ A click-triggered, light-dismiss floating surface positioned with the shared Flo
18084
18450
  attribute wins by presence, including `aria-label=""`; only when it is absent does the property
18085
18451
  or localized "Popover" ("Menu" when `popupRole` is `menu`) fallback apply
18086
18452
  - `popupRole: 'dialog'|'menu' = 'dialog'` (attribute `popup-role`)
18453
+ - `disabled: boolean = false` (reflected, new in 10.0.0) — prevents opening the popover; pointer,
18454
+ keyboard, and programmatic `show()`/`open = true` are all refused while set. Becoming disabled also
18455
+ closes an already-open popover, and initial `disabled` plus `open` normalizes closed in either
18456
+ attribute order. `lr-dropdown` now inherits this from `lr-popover` rather than declaring its own;
18457
+ its consumer-facing behavior is unchanged
18087
18458
 
18088
18459
  To preserve the previous Lyra-shaped defaults explicitly, use
18089
18460
  `placement="bottom-start" distance="4" without-arrow`; origin-aware migration emits those tokens.
@@ -18554,6 +18925,7 @@ A circular progress indicator with the same value contract as `lr-progress-bar`.
18554
18925
  **Properties:** `value: number = 0` (reflected), `max: number = 100`, `indeterminate: boolean = false`
18555
18926
  (reflected), `variant: LyraProgressVariant = 'brand'` (reflected, added in 9.0.0 — matches sibling
18556
18927
  `lr-progress-bar`'s semantic-palette vocabulary: `neutral`/`brand`/`success`/`warning`/`danger`),
18928
+ `showValue: boolean = false` (attribute `show-value`),
18557
18929
  `label: string = ''` (the mapped accessible-name property), and
18558
18930
  `accessibleLabel: string = ''` (attribute `accessible-label`; a Lyra compatibility
18559
18931
  accessible-name spelling retained by this progress component, while several sibling components use
@@ -18563,7 +18935,13 @@ visible default-slot text when supplied, then the localized "Progress". Non-fini
18563
18935
  `value`/`max` are normalized (`max <= 0` falls
18564
18936
  back to `100`, `value` clamps to `[0, max]`) rather than producing NaN geometry.
18565
18937
  **Slots:** default — replaces the built-in center label, which otherwise renders the rounded
18566
- percentage (and nothing at all while `indeterminate`).
18938
+ percentage **only when `show-value` is set** (and nothing at all while `indeterminate`).
18939
+ **Breaking in 10.0.0:** a determinate ring used to render its percentage unconditionally, with no way
18940
+ to suppress it short of slotting replacement content. It now gains `showValue`/`show-value` defaulting
18941
+ to `false`, exactly matching `lr-progress-bar` — which is what "the same value contract as
18942
+ `lr-progress-bar`" above has always claimed but did not deliver. Add `show-value` to keep the
18943
+ percentage. `aria-valuetext` still carries it regardless, mirroring `lr-progress-bar`'s own
18944
+ independence there, so the accessible value is unaffected.
18567
18945
  Its accessible text uses the same visibility filtering, forwarding-slot mutation/reassignment
18568
18946
  tracking, and explicit-empty host-label precedence as `lr-progress-bar`.
18569
18947
  **Live members:** `indicator: SVGCircleElement | null` returns the rendered indicator circle (or
@@ -19147,7 +19525,6 @@ These named interfaces and helper signatures are available to typed integrations
19147
19525
  confirmLabel: unknown;
19148
19526
  cancelLabel: unknown;
19149
19527
  variant: unknown;
19150
- tone: unknown;
19151
19528
  }`
19152
19529
 
19153
19530
  - **`components-overlays-dialog-dialog-contracts`** — Supporting data types and helpers for this component family.
@@ -20707,7 +21084,9 @@ assigned nodes update the announcement without requiring the wrapper component t
20707
21084
 
20708
21085
  The `label` part alias was deprecated in 8.0.0 in favor of the shared form vocabulary
20709
21086
  `form-control-label`. Both names remain on the same node during the compatibility window; use
20710
- `::part(form-control-label)` in new CSS. The alias will not be removed before 10.0.0.
21087
+ `::part(form-control-label)` in new CSS. Removal is not scheduled: Web Awesome still publishes its
21088
+ own deprecated `label` part on `<wa-known-date>`, and a mirrored tag owes its whole upstream
21089
+ surface, so the alias goes only when upstream's does.
20711
21090
 
20712
21091
  **The required marker.** The `*` the legend grows while `required` is the library's shared
20713
21092
  required-field marker, and it takes the same three consumer-settable properties every other
@@ -20873,6 +21252,19 @@ behavior warning; direct SVG candidates and the documented animation vocabulary
20873
21252
  used (a11y-tree inconsistencies across engines).
20874
21253
  - Slot/focus microtasks and autoplay never queue new selection work while detached; reconnecting
20875
21254
  starts again from current state rather than replaying stale work.
21255
+ - Non-selected candidates are hidden by the component's own `::slotted([hidden])` rule, not by the
21256
+ UA's. `::slotted(*)` sets `display: inline-block` on every candidate, and an author-origin
21257
+ declaration always beats the user-agent `[hidden] { display: none }` — so the rule that restores
21258
+ the native meaning of `hidden` is load-bearing, and an author overriding `display` on
21259
+ `::slotted` content from outside must keep the hidden case at `display: none`.
21260
+ `hidden="until-found"` is exempted, exactly as the UA rule exempts it.
21261
+ - **Before script runs, the first candidate is the one that shows.** Selection happens after the
21262
+ first client render and works by setting `hidden`/`aria-hidden` on light-DOM siblings, which Lit
21263
+ hydration never compares, so a server renderer can never produce it. Every candidate after the
21264
+ first is therefore hidden by CSS until a selection has been applied: a server-rendered page — or
21265
+ one whose script never runs — paints one candidate rather than the whole pool. Randomness itself
21266
+ cannot survive SSR (there is no shared seed), so order the pool if a specific candidate should be
21267
+ the pre-hydration one. With `items > 1` the pre-hydration paint is still a single candidate.
20876
21268
 
20877
21269
  ## `lr-tour`
20878
21270
 
@@ -21089,6 +21481,37 @@ These named interfaces and helper signatures are available to typed integrations
21089
21481
 
21090
21482
  # Media, files & maps (`components/media/`)
21091
21483
 
21484
+ ## Breaking changes in 10.0.0
21485
+
21486
+ `<lr-media-card>`'s `alt` becomes optional (`alt?: string`, was `alt: string = ''`), so a decorative
21487
+ image is expressible at last. The image render used to fall through `alt`, then `filename`, then a
21488
+ localized generic description with `||`, which made an explicit `alt=""` indistinguishable from an
21489
+ absent one and published it as `alt="Image attachment"` — there was no way to mark the image
21490
+ decorative, which is the one thing
21491
+ `alt=""` means in HTML. It now reads `??`, matching `<lr-image-viewer>` and `<lr-document-preview>`,
21492
+ which already documented that contract. Omitting `alt` is unchanged; only the value read back from
21493
+ an unset property differs (`''` becomes `undefined`), so a consumer comparing `el.alt === ''` should
21494
+ read `el.alt ?? ''`. The nested `<video controls>` label deliberately does **not** follow: an empty
21495
+ `alt` there would leave an interactive player with no accessible name, and "decorative" is not a
21496
+ state a media control can be in, so the video path still falls through to `filename` and the generic
21497
+ description.
21498
+
21499
+ `<lr-attachment-chip>`'s `lr-preview-request` is no longer cancelable. It was advertised as a veto
21500
+ point, but the chip never read `defaultPrevented` and owns no preview default action to cancel — it
21501
+ never registers or owns a viewer or overlay, by its own documented contract — so `preventDefault()`
21502
+ was a no-op. The flag is removed rather than left as a promise the component cannot keep: a host that
21503
+ was calling `preventDefault()` can drop the call, and one that believed the call was suppressing
21504
+ something was never being served. `<lr-voice-picker>`'s same-named event belongs to a different
21505
+ component, owns a real internal default action, and stays cancelable.
21506
+
21507
+ Also corrected in 10.0.0 — not breaking, but visible. `<lr-flag>` no longer paints a full-size
21508
+ undecoded image beside its own skeleton while loading; `<lr-video>` no longer keeps a second,
21509
+ duplicate controls play button both painted and focusable behind a poster, and it now keeps captions
21510
+ for a `<track>` with no `kind` attribute, whose HTML missing-value default is `subtitles`; and
21511
+ `<lr-avatar>` and `<lr-image-comparer>` honor a consumer's `hidden` slotted child. In each case the
21512
+ component's own author-origin declaration was beating the UA stylesheet's `[hidden] { display: none }`
21513
+ regardless of specificity.
21514
+
21092
21515
  ## Breaking changes in 9.0.0
21093
21516
 
21094
21517
  `<lr-media-card>`'s `accessibleLabel` property now defaults to `null` instead of `''`
@@ -21104,7 +21527,16 @@ Country/language flag image. Flag artwork ships in a **separate, optional peer p
21104
21527
 
21105
21528
  **Properties:**
21106
21529
 
21107
- - `country?: string` (ISO 3166-1 alpha-2, e.g. `"fr"` — takes precedence over `language`)
21530
+ - `country?: string` (ISO 3166-1 **alpha-2 or alpha-3**, e.g. `"fr"` or `"FRA"` — takes
21531
+ precedence over `language`). Length alone disambiguates the two code spaces, so no format hint
21532
+ is needed: a 2-letter value is alpha-2, a 3-letter value is alpha-3. Alpha-3 support exists
21533
+ because public statistical sources (World Bank, UN, IMF, most open-data portals) key country
21534
+ records on alpha-3; the 249 officially-assigned mappings are packed as a ~1.2 KB fixed-width
21535
+ string and expanded lazily on the first alpha-3 lookup, so an alpha-2-only app never pays for
21536
+ them. Withdrawn and user-assigned codes deliberately do not map to a successor state — they
21537
+ take the unresolved path below
21538
+ - `fallback?: string` — placeholder image URL rendered when the code cannot resolve to a current
21539
+ flag. The `fallback` slot wins over it
21108
21540
  - `language?: string` (BCP-47-ish tag, e.g. `"en"`/`"en-US"`, resolved to a representative country
21109
21541
  via `languageToCountry()`)
21110
21542
  - `src?: string` (a pre-resolved flag image URL — takes precedence over `country`/`language` and
@@ -21129,11 +21561,17 @@ authoring types are `LyraFlagShape`, `LyraFlagFidelity`, and `LyraFlagUrlResolve
21129
21561
 
21130
21562
  **Events:** none.
21131
21563
 
21132
- **Slots:** none.
21564
+ **Slots:** `fallback` — rendered in place of the flag when `country`/`language` cannot resolve to a
21565
+ current flag (an unassigned, historical, or malformed code). Wins over the `fallback` property.
21133
21566
 
21134
- **CSS parts:** `image` (the underlying `<img>`, exposed once native loading succeeds), `error`
21567
+ **CSS parts:** `image` (the underlying `<img>`, exposed once native loading succeeds),
21568
+ `fallback-image` (the `fallback` property's placeholder, when no slot content is supplied), `error`
21135
21569
  (contained localized visible text rendered when URL validation, peer resolution, or native image
21136
- loading fails). The host reflects the terminal error state with `data-error`.
21570
+ loading fails). The host reflects the terminal error state with `data-error`, and an unresolvable
21571
+ code with `data-unresolved`. **The two are deliberately distinct:** a dissolved federation or
21572
+ unrecognized territory in a longitudinal dataset is *data*, not a defect, so it renders the neutral
21573
+ fallback (occupying its normal footprint in a table or card grid) rather than localized error
21574
+ wording that reads to a user as a bug. Style the two states apart with those attributes.
21137
21575
 
21138
21576
  **Themeable custom properties:** `--lr-flag-radius` (default `calc(var(--lr-radius) * 0.33)` —
21139
21577
  rectangular corner radius), `--lr-flag-aspect-ratio` (default `4 / 3`), and
@@ -21384,6 +21822,22 @@ operations. Its runtime value is the underlying MapLibre map.
21384
21822
  style-required failure and makes no tile/style request. Assign a hosted vector/raster style from
21385
21823
  a provider whose terms fit your application, or an explicitly network-silent style for local
21386
21824
  geometry.
21825
+ - `legendGradient: readonly (readonly [number, string])[] = []` (attribute: false, type
21826
+ `LyraMapLegendGradientStop[]`) — renders the legend as a **continuous** gradient bar with endpoint
21827
+ captions instead of (or alongside) the discrete `legend` swatches, which is the standard key for a
21828
+ choropleth whose `interpolate` fill is itself a continuous ramp. Takes the same `[value, color]`
21829
+ stop shape as `choropleth.stops`, so the usual assignment is `map.legendGradient =
21830
+ myChoropleth.stops` and the key cannot drift from the layer it describes. Stops are sorted
21831
+ ascending, bounded to 64, and filtered to finite values carrying a CSS-parsable color; fewer than
21832
+ two usable stops render no bar at all, since a one-stop "gradient" is a flat block that describes
21833
+ nothing. Each stop sits at its true proportion of the value range, so the bar shows the ramp the
21834
+ expression actually produces rather than evenly spacing unevenly-spaced values. Part names
21835
+ (`legend-gradient`, `legend-lo`, `legend-hi`) mirror `lr-heatmap`'s gradient legend, and the bar
21836
+ is `aria-hidden`/`inert` with the captions carrying the meaning. Mirrors under RTL
21837
+ - `legendGradientLoLabel: string | null = null` (attribute `legend-gradient-lo-label`),
21838
+ `legendGradientHiLabel: string | null = null` (attribute `legend-gradient-hi-label`) — override
21839
+ the endpoint captions, which otherwise default to the lowest/highest stop value in the component's
21840
+ own locale-aware numeric formatting
21387
21841
  - `legend: readonly LyraMapLegendEntry[] = []` (attribute: false) — immutable defensive snapshots
21388
21842
  of `LyraMapLegendEntry { readonly color: string; readonly label: string; readonly pattern:
21389
21843
  LyraMapLegendPattern }`, where `LyraMapLegendPattern` is `'solid' | 'diagonal' | 'dots' |
@@ -21395,10 +21849,20 @@ omittedCount, truncatedLabelCount, truncated }` result for the latest assignment
21395
21849
  projection renders a localized visible `1–N of M items` summary rather than silently claiming
21396
21850
  the bounded rows are complete.
21397
21851
  - `choropleth?: LyraMapChoroplethLayer` (attribute: false) — `LyraMapChoroplethLayer { sourceId:
21398
- string; geojson: GeoJSON.FeatureCollection; field: string; stops: [number, string][] }` (interpolated
21852
+ string; geojson: GeoJSON.FeatureCollection; field: string; stops: [number, string][]; interpolation?:
21853
+ 'linear' | 'logarithmic' }` (interpolated
21399
21854
  fill-color expression from `field`'s value against `stops`; `stops` must contain at least one
21400
21855
  `[value, color]` pair — an empty array is ignored, leaving whatever fill layer already exists, if
21401
- any, untouched, rather than being applied)
21856
+ any, untouched, rather than being applied).
21857
+ `interpolation` (type `LyraMapChoroplethInterpolation`, default `'linear'`) chooses how the colour
21858
+ is interpolated between stops. `'logarithmic'` compresses the ramp, which is what a heavy-tailed
21859
+ quantity — price, population, income — needs: on a linear ramp every value below the maximum falls
21860
+ into the first colour band, so the map reads as one flat colour plus a couple of outliers. It
21861
+ emits maplibre's own `['interpolate', ['exponential', 0.25], …]`, exposing an existing capability
21862
+ rather than adding one (maplibre has no `['log']` interpolation type; a sub-1 exponential base is
21863
+ the documented way to weight a ramp toward the low end). **`stops` stay in the data's own units
21864
+ under either mode**, so the legend keeps reading in real values instead of log units — no
21865
+ pre-transforming to log10 and hand-relabelling the legend back
21402
21866
  - `markers: LyraMapMarker[] = []` (attribute: false) — `LyraMapMarker { id?: string; lngLat:
21403
21867
  [number, number]; color?: string; label?: string; unsafeHtml?: string }`; an explicit `id` is
21404
21868
  trimmed and must be nonempty, and the first marker for an explicit ID wins. Markers are reconciled
@@ -21433,6 +21897,37 @@ GeoJSON.FeatureCollection; tone?: 'accent' | 'success' | 'warning' |
21433
21897
  persists across a `dataLayers` reassignment gets its GeoJSON updated in place (`setData()`), one
21434
21898
  that's dropped has its private source/layers removed, and a genuinely new `sourceId` gets new
21435
21899
  resources — nothing leaks on removal, style change, or disconnect.
21900
+ - `maxBounds: LyraMapBounds | null = null` (attribute: false) — box the map may not pan outside,
21901
+ `[[west, south], [east, north]]`. Prefer it over calling `map.setMaxBounds()` through the `.map`
21902
+ escape hatch: constraining the camera can wedge maplibre-gl at a sub-1 fractional zoom in a wide
21903
+ container, leaving `getZoom()` returning `null` permanently, every frame throwing from inside the
21904
+ peer's own matrix math, and the canvas never painting again — a blank map, with nothing thrown at
21905
+ the call site to attribute it to. This property applies the same call, then reads the camera back
21906
+ and reverts (restoring zoom and centre) if it did not survive, so the worst case is an
21907
+ unconstrained map plus a dev-mode warning. A malformed box is rejected rather than clamped
21908
+
21909
+ **Choropleth and `dataLayers` updates are diffed before they reach the peer.** `setData()`
21910
+ unconditionally re-tiles and repaints an entire source, which is invisible on a static map and
21911
+ expensive on an animated one. When an update changes only feature *properties* — the values driving
21912
+ the colour ramp — the component emits maplibre-gl's incremental `updateData()` instead. The fast
21913
+ path is deliberately strict, and needs all of: the same feature count, a `string`/`number` `id` on
21914
+ every feature in the same order, and geometry that is the **same object** as last time (not merely
21915
+ deep-equal). Structurally comparing polygon rings would cost about what the re-tile costs, and a
21916
+ false positive would paint stale geometry. Reuse your geometry objects across frames — the
21917
+ efficient way to build an animation anyway — and the fast path applies; otherwise it falls back to
21918
+ `setData()` with no change in behaviour. Peers predating `updateData()` always take the old path.
21919
+
21920
+ **Feature properties are tiled, and therefore bounded in numeric magnitude.** MapLibre GL tiles
21921
+ every GeoJSON source through a worker into a protobuf vector tile, so a property carrying a huge
21922
+ integer throws *inside that worker* — "Given varint doesn't fit into 10 bytes". That throw is not
21923
+ catchable by your app and not a rejected promise; it reaches you only as an opaque message on
21924
+ `lr-map`'s own error handler, while the rest of the layer still paints, so one bad feature in a
21925
+ large collection is invisible until someone walks the data by hand. Both `choropleth.geojson` and
21926
+ `dataLayers[].geojson` are now pre-scanned (first 10,000 features) and any numeric property beyond
21927
+ `Number.MAX_SAFE_INTEGER` draws a dev-mode warning naming the feature and the property. Carry a
21928
+ reduced figure in the feature — a log, a bucket, an index — and keep the exact value in your own
21929
+ payload beside the map.
21930
+
21436
21931
  - `label: string = ''` — purpose-specific accessible name for MapLibre's actual focusable canvas.
21437
21932
  A nonempty host `aria-label` remains on the host and is not duplicated onto the canvas; the canvas
21438
21933
  uses `label` or the localized map name. An explicitly empty host `aria-label` is preserved as an
@@ -21455,13 +21950,20 @@ shared `maplibre-gl` import without constructing a map or allocating a WebGL con
21455
21950
  an element.
21456
21951
 
21457
21952
  **Events:** `lr-map-load` (fired once, after the underlying map's own `'load'`), `lr-map-click`
21458
- (frozen `detail: { readonly lngLat: readonly [lng, lat], readonly feature? }`; the tuple and any
21459
- hit GeoJSON feature are detached and recursively frozen feature is only populated if a
21460
- choropleth fill layer exists and was hit)
21461
-
21462
- **Slots:** none.
21463
-
21464
- **CSS parts:** `base`, `container`, `legend`, `legend-swatch`, `legend-limit`, `marker`, `popup`,
21953
+ (frozen `detail: { readonly lngLat: readonly [lng, lat], readonly feature?, readonly origin?,
21954
+ readonly sourceId? }`; the tuple and any hit GeoJSON feature are detached and recursively frozen).
21955
+ `feature` resolves against the choropleth fill layer **and** every applied `dataLayers`
21956
+ fill/line/circle layer, topmost first — so a shape painted through `dataLayers` is identifiable
21957
+ instead of being indistinguishable from empty space. `origin` is `'choropleth'` or `'data-layer'`,
21958
+ and `sourceId` carries the authored `dataLayers[].sourceId` for a data-layer hit; both are
21959
+ `undefined` whenever `feature` is
21960
+
21961
+ **Slots:** `legend` — custom legend content, rendered inside the legend panel's own layout so it
21962
+ stays positioned with the map instead of floating beside it. Supplying it opens the panel even
21963
+ when `legend` and `legendGradient` are both empty.
21964
+
21965
+ **CSS parts:** `base`, `container`, `legend`, `legend-swatch`, `legend-gradient`, `legend-lo`,
21966
+ `legend-hi`, `legend-limit`, `marker`, `popup`,
21465
21967
  `popup-content`, `popup-close-button`, `attribution`, `attribution-toggle`, `error`.
21466
21968
  `legend` is a localized `role="group"` containing a real list associated to the map canvas with
21467
21969
  `aria-describedby`; each entry is a `listitem`, decorative swatches are inert/accessibility-hidden,
@@ -22063,7 +22565,7 @@ to populate it: set `file` to a real `File` (fresh from a picker/drop), from whi
22063
22565
  `mime-type`/`thumbnail-src` props instead, for reconstructing a chip from server-persisted
22064
22566
  attachment metadata after a page reload, when no real `File` object exists any more. `file` always
22065
22567
  wins when both are present. When a real `File` or `preview-src` is available, the chip offers a
22066
- localized action that emits a cancelable `lr-preview-request`; it never registers or owns a viewer
22568
+ localized action that emits a plain, non-cancelable `lr-preview-request`; it never registers or owns a viewer
22067
22569
  or overlay, so the host composes the desired preview surface.
22068
22570
 
22069
22571
  **Properties:**
@@ -22122,9 +22624,12 @@ derived from `` `${file.name}:${file.size}:${file.lastModified}` ``; when neithe
22122
22624
  generated internal id is used as a last resort.
22123
22625
 
22124
22626
  **Events:** `lr-remove` (`detail: { attachmentId }`, only rendered while `removable`), `lr-retry`
22125
- (`detail: { attachmentId }`, only rendered while `status="error"`), and cancelable
22126
- `lr-preview-request` (`detail: { attachmentId, name, mimeType, src }`). Preventing the preview
22127
- request is a host veto point; the chip itself has no preview default action.
22627
+ (`detail: { attachmentId }`, only rendered while `status="error"`), and
22628
+ `lr-preview-request` (`detail: { attachmentId, name, mimeType, src }`) a plain, non-cancelable
22629
+ notification that the preview action was activated. **Breaking in 10.0.0:** this event was
22630
+ advertised as cancelable, but the chip never read `defaultPrevented` and owns no preview default
22631
+ action to veto (it never registers or owns a viewer/overlay), so `preventDefault()` was a no-op.
22632
+ The flag is gone rather than left as a promise the component cannot keep.
22128
22633
 
22129
22634
  **Slots:** none.
22130
22635
 
@@ -22289,13 +22794,18 @@ final.
22289
22794
  - `mimeType: string = ''` (attribute `mime-type`) — drives auto-detection when `kind` is unset.
22290
22795
  - `filename: string = ''` — shown in the file-chip fallback, used as the download link's suggested
22291
22796
  filename, and folded into the accessible name.
22292
- - `alt: string = ''` — alt text for the image case (and reused as a video label fallback). Falls
22293
- back to `filename`, then a generic per-kind description.
22294
- - `accessibleLabel: string = ''` (attribute `aria-label`) a declarative attribute names the host
22295
- as a whole while its nested button/link keeps a purpose-specific localized action name. A
22296
- property-only assignment can override the nested action when no host label is present. Image alt
22297
- text and the native video's own purpose label remain independent; an explicitly empty host still
22298
- leaves every interactive descendant named.
22797
+ - `alt?: string` — alt text for the image case (and reused as a video label fallback). Unset falls
22798
+ back to `filename`, then a generic per-kind description. An explicit `alt=""` survives to the
22799
+ rendered `<img alt="">`, which is the HTML idiom for a decorative image same contract as
22800
+ `<lr-image-viewer>` and `<lr-document-preview>`. The `<video>` case is deliberately outside that
22801
+ carve-out: an empty `alt` there still falls through to `filename`/the generic description, because
22802
+ an empty accessible name would leave an interactive player unnamed rather than mark it decorative.
22803
+ - `accessibleLabel: string | null = null` (attribute `aria-label`) — a declarative attribute names
22804
+ the host as a whole while its nested button/link keeps a purpose-specific localized action name. A
22805
+ property-only assignment can override the nested action when no host label is present. An explicit
22806
+ empty string behaves like the unset `null` default — both fall through to the generated
22807
+ purpose-specific name. Image alt text and the native video's own purpose label remain independent;
22808
+ an explicitly empty host still leaves every interactive descendant named.
22299
22809
  - `maxHeight: string = ''` (attribute `max-height`) — a CSS length (e.g. `"16rem"`); once set,
22300
22810
  overrides the `--lr-media-card-max-height` custom property for this instance only (applied
22301
22811
  inline on `[part="base"]`, so it reliably wins over a `:host{}`-declared default from outside the
@@ -22361,12 +22871,23 @@ sizing), `--lr-focus-ring-*`, `--lr-transition-fast`.
22361
22871
  **Optional peer deps:** none.
22362
22872
 
22363
22873
  ```html
22364
- <lr-media-card kind="image" src="https://example.com/photo.jpg" alt="Screenshot" filename="photo.jpg"
22365
- @lr-media-open=${(e) => openLightbox(e.detail.src)}
22366
- ></lr-media-card>
22367
- <lr-media-card kind="file" src="https://example.com/report.pdf" filename="report.pdf"
22368
- @lr-before-media-download=${(e) => shouldUseNativeDownload || e.preventDefault()}
22874
+ <lr-media-card
22875
+ id="image-card"
22876
+ kind="image"
22877
+ src="https://example.com/photo.jpg"
22878
+ alt="Screenshot"
22879
+ filename="photo.jpg"
22369
22880
  ></lr-media-card>
22881
+ <lr-media-card id="file-card" kind="file" src="https://example.com/report.pdf" filename="report.pdf">
22882
+ </lr-media-card>
22883
+ <script type="module">
22884
+ document
22885
+ .getElementById("image-card")
22886
+ .addEventListener("lr-media-open", (e) => openLightbox(e.detail.src));
22887
+ document
22888
+ .getElementById("file-card")
22889
+ .addEventListener("lr-before-media-download", (e) => shouldUseNativeDownload || e.preventDefault());
22890
+ </script>
22370
22891
  ```
22371
22892
 
22372
22893
  **Safe-URL checking.** `src` is validated by internal sink-specific helpers before it's
@@ -22466,10 +22987,13 @@ hidden via CSS by default, exposed as a part only so a consumer can override tha
22466
22987
  **Optional peer deps:** none.
22467
22988
 
22468
22989
  ```html
22469
- <lr-attachment-trigger .capabilities=${['files', 'image', 'camera']} accept=".pdf,.docx"
22470
- @lr-files=${(e) => queueFiles(e.detail.capability, e.detail.files)}
22471
- @lr-camera-request=${openCameraFlow}
22472
- ></lr-attachment-trigger>
22990
+ <lr-attachment-trigger accept=".pdf,.docx"></lr-attachment-trigger>
22991
+ <script type="module">
22992
+ const trigger = document.querySelector("lr-attachment-trigger");
22993
+ trigger.capabilities = ["files", "image", "camera"];
22994
+ trigger.addEventListener("lr-files", (e) => queueFiles(e.detail.capability, e.detail.files));
22995
+ trigger.addEventListener("lr-camera-request", openCameraFlow);
22996
+ </script>
22473
22997
  ```
22474
22998
 
22475
22999
  **Known gotchas:**
@@ -22574,14 +23098,14 @@ variant's quiet tint.
22574
23098
  <lr-avatar label="Assistant"><svg slot="icon" viewBox="0 0 24 24"><!-- role glyph --></svg></lr-avatar>
22575
23099
 
22576
23100
  <!-- Far down a long list: defer the request, fall back to a glyph, and report a broken URL. -->
22577
- <lr-avatar
22578
- image="/users/7/photo.jpg"
22579
- label="Ada Lovelace"
22580
- loading="lazy"
22581
- @lr-error=${(e) => reportBrokenAvatar(e.detail.image)}
22582
- >
23101
+ <lr-avatar id="lazy-avatar" image="/users/7/photo.jpg" label="Ada Lovelace" loading="lazy">
22583
23102
  <svg slot="icon" viewBox="0 0 24 24"><!-- fallback glyph --></svg>
22584
23103
  </lr-avatar>
23104
+ <script type="module">
23105
+ document
23106
+ .getElementById("lazy-avatar")
23107
+ .addEventListener("lr-error", (e) => reportBrokenAvatar(e.detail.image));
23108
+ </script>
22585
23109
  ```
22586
23110
 
22587
23111
  **Known gotchas:**
@@ -23160,7 +23684,9 @@ unsupported or unresolved targets report `false` through the return value and `l
23160
23684
  `lr-rate-change` (`detail: { rate }`), `lr-cue-change`
23161
23685
  (`detail: { readonly cueId, readonly index }`; `cueId` is `null` and `index` is `-1` when no cue is active),
23162
23686
  `lr-highlight-activate` (`detail: { highlightId }`), `lr-anchor-result` (`detail: {
23163
- found }`), `lr-search-change` (`detail: { query, matchCount, activeIndex }`), and
23687
+ found }`), `lr-search-change` (`detail: { query, matchCount, matchCountExact, activeIndex }`;
23688
+ `matchCountExact` is always `true` — `search()` matches over the already-loaded `cues` array with no
23689
+ additional ceiling), and
23164
23690
  `lr-render-error` (`detail: { error }`). The native `ended`, `error`, `loadedmetadata`, `pause`,
23165
23691
  `play`, `timeupdate`, and `volumechange`
23166
23692
  events are also relayed exactly once from the host as native `Event` instances. Like the original
@@ -23565,6 +24091,7 @@ These named interfaces and helper signatures are available to typed integrations
23565
24091
  `setFlagUrlResolver(/* public names: value */): unknown`
23566
24092
 
23567
24093
  - **`components-media-flag-language-map-contracts`** — Supporting data types and helpers for this component family.
24094
+ `alpha3ToAlpha2(/* public names: code */): unknown`
23568
24095
  `languageToCountry(/* public names: language */): unknown`
23569
24096
  `localeNativeName(/* public names: tag */): unknown`
23570
24097
 
@@ -23588,9 +24115,19 @@ These named interfaces and helper signatures are available to typed integrations
23588
24115
 
23589
24116
  - **`components-media-map-map-loader-contracts`** — Supporting data types and helpers for this component family.
23590
24117
  `loadMaplibre(): unknown`
24118
+ `MapLibreGeoJsonDiff {
24119
+ update: unknown;
24120
+ id: unknown;
24121
+ addOrUpdateProperties: unknown;
24122
+ key: unknown;
24123
+ value: unknown;
24124
+ removeProperties: unknown;
24125
+ }`
23591
24126
  `MapLibreGeoJsonSource {
23592
24127
  setData: unknown;
23593
24128
  data: unknown;
24129
+ updateData: unknown;
24130
+ diff: unknown;
23594
24131
  }`
23595
24132
  `MapLibreMapCapability {
23596
24133
  getCanvas: unknown;
@@ -23603,6 +24140,8 @@ These named interfaces and helper signatures are available to typed integrations
23603
24140
  setZoom: unknown;
23604
24141
  zoom: unknown;
23605
24142
  resize: unknown;
24143
+ setMaxBounds: unknown;
24144
+ bounds: unknown;
23606
24145
  remove: unknown;
23607
24146
  on: unknown;
23608
24147
  type: unknown;
@@ -23662,11 +24201,13 @@ These named interfaces and helper signatures are available to typed integrations
23662
24201
  }`
23663
24202
 
23664
24203
  - **`components-media-map-map-contracts`** — Supporting data types and helpers for this component family.
24204
+ `buildGeoJsonPropertyDiff(/* public names: previous, next */): unknown`
23665
24205
  `LyraMapChoroplethLayer {
23666
24206
  sourceId: unknown;
23667
24207
  geojson: unknown;
23668
24208
  field: unknown;
23669
24209
  stops: unknown;
24210
+ interpolation: unknown;
23670
24211
  }`
23671
24212
  `LyraMapGeoJsonDataLayer {
23672
24213
  sourceId: unknown;
@@ -23684,6 +24225,8 @@ These named interfaces and helper signatures are available to typed integrations
23684
24225
  setZoom: unknown;
23685
24226
  zoom: unknown;
23686
24227
  resize: unknown;
24228
+ setMaxBounds: unknown;
24229
+ bounds: unknown;
23687
24230
  }`
23688
24231
  `LyraMapLegendEntry {
23689
24232
  color: unknown;
@@ -23821,6 +24364,32 @@ property).
23821
24364
  - `max: number | null = null`, `min: number | null = null` — finite value-axis bounds. They apply to
23822
24365
  the cartesian value axis selected by `indexAxis`, or the radial `r` scale; non-finite writes are
23823
24366
  omitted before Chart.js sees them
24367
+ - `annotations: readonly LyraChartAnnotation[] = []` (attribute: false) — declarative reference
24368
+ lines and shaded bands: a threshold, an event year, a regime change, a highlighted period.
24369
+ `LyraChartAnnotation { axis?: 'x' | 'y'; value?: number; from?: number; to?: number; label?:
24370
+ string; tone?: LyraVariant }` — `tone` is the shared `LyraVariant` vocabulary
24371
+ (`'neutral' | 'brand' | 'success' | 'warning' | 'danger'`), not a chart-local copy. A finite `value` renders
24372
+ a reference line on that axis; a finite `from`/`to` pair renders a band bounded on that axis and
24373
+ spanning the other. `axis` defaults to `'y'`. An entry with neither (or non-finite numbers) is
24374
+ dropped rather than handed to Chart.js; a reversed range is normalized. Labelled entries are
24375
+ included in the generated accessible description, mirroring `lr-heatmap` — the label is
24376
+ consumer-supplied text and so is not localized, and an unlabelled line has no nameable meaning to
24377
+ announce. Needs the optional `chartjs-plugin-annotation` peer, loaded on first actual demand, so a
24378
+ page with no annotated charts never downloads it; without it the chart still renders and a single
24379
+ console warning explains the no-op. The plugin is registered globally, like `chartjs-plugin-zoom`
24380
+ and unlike `chartjs-plugin-datalabels`: it draws nothing unless a chart supplies annotation
24381
+ options, so the registration is unobservable to charts that set none, and registration is also
24382
+ what installs the plugin's own element defaults
24383
+ - `scaleType: 'linear' | 'logarithmic' = 'linear'` (attribute `scale-type`, type
24384
+ `LyraChartScaleType`) — scale type for the **value** axis; the categorical axis is never
24385
+ affected. `'logarithmic'` plots data spanning several orders of magnitude (prices, latency
24386
+ percentiles, file sizes) honestly, where a linear axis collapses everything below the maximum
24387
+ into the baseline. Inherited by `lr-line-chart`, `lr-scatter-chart` and `lr-bar-chart`, and
24388
+ applied to the secondary `y2` axis too when one is present. A logarithmic axis cannot represent
24389
+ zero (`log(0)` is `-Infinity`), so `beginAtZero` is not forwarded in that mode and non-positive
24390
+ points are dropped by Chart.js's own log scale. Chart.js rejects an unregistered scale type at
24391
+ construction, so `LogarithmicScale` is registered with the core — it ships inside the `chart.js`
24392
+ module already loaded, adding no download weight
23824
24393
  - `plugins: LyraChartPlugin[] = []` — peer-neutral per-instance Chart.js plugin structures,
23825
24394
  combined without duplicates with Lyra's
23826
24395
  on-demand data-label plugin and any `config.plugins` entries
@@ -23852,9 +24421,9 @@ property).
23852
24421
  non-integer, negative, and out-of-range indexes are discarded. The component writes the accepted
23853
24422
  legend-toggle snapshot back to this property so a host can persist it, and a programmatic write
23854
24423
  reconciles Chart.js and the DOM legend silently without emitting either legend-visibility event.
23855
- - `withoutLegend: boolean = false` (attribute `without-legend`) — the legend shows by default;
23856
- set this to hide it. Renders a wrapping DOM legend (when shown) whose keyboard-operable buttons
23857
- toggle dataset visibility. The DOM surface preserves long public labels that a canvas legend
24424
+ - `withoutLegend: boolean = false` (attribute `without-legend`, reflected) — the legend shows by
24425
+ default; set this to hide it. Renders a wrapping DOM legend (when shown) whose keyboard-operable
24426
+ buttons toggle dataset visibility. The DOM surface preserves long public labels that a canvas legend
23858
24427
  would clip. Its pressed state follows `hiddenDatasets` whenever that controlled snapshot is
23859
24428
  defined, otherwise the effective dataset's declarative `hidden` value before Chart.js is ready
23860
24429
  and across chart type/plugin rebuilds.
@@ -23889,8 +24458,6 @@ property).
23889
24458
  by radar/polar-area are out of scope)
23890
24459
  - `withoutAnimation: boolean = false` (attribute `without-animation`, reflected) — disables Chart.js
23891
24460
  construction animation; reduced-motion preference also disables it regardless of this value
23892
- - `withoutLegend: boolean = false` (attribute `without-legend`, reflected) — hides the legend;
23893
- it wins over the positive `legend` alias
23894
24461
  - `withoutTooltip: boolean = false` (attribute `without-tooltip`, reflected) — disables the
23895
24462
  Chart.js tooltip plugin for this instance
23896
24463
  - `dataLabels: boolean = false` (attribute `data-labels`) — draws each point's value on the chart via
@@ -24124,7 +24691,7 @@ requested enhancement is disabled and a localized static `feature-warning` is vi
24124
24691
  announced. In particular, unavailable data labels do not remove generated table totals.
24125
24692
 
24126
24693
  ```html
24127
- <lr-chart type="line" x-label="Day" y-label="kWh" legend></lr-chart>
24694
+ <lr-chart type="line" x-label="Day" y-label="kWh"></lr-chart>
24128
24695
  <script>
24129
24696
  const c = document.querySelector('lr-chart');
24130
24697
  c.labels = ['Mon', 'Tue', 'Wed'];
@@ -24169,7 +24736,7 @@ announced. In particular, unavailable data labels do not remove generated table
24169
24736
  off-screen, property changes that would otherwise trigger a Chart.js redraw are skipped (and a
24170
24737
  single redraw fires once it re-enters the viewport). Independently, `updated()` only reaches
24171
24738
  Chart.js when at least one of `type`, `labels`, `datasets`, `description`, `grid`, `indexAxis`,
24172
- `label`, `hiddenDatasets`, `legend`, `legendPosition`, `min`, `max`, `plugins`, the internal resolved auto legend
24739
+ `label`, `hiddenDatasets`, `legendPosition`, `min`, `max`, `plugins`, the internal resolved auto legend
24173
24740
  position, `valueFormatter`, `formatter`, `area`, `height`, `xLabel`, `yLabel`, `y2Label`, `beginAtZero`,
24174
24741
  `stacked`, any `without*` control, `dataLabels`, `stackTotals`, `config`, the parsed
24175
24742
  slotted config, `zoom`, `locale`, `strings`, or the internal loading state actually changed in
@@ -24276,11 +24843,21 @@ passthrough). Not a subclass of `LyraChart`.
24276
24843
  - `valueAxisGutter?: number` (attribute `value-axis-gutter`) — value-axis gutter width.
24277
24844
  - `barGapRatio?: number` (attribute `bar-gap-ratio`) — overrides the internal 0.2 `BAR_GROUP_GAP`
24278
24845
  fraction of a category slot left as a gap between categories. Unset keeps the fixed 0.2.
24279
- - `scale: 'linear' | 'sqrt' = 'linear'` (bar type only) — `'sqrt'` maps a bar's value to height via
24280
- `Math.sqrt(value / domainMax)` instead of the standard linear `niceDomain` fraction (mirroring
24281
- `lr-heatmap`'s matrix-mode `sqrt` scale), so a skewed dataset's smaller bars aren't washed out
24282
- by one dominant value; gridlines/tick labels stay on the linear domain either way, and `type="line"`
24283
- ignores it entirely.
24846
+ - `scale: 'linear' | 'sqrt' | 'logarithmic' = 'linear'` — `'sqrt'` (**bar type only**) maps a bar's
24847
+ value to height via `Math.sqrt(value / domainMax)` instead of the standard linear `niceDomain`
24848
+ fraction (mirroring `lr-heatmap`'s matrix-mode `sqrt` scale), so a skewed dataset's smaller bars
24849
+ aren't washed out by one dominant value; under `'sqrt'` gridlines/tick labels stay on the linear
24850
+ domain and `type="line"` ignores it entirely.
24851
+ `'logarithmic'` is the base-10 value axis for data spanning several orders of magnitude, where a
24852
+ linear axis collapses everything below the maximum into the baseline. Unlike `'sqrt'` it applies
24853
+ to **bars, line points and gridlines alike**, since a log axis whose gridlines stayed linear
24854
+ would misrepresent the plot. Its lower bound is the smallest *positive* datum rather than the
24855
+ linear `lo`: `beginAtZero` defaults to true, so `lo` is normally `0`, which has no logarithm —
24856
+ deriving the floor from the data is what makes a 1…1000 series span three even decades instead of
24857
+ collapsing onto one. Values at or below that floor (including zero and negatives, which have no
24858
+ real logarithm) pin to the axis floor rather than producing `-Infinity` geometry, and a degenerate
24859
+ domain falls back to the linear fraction. `lr-chart`'s own `scaleType` is the Chart.js-backed
24860
+ equivalent for the full charts.
24284
24861
  - `withoutValueAxis: boolean = false` (attribute `without-value-axis`) — suppresses gridlines and
24285
24862
  value-axis tick labels; x-axis category labels remain.
24286
24863
  - `selectedIndices: readonly number[] = []` (attribute: false) — applies to every interactive data mark for
@@ -24427,7 +25004,8 @@ and behavior there. **See `llms/components/lr-chart.md` for the details, code ex
24427
25004
  of every entry in these lists.**
24428
25005
 
24429
25006
  **Properties:** `description`, `grid`, `indexAxis` (`index-axis`), `label`, `hiddenDatasets`, `legendPosition`
24430
- (`legend-position`), `max`, `min`, `plugins`, `stacked`, `withoutAnimation` (`without-animation`),
25007
+ (`legend-position`), `max`, `min`, `plugins`, `scaleType` (`scale-type`), `annotations`,
25008
+ `stacked`, `withoutAnimation` (`without-animation`),
24431
25009
  `withoutLegend` (`without-legend`), `withoutTooltip` (`without-tooltip`), `xLabel` (`x-label`),
24432
25010
  `yLabel` (`y-label`), plus additive `labels`, `datasets`, `valueFormatter`, `formatter`, `area`, `zoom`,
24433
25011
  `height`, `y2Label` (`y2-label`), `beginAtZero` (`begin-at-zero`), `dataLabels`
@@ -24468,7 +25046,7 @@ together. The mirrored hooks are `--border-color-1`,
24468
25046
  `zoom` is set, and `chartjs-plugin-datalabels` only once `data-labels`/`stack-totals` is set.
24469
25047
 
24470
25048
  ```html
24471
- <lr-bar-chart legend></lr-bar-chart>
25049
+ <lr-bar-chart></lr-bar-chart>
24472
25050
  <lr-pie-chart></lr-pie-chart>
24473
25051
  <script>
24474
25052
  document.querySelector('lr-bar-chart').labels = ['A', 'B'];
@@ -24500,6 +25078,8 @@ Bins `values` into `bins` equal-width buckets and renders as a bar chart (extend
24500
25078
  - `seriesLabel: string = ''` (attribute `series-label`) — dataset label used for the
24501
25079
  legend/tooltip/table; empty falls back to localized "Frequency". Inherited `label` keeps its
24502
25080
  chart-wide accessible-name meaning.
25081
+ - inherits `lr-chart`'s full surface, including `scaleType` (`scale-type`) and `annotations` —
25082
+ a logarithmic frequency axis and threshold/band markers both apply to a histogram
24503
25083
  - `labels`/`datasets`/`type` are **derived, read-only** (installed as getter/setter pairs on the
24504
25084
  prototype; direct writes are silently ignored) — `labels`/`datasets` are computed from
24505
25085
  `values`/`bins` (memoized per instance, keyed by reference equality on `values` plus the
@@ -24746,6 +25326,7 @@ These named interfaces and helper signatures are available to typed integrations
24746
25326
 
24747
25327
  - **`components-charts-chart-chart-core-loader-contracts`** — Supporting data types and helpers for this component family.
24748
25328
  `ChartJsModule {
25329
+ LogarithmicScale: unknown;
24749
25330
  Chart: unknown;
24750
25331
  defaults: unknown;
24751
25332
  plugins: unknown;
@@ -24780,6 +25361,9 @@ These named interfaces and helper signatures are available to typed integrations
24780
25361
  `ChartPluginCapability {
24781
25362
  id: unknown;
24782
25363
  }`
25364
+ `loadAnnotationPlugin(/* public names: importAnnotation */): unknown`
25365
+ `loadChartAndAnnotation(/* public names: loadChart, importAnnotation */): unknown`
25366
+ `loadChartJsWithAnnotationResult(/* public names: importAnnotation */): unknown`
24783
25367
 
24784
25368
  - **`components-charts-chart-chart-legend-visibility-contracts`** — Supporting data types and helpers for this component family.
24785
25369
  `LyraChartLegendVisibilityChangeDetail {
@@ -24814,6 +25398,14 @@ These named interfaces and helper signatures are available to typed integrations
24814
25398
 
24815
25399
  - **`components-charts-chart-chart-contracts`** — Supporting data types and helpers for this component family.
24816
25400
  `lockChartType(/* public names: ctor, value */): unknown`
25401
+ `LyraChartAnnotation {
25402
+ axis: unknown;
25403
+ value: unknown;
25404
+ from: unknown;
25405
+ to: unknown;
25406
+ label: unknown;
25407
+ tone: unknown;
25408
+ }`
24817
25409
  `LyraChartArea {
24818
25410
  top: unknown;
24819
25411
  left: unknown;
@@ -25083,11 +25675,11 @@ entry) or a third-party PDF/office-doc viewer, but neither is a dependency of th
25083
25675
 
25084
25676
  ```html
25085
25677
  <lr-document-preview
25678
+ id="text-preview"
25086
25679
  filename="board-notes.txt"
25087
25680
  mime-type="text/plain"
25088
25681
  src="/files/board-notes.txt"
25089
25682
  max-height="24rem"
25090
- @lr-render-error=${(e) => console.error(e.detail.error)}
25091
25683
  ></lr-document-preview>
25092
25684
 
25093
25685
  <!-- A host driving its own server-side conversion -->
@@ -25097,6 +25689,11 @@ entry) or a third-party PDF/office-doc viewer, but neither is a dependency of th
25097
25689
  <lr-document-preview filename="deck.pptx" mime-type="application/vnd.ms-powerpoint" src="/files/deck.pptx">
25098
25690
  <lr-code-block slot="unsupported" language="text">Open in PowerPoint to preview.</lr-code-block>
25099
25691
  </lr-document-preview>
25692
+ <script type="module">
25693
+ document
25694
+ .getElementById("text-preview")
25695
+ .addEventListener("lr-render-error", (e) => console.error(e.detail.error));
25696
+ </script>
25100
25697
  ```
25101
25698
 
25102
25699
  Accessibility: after the initial silent baseline, entering `"converting"` without numeric
@@ -25181,8 +25778,9 @@ value, without suppressing the visible `name` heading.
25181
25778
 
25182
25779
  - `lr-close` — `detail: DocumentViewerCloseReason`, the viewer shell dialog's dismissal reason.
25183
25780
  The event is emitted after the viewer sets `open` to `false`. A registered renderer may compose
25184
- its own descendant dialog; closing that inner dialog keeps its normal `lr-dialog-close` path and
25185
- does not close the document viewer.
25781
+ its own descendant dialog; closing that inner dialog keeps its own `lr-close` path — the shell
25782
+ guards on `event.target !== event.currentTarget` — and does not close the document viewer.
25783
+ (`<lr-dialog>`'s close event was spelled `lr-dialog-close` before 10.0.0.)
25186
25784
  - `lr-download` — `detail: { src, filename }`, emitted when the native safe download action is
25187
25785
  activated. The browser download itself is handled by the link.
25188
25786
  - `lr-anchor-result` — `detail: { found }`. Emitted by this shell as `{ found: false }` once per
@@ -26015,7 +26613,9 @@ current page and
26015
26613
  `zoom: number = 1` is clamped to `0.25`–`4`. `maxHeight: string = ''` (attribute `max-height`) is a
26016
26614
  CSS length that, once set, overrides `--lr-pdf-viewer-height` — the block size of the virtualized
26017
26615
  page list — declaratively, writing it inline on `[part="base"]`; invalid CSS `max-height` values,
26018
- declaration breaks, and `url()` are ignored. `anchorKinds: readonly LyraAnchorKind[] = ['page',
26616
+ declaration breaks, and `url()` are ignored. `workerSrc: string = ''` (attribute `worker-src`) is the
26617
+ URL of the PDF.js web worker chunk — see **Configuring the PDF.js worker** below.
26618
+ `anchorKinds: readonly LyraAnchorKind[] = ['page',
26019
26619
  'text-quote', 'region']` (this viewer's supported `LyraAnchor.kind` values for the shared
26020
26620
  anchor-target contract). The other inherited anchor-target properties are `highlights:
26021
26621
  LyraHighlight[] = []` (property only; reassign after mutation), `activeHighlightId: string | null =
@@ -26032,7 +26632,8 @@ nonnegative dimensions.
26032
26632
  - `lr-load` — `detail: { pageCount }` — the document reached `ready`. `page` is reset to `1` first.
26033
26633
  - `lr-page-change` — `detail: { page, pageCount }` — fired for scroll-driven page crossings as well
26034
26634
  as `page` assignments and `nextPage()`/`previousPage()`/`goToPage()`.
26035
- - `lr-zoom-change` — `detail: { zoom }`.
26635
+ - `lr-zoom-change` — `detail: { zoom }` — fired for `zoom` assignments as well as
26636
+ `zoomIn()`/`zoomOut()`. Never fired for the initial `1`, only for a transition away from it.
26036
26637
  - `lr-search-change` — `detail: { query, matchCount, matchCountExact, activeIndex }` — from `search()`/`searchNext()`/
26037
26638
  `searchPrevious()`/`clearSearch()` and effective-locale re-evaluation. A `src` change invalidates document-relative matches and emits
26038
26639
  the canonical reset `{ query: '', matchCount: 0, matchCountExact: true, activeIndex: -1 }`.
@@ -26047,6 +26648,30 @@ nonnegative dimensions.
26047
26648
  `pageViewerSnapshot` (`identity`, `status`, `page`, `pageCount`). `identity` changes for every load,
26048
26649
  including same-count replacements.
26049
26650
 
26651
+ **`lr-page-change`/`lr-zoom-change` are state broadcasts, not user-intent signals.** This differs
26652
+ deliberately from the same-named `<lr-pagination>` event and from `<lr-pan-zoom>`'s `lr-zoom-change`,
26653
+ and the distinction is worth internalizing before wiring a handler. Pagination and pan-zoom are
26654
+ *controlled*: pagination never mutates its own `page`, so its event is a request the host applies,
26655
+ and pan-zoom's `zoom` is bound by a parent, so echoing a programmatic write back would feed a loop.
26656
+ This viewer instead *owns* `page` and `zoom` — scrolling the page list changes `page` with no
26657
+ consumer action at all — so there is no useful "the user did this" subset to isolate, and every
26658
+ accepted transition is announced identically: scrolling, `nextPage()`/`previousPage()`/`goToPage()`,
26659
+ `zoomIn()`/`zoomOut()`, anchor resolution, the reset to page 1 when a new `src` finishes loading,
26660
+ and a plain `viewer.page = 3` / `viewer.zoom = 2` assignment. A handler that mirrors the event back
26661
+ into the property it came from is therefore idempotent rather than looping, but it is also
26662
+ redundant — read the property, or `pageViewerSnapshot`, instead.
26663
+
26664
+ A write that clamps or rounds back onto the value already in effect is not a transition and stays
26665
+ silent: on a 3-page document already showing page 1, `viewer.page = -7` and `viewer.page = 1.4` both
26666
+ settle on page 1 and emit nothing, and `viewer.zoom = 999` at 4× emits nothing.
26667
+
26668
+ For page-addressed integrations prefer the atomic `pageViewerSnapshot` /
26669
+ `lr-page-viewer-state-change` channel over this pair: it carries page, count, load status and
26670
+ document `identity` together, and a late subscriber can read the current value synchronously instead
26671
+ of having missed the announcement. `<lr-page-rail>` binds that channel for any viewer exposing
26672
+ `pageViewerSnapshot` — including this one — and falls back to `lr-load`/`lr-page-change` only for
26673
+ older structural sources that do not.
26674
+
26050
26675
  **Methods:** `nextPage()`, `previousPage()`, `zoomIn()`, and `zoomOut()` update the corresponding
26051
26676
  controlled state within its supported range. `getPageText(page)` resolves the raw reading-order text
26052
26677
  of one page (per-page LRU-cached, 64 pages), rejecting on no loaded document or an out-of-range page.
@@ -26104,6 +26729,39 @@ a PDF is opened. An absent `pdfjs-dist` fails closed and renders
26104
26729
  `[part="error"]` with the localized `pdfViewerMissingLibrary` message — there is no partial PDF
26105
26730
  rendering without it.
26106
26731
 
26732
+ **Configuring the PDF.js worker.** PDF.js renders in a web worker and rejects every document with
26733
+ `No "GlobalWorkerOptions.workerSrc" specified.` until it has been told where that worker lives. The
26734
+ worker is a separate file inside the peer (`pdfjs-dist/build/pdf.worker.min.mjs`) that only the
26735
+ application's own bundler can turn into a real URL — a bare package specifier does not resolve in a
26736
+ browser without an import map, and resolving it against this library's own module URL would point
26737
+ into `@aceshooting/lyra-ui`'s files, where no worker exists. So a bundled application supplies it,
26738
+ either way round:
26739
+
26740
+ ```ts
26741
+ // 1. Per element, through the public property/attribute.
26742
+ import workerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?worker&url'; // Vite; see your bundler
26743
+ const viewer = document.querySelector('lr-pdf-viewer');
26744
+ viewer.workerSrc = workerUrl;
26745
+ // or, declaratively: <lr-pdf-viewer worker-src="/assets/pdf.worker.min.mjs"></lr-pdf-viewer>
26746
+
26747
+ // 2. Once for the whole application, on PDF.js's own singleton, before any viewer loads a document.
26748
+ import { GlobalWorkerOptions } from 'pdfjs-dist';
26749
+ GlobalWorkerOptions.workerSrc = workerUrl;
26750
+ ```
26751
+
26752
+ `workerSrc` accepts a document-relative URL (resolved against the document base) as well as an
26753
+ absolute one; only `http:`, `https:`, `blob:` and `file:` URLs are accepted, and anything else — a
26754
+ `javascript:` or `data:` URL in particular — is ignored rather than handed to `new Worker()`.
26755
+
26756
+ `GlobalWorkerOptions` is PDF.js's process-wide singleton and the PDF.js module itself is loaded once
26757
+ per page, so `workerSrc` is applied only while that singleton is still unset. Two consequences worth
26758
+ knowing before reaching for the per-element form: a worker the application configured itself is never
26759
+ overwritten, and when several viewers carry different `workerSrc` values only the first one to load
26760
+ PDF.js takes effect for the whole page. Assigning `workerSrc` after PDF.js has already loaded is not
26761
+ silently dropped — it is re-applied on the next load — but it still cannot displace an
26762
+ already-configured worker. Option 2 above is the right choice for an application that wants one
26763
+ explicit worker everywhere.
26764
+
26107
26765
  Remote resources are capped at 25 MB; exceeding it surfaces the localized
26108
26766
  `documentPreviewResourceTooLarge` message instead of the PDF.
26109
26767
 
@@ -26543,9 +27201,12 @@ each tone's highlighted-cell background. `--lr-notebook-viewer-highlight-active-
26543
27201
  `text/plain`).
26544
27202
 
26545
27203
  ```html
26546
- <lr-notebook-viewer .notebook=${result} max-height="30rem"
26547
- @lr-load=${(e) => console.log(e.detail.cellCount, 'cells')}
26548
- ></lr-notebook-viewer>
27204
+ <lr-notebook-viewer max-height="30rem"></lr-notebook-viewer>
27205
+ <script type="module">
27206
+ const viewer = document.querySelector("lr-notebook-viewer");
27207
+ viewer.notebook = result;
27208
+ viewer.addEventListener("lr-load", (e) => console.log(e.detail.cellCount, "cells"));
27209
+ </script>
26549
27210
  ```
26550
27211
 
26551
27212
  A notebook major version outside 4.0–4.5, an invalid shape, or more than 2,000 cells renders a
@@ -27165,6 +27826,79 @@ These named interfaces and helper signatures are available to typed integrations
27165
27826
  children: unknown;
27166
27827
  }`
27167
27828
 
27829
+ - **`components-viewers-pptx-viewer-pptx-loader-contracts`** — Supporting data types and helpers for this component family.
27830
+ `adaptPptxViewer(/* public names: value */): unknown`
27831
+ `getPptxRenderer(): unknown`
27832
+ `loadPptxRenderer(/* public names: importer */): unknown`
27833
+ `PptxRendererModule {
27834
+ PptxViewer: unknown;
27835
+ open: unknown;
27836
+ input: unknown;
27837
+ container: unknown;
27838
+ options: unknown;
27839
+ RECOMMENDED_ZIP_LIMITS: unknown;
27840
+ }`
27841
+ `PptxSearchHighlightHandle {
27842
+ dispose: unknown;
27843
+ }`
27844
+ `PptxTextSearchResult {
27845
+ slideIndex: unknown;
27846
+ nodeId: unknown;
27847
+ matchStart: unknown;
27848
+ matchEnd: unknown;
27849
+ text: unknown;
27850
+ }`
27851
+ `PptxThumbnailHandle {
27852
+ ready: unknown;
27853
+ dispose: unknown;
27854
+ }`
27855
+ `PptxViewerAdapter {
27856
+ slideCount: unknown;
27857
+ currentSlideIndex: unknown;
27858
+ goToSlide: unknown;
27859
+ index: unknown;
27860
+ searchText: unknown;
27861
+ query: unknown;
27862
+ options: unknown;
27863
+ matchCase: unknown;
27864
+ highlightSearchResult: unknown;
27865
+ result: unknown;
27866
+ scrollIntoView: unknown;
27867
+ renderThumbnailToContainer: unknown;
27868
+ container: unknown;
27869
+ width: unknown;
27870
+ clearSearchHighlights: unknown;
27871
+ subscribe: unknown;
27872
+ listener: unknown;
27873
+ event: unknown;
27874
+ destroy: unknown;
27875
+ }`
27876
+ `PptxViewerApi {
27877
+ slideCount: unknown;
27878
+ currentSlideIndex: unknown;
27879
+ goToSlide: unknown;
27880
+ index: unknown;
27881
+ searchText: unknown;
27882
+ query: unknown;
27883
+ options: unknown;
27884
+ matchCase: unknown;
27885
+ highlightSearchResult: unknown;
27886
+ result: unknown;
27887
+ scrollIntoView: unknown;
27888
+ renderThumbnailToContainer: unknown;
27889
+ container: unknown;
27890
+ width: unknown;
27891
+ clearSearchHighlights: unknown;
27892
+ destroy: unknown;
27893
+ }`
27894
+ `PptxZipLimits {
27895
+ maxEntries: unknown;
27896
+ maxEntryUncompressedBytes: unknown;
27897
+ maxTotalUncompressedBytes: unknown;
27898
+ maxMediaBytes: unknown;
27899
+ maxConcurrency: unknown;
27900
+ }`
27901
+
27168
27902
  - **`components-viewers-spreadsheet-viewer-spreadsheet-loader-contracts`** — Supporting data types and helpers for this component family.
27169
27903
  `clearSheetJsCache(): unknown`
27170
27904
  `loadSheetJsCached(): unknown`
@@ -27477,8 +28211,9 @@ support (`highlights`, `activeHighlightId`, `scrollToAnchor()`, the `lr-highligh
27477
28211
  section above for the full write-up of shared behavior.
27478
28212
 
27479
28213
  **Properties:** `content: string = ''`, `tabSize: number = 4` (attribute `tab-size`) — the same
27480
- finite-integer-guarded leading-indentation expansion used by `<lr-markdown>`; values outside 1–32
27481
- or non-finite values fall back to `4`, independently of rendered code's
28214
+ finite-integer-guarded leading-indentation expansion used by `<lr-markdown>`; finite values are
28215
+ clamped to `[1, 32]` (`0` becomes `1`, `33` becomes `32`), and only non-finite values (`NaN`,
28216
+ `Infinity`) fall back to `4`, independently of rendered code's
27482
28217
  `--lr-code-block-tab-size`; `marked: LyraMarkedParser | undefined` (readonly, no attribute) — this
27483
28218
  instance's isolated peer-neutral configurable parser; `htmlMode: 'sanitize' | 'escape' | 'trusted' =
27484
28219
  'sanitize'` (attribute `html-mode`), `gfm: boolean = true`, `linkTarget: string | null = '_blank'` (attribute
@@ -28217,13 +28952,16 @@ Plus shared tokens — `--lr-space-xs/-s/-m`, `--lr-radius`,
28217
28952
  conversation-id="sess_123"
28218
28953
  label="Q3 roadmap planning"
28219
28954
  excerpt="Let's revisit the timeline for the launch…"
28220
- .timestamp=${session.updatedAt}
28221
- ?active=${session.id === currentSessionId}
28222
- @lr-select=${(e) => openSession(e.detail.conversationId)}
28223
- @lr-rename=${(e) => renameSession(e.detail.conversationId, e.detail.label)}
28224
28955
  >
28225
28956
  <button slot="actions" aria-label="Delete conversation">✕</button>
28226
28957
  </lr-conversation-item>
28958
+ <script type="module">
28959
+ const item = document.querySelector("lr-conversation-item");
28960
+ item.timestamp = session.updatedAt;
28961
+ item.active = session.id === currentSessionId;
28962
+ item.addEventListener("lr-select", (e) => openSession(e.detail.conversationId));
28963
+ item.addEventListener("lr-rename", (e) => renameSession(e.detail.conversationId, e.detail.label));
28964
+ </script>
28227
28965
  ```
28228
28966
 
28229
28967
  `role="button"` lives on `[part="select-button"]`, so the row has
@@ -28472,19 +29210,18 @@ shared tokens — `--lr-space-xs/-s`, `--lr-color-border/-surface/-brand/-brand-
28472
29210
  **Optional peer deps:** none.
28473
29211
 
28474
29212
  ```html
28475
- <lr-model-select
28476
- provider="openai"
28477
- .catalog=${[
28478
- { id: 'gpt-4o', label: 'GPT-4o', icon: '✦' },
28479
- { id: 'gpt-4o-mini', label: 'GPT-4o mini' },
28480
- ]}
28481
- value="gpt-4o"
28482
- placeholder="Choose a model…"
28483
- @lr-change=${(e) => setModel(e.detail.value, e.detail.inCatalog)}
28484
- ></lr-model-select>
29213
+ <lr-model-select provider="openai" value="gpt-4o" placeholder="Choose a model…"></lr-model-select>
28485
29214
 
28486
29215
  <!-- No fixed catalog yet: falls back to free-text entry -->
28487
29216
  <lr-model-select provider="ollama" placeholder="Type a model id…" allow-custom></lr-model-select>
29217
+ <script type="module">
29218
+ const select = document.querySelector("lr-model-select");
29219
+ select.catalog = [
29220
+ { id: "gpt-4o", label: "GPT-4o", icon: "✦" },
29221
+ { id: "gpt-4o-mini", label: "GPT-4o mini" },
29222
+ ];
29223
+ select.addEventListener("lr-change", (e) => setModel(e.detail.value, e.detail.inCatalog));
29224
+ </script>
28488
29225
  ```
28489
29226
 
28490
29227
  **Known gotchas:**
@@ -29062,15 +29799,15 @@ selector label), `temperature-row`, `temperature-label`, `temperature-value`
29062
29799
  internally (both imported unconditionally as side effects, not optional).
29063
29800
 
29064
29801
  ```html
29065
- <lr-model-settings-panel
29066
- provider="OpenAI"
29067
- .catalog=${['gpt-4o', 'gpt-4o-mini', 'gpt-4.1']}
29068
- model="gpt-4o"
29069
- temperature="0.7"
29070
- @lr-change=${(e) => console.log(e.detail)}
29071
- ></lr-model-settings-panel>
29802
+ <lr-model-settings-panel provider="OpenAI" model="gpt-4o" temperature="0.7"></lr-model-settings-panel>
29072
29803
 
29073
- <lr-model-settings-panel layout="compact" .catalog=${catalog}></lr-model-settings-panel>
29804
+ <lr-model-settings-panel layout="compact"></lr-model-settings-panel>
29805
+ <script type="module">
29806
+ const [panel, compactPanel] = document.querySelectorAll("lr-model-settings-panel");
29807
+ panel.catalog = ["gpt-4o", "gpt-4o-mini", "gpt-4.1"];
29808
+ panel.addEventListener("lr-change", (e) => console.log(e.detail));
29809
+ compactPanel.catalog = catalog;
29810
+ </script>
29074
29811
  ```
29075
29812
 
29076
29813
  The internal `lr-slider` renders with its own value readout suppressed (`.showValue=${false}`);
@@ -29496,13 +30233,18 @@ component's existing requirement of a height-bounded parent, exactly as slotted
29496
30233
  inline style) still wins over the built-in one.
29497
30234
 
29498
30235
  ```html
29499
- <lr-chat-viewport unread-start-index="12" @lr-follow-change=${(e) => console.log(e.detail.following)}>
30236
+ <lr-chat-viewport unread-start-index="12">
29500
30237
  <lr-chat-message message-role="user">…</lr-chat-message>
29501
30238
  <lr-chat-message message-role="assistant" status="streaming">
29502
- <lr-streaming-text streaming .content=${partial}></lr-streaming-text>
30239
+ <lr-streaming-text streaming></lr-streaming-text>
29503
30240
  </lr-chat-message>
29504
30241
  </lr-chat-viewport>
29505
30242
  <lr-chat-composer status="streaming"></lr-chat-composer>
30243
+ <script type="module">
30244
+ const viewport = document.querySelector("lr-chat-viewport");
30245
+ viewport.querySelector("lr-streaming-text").content = partial;
30246
+ viewport.addEventListener("lr-follow-change", (e) => console.log(e.detail.following));
30247
+ </script>
29506
30248
  ```
29507
30249
 
29508
30250
  ## `lr-suggestion-chips`
@@ -29550,9 +30292,14 @@ Enter/Space activate. Renders inside an internal `lr-scroller` (`orientation="ho
29550
30292
  `hide-scrollbar`) unless `wrap` is set.
29551
30293
 
29552
30294
  ```html
29553
- <lr-suggestion-chips .suggestions=${followUps}
29554
- @lr-suggestion-select=${(e) => (composer.value = e.detail.label)}></lr-suggestion-chips>
30295
+ <lr-suggestion-chips></lr-suggestion-chips>
29555
30296
  <lr-chat-composer></lr-chat-composer>
30297
+ <script type="module">
30298
+ const chips = document.querySelector("lr-suggestion-chips");
30299
+ const composer = document.querySelector("lr-chat-composer");
30300
+ chips.suggestions = followUps;
30301
+ chips.addEventListener("lr-suggestion-select", (e) => (composer.value = e.detail.label));
30302
+ </script>
29556
30303
  ```
29557
30304
 
29558
30305
  ## `lr-thread-list`
@@ -29735,14 +30482,14 @@ short one, and falls back to exactly `24rem` in an auto-height container.
29735
30482
  style the pinned band with `lr-thread-list::part(group-sticky)`.
29736
30483
 
29737
30484
  ```html
29738
- <lr-thread-list
29739
- searchable
29740
- sticky-groups
29741
- .threads=${threads}
29742
- active-conversation-id=${activeThreadId}
29743
- .rowActions=${['pin', 'archive', 'delete']}
29744
- @lr-select=${(e) => openThread(e.detail.conversationId)}
29745
- ></lr-thread-list>
30485
+ <lr-thread-list searchable sticky-groups></lr-thread-list>
30486
+ <script type="module">
30487
+ const list = document.querySelector("lr-thread-list");
30488
+ list.threads = threads;
30489
+ list.activeConversationId = activeThreadId;
30490
+ list.rowActions = ["pin", "archive", "delete"];
30491
+ list.addEventListener("lr-select", (e) => openThread(e.detail.conversationId));
30492
+ </script>
29746
30493
  ```
29747
30494
 
29748
30495
  Composed with `lr-multi-split` (or `lr-app-rail` + `lr-responsive-panel`): thread-list in the start
@@ -29791,8 +30538,12 @@ assigned to `animation-duration` alone. The spinner stops outright under
29791
30538
  `prefers-reduced-motion: reduce`.
29792
30539
 
29793
30540
  ```html
29794
- <lr-checkpoint checkpoint-id="ck_18" label="Before refactor" .timestamp=${t}
29795
- @lr-restore=${(e) => restoreTo(e.detail.checkpointId)}></lr-checkpoint>
30541
+ <lr-checkpoint checkpoint-id="ck_18" label="Before refactor"></lr-checkpoint>
30542
+ <script type="module">
30543
+ const checkpoint = document.querySelector("lr-checkpoint");
30544
+ checkpoint.timestamp = t;
30545
+ checkpoint.addEventListener("lr-restore", (e) => restoreTo(e.detail.checkpointId));
30546
+ </script>
29796
30547
  ```
29797
30548
 
29798
30549
  ## `lr-usage-badge`
@@ -29835,8 +30586,11 @@ describable), `summary`, `tokens-in`, `tokens-out`, `cost`, `latency`, `tooltip`
29835
30586
  cost-text="$0.012"
29836
30587
  latency-ms="2350"
29837
30588
  ></lr-usage-badge>
29838
- <lr-markdown .content="${answer}"></lr-markdown>
30589
+ <lr-markdown></lr-markdown>
29839
30590
  </lr-chat-message>
30591
+ <script type="module">
30592
+ document.querySelector("lr-chat-message lr-markdown").content = answer;
30593
+ </script>
29840
30594
  ```
29841
30595
 
29842
30596
  ## `lr-widget-renderer`
@@ -29870,9 +30624,9 @@ readonly slot?: string; readonly actionId?: string; readonly payload?: unknown }
29870
30624
  - `LyraWidgetDocument { readonly version: '2'; readonly root: LyraWidgetNode }` — the sole versioned tree source.
29871
30625
  - `createWidgetDocument(root: LyraWidgetNode): LyraWidgetDocument` — creates an immediate frozen
29872
30626
  version-two snapshot for former unversioned tree assignments. Traversal uses the renderer's depth,
29873
- node, and per-node prop ceilings; malformed, cyclic, duplicate-id, or hostile structure throws
29874
- `TypeError`. Node records, child arrays, and prop records are copied and frozen, while opaque prop
29875
- values and action payloads intentionally retain caller identity.
30627
+ node, per-node prop, and per-string length ceilings; malformed, cyclic, duplicate-id, or hostile
30628
+ structure throws `TypeError`. Node records, child arrays, and prop records are copied and frozen,
30629
+ while opaque prop values and action payloads intentionally retain caller identity.
29876
30630
 
29877
30631
  The package root and the normal `widget-renderer.js` registration entry expose the renderer
29878
30632
  `LyraWidgetRenderer`/`LyraWidgetRendererEventMap` together with the complete stable authoring
@@ -30139,15 +30893,18 @@ stale-value row), `option-preview` (a pointer-only per-row preview icon, `tabind
30139
30893
  trigger), `expand-icon`, `empty`, `hint`, `error`.
30140
30894
 
30141
30895
  ```html
30142
- <lr-voice-picker provider="elevenlabs" .catalog=${voices} allow-custom
30143
- @lr-change=${(e) => setVoice(e.detail.value)}
30144
- @lr-preview-request=${(e) => {
30896
+ <lr-voice-picker provider="elevenlabs" allow-custom></lr-voice-picker>
30897
+ <script type="module">
30898
+ const picker = document.querySelector("lr-voice-picker");
30899
+ picker.catalog = voices;
30900
+ picker.addEventListener("lr-change", (e) => setVoice(e.detail.value));
30901
+ picker.addEventListener("lr-preview-request", (e) => {
30145
30902
  if (!e.detail.previewUrl) {
30146
30903
  e.preventDefault();
30147
30904
  playSample(e.detail.voiceId);
30148
30905
  }
30149
- }}
30150
- ></lr-voice-picker>
30906
+ });
30907
+ </script>
30151
30908
  ```
30152
30909
 
30153
30910
  **Known gotchas:**
@@ -30293,6 +31050,26 @@ optional-peer fallback.
30293
31050
  Every public data/value property is controlled: forwarded child intents bubble without mutating
30294
31051
  `messages`, `composerValue`, selections, run state, or persistence-owned data inside the shell.
30295
31052
 
31053
+ **Only the transcript scrolls.** `[part='base']` is a three-row grid — header, conversation,
31054
+ composer — and only the middle row can shrink, so the composed `lr-chat-viewport` owns the
31055
+ scrolling and the chrome rows stay put at their content size. The trade: give the workspace less
31056
+ block-size than the chrome needs and the conversation row collapses to zero first, after which the
31057
+ header or composer is clipped with no scrollbar. That takes unusually large slotted chrome — a very
31058
+ tall `header-actions` toolbar, or a `composer` replacement much taller than the built-in one — and
31059
+ the region that supplied it caps and scrolls itself through the public parts:
31060
+
31061
+ ```css
31062
+ lr-agent-workspace::part(header) {
31063
+ max-block-size: 4rem;
31064
+ overflow: auto;
31065
+ }
31066
+ ```
31067
+
31068
+ The same applies to `::part(composer)`. Both declarations are needed: the cap keeps the grid track
31069
+ inside the workspace, and `overflow` makes the capped region scrollable instead of spilling. No
31070
+ component-owned custom property duplicates this, because a `::part()` rule from your tree already
31071
+ wins over the shadow stylesheet regardless of specificity.
31072
+
30296
31073
  ## `lr-message-parts`
30297
31074
 
30298
31075
  Ordered renderer for provider-neutral `MessagePart[]`: text, reasoning, tool call/result, citation,
@@ -30354,7 +31131,8 @@ import "@aceshooting/lyra-ui/components/conversation/message-parts/message-parts
30354
31131
  - `lr-copy` event — Passthrough from rendered JSON content.
30355
31132
  - `lr-highlight-activate` event — Passthrough from rendered Markdown.
30356
31133
  - `lr-link-click` event — Passthrough from rendered Markdown.
30357
- - `lr-preview-request` event — Cancelable passthrough from a rendered attachment.
31134
+ - `lr-preview-request` event — Passthrough from a rendered attachment. Not cancelable as of 10.0.0:
31135
+ `<lr-attachment-chip>` dropped the flag, since it owns no preview default action to veto.
30358
31136
  - `lr-remove` event — Passthrough from a rendered attachment.
30359
31137
  - `lr-render-error` event — Passthrough from rendered Markdown, tool-result, or widget content.
30360
31138
  - `lr-retry` event — Passthrough from a rendered attachment.
@@ -30603,6 +31381,7 @@ These named interfaces and helper signatures are available to typed integrations
30603
31381
  - **`components-conversation-code-block-code-loader-contracts`** — Supporting data types and helpers for this component family.
30604
31382
  `loadShikiHighlighter(): unknown`
30605
31383
  `loadShikiLanguage(/* public names: hl, lang */): unknown`
31384
+ `shikiHasLoadedLanguage(/* public names: hl, lang */): unknown`
30606
31385
 
30607
31386
  - **`components-conversation-code-block-shiki-types-contracts`** — Supporting data types and helpers for this component family.
30608
31387
  `loadShikiHighlighterCore(/* public names: languages */): unknown`
@@ -30953,11 +31732,15 @@ referenced: `--lr-color-text-quiet`, `--lr-color-surface`, `--lr-color-border`,
30953
31732
  summary="Searching web…"
30954
31733
  duration-ms="820"
30955
31734
  call-id="call_123"
30956
- @lr-tool-call-chip-select=${(e) => openDetail(e.detail.callId)}
30957
31735
  >
30958
31736
  <pre slot="icon" style="display:none"></pre>
30959
31737
  <code>{"query": "lyra ui components"}</code>
30960
31738
  </lr-tool-call-chip>
31739
+ <script type="module">
31740
+ document
31741
+ .querySelector("lr-tool-call-chip")
31742
+ .addEventListener("lr-tool-call-chip-select", (e) => openDetail(e.detail.callId));
31743
+ </script>
30961
31744
  ```
30962
31745
 
30963
31746
  The default slot's tooltip is positioned with the same `internal/positioner.js` `place()` helper
@@ -31049,12 +31832,13 @@ of course pull in whatever they need (a charting library, a markdown renderer),
31049
31832
  the lazy `load()` path in the registry exists for.
31050
31833
 
31051
31834
  ```html
31052
- <lr-tool-result-view
31053
- tool-name="get_weather"
31054
- .result=${{ tempC: 21, condition: 'cloudy' }}
31055
- .args=${{ city: 'Brussels' }}
31056
- @lr-render-error=${(e) => console.warn('renderer failed', e.detail)}
31057
- ></lr-tool-result-view>
31835
+ <lr-tool-result-view tool-name="get_weather"></lr-tool-result-view>
31836
+ <script type="module">
31837
+ const view = document.querySelector("lr-tool-result-view");
31838
+ view.result = { tempC: 21, condition: "cloudy" };
31839
+ view.args = { city: "Brussels" };
31840
+ view.addEventListener("lr-render-error", (e) => console.warn("renderer failed", e.detail));
31841
+ </script>
31058
31842
  ```
31059
31843
 
31060
31844
  ### `registerToolRenderer()` and the tool-renderer registry (`registry.ts`)
@@ -31268,20 +32052,22 @@ tokens `--lr-color-surface/-border/-text-quiet/-brand/-brand-quiet/-success/-suc
31268
32052
  **Optional peer deps:** none.
31269
32053
 
31270
32054
  ```html
31271
- <lr-tool-result-dialog
31272
- tool-name="run_query"
31273
- status="success"
31274
- duration-ms="1240"
31275
- ?open=${dialogOpen}
31276
- @lr-close=${(e) => (dialogOpen = false)}
31277
- @lr-maximize-change=${(e) => console.log('maximized:', e.detail.maximized)}
31278
- >
32055
+ <lr-tool-result-dialog tool-name="run_query" status="success" duration-ms="1240">
31279
32056
  <lr-tab-group slot="body">
31280
32057
  <div slot="preview" label="Preview">…</div>
31281
- <div slot="json" label="JSON"><lr-json-viewer .data=${result}></lr-json-viewer></div>
32058
+ <div slot="json" label="JSON"><lr-json-viewer></lr-json-viewer></div>
31282
32059
  </lr-tab-group>
31283
32060
  <button slot="footer">Rerun</button>
31284
32061
  </lr-tool-result-dialog>
32062
+ <script type="module">
32063
+ const dialog = document.querySelector("lr-tool-result-dialog");
32064
+ dialog.querySelector("lr-json-viewer").data = result;
32065
+ dialog.open = true;
32066
+ dialog.addEventListener("lr-close", () => (dialog.open = false));
32067
+ dialog.addEventListener("lr-maximize-change", (e) =>
32068
+ console.log("maximized:", e.detail.maximized)
32069
+ );
32070
+ </script>
31285
32071
  ```
31286
32072
 
31287
32073
  While open, `[part="panel"]` takes `role="dialog"` + `aria-modal="true"` with `aria-labelledby`
@@ -31413,23 +32199,25 @@ assigned elements.
31413
32199
  dependencies of this package imported directly, not optional peers.
31414
32200
 
31415
32201
  ```html
31416
- <lr-tool-select-dialog
31417
- label="Select tools"
31418
- .tools=${[
31419
- { id: 'search', name: 'Web search', category: 'Research' },
31420
- { id: 'python', name: 'Python', category: 'Code', description: 'Run sandboxed Python' },
31421
- { id: 'admin', name: 'Admin console', disabled: true, disabledReason: 'Requires admin approval' },
31422
- ]}
31423
- .selectedToolIds=${enabledToolIds}
31424
- ?use-defaults=${usingDefaults}
31425
- ?open=${dialogOpen}
31426
- @lr-change=${(e) => updateTools(e.detail.selectedToolIds, e.detail.useDefaults)}
31427
- @lr-close=${() => (dialogOpen = false)}
31428
- >
31429
- <button slot="footer" @click=${(e) => e.target.closest('lr-tool-select-dialog').close('done')}>
31430
- Done
31431
- </button>
32202
+ <lr-tool-select-dialog label="Select tools">
32203
+ <button slot="footer" id="done-btn">Done</button>
31432
32204
  </lr-tool-select-dialog>
32205
+ <script type="module">
32206
+ const dialog = document.querySelector("lr-tool-select-dialog");
32207
+ dialog.tools = [
32208
+ { id: "search", name: "Web search", category: "Research" },
32209
+ { id: "python", name: "Python", category: "Code", description: "Run sandboxed Python" },
32210
+ { id: "admin", name: "Admin console", disabled: true, disabledReason: "Requires admin approval" },
32211
+ ];
32212
+ dialog.selectedToolIds = enabledToolIds;
32213
+ dialog.useDefaults = usingDefaults;
32214
+ dialog.open = true;
32215
+ dialog.addEventListener("lr-change", (e) =>
32216
+ updateTools(e.detail.selectedToolIds, e.detail.useDefaults)
32217
+ );
32218
+ dialog.addEventListener("lr-close", () => (dialog.open = false));
32219
+ dialog.querySelector("#done-btn").addEventListener("click", () => dialog.close("done"));
32220
+ </script>
31433
32221
  ```
31434
32222
 
31435
32223
  `useDefaults` is a single top-level switch: while `true`, every per-tool checkbox renders disabled
@@ -31788,15 +32576,14 @@ other text-entry surface in the library provides), plus shared tokens
31788
32576
  package, not an optional peer.
31789
32577
 
31790
32578
  ```html
31791
- <lr-tool-approval-dialog
31792
- tool-name="send_email"
31793
- .args=${{ to: 'ops@example.com', subject: 'Deploy finished' }}
31794
- @lr-approve=${(e) => runTool(e.detail.args)}
31795
- @lr-deny=${() => console.log('denied')}
31796
- @lr-close=${(e) => console.log('closed:', e.detail)}
31797
- ></lr-tool-approval-dialog>
32579
+ <lr-tool-approval-dialog tool-name="send_email"></lr-tool-approval-dialog>
31798
32580
  <script type="module">
31799
- document.querySelector('lr-tool-approval-dialog').open = true;
32581
+ const dialog = document.querySelector("lr-tool-approval-dialog");
32582
+ dialog.args = { to: "ops@example.com", subject: "Deploy finished" };
32583
+ dialog.addEventListener("lr-approve", (e) => runTool(e.detail.args));
32584
+ dialog.addEventListener("lr-deny", () => console.log("denied"));
32585
+ dialog.addEventListener("lr-close", (e) => console.log("closed:", e.detail));
32586
+ dialog.open = true;
31800
32587
  </script>
31801
32588
  ```
31802
32589
 
@@ -32014,20 +32801,22 @@ form: `--lr-space-l/-xs/-s`, `--lr-color-border`, `--lr-radius`, `--lr-color-sur
32014
32801
  dependencies of this package imported directly, not optional peers.
32015
32802
 
32016
32803
  ```html
32017
- <lr-tool-param-form
32018
- .schema=${{
32019
- type: 'object',
32804
+ <lr-tool-param-form></lr-tool-param-form>
32805
+ <script type="module">
32806
+ const form = document.querySelector("lr-tool-param-form");
32807
+ form.schema = {
32808
+ type: "object",
32020
32809
  properties: {
32021
- title: { type: 'string', title: 'Title' },
32022
- attendees: { type: 'string', enum: ['team', 'everyone'], default: 'team' },
32023
- allDay: { type: 'boolean', title: 'All day' },
32810
+ title: { type: "string", title: "Title" },
32811
+ attendees: { type: "string", enum: ["team", "everyone"], default: "team" },
32812
+ allDay: { type: "boolean", title: "All day" },
32024
32813
  },
32025
- required: ['title'],
32026
- }}
32027
- .value=${draftArgs}
32028
- @lr-input=${(e) => (draftArgs = e.detail.value)}
32029
- @lr-validity-change=${(e) => (formIsValid = e.detail.valid)}
32030
- ></lr-tool-param-form>
32814
+ required: ["title"],
32815
+ };
32816
+ form.value = draftArgs;
32817
+ form.addEventListener("lr-input", (e) => (draftArgs = e.detail.value));
32818
+ form.addEventListener("lr-validity-change", (e) => (formIsValid = e.detail.valid));
32819
+ </script>
32031
32820
  ```
32032
32821
 
32033
32822
  This component owns no Submit/Cancel/Approve chrome — a consumer composes it inside their own dialog
@@ -32419,7 +33208,9 @@ default the component creates a plain-text `Blob`/object URL and activates a syn
32419
33208
  `<a download>`; `preventDefault()` suppresses that built-in download so the host can substitute
32420
33209
  server-side or other handling),
32421
33210
  `lr-follow-change` (`detail: { following }`), `lr-search-change` (`detail: { query, matchCount,
32422
- activeIndex }`), `lr-highlight-activate` (`detail: { highlightId }`), and `lr-text-select` (`detail: {
33211
+ matchCountExact, activeIndex }`; `matchCountExact` is `false` once a search hits the 10,000-match
33212
+ ceiling, marking `matchCount` as a lower bound rather than an exact total),
33213
+ `lr-highlight-activate` (`detail: { highlightId }`), and `lr-text-select` (`detail: {
32423
33214
  text, anchor, rects }`).
32424
33215
 
32425
33216
  **CSS parts:** `base`, `toolbar` (only rendered when copy/download are enabled), `copy-button`,
@@ -32517,9 +33308,11 @@ columns. Consumes the same `LyraSpan[]` as `<lr-span-waterfall>`.
32517
33308
  under `lr-span-waterfall` above (exported from `trace-tree/span.ts`); hierarchy comes from
32518
33309
  `parentId`, and a span whose `parentId` is missing or doesn't resolve within the same array renders
32519
33310
  as a root rather than being dropped. `activeSpanId: string | null = null`
32520
- (attribute `active-span-id`), `label: string = ''`, `showTokens: boolean = false` (attribute
33311
+ (attribute `active-span-id`), `label?: string`, `showTokens: boolean = false` (attribute
32521
33312
  `show-tokens`) — surfaces `tokensIn`/`tokensOut`, `showCost: boolean = false` (attribute
32522
33313
  `show-cost`) — surfaces `costText`, and `hideBars: boolean = false` (attribute `hide-bars`).
33314
+ `label` is an optional accessible-name override for the `role="tree"` element: omission localizes
33315
+ the default, and any supplied string — including `''` — is rendered verbatim.
32523
33316
  Token counts render only when finite and non-negative; invalid metrics are omitted rather than
32524
33317
  reaching `Intl.NumberFormat`. A row's accessible name includes its optional `detail` text as well
32525
33318
  as its name/status/metrics, and updates when the supplied span data changes. Every trace view uses
@@ -32841,9 +33634,13 @@ repainting everything else that reads them.
32841
33634
 
32842
33635
  ```html
32843
33636
  <lr-tool-call-chip status="pending"></lr-tool-call-chip>
32844
- <lr-confirm-bar tool-name="run_shell" .args=${args}
32845
- @lr-approve=${(e) => run(e.detail.args)} @lr-deny=${() => cancel()}
32846
- ></lr-confirm-bar>
33637
+ <lr-confirm-bar tool-name="run_shell"></lr-confirm-bar>
33638
+ <script type="module">
33639
+ const bar = document.querySelector("lr-confirm-bar");
33640
+ bar.args = args;
33641
+ bar.addEventListener("lr-approve", (e) => run(e.detail.args));
33642
+ bar.addEventListener("lr-deny", () => cancel());
33643
+ </script>
32847
33644
  ```
32848
33645
 
32849
33646
  An `lr-approve`/`lr-deny` listener that needs to await its own async work before finalizing calls
@@ -32905,9 +33702,13 @@ phase write queued while detached.
32905
33702
  viewport's aspect ratio.
32906
33703
 
32907
33704
  ```html
32908
- <lr-browser-frame phase="streaming" url="https://example.com" .pings=${pings}
32909
- @lr-take-over=${(e) => setController(e.detail.controller)} @lr-stop=${() => stopSession()}
32910
- ></lr-browser-frame>
33705
+ <lr-browser-frame phase="streaming" url="https://example.com"></lr-browser-frame>
33706
+ <script type="module">
33707
+ const frame = document.querySelector("lr-browser-frame");
33708
+ frame.pings = pings;
33709
+ frame.addEventListener("lr-take-over", (e) => setController(e.detail.controller));
33710
+ frame.addEventListener("lr-stop", () => stopSession());
33711
+ </script>
32911
33712
  ```
32912
33713
 
32913
33714
  **Additional API surface:**
@@ -32981,11 +33782,17 @@ ancestor. They exist because `::part(view-button)[aria-pressed='true']` is inval
32981
33782
  library-wide brand tokens as the only prior lever.
32982
33783
 
32983
33784
  ```html
32984
- <lr-artifact-panel label="report.md" kind="document" .versions=${versions}
32985
- @lr-restore=${(e) => restoreVersion(e.detail.versionId)}>
32986
- <lr-markdown .content=${markdown}></lr-markdown>
32987
- <lr-code-block slot="code" language="markdown" .code=${markdown}></lr-code-block>
33785
+ <lr-artifact-panel label="report.md" kind="document">
33786
+ <lr-markdown id="preview"></lr-markdown>
33787
+ <lr-code-block slot="code" id="code" language="markdown"></lr-code-block>
32988
33788
  </lr-artifact-panel>
33789
+ <script type="module">
33790
+ const panel = document.querySelector("lr-artifact-panel");
33791
+ panel.versions = versions;
33792
+ panel.querySelector("#preview").content = markdown;
33793
+ panel.querySelector("#code").code = markdown;
33794
+ panel.addEventListener("lr-restore", (e) => restoreVersion(e.detail.versionId));
33795
+ </script>
32989
33796
  ```
32990
33797
 
32991
33798
  ## `lr-agent-run`
@@ -33094,7 +33901,9 @@ hierarchical trace tree from one shared `spans` array.
33094
33901
  (`'agent' | 'llm' | 'tool' | 'retriever' | 'embedding' | 'other'`). Empty shows every kind;
33095
33902
  pre-settable (e.g. to hide `retriever`/`embedding` by default) and readable back after
33096
33903
  `lr-span-visibility-change`
33097
- - `label: string = ''` — forwarded to the composed `lr-trace-tree`
33904
+ - `label?: string` — forwarded to the composed `lr-trace-tree`. Omission leaves that tree's own
33905
+ `label` unset so it localizes its own default; any supplied string (including `''`) is
33906
+ forwarded verbatim
33098
33907
  - `showTokens: boolean = false` (attribute `show-tokens`), `showCost: boolean = false` (attribute
33099
33908
  `show-cost`), `showBars: boolean = true` (attribute `show-bars`, renamed from `hideBars` in
33100
33909
  9.0.0 to match the positive polarity of its two siblings above — default inverted so the
@@ -33623,7 +34432,7 @@ persistence.
33623
34432
  `versions: readonly PromptStudioVersion[] = []` is a property-only host-controlled input;
33624
34433
  empty/blank message and version ids are omitted and later duplicates use deterministic first-wins
33625
34434
  identity before rendering, editing, focus, selection, and events;
33626
- `selectedVersionId: string = ''` (attribute `selected-version-id`); `label: string = ''`;
34435
+ `selectedVersionId: string | null = null` (attribute `selected-version-id`); `label: string = ''`;
33627
34436
  `heading: string = ''` — visible toolbar heading, falling back to the localized Prompt Studio
33628
34437
  label when unset;
33629
34438
  `running: boolean = false`, `disabled: boolean = false`, and `reorderable: boolean = false`
@@ -33690,7 +34499,8 @@ It intentionally does not fetch remote references or validate values.
33690
34499
 
33691
34500
  **Properties:** clone-owned, bounded, frozen `schema: JsonSchemaNode | null = null` and
33692
34501
  `issues: readonly SchemaValidationIssue[] = []` (attribute: false); reassign a new schema record or
33693
- issue array after changes. `selectedPath: string = ''` (attribute `selected-path`);
34502
+ issue array after changes. `selectedPath: string | null = null` (attribute `selected-path`)
34503
+ `null` means no selection, while the empty string is the valid JSON Pointer for the schema root;
33694
34504
  `maxDepth: number = 20` (attribute `max-depth`, clamped to 100); `label: string = ''`.
33695
34505
 
33696
34506
  **Exported types:** `JsonSchemaNode` covers `$ref`, type/title/description, properties/items,
@@ -34221,6 +35031,44 @@ These named interfaces and helper signatures are available to typed integrations
34221
35031
 
34222
35032
  # Retrieval, knowledge graph & grounding (`components/retrieval/`)
34223
35033
 
35034
+ ## Breaking changes in 10.0.0
35035
+
35036
+ `lr-entity-card`, `lr-entity-chip` and `lr-neighbor-list` no longer emit `lr-entity-activate`. The
35037
+ canonical name for that gesture is `lr-entity-select` (`detail: { entityId }`), fired from the same
35038
+ gesture with the same detail — only the second spelling is gone. It is removed outright rather than
35039
+ kept as a dual-emitting alias, because the library has no released consumers and an alias is a
35040
+ permanent tax paid to protect users who do not exist. Rename the listener; nothing else changes.
35041
+
35042
+ Two composites narrow with them. `lr-entity-dossier` surfaces its embedded entity card's and
35043
+ neighbor list's gesture as `lr-entity-select` only, and `lr-provenance-panel` does the same for its
35044
+ embedded entity chip. On both, `lr-entity-activate` now reaches a host only from the embedded
35045
+ community card or relationship path strip, which is also the only source of the richer
35046
+ `{ entityId, occurrenceIndex? }` detail — so on these two elements the names now carry different
35047
+ shapes rather than being two spellings of one event.
35048
+
35049
+ `lr-community-card` and `lr-path-strip` keep `lr-entity-activate` unchanged. It is their only name
35050
+ and never was an alias, so do **not** rename those listeners.
35051
+
35052
+ `lr-rag-eval-dashboard` no longer emits `lr-run-select`; listen for `lr-run-change`
35053
+ (`detail: { run }`, unchanged). Same removal, same reason.
35054
+
35055
+ `lr-knowledge-graph-explorer`'s `lr-search-change` detail is now exactly
35056
+ `{ query, matchCount, matchCountExact }`. The old `searchQuery` member is replaced by the canonical
35057
+ `query` rather than carried beside it, so the event finally has the `LyraSearchChangeDetail` shape
35058
+ the rest of the library's search emitters use — read `e.detail.query`. The detail deliberately has no
35059
+ `activeIndex` (this is a live node filter, not a cursor-based search) and `matchCountExact` is always
35060
+ `true`, since that filter has no truncating ceiling. The `searchQuery` **property** is a different
35061
+ member and is unaffected: the component still applies the query to it before emitting, so reassigning
35062
+ it from the handler stays a no-op.
35063
+
35064
+ Also corrected in 10.0.0 — not breaking, but visible. A chip with no `entity-id` renders its button
35065
+ disabled, and now looks it: `lr-entity-chip` used to paint that state pixel-identical to a working
35066
+ chip — full opacity, a hand cursor, complete hover and press feedback for a control that cannot emit
35067
+ anything — and now dims to `--lr-opacity-disabled` with a `not-allowed` cursor and no pointer
35068
+ response. `lr-embedding-explorer`'s selected point has a focus ring again. And
35069
+ `lr-knowledge-graph-explorer` no longer announces on mount: a preset `search-query` used to fire its
35070
+ live region before any user action.
35071
+
34224
35072
  ## Breaking changes in 9.0.0
34225
35073
 
34226
35074
  `lr-graph`'s exported types `GraphLayout`, `GraphRenderer`, `GraphSelectionMode`, `GraphPickKind`, and
@@ -34672,7 +35520,7 @@ only that row's decorative swatch opacity. Also reads `--lr-graph-cat-1` through
34672
35520
 
34673
35521
  A dossier card for one knowledge-graph entity: type badge, description, key/value property rows,
34674
35522
  degree, community chip, plus a built-in "focus in graph" action. Never fetches or focuses a graph
34675
- itself — `lr-entity-activate` is a request a host routes into `lr-graph`'s own
35523
+ itself — `lr-entity-select` is a request a host routes into `lr-graph`'s own
34676
35524
  `focusNode(id, options?)`.
34677
35525
 
34678
35526
  **Properties:**
@@ -34697,7 +35545,7 @@ number; communityId?: string }`; field names deliberately mirror `lr-graph`'s `L
34697
35545
  set — there is nothing left to tighten. The exported alias `EntityCardAppearance` is retained as a
34698
35546
  name for the same union.
34699
35547
 
34700
- **Events:** `lr-entity-activate` (`detail: { entityId }`, the built-in focus button was activated).
35548
+ **Events:** `lr-entity-select` (`detail: { entityId }`, the built-in focus button was activated).
34701
35549
 
34702
35550
  **Slots:** default (extra body content below the property rows, e.g. a `lr-neighbor-list`),
34703
35551
  `actions` (extra header actions alongside the built-in focus button).
@@ -34730,7 +35578,7 @@ from tokens.
34730
35578
  };
34731
35579
  document
34732
35580
  .getElementById("card")
34733
- .addEventListener("lr-entity-activate", (e) =>
35581
+ .addEventListener("lr-entity-select", (e) =>
34734
35582
  graph.focusNode(e.detail.entityId)
34735
35583
  );
34736
35584
  </script>
@@ -34767,7 +35615,7 @@ before the type template is composed, so it never produces a leading punctuation
34767
35615
  `, person`. An authored host `aria-label` intentionally names only the custom-element boundary;
34768
35616
  it is not copied onto the shadow button because host naming does not cross that boundary.
34769
35617
 
34770
- **Events:** `lr-entity-activate` (`detail: { entityId }`, click, or Enter while focused),
35618
+ **Events:** `lr-entity-select` (`detail: { entityId }`, click, or Enter while focused),
34771
35619
  `lr-entity-open` (`detail: { entityId }`, dblclick, or Space while focused).
34772
35620
 
34773
35621
  **Slots:** default — rich preview content (typically a compact `lr-entity-card`), shown in a
@@ -34815,7 +35663,7 @@ graph data) and never mutates a graph.
34815
35663
  - `label: string = ''` — fallback name for the stable group. A non-empty host `aria-label` makes
34816
35664
  the host the sole overall owner; an explicitly empty host label stays empty on the group
34817
35665
 
34818
- **Events:** `lr-entity-activate` (`detail: { entityId }`, a row's node button was activated),
35666
+ **Events:** `lr-entity-select` (`detail: { entityId }`, a row's node button was activated),
34819
35667
  `lr-node-expand` (`detail: { nodeId }`, a row's expand button was activated — deliberately the same
34820
35668
  name and detail shape as `lr-graph`'s own event, so one host handler serves both).
34821
35669
 
@@ -35186,8 +36034,10 @@ chip` row, one `lr-path-strip` per relationship, `lr-community-card`, `lr-chunk-
35186
36034
  **Events:** `lr-toggle` (`detail: { section, expanded }`, a section header was toggled —
35187
36035
  `section` is `'entities' | 'relationships' | 'communities' | 'chunks'`). Because the panel is a
35188
36036
  conduit, every affordance it renders also reaches a listener on the panel itself, and all are
35189
- part of its typed event map: `lr-entity-activate` (`detail: { entityId, occurrenceIndex? }`, from an entity chip, community
35190
- card member, or path-strip node), `lr-entity-open` (`detail: { entityId }`, an entity chip double-click or
36037
+ part of its typed event map: `lr-entity-select` (`detail: { entityId }`, from an entity chip),
36038
+ `lr-entity-activate` (`detail: { entityId, occurrenceIndex? }`, from a community card member or
36039
+ path-strip node — the only name either one emits, and the only one carrying `occurrenceIndex`),
36040
+ `lr-entity-open` (`detail: { entityId }`, an entity chip double-click or
35191
36041
  Space), `lr-drill` (`detail: { communityId }`, a community card's title, drill button, or overflow chip), and
35192
36042
  `lr-relation-activate` (`detail: { relation, sourceNodeId?, targetNodeId?, occurrenceIndex }`, a relationship path-strip
35193
36043
  edge), plus `lr-chunk-open` (`detail: { chunkId, sourceId, anchor? }`) and `lr-expand`
@@ -35582,7 +36432,10 @@ shape?: 'circle' | 'square' | 'diamond' }`, the `lr-graph.nodeTypes` entry shape
35582
36432
  `aria-label` names the dossier as a whole and is not cloned onto the strip
35583
36433
 
35584
36434
  **Events:** declares none of its own. Every composed child's event bubbles through unmodified
35585
- (`composed: true`): `lr-entity-activate` (`detail: { entityId, occurrenceIndex? }`), `lr-node-expand` (`detail: { nodeId }`),
36435
+ (`composed: true`): `lr-entity-select` (`detail: { entityId }`, surfaced from the embedded entity
36436
+ card or neighbor list), `lr-entity-activate` (`detail: { entityId, occurrenceIndex? }` — surfaced
36437
+ from the embedded provenance panel's own community card or relationship path strip, the only
36438
+ source carrying `occurrenceIndex`), `lr-node-expand` (`detail: { nodeId }`),
35586
36439
  `lr-chunk-open` (`detail: { chunkId, sourceId, anchor? }`), `lr-expand` (`detail: { chunkId, expanded }`),
35587
36440
  `lr-toggle` (`detail: { section, expanded }`), and `lr-tab-show`
35588
36441
  (`detail: { tabId: LyraEntityDossierTab }`, where `LyraEntityDossierTab = 'relationships' | 'chunks'
@@ -35877,9 +36730,14 @@ same self-toggle-then-emit contract `lr-graph-legend` uses, so every feature wor
35877
36730
  - `lr-hidden-types-change` (`detail: { hiddenTypes: string[] }`) — a node type's visibility changed
35878
36731
  via the composed legend. Follows the same self-toggle-then-emit contract as `lr-pin-change`/
35879
36732
  `lr-search-change`, so reassigning back is optional.
35880
- - `lr-search-change` (`detail: { searchQuery: string }`) — the user typed in the toolbar's search
35881
- box. Already self-applied before emitting, so reassigning back is optional; a direct host
35882
- assignment to `searchQuery` stays silent.
36733
+ - `lr-search-change` (`detail: { query: string; matchCount: number; matchCountExact: boolean }`) —
36734
+ the user typed in the toolbar's search box. `query` is the canonical `LyraSearchChangeDetail`
36735
+ field name. `matchCount` is the same live node-filter total the result list and its live-region
36736
+ announcement already compute (`0` while the query is empty). `matchCountExact` is always `true` —
36737
+ this component's node filter has no truncating ceiling, unlike a paginated text-search viewer.
36738
+ There is no `activeIndex`: this is a live node filter, not a cursor-based search. The component
36739
+ has already applied the query to its own `searchQuery` property before emitting, so reassigning
36740
+ it back is optional and a direct host assignment stays silent.
35883
36741
  - Bubbling straight through from composed children, unmodified: `lr-node-click`
35884
36742
  (`detail: { nodeId, x, y }`), `lr-link-click` (`detail: { sourceNodeId, targetNodeId, linkId? }`), `lr-community-click`
35885
36743
  (`detail: { communityId }`), `lr-node-expand` (`detail: { nodeId }`, from `lr-graph` and/or `lr-neighbor-list`),
@@ -36483,7 +37341,7 @@ duplicates are omitted first-wins before metric fallback, slice derivation/filte
36483
37341
  history, counts, rendering, or actions.
36484
37342
 
36485
37343
  **Events:** `lr-metric-change` (`{ metricId }`), `lr-slice-change` (`{ slice }`), and
36486
- `lr-run-select` (`{ run }`). All are controlled intents; the component does not mutate the
37344
+ `lr-run-change` (`{ run }`). All are controlled intents; the component does not mutate the
36487
37345
  corresponding selection properties.
36488
37346
 
36489
37347
  **CSS parts:** `base`, `heading`, `slices`, `slice`, `slice-selected`, `metrics`, `metric`,