@aceshooting/lyra-ui 1.2.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/README.md +98 -14
  2. package/custom-elements.json +30279 -12124
  3. package/dist/components/app-rail/app-rail-item.d.ts +30 -0
  4. package/dist/components/app-rail/app-rail-item.js +68 -0
  5. package/dist/components/app-rail/app-rail-item.styles.d.ts +1 -0
  6. package/dist/components/app-rail/app-rail-item.styles.js +65 -0
  7. package/dist/components/app-rail/app-rail.d.ts +168 -0
  8. package/dist/components/app-rail/app-rail.js +419 -0
  9. package/dist/components/app-rail/app-rail.styles.d.ts +1 -0
  10. package/dist/components/app-rail/app-rail.styles.js +128 -0
  11. package/dist/components/attachment-chip/attachment-chip.d.ts +141 -0
  12. package/dist/components/attachment-chip/attachment-chip.js +356 -0
  13. package/dist/components/attachment-chip/attachment-chip.styles.d.ts +1 -0
  14. package/dist/components/attachment-chip/attachment-chip.styles.js +184 -0
  15. package/dist/components/attachment-trigger/attachment-trigger.d.ts +96 -0
  16. package/dist/components/attachment-trigger/attachment-trigger.js +270 -0
  17. package/dist/components/attachment-trigger/attachment-trigger.styles.d.ts +1 -0
  18. package/dist/components/attachment-trigger/attachment-trigger.styles.js +90 -0
  19. package/dist/components/chart/bar-chart.js +2 -18
  20. package/dist/components/chart/box-plot.d.ts +25 -1
  21. package/dist/components/chart/box-plot.js +147 -7
  22. package/dist/components/chart/box-plot.styles.js +13 -0
  23. package/dist/components/chart/bubble-chart.js +2 -18
  24. package/dist/components/chart/chart-loader.d.ts +44 -13
  25. package/dist/components/chart/chart-loader.js +65 -18
  26. package/dist/components/chart/chart.d.ts +55 -12
  27. package/dist/components/chart/chart.js +247 -49
  28. package/dist/components/chart/doughnut-chart.js +2 -18
  29. package/dist/components/chart/histogram-bin.d.ts +7 -1
  30. package/dist/components/chart/histogram-bin.js +32 -14
  31. package/dist/components/chart/histogram.js +8 -16
  32. package/dist/components/chart/line-chart.js +2 -18
  33. package/dist/components/chart/lite-chart.d.ts +134 -3
  34. package/dist/components/chart/lite-chart.js +382 -67
  35. package/dist/components/chart/lite-chart.styles.js +9 -0
  36. package/dist/components/chart/pie-chart.js +2 -18
  37. package/dist/components/chart/polar-area-chart.js +2 -18
  38. package/dist/components/chart/radar-chart.js +2 -18
  39. package/dist/components/chart/scatter-chart.js +2 -18
  40. package/dist/components/chat-composer/chat-composer.d.ts +133 -0
  41. package/dist/components/chat-composer/chat-composer.js +366 -0
  42. package/dist/components/chat-composer/chat-composer.styles.d.ts +1 -0
  43. package/dist/components/chat-composer/chat-composer.styles.js +145 -0
  44. package/dist/components/chat-message/chat-message.d.ts +141 -0
  45. package/dist/components/chat-message/chat-message.js +331 -0
  46. package/dist/components/chat-message/chat-message.styles.d.ts +1 -0
  47. package/dist/components/chat-message/chat-message.styles.js +203 -0
  48. package/dist/components/checkbox/checkbox.d.ts +117 -0
  49. package/dist/components/checkbox/checkbox.js +353 -0
  50. package/dist/components/checkbox/checkbox.styles.d.ts +1 -0
  51. package/dist/components/checkbox/checkbox.styles.js +77 -0
  52. package/dist/components/chip/chip-group.d.ts +56 -0
  53. package/dist/components/chip/chip-group.js +130 -0
  54. package/dist/components/chip/chip-group.styles.d.ts +1 -0
  55. package/dist/components/chip/chip-group.styles.js +57 -0
  56. package/dist/components/chip/chip.d.ts +64 -0
  57. package/dist/components/chip/chip.js +122 -0
  58. package/dist/components/chip/chip.styles.d.ts +1 -0
  59. package/dist/components/chip/chip.styles.js +115 -0
  60. package/dist/components/citation-badge/citation-badge.d.ts +113 -0
  61. package/dist/components/citation-badge/citation-badge.js +318 -0
  62. package/dist/components/citation-badge/citation-badge.styles.d.ts +1 -0
  63. package/dist/components/citation-badge/citation-badge.styles.js +96 -0
  64. package/dist/components/code-block/code-block.d.ts +127 -0
  65. package/dist/components/code-block/code-block.js +382 -0
  66. package/dist/components/code-block/code-block.styles.d.ts +1 -0
  67. package/dist/components/code-block/code-block.styles.js +187 -0
  68. package/dist/components/code-block/code-loader.d.ts +87 -0
  69. package/dist/components/code-block/code-loader.js +142 -0
  70. package/dist/components/combobox/combobox.d.ts +65 -6
  71. package/dist/components/combobox/combobox.js +258 -48
  72. package/dist/components/combobox/combobox.styles.js +3 -3
  73. package/dist/components/combobox/option.d.ts +5 -1
  74. package/dist/components/combobox/option.js +35 -0
  75. package/dist/components/context-meter/context-meter.d.ts +53 -0
  76. package/dist/components/context-meter/context-meter.js +159 -0
  77. package/dist/components/context-meter/context-meter.styles.d.ts +1 -0
  78. package/dist/components/context-meter/context-meter.styles.js +114 -0
  79. package/dist/components/conversation-item/conversation-item.d.ts +125 -0
  80. package/dist/components/conversation-item/conversation-item.js +331 -0
  81. package/dist/components/conversation-item/conversation-item.styles.d.ts +1 -0
  82. package/dist/components/conversation-item/conversation-item.styles.js +155 -0
  83. package/dist/components/date-picker/calendar-core.d.ts +24 -0
  84. package/dist/components/date-picker/calendar-core.js +51 -4
  85. package/dist/components/date-picker/date-input.d.ts +100 -9
  86. package/dist/components/date-picker/date-input.js +383 -66
  87. package/dist/components/date-picker/date-picker.d.ts +35 -4
  88. package/dist/components/date-picker/date-picker.js +171 -44
  89. package/dist/components/dialog/confirm.d.ts +40 -0
  90. package/dist/components/dialog/confirm.js +76 -0
  91. package/dist/components/dialog/dialog.d.ts +129 -0
  92. package/dist/components/dialog/dialog.js +288 -0
  93. package/dist/components/dialog/dialog.styles.d.ts +1 -0
  94. package/dist/components/dialog/dialog.styles.js +96 -0
  95. package/dist/components/dock-panel/dock-panel.d.ts +142 -0
  96. package/dist/components/dock-panel/dock-panel.js +359 -0
  97. package/dist/components/dock-panel/dock-panel.styles.d.ts +1 -0
  98. package/dist/components/dock-panel/dock-panel.styles.js +159 -0
  99. package/dist/components/document-preview/document-preview.d.ts +143 -0
  100. package/dist/components/document-preview/document-preview.js +388 -0
  101. package/dist/components/document-preview/document-preview.styles.d.ts +1 -0
  102. package/dist/components/document-preview/document-preview.styles.js +191 -0
  103. package/dist/components/empty/empty.d.ts +1 -2
  104. package/dist/components/empty/empty.js +18 -12
  105. package/dist/components/empty/empty.styles.js +0 -3
  106. package/dist/components/export-button/csv.js +1 -1
  107. package/dist/components/export-button/export-button.d.ts +12 -0
  108. package/dist/components/export-button/export-button.js +35 -5
  109. package/dist/components/export-button/export-button.styles.js +5 -1
  110. package/dist/components/file-input/accept.js +2 -0
  111. package/dist/components/file-input/file-input.d.ts +10 -1
  112. package/dist/components/file-input/file-input.js +36 -5
  113. package/dist/components/flag/flag.d.ts +29 -13
  114. package/dist/components/flag/flag.js +54 -14
  115. package/dist/components/flag/flag.styles.js +1 -1
  116. package/dist/components/flag/language-map.d.ts +4 -1
  117. package/dist/components/flag/language-map.js +6 -3
  118. package/dist/components/gauge/gauge.d.ts +10 -1
  119. package/dist/components/gauge/gauge.js +41 -13
  120. package/dist/components/generation-status/generation-status.d.ts +117 -0
  121. package/dist/components/generation-status/generation-status.js +327 -0
  122. package/dist/components/generation-status/generation-status.styles.d.ts +1 -0
  123. package/dist/components/generation-status/generation-status.styles.js +84 -0
  124. package/dist/components/graph/graph.d.ts +37 -3
  125. package/dist/components/graph/graph.js +132 -20
  126. package/dist/components/heatmap/calendar-grid.d.ts +19 -7
  127. package/dist/components/heatmap/calendar-grid.js +42 -18
  128. package/dist/components/heatmap/heatmap-scale.d.ts +11 -1
  129. package/dist/components/heatmap/heatmap-scale.js +14 -2
  130. package/dist/components/heatmap/heatmap.d.ts +227 -12
  131. package/dist/components/heatmap/heatmap.js +488 -93
  132. package/dist/components/json-viewer/json-viewer.d.ts +70 -0
  133. package/dist/components/json-viewer/json-viewer.js +361 -0
  134. package/dist/components/json-viewer/json-viewer.styles.d.ts +1 -0
  135. package/dist/components/json-viewer/json-viewer.styles.js +177 -0
  136. package/dist/components/kbd/kbd.d.ts +77 -0
  137. package/dist/components/kbd/kbd.js +231 -0
  138. package/dist/components/kbd/kbd.styles.d.ts +1 -0
  139. package/dist/components/kbd/kbd.styles.js +52 -0
  140. package/dist/components/live-region/live-region.d.ts +90 -0
  141. package/dist/components/live-region/live-region.js +189 -0
  142. package/dist/components/live-region/live-region.styles.d.ts +1 -0
  143. package/dist/components/live-region/live-region.styles.js +10 -0
  144. package/dist/components/map/map.d.ts +32 -7
  145. package/dist/components/map/map.js +133 -32
  146. package/dist/components/markdown/markdown-loader.d.ts +58 -0
  147. package/dist/components/markdown/markdown-loader.js +77 -0
  148. package/dist/components/markdown/markdown.d.ts +119 -0
  149. package/dist/components/markdown/markdown.js +389 -0
  150. package/dist/components/markdown/markdown.styles.d.ts +1 -0
  151. package/dist/components/markdown/markdown.styles.js +88 -0
  152. package/dist/components/media-card/media-card.d.ts +130 -0
  153. package/dist/components/media-card/media-card.js +273 -0
  154. package/dist/components/media-card/media-card.styles.d.ts +1 -0
  155. package/dist/components/media-card/media-card.styles.js +132 -0
  156. package/dist/components/mention-popover/mention-popover.d.ts +203 -0
  157. package/dist/components/mention-popover/mention-popover.js +493 -0
  158. package/dist/components/mention-popover/mention-popover.styles.d.ts +1 -0
  159. package/dist/components/mention-popover/mention-popover.styles.js +101 -0
  160. package/dist/components/menu/menu-item.d.ts +91 -0
  161. package/dist/components/menu/menu-item.js +206 -0
  162. package/dist/components/menu/menu-item.styles.d.ts +1 -0
  163. package/dist/components/menu/menu-item.styles.js +75 -0
  164. package/dist/components/menu/menu.d.ts +167 -0
  165. package/dist/components/menu/menu.js +461 -0
  166. package/dist/components/menu/menu.styles.d.ts +1 -0
  167. package/dist/components/menu/menu.styles.js +67 -0
  168. package/dist/components/model-select/model-select.d.ts +170 -0
  169. package/dist/components/model-select/model-select.js +588 -0
  170. package/dist/components/model-select/model-select.styles.d.ts +1 -0
  171. package/dist/components/model-select/model-select.styles.js +203 -0
  172. package/dist/components/model-settings-panel/model-settings-panel.d.ts +93 -0
  173. package/dist/components/model-settings-panel/model-settings-panel.js +209 -0
  174. package/dist/components/model-settings-panel/model-settings-panel.styles.d.ts +1 -0
  175. package/dist/components/model-settings-panel/model-settings-panel.styles.js +82 -0
  176. package/dist/components/playback/playback.d.ts +19 -3
  177. package/dist/components/playback/playback.js +109 -33
  178. package/dist/components/playback/playback.styles.js +6 -1
  179. package/dist/components/responsive-panel/responsive-panel.d.ts +163 -0
  180. package/dist/components/responsive-panel/responsive-panel.js +363 -0
  181. package/dist/components/responsive-panel/responsive-panel.styles.d.ts +1 -0
  182. package/dist/components/responsive-panel/responsive-panel.styles.js +103 -0
  183. package/dist/components/result-card/result-card.d.ts +50 -0
  184. package/dist/components/result-card/result-card.js +89 -0
  185. package/dist/components/result-card/result-card.styles.d.ts +1 -0
  186. package/dist/components/result-card/result-card.styles.js +49 -0
  187. package/dist/components/result-card/result-field.d.ts +36 -0
  188. package/dist/components/result-card/result-field.js +87 -0
  189. package/dist/components/result-card/result-field.styles.d.ts +1 -0
  190. package/dist/components/result-card/result-field.styles.js +32 -0
  191. package/dist/components/select/select.d.ts +84 -4
  192. package/dist/components/select/select.js +251 -36
  193. package/dist/components/skeleton/skeleton.d.ts +3 -0
  194. package/dist/components/skeleton/skeleton.js +7 -1
  195. package/dist/components/skeleton/skeleton.styles.js +5 -4
  196. package/dist/components/slider/slider.d.ts +141 -0
  197. package/dist/components/slider/slider.js +467 -0
  198. package/dist/components/slider/slider.styles.d.ts +1 -0
  199. package/dist/components/slider/slider.styles.js +87 -0
  200. package/dist/components/source-card/source-card.d.ts +104 -0
  201. package/dist/components/source-card/source-card.js +195 -0
  202. package/dist/components/source-card/source-card.styles.d.ts +1 -0
  203. package/dist/components/source-card/source-card.styles.js +69 -0
  204. package/dist/components/source-list/source-list.d.ts +63 -0
  205. package/dist/components/source-list/source-list.js +130 -0
  206. package/dist/components/source-list/source-list.styles.d.ts +1 -0
  207. package/dist/components/source-list/source-list.styles.js +59 -0
  208. package/dist/components/sparkline/sparkline.js +58 -20
  209. package/dist/components/split/split.d.ts +224 -5
  210. package/dist/components/split/split.js +617 -43
  211. package/dist/components/split/split.styles.js +47 -0
  212. package/dist/components/stat/stat.d.ts +15 -4
  213. package/dist/components/stat/stat.js +53 -12
  214. package/dist/components/stream-status/stream-status.d.ts +126 -0
  215. package/dist/components/stream-status/stream-status.js +292 -0
  216. package/dist/components/stream-status/stream-status.styles.d.ts +1 -0
  217. package/dist/components/stream-status/stream-status.styles.js +103 -0
  218. package/dist/components/streaming-text/streaming-text.d.ts +104 -0
  219. package/dist/components/streaming-text/streaming-text.js +224 -0
  220. package/dist/components/streaming-text/streaming-text.styles.d.ts +1 -0
  221. package/dist/components/streaming-text/streaming-text.styles.js +63 -0
  222. package/dist/components/switch/switch.d.ts +103 -0
  223. package/dist/components/switch/switch.js +250 -0
  224. package/dist/components/switch/switch.styles.d.ts +1 -0
  225. package/dist/components/switch/switch.styles.js +75 -0
  226. package/dist/components/table/table.d.ts +89 -5
  227. package/dist/components/table/table.js +243 -26
  228. package/dist/components/table/table.styles.js +6 -1
  229. package/dist/components/tabs/tabs.d.ts +74 -0
  230. package/dist/components/tabs/tabs.js +254 -0
  231. package/dist/components/tabs/tabs.styles.d.ts +1 -0
  232. package/dist/components/tabs/tabs.styles.js +74 -0
  233. package/dist/components/thinking-panel/thinking-panel.d.ts +123 -0
  234. package/dist/components/thinking-panel/thinking-panel.js +260 -0
  235. package/dist/components/thinking-panel/thinking-panel.styles.d.ts +1 -0
  236. package/dist/components/thinking-panel/thinking-panel.styles.js +123 -0
  237. package/dist/components/time-range/time-range.d.ts +59 -2
  238. package/dist/components/time-range/time-range.js +163 -67
  239. package/dist/components/toast/toast-item.d.ts +12 -2
  240. package/dist/components/toast/toast-item.js +106 -44
  241. package/dist/components/toast/toast-item.styles.js +59 -28
  242. package/dist/components/toast/toast.js +17 -5
  243. package/dist/components/toast/toaster.js +10 -1
  244. package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +131 -0
  245. package/dist/components/tool-approval-dialog/tool-approval-dialog.js +329 -0
  246. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.d.ts +1 -0
  247. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +160 -0
  248. package/dist/components/tool-call-chip/tool-call-chip.d.ts +105 -0
  249. package/dist/components/tool-call-chip/tool-call-chip.js +349 -0
  250. package/dist/components/tool-call-chip/tool-call-chip.styles.d.ts +1 -0
  251. package/dist/components/tool-call-chip/tool-call-chip.styles.js +203 -0
  252. package/dist/components/tool-param-form/tool-param-form.d.ts +206 -0
  253. package/dist/components/tool-param-form/tool-param-form.js +610 -0
  254. package/dist/components/tool-param-form/tool-param-form.styles.d.ts +1 -0
  255. package/dist/components/tool-param-form/tool-param-form.styles.js +75 -0
  256. package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +122 -0
  257. package/dist/components/tool-result-dialog/tool-result-dialog.js +358 -0
  258. package/dist/components/tool-result-dialog/tool-result-dialog.styles.d.ts +1 -0
  259. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +176 -0
  260. package/dist/components/tool-result-view/registry.d.ts +73 -0
  261. package/dist/components/tool-result-view/registry.js +89 -0
  262. package/dist/components/tool-result-view/tool-result-view.d.ts +58 -0
  263. package/dist/components/tool-result-view/tool-result-view.js +152 -0
  264. package/dist/components/tool-result-view/tool-result-view.styles.d.ts +1 -0
  265. package/dist/components/tool-result-view/tool-result-view.styles.js +13 -0
  266. package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +151 -0
  267. package/dist/components/tool-select-dialog/tool-select-dialog.js +350 -0
  268. package/dist/components/tool-select-dialog/tool-select-dialog.styles.d.ts +1 -0
  269. package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +191 -0
  270. package/dist/components/tree/tree-node.d.ts +15 -3
  271. package/dist/components/tree/tree-node.js +20 -7
  272. package/dist/components/tree/tree.d.ts +25 -10
  273. package/dist/components/tree/tree.js +39 -31
  274. package/dist/components/typing-indicator/typing-indicator.d.ts +70 -0
  275. package/dist/components/typing-indicator/typing-indicator.js +108 -0
  276. package/dist/components/typing-indicator/typing-indicator.styles.d.ts +1 -0
  277. package/dist/components/typing-indicator/typing-indicator.styles.js +132 -0
  278. package/dist/components/virtual-list/virtual-list.d.ts +210 -0
  279. package/dist/components/virtual-list/virtual-list.js +607 -0
  280. package/dist/components/virtual-list/virtual-list.styles.d.ts +1 -0
  281. package/dist/components/virtual-list/virtual-list.styles.js +56 -0
  282. package/dist/components/widget/widget.d.ts +5 -4
  283. package/dist/components/widget/widget.js +54 -120
  284. package/dist/components/widget/widget.styles.js +8 -2
  285. package/dist/components/word-cloud/word-cloud-layout.d.ts +7 -0
  286. package/dist/components/word-cloud/word-cloud-layout.js +29 -2
  287. package/dist/components/word-cloud/word-cloud.d.ts +28 -2
  288. package/dist/components/word-cloud/word-cloud.js +69 -19
  289. package/dist/components/word-cloud/word-cloud.styles.js +16 -3
  290. package/dist/internal/anchored-validity.d.ts +1 -0
  291. package/dist/internal/anchored-validity.js +86 -0
  292. package/dist/internal/announcer.d.ts +57 -0
  293. package/dist/internal/announcer.js +71 -0
  294. package/dist/internal/form-associated.d.ts +8 -0
  295. package/dist/internal/form-associated.js +98 -15
  296. package/dist/internal/group-by-recency.d.ts +50 -0
  297. package/dist/internal/group-by-recency.js +80 -0
  298. package/dist/internal/numbers.d.ts +12 -0
  299. package/dist/internal/numbers.js +26 -0
  300. package/dist/internal/overlay-manager.d.ts +51 -0
  301. package/dist/internal/overlay-manager.js +523 -0
  302. package/dist/internal/positioner.js +27 -3
  303. package/dist/internal/rtl.d.ts +23 -0
  304. package/dist/internal/rtl.js +28 -0
  305. package/dist/internal/safe-url.d.ts +12 -0
  306. package/dist/internal/safe-url.js +41 -0
  307. package/dist/internal/scroll-lock.d.ts +10 -5
  308. package/dist/internal/scroll-lock.js +30 -14
  309. package/dist/internal/tokens.styles.js +22 -10
  310. package/dist/lyra.d.ts +133 -31
  311. package/dist/lyra.js +96 -26
  312. package/llms-full.txt +4546 -183
  313. package/llms.txt +21 -5
  314. package/package.json +41 -6
  315. package/dist/components/chart/bar-chart.stories.d.ts +0 -5
  316. package/dist/components/chart/bar-chart.stories.js +0 -20
  317. package/dist/components/chart/box-plot.stories.d.ts +0 -5
  318. package/dist/components/chart/box-plot.stories.js +0 -29
  319. package/dist/components/chart/bubble-chart.stories.d.ts +0 -5
  320. package/dist/components/chart/bubble-chart.stories.js +0 -26
  321. package/dist/components/chart/chart.stories.d.ts +0 -32
  322. package/dist/components/chart/chart.stories.js +0 -141
  323. package/dist/components/chart/doughnut-chart.stories.d.ts +0 -5
  324. package/dist/components/chart/doughnut-chart.stories.js +0 -26
  325. package/dist/components/chart/histogram.stories.d.ts +0 -5
  326. package/dist/components/chart/histogram.stories.js +0 -17
  327. package/dist/components/chart/line-chart.stories.d.ts +0 -22
  328. package/dist/components/chart/line-chart.stories.js +0 -99
  329. package/dist/components/chart/lite-chart.stories.d.ts +0 -14
  330. package/dist/components/chart/lite-chart.stories.js +0 -114
  331. package/dist/components/chart/pie-chart.stories.d.ts +0 -5
  332. package/dist/components/chart/pie-chart.stories.js +0 -26
  333. package/dist/components/chart/polar-area-chart.stories.d.ts +0 -5
  334. package/dist/components/chart/polar-area-chart.stories.js +0 -20
  335. package/dist/components/chart/radar-chart.stories.d.ts +0 -5
  336. package/dist/components/chart/radar-chart.stories.js +0 -20
  337. package/dist/components/chart/scatter-chart.stories.d.ts +0 -5
  338. package/dist/components/chart/scatter-chart.stories.js +0 -31
  339. package/dist/components/combobox/combobox.stories.d.ts +0 -24
  340. package/dist/components/combobox/combobox.stories.js +0 -102
  341. package/dist/components/date-picker/date-input.stories.d.ts +0 -10
  342. package/dist/components/date-picker/date-input.stories.js +0 -48
  343. package/dist/components/date-picker/date-picker.stories.d.ts +0 -10
  344. package/dist/components/date-picker/date-picker.stories.js +0 -25
  345. package/dist/components/empty/empty.stories.d.ts +0 -7
  346. package/dist/components/empty/empty.stories.js +0 -34
  347. package/dist/components/export-button/export-button.stories.d.ts +0 -7
  348. package/dist/components/export-button/export-button.stories.js +0 -37
  349. package/dist/components/file-input/file-input.stories.d.ts +0 -7
  350. package/dist/components/file-input/file-input.stories.js +0 -19
  351. package/dist/components/flag/flag.stories.d.ts +0 -6
  352. package/dist/components/flag/flag.stories.js +0 -31
  353. package/dist/components/gauge/gauge.stories.d.ts +0 -8
  354. package/dist/components/gauge/gauge.stories.js +0 -19
  355. package/dist/components/graph/graph.stories.d.ts +0 -8
  356. package/dist/components/graph/graph.stories.js +0 -68
  357. package/dist/components/heatmap/heatmap.stories.d.ts +0 -27
  358. package/dist/components/heatmap/heatmap.stories.js +0 -179
  359. package/dist/components/map/map.stories.d.ts +0 -15
  360. package/dist/components/map/map.stories.js +0 -135
  361. package/dist/components/playback/playback.stories.d.ts +0 -7
  362. package/dist/components/playback/playback.stories.js +0 -16
  363. package/dist/components/select/select.stories.d.ts +0 -21
  364. package/dist/components/select/select.stories.js +0 -91
  365. package/dist/components/skeleton/skeleton.stories.d.ts +0 -5
  366. package/dist/components/skeleton/skeleton.stories.js +0 -16
  367. package/dist/components/sparkline/sparkline.stories.d.ts +0 -11
  368. package/dist/components/sparkline/sparkline.stories.js +0 -39
  369. package/dist/components/split/split.stories.d.ts +0 -7
  370. package/dist/components/split/split.stories.js +0 -36
  371. package/dist/components/stat/stat.stories.d.ts +0 -9
  372. package/dist/components/stat/stat.stories.js +0 -81
  373. package/dist/components/table/table.stories.d.ts +0 -12
  374. package/dist/components/table/table.stories.js +0 -67
  375. package/dist/components/time-range/time-range.stories.d.ts +0 -8
  376. package/dist/components/time-range/time-range.stories.js +0 -26
  377. package/dist/components/toast/toast.stories.d.ts +0 -8
  378. package/dist/components/toast/toast.stories.js +0 -72
  379. package/dist/components/tree/tree.stories.d.ts +0 -9
  380. package/dist/components/tree/tree.stories.js +0 -52
  381. package/dist/components/widget/widget.stories.d.ts +0 -9
  382. package/dist/components/widget/widget.stories.js +0 -74
  383. package/dist/components/word-cloud/word-cloud.stories.d.ts +0 -10
  384. package/dist/components/word-cloud/word-cloud.stories.js +0 -55
@@ -42,18 +42,19 @@ export declare class LyraWidget extends LyraElement {
42
42
  compact: boolean;
43
43
  private hasActionsSlot;
44
44
  private releaseScrollLock?;
45
- private lastTrigger?;
45
+ private overlayHandle?;
46
+ private explicitTrigger?;
46
47
  private readonly bodyId;
47
48
  protected willUpdate(changed: PropertyValues): void;
48
49
  protected updated(changed: PropertyValues): void;
49
50
  connectedCallback(): void;
50
51
  disconnectedCallback(): void;
52
+ private activateFullscreenOverlay;
53
+ private deactivateFullscreenOverlay;
51
54
  private onActionsSlotChange;
52
55
  private toggleCollapsed;
53
56
  private toggleFullscreen;
54
- private onDocKeyDown;
55
- private getFocusableElements;
56
- private getActiveElement;
57
+ private dismissFullscreen;
57
58
  private onBackdropClick;
58
59
  render(): TemplateResult;
59
60
  }
@@ -7,47 +7,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { html, nothing } from 'lit';
8
8
  import { property, state } from 'lit/decorators.js';
9
9
  import { LyraElement } from '../../internal/lyra-element.js';
10
+ import { activateOverlay, collectFocusableElements, deepActiveElement, } from '../../internal/overlay-manager.js';
10
11
  import { defineElement } from '../../internal/prefix.js';
11
12
  import { lockScroll } from '../../internal/scroll-lock.js';
12
13
  import { nextId } from '../../internal/a11y.js';
13
14
  import { chevronIcon, closeIcon, expandIcon } from '../../internal/icons.js';
14
15
  import { styles } from './widget.styles.js';
15
- const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
16
- // Shadow-piercing so a slotted custom element's real focusable target (e.g.
17
- // an <input> inside its own shadow root) is found even though the host tag
18
- // itself doesn't match FOCUSABLE_SELECTOR.
19
- function collectFocusable(el) {
20
- const result = [];
21
- if (el.matches(FOCUSABLE_SELECTOR)) {
22
- result.push(el);
23
- }
24
- if (el instanceof HTMLSlotElement) {
25
- for (const assigned of el.assignedElements({ flatten: true })) {
26
- result.push(...collectFocusable(assigned));
27
- }
28
- return result;
29
- }
30
- const container = el.shadowRoot ?? el;
31
- for (const child of Array.from(container.children)) {
32
- result.push(...collectFocusable(child));
33
- }
34
- return result;
35
- }
36
- /**
37
- * Whether `el` is actually laid out/paintable — used to drop e.g. a
38
- * `[collapsed]` body's slotted content from the fullscreen tab order.
39
- * `el.offsetParent !== null` is the usual shorthand for this, but it's
40
- * unreliable here: it resolves `null` for an element whose nearest
41
- * *positioned* ancestor (fullscreen's `[part="base"] { position: fixed }`)
42
- * lives across a slot-projection boundary from the element itself (true for
43
- * every element this scans, since they're all slotted content), even though
44
- * the element is genuinely rendered. `checkVisibility()` (falling back to
45
- * `getClientRects().length` on engines without it) correctly follows
46
- * flattened-tree/slot assignment instead.
47
- */
48
- function isRendered(el) {
49
- return el.checkVisibility ? el.checkVisibility() : el.getClientRects().length > 0;
50
- }
51
16
  /**
52
17
  * `<lyra-widget>` — a titled panel shell with an optional collapse toggle and
53
18
  * an optional fullscreen-expand toggle. Fullscreen promotes the same host
@@ -99,48 +64,19 @@ export class LyraWidget extends LyraElement {
99
64
  this.emit('lyra-collapse-change', this.collapsed);
100
65
  };
101
66
  this.toggleFullscreen = (e) => {
102
- this.lastTrigger = e.currentTarget;
67
+ if (!this.fullscreen)
68
+ this.explicitTrigger = e.currentTarget;
103
69
  this.fullscreen = !this.fullscreen;
104
70
  this.emit('lyra-fullscreen-change', this.fullscreen);
105
- if (!this.fullscreen) {
106
- this.lastTrigger?.focus();
107
- }
108
71
  };
109
- this.onDocKeyDown = (e) => {
110
- if (!this.fullscreen)
111
- return;
112
- if (e.key === 'Escape') {
113
- e.preventDefault();
114
- this.fullscreen = false;
115
- this.emit('lyra-fullscreen-change', false);
116
- this.lastTrigger?.focus();
117
- return;
118
- }
119
- if (e.key !== 'Tab')
120
- return;
121
- const focusable = this.getFocusableElements();
122
- if (focusable.length === 0) {
123
- e.preventDefault();
124
- return;
125
- }
126
- const first = focusable[0];
127
- const last = focusable[focusable.length - 1];
128
- const active = this.getActiveElement();
129
- if (e.shiftKey && active === first) {
130
- e.preventDefault();
131
- last.focus();
132
- }
133
- else if (!e.shiftKey && active === last) {
134
- e.preventDefault();
135
- first.focus();
136
- }
137
- };
138
- this.onBackdropClick = () => {
72
+ this.dismissFullscreen = () => {
139
73
  if (!this.fullscreen)
140
74
  return;
141
75
  this.fullscreen = false;
142
76
  this.emit('lyra-fullscreen-change', false);
143
- this.lastTrigger?.focus();
77
+ };
78
+ this.onBackdropClick = () => {
79
+ this.overlayHandle?.dismissBackdrop();
144
80
  };
145
81
  }
146
82
  static { this.styles = [LyraElement.styles, styles]; }
@@ -150,13 +86,10 @@ export class LyraWidget extends LyraElement {
150
86
  }
151
87
  if (changed.has('fullscreen')) {
152
88
  if (this.fullscreen) {
153
- this.releaseScrollLock = lockScroll();
154
- document.addEventListener('keydown', this.onDocKeyDown);
89
+ this.activateFullscreenOverlay();
155
90
  }
156
91
  else {
157
- this.releaseScrollLock?.();
158
- this.releaseScrollLock = undefined;
159
- document.removeEventListener('keydown', this.onDocKeyDown);
92
+ this.deactivateFullscreenOverlay();
160
93
  }
161
94
  }
162
95
  }
@@ -167,14 +100,23 @@ export class LyraWidget extends LyraElement {
167
100
  // because a mouse click natively focuses the button that triggered it --
168
101
  // not true for a directly-set `fullscreen` property, and not guaranteed
169
102
  // for every input method/browser even in the click case.
103
+ //
104
+ // The `collapsed` branch covers the same modal-focus-trap requirement for
105
+ // a second case: collapsing the body while fullscreen hides (display:none)
106
+ // whatever was focused inside it, which the browser resolves by silently
107
+ // moving focus outside the panel. The shared manager then reclaims it while
108
+ // preserving focus that is still on one of the visible header controls.
170
109
  updated(changed) {
171
110
  if (changed.has('fullscreen') && this.fullscreen) {
172
- const first = this.getFocusableElements()[0];
173
- if (first) {
174
- first.focus();
175
- }
176
- else {
177
- this.shadowRoot?.querySelector('[part="base"]')?.focus();
111
+ this.overlayHandle?.focusInitial();
112
+ }
113
+ else if (changed.has('collapsed') && this.fullscreen) {
114
+ const panel = this.shadowRoot?.querySelector('[part="base"]');
115
+ const active = deepActiveElement(this.ownerDocument);
116
+ if (panel && !collectFocusableElements(panel).includes(active)) {
117
+ if (active && typeof active.blur === 'function')
118
+ active.blur();
119
+ this.overlayHandle?.focusInitial();
178
120
  }
179
121
  }
180
122
  }
@@ -183,49 +125,42 @@ export class LyraWidget extends LyraElement {
183
125
  // A reconnect (e.g. a drag-and-drop reparent that keeps this same
184
126
  // element instance) fires disconnectedCallback then connectedCallback
185
127
  // synchronously with no update in between, so willUpdate never reruns
186
- // to notice `fullscreen` is still true. Restore the scroll lock/trap it
187
- // dropped. `hasUpdated` excludes the initial mount, where willUpdate's
188
- // first pass already establishes them from the starting property value.
189
- if (this.hasUpdated && this.fullscreen && !this.releaseScrollLock) {
190
- this.releaseScrollLock = lockScroll();
191
- document.addEventListener('keydown', this.onDocKeyDown);
128
+ // to notice `fullscreen` is still true. Restore the shared overlay
129
+ // registration and scroll lock it dropped.
130
+ if (this.hasUpdated && this.fullscreen) {
131
+ if (this.overlayHandle?.isActive()) {
132
+ this.overlayHandle.resume();
133
+ }
134
+ else {
135
+ this.activateFullscreenOverlay();
136
+ }
137
+ if (!this.releaseScrollLock)
138
+ this.releaseScrollLock = lockScroll(this.ownerDocument);
139
+ queueMicrotask(() => this.overlayHandle?.focusInitial());
192
140
  }
193
141
  }
194
142
  disconnectedCallback() {
195
143
  super.disconnectedCallback();
196
144
  this.releaseScrollLock?.();
197
145
  this.releaseScrollLock = undefined;
198
- document.removeEventListener('keydown', this.onDocKeyDown);
146
+ this.overlayHandle?.suspend();
199
147
  }
200
- // Bounds Tab/Shift+Tab to the panel while fullscreen (a modal presentation)
201
- // so keyboard focus can't escape to page content hidden behind the
202
- // backdrop. Order follows the header's actions slot, then the collapse/
203
- // fullscreen buttons, then the body slot -- the same order the flattened
204
- // tree already tabs through.
205
- getFocusableElements() {
206
- const root = this.shadowRoot;
207
- if (!root)
208
- return [];
209
- const fromSlot = (selector) => {
210
- const slot = root.querySelector(selector);
211
- return slot ? slot.assignedElements({ flatten: true }).flatMap(collectFocusable) : [];
212
- };
213
- const shadowButtons = Array.from(root.querySelectorAll('[part="collapse-button"], [part="fullscreen-button"]'));
214
- return [
215
- ...fromSlot('slot[name="actions"]'),
216
- ...shadowButtons,
217
- ...fromSlot('[part="body"] slot:not([name])'),
218
- ].filter(isRendered);
148
+ activateFullscreenOverlay() {
149
+ this.releaseScrollLock ??= lockScroll(this.ownerDocument);
150
+ this.overlayHandle = activateOverlay({
151
+ host: this,
152
+ panel: () => this.shadowRoot?.querySelector('[part="base"]') ?? null,
153
+ onEscape: this.dismissFullscreen,
154
+ onBackdrop: this.dismissFullscreen,
155
+ restoreFocusTo: this.explicitTrigger,
156
+ });
157
+ this.explicitTrigger = undefined;
219
158
  }
220
- getActiveElement() {
221
- let active = document.activeElement;
222
- while (active) {
223
- const inner = active.shadowRoot?.activeElement ?? null;
224
- if (!inner)
225
- break;
226
- active = inner;
227
- }
228
- return active;
159
+ deactivateFullscreenOverlay() {
160
+ this.releaseScrollLock?.();
161
+ this.releaseScrollLock = undefined;
162
+ this.overlayHandle?.deactivate();
163
+ this.overlayHandle = undefined;
229
164
  }
230
165
  render() {
231
166
  const hasLabel = this.label.length > 0;
@@ -261,11 +196,10 @@ export class LyraWidget extends LyraElement {
261
196
  aria-expanded=${this.collapsed ? 'false' : 'true'}
262
197
  aria-label=${this.collapsed ? 'Expand panel' : 'Collapse panel'}
263
198
  aria-controls=${this.bodyId}
199
+ style="transform:rotate(${this.collapsed ? '0deg' : '90deg'})"
264
200
  @click=${this.toggleCollapsed}
265
201
  >
266
- <span style="display:inline-flex;transform:rotate(${this.collapsed ? '0deg' : '90deg'})"
267
- >${chevronIcon()}</span
268
- >
202
+ ${chevronIcon()}
269
203
  </button>`
270
204
  : nothing}
271
205
  ${this.expandable
@@ -29,6 +29,12 @@ export const styles = css `
29
29
  flex: 1 1 auto;
30
30
  min-inline-size: 0;
31
31
  }
32
+ [part='label'],
33
+ [part='sublabel'] {
34
+ overflow: hidden;
35
+ text-overflow: ellipsis;
36
+ white-space: nowrap;
37
+ }
32
38
  [part='label'] {
33
39
  font-weight: 600;
34
40
  }
@@ -80,12 +86,12 @@ export const styles = css `
80
86
  position: fixed;
81
87
  inset: var(--lyra-widget-fullscreen-inset, 0);
82
88
  background: var(--lyra-widget-overlay-color);
83
- z-index: 999;
89
+ z-index: var(--lyra-overlay-stack-index, 1000);
84
90
  }
85
91
  :host([fullscreen]) [part='base'] {
86
92
  position: fixed;
87
93
  inset: var(--lyra-widget-fullscreen-inset);
88
- z-index: 1000;
94
+ z-index: calc(var(--lyra-overlay-stack-index, 1000) + 1);
89
95
  box-shadow: var(--lyra-shadow);
90
96
  }
91
97
  :host([fullscreen]) [part='body'] {
@@ -52,6 +52,13 @@ export interface WordCloudLayoutResult {
52
52
  }
53
53
  /** DOM-node/compute-time safety cap — mirrors lyra-sparkline's `MAX_BARS`. */
54
54
  export declare const MAX_WORDS = 150;
55
+ /** Largest accepted font size in CSS pixels. This keeps measurement and
56
+ * placement geometry finite enough for an interactive render even when a
57
+ * caller supplies an otherwise-valid but impractically large number. */
58
+ export declare const MAX_FONT_SIZE_PX = 512;
59
+ /** Maximum number of candidate positions tested for any one word. Together
60
+ * with `MAX_WORDS`, this puts a hard upper bound on spiral-search work. */
61
+ export declare const MAX_SPIRAL_ITERATIONS = 4096;
55
62
  /** Minimum gap enforced both between placed words and around the returned bounding box. */
56
63
  export declare const GAP = 3;
57
64
  /**
@@ -1,5 +1,12 @@
1
1
  /** DOM-node/compute-time safety cap — mirrors lyra-sparkline's `MAX_BARS`. */
2
2
  export const MAX_WORDS = 150;
3
+ /** Largest accepted font size in CSS pixels. This keeps measurement and
4
+ * placement geometry finite enough for an interactive render even when a
5
+ * caller supplies an otherwise-valid but impractically large number. */
6
+ export const MAX_FONT_SIZE_PX = 512;
7
+ /** Maximum number of candidate positions tested for any one word. Together
8
+ * with `MAX_WORDS`, this puts a hard upper bound on spiral-search work. */
9
+ export const MAX_SPIRAL_ITERATIONS = 4096;
3
10
  /** Minimum gap enforced both between placed words and around the returned bounding box. */
4
11
  export const GAP = 3;
5
12
  const ROTATE_PROBABILITY = 0.25;
@@ -9,6 +16,23 @@ const RADIUS_STEP_PER_RADIAN = 3;
9
16
  * generous enough that only a pathological input (e.g. one giant word
10
17
  * repeated many times) ever exhausts it. */
11
18
  const MAX_RADIUS_AREA_FACTOR = 6;
19
+ /** Fallback used by `resolveFontSizeBounds()` for any non-finite/non-positive
20
+ * `minFontSize`/`maxFontSize` input. */
21
+ const MIN_SANE_FONT_SIZE = 1;
22
+ /** Normalizes possibly-invalid minFontSize/maxFontSize into a finite,
23
+ * positive, bounded, correctly-ordered pair — non-finite/negative inputs
24
+ * fall back to MIN_SANE_FONT_SIZE, huge finite values are capped, and a
25
+ * reversed pair (max < min) is swapped rather than left to invert the
26
+ * weight-to-size mapping. */
27
+ function resolveFontSizeBounds(minFontSize, maxFontSize) {
28
+ const min = Number.isFinite(minFontSize) && minFontSize > 0
29
+ ? Math.min(minFontSize, MAX_FONT_SIZE_PX)
30
+ : MIN_SANE_FONT_SIZE;
31
+ const max = Number.isFinite(maxFontSize) && maxFontSize > 0
32
+ ? Math.min(maxFontSize, MAX_FONT_SIZE_PX)
33
+ : MIN_SANE_FONT_SIZE;
34
+ return min <= max ? [min, max] : [max, min];
35
+ }
12
36
  /** Clamps a (possibly negative/non-finite) input weight for scale math only —
13
37
  * never fed back to callers, who should still see their own original `weight`. */
14
38
  function effectiveWeight(weight) {
@@ -29,7 +53,8 @@ function rectsOverlap(ax, ay, aw, ah, bx, by, bw, bh) {
29
53
  * any word already placed). Deterministic given a deterministic `random`.
30
54
  */
31
55
  export function layoutWordCloud(words, options) {
32
- const { minFontSize, maxFontSize, scale, orientations, measureText } = options;
56
+ const { scale, orientations, measureText } = options;
57
+ const [minFontSize, maxFontSize] = resolveFontSizeBounds(options.minFontSize, options.maxFontSize);
33
58
  const random = options.random ?? Math.random;
34
59
  const skipped = [];
35
60
  const decorated = words
@@ -76,7 +101,9 @@ export function layoutWordCloud(words, options) {
76
101
  let x = 0;
77
102
  let y = 0;
78
103
  let foundSpot = placed.length === 0;
79
- while (!foundSpot && radius < maxRadius) {
104
+ let iterations = 0;
105
+ while (!foundSpot && radius < maxRadius && iterations < MAX_SPIRAL_ITERATIONS) {
106
+ iterations++;
80
107
  x = radius * Math.cos(theta);
81
108
  y = radius * Math.sin(theta);
82
109
  let collides = false;
@@ -16,12 +16,19 @@ export type { WordCloudWord };
16
16
  * Instead, like `lyra-heatmap`'s cells, the whole `[part="svg"]` is one tab
17
17
  * stop with roving arrow-key focus (Home/End jump to the first/last word,
18
18
  * Enter/Space activates the focused one), a drawn `[part="focus-ring"]`, and
19
- * a visually-hidden `aria-live="polite"` status announcement.
19
+ * a visually-hidden `aria-live="polite"` status announcement. The SVG focus
20
+ * target carries the group role and accessible name so the semantics follow
21
+ * the element a keyboard user actually focuses.
20
22
  *
21
23
  * @customElement lyra-word-cloud
22
24
  * @event lyra-word-click - Fired on click, or Enter/Space on the focused word.
23
25
  * `detail: { text, weight, group }`.
24
- * @csspart base, svg, word, focus-ring, live-region, empty
26
+ * @csspart base - The word-cloud wrapper.
27
+ * @csspart svg - The word-cloud SVG.
28
+ * @csspart word - A rendered word.
29
+ * @csspart focus-ring - The keyboard focus ring.
30
+ * @csspart live-region - The visually hidden announcement region.
31
+ * @csspart empty - The empty-state message.
25
32
  */
26
33
  export declare class LyraWordCloud extends LyraElement {
27
34
  static styles: import("lit").CSSResultGroup[];
@@ -43,6 +50,19 @@ export declare class LyraWordCloud extends LyraElement {
43
50
  private focusedIndex;
44
51
  /** Text of the visually-hidden `aria-live="polite"` status announcement. */
45
52
  private liveText;
53
+ /**
54
+ * Whether `role`/`aria-label` were present on the host *before* this
55
+ * element's own code ever wrote to them -- snapshotted once, in the very
56
+ * first `willUpdate()` (guarded by `hasUpdated`, which Lit only flips to
57
+ * `true` after that first update commits). Re-checking `hasAttribute()` on
58
+ * every update instead would self-poison: once this element writes its own
59
+ * default `aria-label` on the first render, `hasAttribute('aria-label')` is
60
+ * permanently `true` afterwards, which would wrongly look like an
61
+ * author-supplied value and freeze the label instead of refreshing it as
62
+ * `words` changes on later updates.
63
+ */
64
+ private authorSuppliedRole;
65
+ private authorSuppliedAriaLabel;
46
66
  private measureText;
47
67
  private fontFamily;
48
68
  private paletteColors;
@@ -50,6 +70,12 @@ export declare class LyraWordCloud extends LyraElement {
50
70
  * independent of the weight-sorted placement order. */
51
71
  private navOrder;
52
72
  protected willUpdate(changed: PropertyValues): void;
73
+ private relayout;
74
+ /** Forces a relayout so the font-family theme token (`--lyra-font`) is
75
+ * re-read from computed style — mirrors `lyra-chart`'s `refreshTheme()`.
76
+ * No global theme-broadcast event exists in lyra-ui to subscribe to
77
+ * automatically; call this from a consumer's own theme-toggle handler. */
78
+ refreshTheme(): void;
53
79
  private activate;
54
80
  private announce;
55
81
  private onWordClick;
@@ -53,12 +53,19 @@ function warnSkippedWords(count) {
53
53
  * Instead, like `lyra-heatmap`'s cells, the whole `[part="svg"]` is one tab
54
54
  * stop with roving arrow-key focus (Home/End jump to the first/last word,
55
55
  * Enter/Space activates the focused one), a drawn `[part="focus-ring"]`, and
56
- * a visually-hidden `aria-live="polite"` status announcement.
56
+ * a visually-hidden `aria-live="polite"` status announcement. The SVG focus
57
+ * target carries the group role and accessible name so the semantics follow
58
+ * the element a keyboard user actually focuses.
57
59
  *
58
60
  * @customElement lyra-word-cloud
59
61
  * @event lyra-word-click - Fired on click, or Enter/Space on the focused word.
60
62
  * `detail: { text, weight, group }`.
61
- * @csspart base, svg, word, focus-ring, live-region, empty
63
+ * @csspart base - The word-cloud wrapper.
64
+ * @csspart svg - The word-cloud SVG.
65
+ * @csspart word - A rendered word.
66
+ * @csspart focus-ring - The keyboard focus ring.
67
+ * @csspart live-region - The visually hidden announcement region.
68
+ * @csspart empty - The empty-state message.
62
69
  */
63
70
  export class LyraWordCloud extends LyraElement {
64
71
  constructor() {
@@ -78,6 +85,19 @@ export class LyraWordCloud extends LyraElement {
78
85
  this.focusedIndex = null;
79
86
  /** Text of the visually-hidden `aria-live="polite"` status announcement. */
80
87
  this.liveText = '';
88
+ /**
89
+ * Whether `role`/`aria-label` were present on the host *before* this
90
+ * element's own code ever wrote to them -- snapshotted once, in the very
91
+ * first `willUpdate()` (guarded by `hasUpdated`, which Lit only flips to
92
+ * `true` after that first update commits). Re-checking `hasAttribute()` on
93
+ * every update instead would self-poison: once this element writes its own
94
+ * default `aria-label` on the first render, `hasAttribute('aria-label')` is
95
+ * permanently `true` afterwards, which would wrongly look like an
96
+ * author-supplied value and freeze the label instead of refreshing it as
97
+ * `words` changes on later updates.
98
+ */
99
+ this.authorSuppliedRole = false;
100
+ this.authorSuppliedAriaLabel = false;
81
101
  this.measureText = (text, fontSize) => {
82
102
  const ctx = getScratchCtx();
83
103
  if (!ctx)
@@ -150,22 +170,44 @@ export class LyraWordCloud extends LyraElement {
150
170
  changed.has('maxFontSize') ||
151
171
  changed.has('scale') ||
152
172
  changed.has('orientations')) {
153
- this.cachedLayout = layoutWordCloud(this.words, {
154
- minFontSize: this.minFontSize,
155
- maxFontSize: this.maxFontSize,
156
- scale: this.scale,
157
- orientations: this.orientations,
158
- measureText: this.measureText,
159
- });
160
- if (this.cachedLayout.skipped.length > 0)
161
- warnSkippedWords(this.cachedLayout.skipped.length);
162
- // The previous focus cursor may no longer address a real word once the
163
- // data changes out from under it.
164
- this.focusedIndex = null;
165
- this.liveText = '';
173
+ this.relayout();
166
174
  }
167
- this.setAttribute('role', 'group');
168
- this.setAttribute('aria-label', `Word cloud of ${this.words.length} word${this.words.length === 1 ? '' : 's'}`);
175
+ if (!this.hasUpdated) {
176
+ this.authorSuppliedRole = this.hasAttribute('role');
177
+ this.authorSuppliedAriaLabel = this.hasAttribute('aria-label');
178
+ }
179
+ // Only default role/aria-label when the author hasn't already supplied
180
+ // one -- unconditionally overwriting them on every update (including
181
+ // ones triggered purely by a `words` re-layout) would silently clobber a
182
+ // host's own accessible name/role on the very next data refresh.
183
+ if (!this.authorSuppliedRole)
184
+ this.setAttribute('role', 'group');
185
+ if (!this.authorSuppliedAriaLabel) {
186
+ this.setAttribute('aria-label', `Word cloud of ${this.cachedLayout.placed.length} word${this.cachedLayout.placed.length === 1 ? '' : 's'}`);
187
+ }
188
+ }
189
+ relayout() {
190
+ this.cachedLayout = layoutWordCloud(this.words, {
191
+ minFontSize: this.minFontSize,
192
+ maxFontSize: this.maxFontSize,
193
+ scale: this.scale,
194
+ orientations: this.orientations,
195
+ measureText: this.measureText,
196
+ });
197
+ if (this.cachedLayout.skipped.length > 0)
198
+ warnSkippedWords(this.cachedLayout.skipped.length);
199
+ // The previous focus cursor may no longer address a real word once the
200
+ // data changes out from under it.
201
+ this.focusedIndex = null;
202
+ this.liveText = '';
203
+ }
204
+ /** Forces a relayout so the font-family theme token (`--lyra-font`) is
205
+ * re-read from computed style — mirrors `lyra-chart`'s `refreshTheme()`.
206
+ * No global theme-broadcast event exists in lyra-ui to subscribe to
207
+ * automatically; call this from a consumer's own theme-toggle handler. */
208
+ refreshTheme() {
209
+ this.relayout();
210
+ this.requestUpdate();
169
211
  }
170
212
  activate(word) {
171
213
  this.emit('lyra-word-click', { text: word.text, weight: word.weight, group: word.group });
@@ -206,7 +248,15 @@ export class LyraWordCloud extends LyraElement {
206
248
  const ring = focused ? this.focusRingRect(focused) : undefined;
207
249
  return html `
208
250
  <div part="base">
209
- <svg part="svg" tabindex="0" viewBox="0 0 ${layout.width} ${layout.height}" @keydown=${this.onKeyDown}>
251
+ <svg
252
+ part="svg"
253
+ role="group"
254
+ aria-label=${this.getAttribute('aria-label') ?? nothing}
255
+ aria-describedby="live-region"
256
+ tabindex="0"
257
+ viewBox="0 0 ${layout.width} ${layout.height}"
258
+ @keydown=${this.onKeyDown}
259
+ >
210
260
  ${layout.placed.map((w) => svg `<text
211
261
  part="word"
212
262
  x=${w.x}
@@ -220,7 +270,7 @@ export class LyraWordCloud extends LyraElement {
220
270
  ? svg `<rect part="focus-ring" x=${ring.x} y=${ring.y} width=${ring.width} height=${ring.height}></rect>`
221
271
  : ''}
222
272
  </svg>
223
- <div part="live-region" class="sr-only" role="status" aria-live="polite">${this.liveText}</div>
273
+ <div id="live-region" part="live-region" class="sr-only" role="status" aria-live="polite">${this.liveText}</div>
224
274
  </div>
225
275
  `;
226
276
  }
@@ -16,6 +16,18 @@ export const styles = css `
16
16
  --lyra-word-cloud-color-7: #0a7d91;
17
17
  --lyra-word-cloud-color-8: #57606a;
18
18
  }
19
+ @media (prefers-color-scheme: dark) {
20
+ :host {
21
+ --lyra-word-cloud-color-1: var(--wa-color-brand-fill-loud, #4ea0f0);
22
+ --lyra-word-cloud-color-2: var(--wa-color-success-fill-loud, #3fb950);
23
+ --lyra-word-cloud-color-3: var(--wa-color-warning-fill-loud, #d29922);
24
+ --lyra-word-cloud-color-4: var(--wa-color-danger-fill-loud, #fa524a);
25
+ --lyra-word-cloud-color-5: #b083f5;
26
+ --lyra-word-cloud-color-6: #f470b8;
27
+ --lyra-word-cloud-color-7: #52d6e8;
28
+ --lyra-word-cloud-color-8: #c9d1d9;
29
+ }
30
+ }
19
31
  [part='base'] {
20
32
  display: flex;
21
33
  flex-direction: column;
@@ -37,15 +49,16 @@ export const styles = css `
37
49
  font-weight: 600;
38
50
  text-anchor: middle;
39
51
  dominant-baseline: middle;
40
- transition: opacity var(--lyra-transition-fast);
52
+ transition: text-decoration-color var(--lyra-transition-fast);
53
+ text-decoration: underline transparent;
41
54
  }
42
55
  [part='word']:hover {
43
- opacity: 0.75;
56
+ text-decoration-color: currentColor;
44
57
  }
45
58
  [part='focus-ring'] {
46
59
  fill: none;
47
60
  stroke: var(--lyra-focus-ring-color);
48
- stroke-width: 2px;
61
+ stroke-width: var(--lyra-focus-ring-width);
49
62
  pointer-events: none;
50
63
  }
51
64
  [part='empty'] {
@@ -0,0 +1 @@
1
+ export {};