@aceshooting/lyra-ui 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/README.md +12 -1
  2. package/custom-elements.json +21460 -8489
  3. package/dist/components/app-rail/app-rail.d.ts +171 -0
  4. package/dist/components/app-rail/app-rail.js +483 -0
  5. package/dist/components/app-rail/app-rail.styles.d.ts +1 -0
  6. package/dist/components/app-rail/app-rail.styles.js +125 -0
  7. package/dist/components/attachment-chip/attachment-chip.d.ts +114 -0
  8. package/dist/components/attachment-chip/attachment-chip.js +312 -0
  9. package/dist/components/attachment-chip/attachment-chip.styles.d.ts +1 -0
  10. package/dist/components/attachment-chip/attachment-chip.styles.js +184 -0
  11. package/dist/components/attachment-trigger/attachment-trigger.d.ts +83 -0
  12. package/dist/components/attachment-trigger/attachment-trigger.js +258 -0
  13. package/dist/components/attachment-trigger/attachment-trigger.styles.d.ts +1 -0
  14. package/dist/components/attachment-trigger/attachment-trigger.styles.js +68 -0
  15. package/dist/components/chart/box-plot.js +11 -1
  16. package/dist/components/chart/chart-loader.d.ts +44 -13
  17. package/dist/components/chart/chart-loader.js +65 -18
  18. package/dist/components/chart/chart.d.ts +12 -2
  19. package/dist/components/chart/chart.js +121 -14
  20. package/dist/components/chart/histogram-bin.d.ts +4 -1
  21. package/dist/components/chart/histogram-bin.js +24 -14
  22. package/dist/components/chart/lite-chart.d.ts +63 -0
  23. package/dist/components/chart/lite-chart.js +181 -23
  24. package/dist/components/chart/lite-chart.styles.js +9 -0
  25. package/dist/components/chat-composer/chat-composer.d.ts +92 -0
  26. package/dist/components/chat-composer/chat-composer.js +285 -0
  27. package/dist/components/chat-composer/chat-composer.styles.d.ts +1 -0
  28. package/dist/components/chat-composer/chat-composer.styles.js +135 -0
  29. package/dist/components/chat-message/chat-message.d.ts +113 -0
  30. package/dist/components/chat-message/chat-message.js +291 -0
  31. package/dist/components/chat-message/chat-message.styles.d.ts +1 -0
  32. package/dist/components/chat-message/chat-message.styles.js +203 -0
  33. package/dist/components/checkbox/checkbox.d.ts +59 -0
  34. package/dist/components/checkbox/checkbox.js +230 -0
  35. package/dist/components/checkbox/checkbox.styles.d.ts +1 -0
  36. package/dist/components/checkbox/checkbox.styles.js +70 -0
  37. package/dist/components/chip/chip-group.d.ts +56 -0
  38. package/dist/components/chip/chip-group.js +124 -0
  39. package/dist/components/chip/chip-group.styles.d.ts +1 -0
  40. package/dist/components/chip/chip-group.styles.js +57 -0
  41. package/dist/components/chip/chip.d.ts +64 -0
  42. package/dist/components/chip/chip.js +115 -0
  43. package/dist/components/chip/chip.styles.d.ts +1 -0
  44. package/dist/components/chip/chip.styles.js +115 -0
  45. package/dist/components/citation-badge/citation-badge.d.ts +113 -0
  46. package/dist/components/citation-badge/citation-badge.js +300 -0
  47. package/dist/components/citation-badge/citation-badge.styles.d.ts +1 -0
  48. package/dist/components/citation-badge/citation-badge.styles.js +96 -0
  49. package/dist/components/code-block/code-block.d.ts +89 -0
  50. package/dist/components/code-block/code-block.js +317 -0
  51. package/dist/components/code-block/code-block.styles.d.ts +1 -0
  52. package/dist/components/code-block/code-block.styles.js +187 -0
  53. package/dist/components/code-block/code-loader.d.ts +44 -0
  54. package/dist/components/code-block/code-loader.js +79 -0
  55. package/dist/components/combobox/combobox.d.ts +19 -1
  56. package/dist/components/combobox/combobox.js +84 -14
  57. package/dist/components/combobox/option.d.ts +5 -1
  58. package/dist/components/combobox/option.js +35 -0
  59. package/dist/components/context-meter/context-meter.d.ts +53 -0
  60. package/dist/components/context-meter/context-meter.js +150 -0
  61. package/dist/components/context-meter/context-meter.styles.d.ts +1 -0
  62. package/dist/components/context-meter/context-meter.styles.js +120 -0
  63. package/dist/components/conversation-item/conversation-item.d.ts +128 -0
  64. package/dist/components/conversation-item/conversation-item.js +322 -0
  65. package/dist/components/conversation-item/conversation-item.styles.d.ts +1 -0
  66. package/dist/components/conversation-item/conversation-item.styles.js +155 -0
  67. package/dist/components/date-picker/date-input.d.ts +24 -0
  68. package/dist/components/date-picker/date-input.js +134 -22
  69. package/dist/components/date-picker/date-picker.d.ts +7 -0
  70. package/dist/components/date-picker/date-picker.js +85 -16
  71. package/dist/components/dialog/confirm.d.ts +40 -0
  72. package/dist/components/dialog/confirm.js +79 -0
  73. package/dist/components/dialog/dialog.d.ts +85 -0
  74. package/dist/components/dialog/dialog.js +272 -0
  75. package/dist/components/dialog/dialog.styles.d.ts +1 -0
  76. package/dist/components/dialog/dialog.styles.js +52 -0
  77. package/dist/components/dock-panel/dock-panel.d.ts +134 -0
  78. package/dist/components/dock-panel/dock-panel.js +345 -0
  79. package/dist/components/dock-panel/dock-panel.styles.d.ts +1 -0
  80. package/dist/components/dock-panel/dock-panel.styles.js +145 -0
  81. package/dist/components/document-preview/document-preview.d.ts +135 -0
  82. package/dist/components/document-preview/document-preview.js +372 -0
  83. package/dist/components/document-preview/document-preview.styles.d.ts +1 -0
  84. package/dist/components/document-preview/document-preview.styles.js +191 -0
  85. package/dist/components/export-button/csv.js +1 -1
  86. package/dist/components/export-button/export-button.js +2 -0
  87. package/dist/components/flag/flag.d.ts +42 -5
  88. package/dist/components/flag/flag.js +70 -3
  89. package/dist/components/gauge/gauge.js +19 -10
  90. package/dist/components/generation-status/generation-status.d.ts +109 -0
  91. package/dist/components/generation-status/generation-status.js +273 -0
  92. package/dist/components/generation-status/generation-status.styles.d.ts +1 -0
  93. package/dist/components/generation-status/generation-status.styles.js +84 -0
  94. package/dist/components/heatmap/calendar-grid.d.ts +4 -1
  95. package/dist/components/heatmap/calendar-grid.js +25 -12
  96. package/dist/components/heatmap/heatmap-scale.d.ts +6 -0
  97. package/dist/components/heatmap/heatmap-scale.js +7 -1
  98. package/dist/components/heatmap/heatmap.d.ts +89 -3
  99. package/dist/components/heatmap/heatmap.js +158 -29
  100. package/dist/components/json-viewer/json-viewer.d.ts +53 -0
  101. package/dist/components/json-viewer/json-viewer.js +283 -0
  102. package/dist/components/json-viewer/json-viewer.styles.d.ts +1 -0
  103. package/dist/components/json-viewer/json-viewer.styles.js +176 -0
  104. package/dist/components/kbd/kbd.d.ts +77 -0
  105. package/dist/components/kbd/kbd.js +214 -0
  106. package/dist/components/kbd/kbd.styles.d.ts +1 -0
  107. package/dist/components/kbd/kbd.styles.js +52 -0
  108. package/dist/components/live-region/live-region.d.ts +81 -0
  109. package/dist/components/live-region/live-region.js +153 -0
  110. package/dist/components/live-region/live-region.styles.d.ts +1 -0
  111. package/dist/components/live-region/live-region.styles.js +10 -0
  112. package/dist/components/map/map.d.ts +8 -6
  113. package/dist/components/map/map.js +44 -8
  114. package/dist/components/markdown/markdown-loader.d.ts +34 -0
  115. package/dist/components/markdown/markdown-loader.js +43 -0
  116. package/dist/components/markdown/markdown.d.ts +81 -0
  117. package/dist/components/markdown/markdown.js +284 -0
  118. package/dist/components/markdown/markdown.styles.d.ts +1 -0
  119. package/dist/components/markdown/markdown.styles.js +82 -0
  120. package/dist/components/media-card/media-card.d.ts +122 -0
  121. package/dist/components/media-card/media-card.js +295 -0
  122. package/dist/components/media-card/media-card.styles.d.ts +1 -0
  123. package/dist/components/media-card/media-card.styles.js +132 -0
  124. package/dist/components/mention-popover/mention-popover.d.ts +200 -0
  125. package/dist/components/mention-popover/mention-popover.js +475 -0
  126. package/dist/components/mention-popover/mention-popover.styles.d.ts +1 -0
  127. package/dist/components/mention-popover/mention-popover.styles.js +101 -0
  128. package/dist/components/menu/menu-item.d.ts +62 -0
  129. package/dist/components/menu/menu-item.js +119 -0
  130. package/dist/components/menu/menu-item.styles.d.ts +1 -0
  131. package/dist/components/menu/menu-item.styles.js +67 -0
  132. package/dist/components/menu/menu.d.ts +143 -0
  133. package/dist/components/menu/menu.js +365 -0
  134. package/dist/components/menu/menu.styles.d.ts +1 -0
  135. package/dist/components/menu/menu.styles.js +66 -0
  136. package/dist/components/model-select/model-select.d.ts +125 -0
  137. package/dist/components/model-select/model-select.js +490 -0
  138. package/dist/components/model-select/model-select.styles.d.ts +1 -0
  139. package/dist/components/model-select/model-select.styles.js +189 -0
  140. package/dist/components/model-settings-panel/model-settings-panel.d.ts +69 -0
  141. package/dist/components/model-settings-panel/model-settings-panel.js +145 -0
  142. package/dist/components/model-settings-panel/model-settings-panel.styles.d.ts +1 -0
  143. package/dist/components/model-settings-panel/model-settings-panel.styles.js +82 -0
  144. package/dist/components/playback/playback.d.ts +13 -1
  145. package/dist/components/playback/playback.js +47 -14
  146. package/dist/components/responsive-panel/responsive-panel.d.ts +150 -0
  147. package/dist/components/responsive-panel/responsive-panel.js +365 -0
  148. package/dist/components/responsive-panel/responsive-panel.styles.d.ts +1 -0
  149. package/dist/components/responsive-panel/responsive-panel.styles.js +103 -0
  150. package/dist/components/result-card/result-card.d.ts +44 -0
  151. package/dist/components/result-card/result-card.js +83 -0
  152. package/dist/components/result-card/result-card.styles.d.ts +1 -0
  153. package/dist/components/result-card/result-card.styles.js +50 -0
  154. package/dist/components/result-card/result-field.d.ts +36 -0
  155. package/dist/components/result-card/result-field.js +87 -0
  156. package/dist/components/result-card/result-field.styles.d.ts +1 -0
  157. package/dist/components/result-card/result-field.styles.js +32 -0
  158. package/dist/components/select/select.d.ts +45 -1
  159. package/dist/components/select/select.js +114 -17
  160. package/dist/components/select/select.styles.js +26 -2
  161. package/dist/components/slider/slider.d.ts +89 -0
  162. package/dist/components/slider/slider.js +352 -0
  163. package/dist/components/slider/slider.styles.d.ts +1 -0
  164. package/dist/components/slider/slider.styles.js +87 -0
  165. package/dist/components/source-card/source-card.d.ts +92 -0
  166. package/dist/components/source-card/source-card.js +148 -0
  167. package/dist/components/source-card/source-card.styles.d.ts +1 -0
  168. package/dist/components/source-card/source-card.styles.js +69 -0
  169. package/dist/components/source-list/source-list.d.ts +63 -0
  170. package/dist/components/source-list/source-list.js +122 -0
  171. package/dist/components/source-list/source-list.styles.d.ts +1 -0
  172. package/dist/components/source-list/source-list.styles.js +59 -0
  173. package/dist/components/sparkline/sparkline.js +27 -13
  174. package/dist/components/split/split.d.ts +93 -1
  175. package/dist/components/split/split.js +284 -15
  176. package/dist/components/split/split.styles.js +30 -0
  177. package/dist/components/stat/stat.d.ts +22 -1
  178. package/dist/components/stat/stat.js +49 -3
  179. package/dist/components/stat/stat.styles.js +20 -0
  180. package/dist/components/stream-status/stream-status.d.ts +110 -0
  181. package/dist/components/stream-status/stream-status.js +210 -0
  182. package/dist/components/stream-status/stream-status.styles.d.ts +1 -0
  183. package/dist/components/stream-status/stream-status.styles.js +103 -0
  184. package/dist/components/streaming-text/streaming-text.d.ts +98 -0
  185. package/dist/components/streaming-text/streaming-text.js +209 -0
  186. package/dist/components/streaming-text/streaming-text.styles.d.ts +1 -0
  187. package/dist/components/streaming-text/streaming-text.styles.js +62 -0
  188. package/dist/components/switch/switch.d.ts +58 -0
  189. package/dist/components/switch/switch.js +179 -0
  190. package/dist/components/switch/switch.styles.d.ts +1 -0
  191. package/dist/components/switch/switch.styles.js +75 -0
  192. package/dist/components/table/table.d.ts +73 -4
  193. package/dist/components/table/table.js +169 -20
  194. package/dist/components/table/table.styles.js +6 -1
  195. package/dist/components/tabs/tabs.d.ts +51 -0
  196. package/dist/components/tabs/tabs.js +190 -0
  197. package/dist/components/tabs/tabs.styles.d.ts +1 -0
  198. package/dist/components/tabs/tabs.styles.js +63 -0
  199. package/dist/components/thinking-panel/thinking-panel.d.ts +121 -0
  200. package/dist/components/thinking-panel/thinking-panel.js +235 -0
  201. package/dist/components/thinking-panel/thinking-panel.styles.d.ts +1 -0
  202. package/dist/components/thinking-panel/thinking-panel.styles.js +117 -0
  203. package/dist/components/toast/toast-item.d.ts +1 -0
  204. package/dist/components/toast/toast-item.js +31 -6
  205. package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +130 -0
  206. package/dist/components/tool-approval-dialog/tool-approval-dialog.js +403 -0
  207. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.d.ts +1 -0
  208. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +160 -0
  209. package/dist/components/tool-call-chip/tool-call-chip.d.ts +89 -0
  210. package/dist/components/tool-call-chip/tool-call-chip.js +288 -0
  211. package/dist/components/tool-call-chip/tool-call-chip.styles.d.ts +1 -0
  212. package/dist/components/tool-call-chip/tool-call-chip.styles.js +203 -0
  213. package/dist/components/tool-param-form/tool-param-form.d.ts +145 -0
  214. package/dist/components/tool-param-form/tool-param-form.js +366 -0
  215. package/dist/components/tool-param-form/tool-param-form.styles.d.ts +1 -0
  216. package/dist/components/tool-param-form/tool-param-form.styles.js +75 -0
  217. package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +102 -0
  218. package/dist/components/tool-result-dialog/tool-result-dialog.js +393 -0
  219. package/dist/components/tool-result-dialog/tool-result-dialog.styles.d.ts +1 -0
  220. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +176 -0
  221. package/dist/components/tool-result-view/registry.d.ts +81 -0
  222. package/dist/components/tool-result-view/registry.js +84 -0
  223. package/dist/components/tool-result-view/tool-result-view.d.ts +55 -0
  224. package/dist/components/tool-result-view/tool-result-view.js +138 -0
  225. package/dist/components/tool-result-view/tool-result-view.styles.d.ts +1 -0
  226. package/dist/components/tool-result-view/tool-result-view.styles.js +13 -0
  227. package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +151 -0
  228. package/dist/components/tool-select-dialog/tool-select-dialog.js +439 -0
  229. package/dist/components/tool-select-dialog/tool-select-dialog.styles.d.ts +1 -0
  230. package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +182 -0
  231. package/dist/components/tree/tree-node.d.ts +11 -2
  232. package/dist/components/tree/tree-node.js +16 -6
  233. package/dist/components/tree/tree.d.ts +8 -2
  234. package/dist/components/tree/tree.js +18 -11
  235. package/dist/components/typing-indicator/typing-indicator.d.ts +60 -0
  236. package/dist/components/typing-indicator/typing-indicator.js +96 -0
  237. package/dist/components/typing-indicator/typing-indicator.styles.d.ts +1 -0
  238. package/dist/components/typing-indicator/typing-indicator.styles.js +132 -0
  239. package/dist/components/virtual-list/virtual-list.d.ts +173 -0
  240. package/dist/components/virtual-list/virtual-list.js +461 -0
  241. package/dist/components/virtual-list/virtual-list.styles.d.ts +1 -0
  242. package/dist/components/virtual-list/virtual-list.styles.js +44 -0
  243. package/dist/components/widget/widget.d.ts +10 -0
  244. package/dist/components/widget/widget.js +24 -1
  245. package/dist/components/widget/widget.styles.js +9 -2
  246. package/dist/components/word-cloud/word-cloud-layout.js +14 -1
  247. package/dist/components/word-cloud/word-cloud.d.ts +6 -0
  248. package/dist/components/word-cloud/word-cloud.js +25 -14
  249. package/dist/components/word-cloud/word-cloud.styles.js +4 -2
  250. package/dist/internal/announcer.d.ts +57 -0
  251. package/dist/internal/announcer.js +71 -0
  252. package/dist/internal/form-associated.d.ts +1 -0
  253. package/dist/internal/form-associated.js +55 -11
  254. package/dist/internal/group-by-recency.d.ts +50 -0
  255. package/dist/internal/group-by-recency.js +80 -0
  256. package/dist/internal/rtl.d.ts +23 -0
  257. package/dist/internal/rtl.js +28 -0
  258. package/dist/internal/scroll-lock.d.ts +10 -5
  259. package/dist/internal/scroll-lock.js +30 -14
  260. package/dist/internal/tokens.styles.js +6 -0
  261. package/dist/lyra.d.ts +130 -31
  262. package/dist/lyra.js +94 -26
  263. package/llms-full.txt +3921 -32
  264. package/llms.txt +16 -1
  265. package/package.json +23 -5
  266. package/dist/components/chart/bar-chart.stories.d.ts +0 -5
  267. package/dist/components/chart/bar-chart.stories.js +0 -20
  268. package/dist/components/chart/box-plot.stories.d.ts +0 -5
  269. package/dist/components/chart/box-plot.stories.js +0 -29
  270. package/dist/components/chart/bubble-chart.stories.d.ts +0 -5
  271. package/dist/components/chart/bubble-chart.stories.js +0 -26
  272. package/dist/components/chart/chart.stories.d.ts +0 -32
  273. package/dist/components/chart/chart.stories.js +0 -141
  274. package/dist/components/chart/doughnut-chart.stories.d.ts +0 -5
  275. package/dist/components/chart/doughnut-chart.stories.js +0 -26
  276. package/dist/components/chart/histogram.stories.d.ts +0 -5
  277. package/dist/components/chart/histogram.stories.js +0 -17
  278. package/dist/components/chart/line-chart.stories.d.ts +0 -22
  279. package/dist/components/chart/line-chart.stories.js +0 -99
  280. package/dist/components/chart/lite-chart.stories.d.ts +0 -12
  281. package/dist/components/chart/lite-chart.stories.js +0 -98
  282. package/dist/components/chart/pie-chart.stories.d.ts +0 -5
  283. package/dist/components/chart/pie-chart.stories.js +0 -26
  284. package/dist/components/chart/polar-area-chart.stories.d.ts +0 -5
  285. package/dist/components/chart/polar-area-chart.stories.js +0 -20
  286. package/dist/components/chart/radar-chart.stories.d.ts +0 -5
  287. package/dist/components/chart/radar-chart.stories.js +0 -20
  288. package/dist/components/chart/scatter-chart.stories.d.ts +0 -5
  289. package/dist/components/chart/scatter-chart.stories.js +0 -31
  290. package/dist/components/combobox/combobox.stories.d.ts +0 -24
  291. package/dist/components/combobox/combobox.stories.js +0 -102
  292. package/dist/components/date-picker/date-input.stories.d.ts +0 -10
  293. package/dist/components/date-picker/date-input.stories.js +0 -48
  294. package/dist/components/date-picker/date-picker.stories.d.ts +0 -10
  295. package/dist/components/date-picker/date-picker.stories.js +0 -25
  296. package/dist/components/empty/empty.stories.d.ts +0 -7
  297. package/dist/components/empty/empty.stories.js +0 -34
  298. package/dist/components/export-button/export-button.stories.d.ts +0 -7
  299. package/dist/components/export-button/export-button.stories.js +0 -37
  300. package/dist/components/file-input/file-input.stories.d.ts +0 -7
  301. package/dist/components/file-input/file-input.stories.js +0 -19
  302. package/dist/components/flag/flag.stories.d.ts +0 -5
  303. package/dist/components/flag/flag.stories.js +0 -17
  304. package/dist/components/gauge/gauge.stories.d.ts +0 -8
  305. package/dist/components/gauge/gauge.stories.js +0 -19
  306. package/dist/components/graph/graph.stories.d.ts +0 -8
  307. package/dist/components/graph/graph.stories.js +0 -68
  308. package/dist/components/heatmap/heatmap.stories.d.ts +0 -22
  309. package/dist/components/heatmap/heatmap.stories.js +0 -154
  310. package/dist/components/map/map.stories.d.ts +0 -15
  311. package/dist/components/map/map.stories.js +0 -135
  312. package/dist/components/playback/playback.stories.d.ts +0 -7
  313. package/dist/components/playback/playback.stories.js +0 -16
  314. package/dist/components/select/select.stories.d.ts +0 -19
  315. package/dist/components/select/select.stories.js +0 -75
  316. package/dist/components/skeleton/skeleton.stories.d.ts +0 -5
  317. package/dist/components/skeleton/skeleton.stories.js +0 -16
  318. package/dist/components/sparkline/sparkline.stories.d.ts +0 -11
  319. package/dist/components/sparkline/sparkline.stories.js +0 -39
  320. package/dist/components/split/split.stories.d.ts +0 -7
  321. package/dist/components/split/split.stories.js +0 -36
  322. package/dist/components/stat/stat.stories.d.ts +0 -8
  323. package/dist/components/stat/stat.stories.js +0 -64
  324. package/dist/components/table/table.stories.d.ts +0 -12
  325. package/dist/components/table/table.stories.js +0 -67
  326. package/dist/components/time-range/time-range.stories.d.ts +0 -8
  327. package/dist/components/time-range/time-range.stories.js +0 -26
  328. package/dist/components/toast/toast.stories.d.ts +0 -8
  329. package/dist/components/toast/toast.stories.js +0 -72
  330. package/dist/components/tree/tree.stories.d.ts +0 -9
  331. package/dist/components/tree/tree.stories.js +0 -52
  332. package/dist/components/widget/widget.stories.d.ts +0 -7
  333. package/dist/components/widget/widget.stories.js +0 -41
  334. package/dist/components/word-cloud/word-cloud.stories.d.ts +0 -10
  335. package/dist/components/word-cloud/word-cloud.stories.js +0 -55
@@ -0,0 +1,187 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ /* Consumer-tunable scroll cap -- 'none' means the block grows with its
6
+ content, matching every other block-level component in this library
7
+ until a caller opts in via the max-height attribute (same convention
8
+ as --lyra-json-viewer-max-height). */
9
+ --lyra-code-block-max-height: none;
10
+ /* Contained here rather than left as a bare font-family literal so a
11
+ host page can retheme it -- same rationale as --lyra-markdown-font-mono
12
+ and --lyra-json-viewer-font, no shared --wa-*/--lyra-* monospace token
13
+ exists to resolve through. */
14
+ --lyra-code-block-font: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
15
+ font-size: 0.8125rem;
16
+ }
17
+ [part='base'] {
18
+ border: 1px solid var(--lyra-color-border);
19
+ border-radius: var(--lyra-radius);
20
+ background: var(--lyra-color-surface);
21
+ overflow: hidden;
22
+ }
23
+ [part='header'] {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: var(--lyra-space-xs);
27
+ padding: var(--lyra-space-xs) var(--lyra-space-s);
28
+ border-block-end: 1px solid var(--lyra-color-border);
29
+ /* --lyra-color-surface (not -brand-quiet) -- pairing
30
+ --lyra-color-text-quiet (the toggle/copy-button color below) against
31
+ --lyra-color-brand-quiet fails WCAG AA contrast in this token
32
+ palette; --lyra-color-surface is the same header background
33
+ lyra-json-viewer's own toolbar already uses with that same text
34
+ color. */
35
+ background: var(--lyra-color-surface);
36
+ font-family: var(--lyra-font);
37
+ }
38
+ [part='toggle'] {
39
+ /* Deliberately smaller than the shared --lyra-icon-button-size (2.5rem,
40
+ meant for a standalone icon-only button) -- this sits inline in a
41
+ dense header row, same reasoning as lyra-json-viewer's own toggle. */
42
+ inline-size: 1.25rem;
43
+ block-size: 1.25rem;
44
+ flex: 0 0 auto;
45
+ display: inline-flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ padding: 0;
49
+ border: none;
50
+ background: none;
51
+ color: var(--lyra-color-text-quiet);
52
+ border-radius: var(--lyra-radius);
53
+ cursor: pointer;
54
+ }
55
+ [part='toggle']:hover {
56
+ background: var(--lyra-color-brand-quiet);
57
+ color: var(--lyra-color-brand);
58
+ }
59
+ [part='toggle'] .chevron {
60
+ display: inline-flex;
61
+ transition: transform var(--lyra-transition-fast);
62
+ }
63
+ /* Chevron points at the content: rotated (pointing down) while expanded,
64
+ resting (pointing right) while collapsed -- same rotation direction as
65
+ lyra-thinking-panel's and lyra-json-viewer's own toggles. */
66
+ :host(:not([collapsed])) [part='toggle'] .chevron {
67
+ transform: rotate(90deg);
68
+ }
69
+ [part='filename'] {
70
+ flex: 1 1 auto;
71
+ min-inline-size: 0;
72
+ overflow: hidden;
73
+ text-overflow: ellipsis;
74
+ white-space: nowrap;
75
+ font-family: var(--lyra-code-block-font);
76
+ font-size: 0.75rem;
77
+ font-weight: 600;
78
+ color: var(--lyra-color-text);
79
+ }
80
+ [part='language'] {
81
+ flex: 0 0 auto;
82
+ padding: 0.0625rem 0.4375rem;
83
+ border-radius: 999px;
84
+ /* --lyra-color-brand + -brand-quiet (not -text-quiet + -surface) --
85
+ this pill needs to read as distinct from the [part="header"]
86
+ background it sits on (also -surface as of the comment above), and
87
+ -brand on -brand-quiet is a pairing already relied on elsewhere in
88
+ this library (e.g. hover states below) that passes contrast, unlike
89
+ -text-quiet on -brand-quiet. */
90
+ background: var(--lyra-color-brand-quiet);
91
+ color: var(--lyra-color-brand);
92
+ font-size: 0.6875rem;
93
+ line-height: 1.4;
94
+ text-transform: uppercase;
95
+ letter-spacing: 0.02em;
96
+ }
97
+ /* Pushed to the end of the header whether or not filename/language
98
+ precede it -- margin-inline-start:auto works whether this is the first
99
+ flex child (copyable alone) or the last of several. */
100
+ [part='copy-button'] {
101
+ flex: 0 0 auto;
102
+ margin-inline-start: auto;
103
+ border: none;
104
+ background: none;
105
+ color: var(--lyra-color-text-quiet);
106
+ font: inherit;
107
+ font-size: 0.75rem;
108
+ line-height: 1;
109
+ padding: 0.1875rem var(--lyra-space-xs);
110
+ border-radius: var(--lyra-radius);
111
+ cursor: pointer;
112
+ }
113
+ [part='copy-button']:hover {
114
+ background: var(--lyra-color-brand-quiet);
115
+ color: var(--lyra-color-brand);
116
+ }
117
+ [part='toggle']:focus-visible,
118
+ [part='copy-button']:focus-visible {
119
+ outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
120
+ outline-offset: var(--lyra-focus-ring-offset);
121
+ }
122
+ [part='body'] {
123
+ display: block;
124
+ max-block-size: var(--lyra-code-block-max-height);
125
+ overflow: auto;
126
+ }
127
+ [part='body'][hidden] {
128
+ display: none;
129
+ }
130
+ [part='body']:focus-visible {
131
+ outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
132
+ /* Negative (inward) so the ring isn't clipped by this element's own
133
+ overflow:auto -- same reasoning as lyra-virtual-list's [part="base"]. */
134
+ outline-offset: calc(-1 * var(--lyra-focus-ring-offset));
135
+ }
136
+ [part='body'] lyra-skeleton {
137
+ display: block;
138
+ padding: var(--lyra-space-s) var(--lyra-space-m);
139
+ --lyra-skeleton-w: 100%;
140
+ --lyra-skeleton-h: 8rem;
141
+ }
142
+ [part='pre'] {
143
+ margin: 0;
144
+ padding: var(--lyra-space-s) var(--lyra-space-m);
145
+ /* A default background so the plain-fallback path still reads as a
146
+ proper code block -- shiki's own inline background-color (part of the
147
+ generated-token-colors exception documented in code-block.ts's
148
+ tokenize()) silently overrides this the moment highlighting succeeds,
149
+ since an element's own style attribute always wins over an external
150
+ stylesheet rule at equal or lower specificity. */
151
+ background: var(--lyra-color-surface);
152
+ font-family: var(--lyra-code-block-font);
153
+ font-size: inherit;
154
+ line-height: 1.5;
155
+ white-space: pre;
156
+ }
157
+ [part='code'] {
158
+ font-family: inherit;
159
+ }
160
+ /*
161
+ * Activates shiki's "dual themes" dark variant. codeToHtml() (see
162
+ * tokenize() in code-block.ts) renders every token with its *light* color
163
+ * as a plain inline color/background-color and its *dark* color stashed in
164
+ * the --shiki-dark/--shiki-dark-bg custom properties shiki itself defines
165
+ * inline on the same elements -- shiki's own documented pattern for
166
+ * toggling them is exactly this: an external stylesheet rule that
167
+ * reassigns color/background-color from those variables. This requires
168
+ * !important because an inline style="..." attribute always outranks an
169
+ * external stylesheet at any selector specificity short of !important --
170
+ * there's no other way for a page-level rule to override an element's own
171
+ * style attribute. This is the one legitimate exception to "every color is
172
+ * a --lyra-* token" in this file: these values come from shiki's theme
173
+ * data, not this library's design tokens.
174
+ */
175
+ @media (prefers-color-scheme: dark) {
176
+ [part='pre'],
177
+ [part='pre'] span {
178
+ color: var(--shiki-dark, inherit) !important;
179
+ background-color: var(--shiki-dark-bg, transparent) !important;
180
+ }
181
+ }
182
+ @media (prefers-reduced-motion: reduce) {
183
+ [part='toggle'] .chevron {
184
+ transition: none !important;
185
+ }
186
+ }
187
+ `;
@@ -0,0 +1,44 @@
1
+ import type { Highlighter, BundledTheme } from 'shiki';
2
+ /** Re-exported under a component-scoped name so importers don't need their
3
+ * own `import type { Highlighter } from 'shiki'`. */
4
+ export type ShikiHighlighter = Highlighter;
5
+ /**
6
+ * The two bundled themes every highlighter instance is seeded with, so a
7
+ * single `codeToHtml()` call can emit a light *and* dark rendering at once
8
+ * (shiki's "dual themes" feature — https://shiki.style/guide/dual-themes —
9
+ * rather than maintaining two separately-highlighted copies). `github-light`/
10
+ * `github-dark` are well-known, reasonably neutral, and already part of
11
+ * shiki's bundled theme set, so picking them costs no extra install. See the
12
+ * `prefers-color-scheme` block in `code-block.styles.ts` for how the dark
13
+ * variant actually activates.
14
+ */
15
+ export declare const SHIKI_LIGHT_THEME: BundledTheme;
16
+ export declare const SHIKI_DARK_THEME: BundledTheme;
17
+ /** Passed directly as `codeToHtml()`'s `themes` option — see `tokenize()` in `code-block.ts`. */
18
+ export declare const SHIKI_THEMES: Record<'light' | 'dark', BundledTheme>;
19
+ /**
20
+ * Lazily loads the optional peer dependency `shiki` once per page and builds
21
+ * (and caches) a single `Highlighter` instance seeded with `SHIKI_THEMES` and
22
+ * *zero* language grammars. Creating the highlighter — compiling its regex
23
+ * engine, parsing the seed themes — is the expensive part, not the dynamic
24
+ * `import()` itself, so the created instance is what's cached here rather
25
+ * than just the resolved module (one level deeper than `map-loader.ts`'s
26
+ * single-dependency cached-promise shape, which this otherwise mirrors).
27
+ * Resolves to `null` (with a one-time `console.warn`) if shiki isn't
28
+ * installed — `<lyra-code-block>` falls back to plain unhighlighted text in
29
+ * that case, which is a fully supported default, not a degraded mode. No
30
+ * language grammar is loaded up front; `loadShikiLanguage()` below loads each
31
+ * one incrementally the first time a `language` value actually requests it.
32
+ */
33
+ export declare function loadShikiHighlighter(): Promise<ShikiHighlighter | null>;
34
+ /**
35
+ * Ensures `lang` is loaded into `hl`, loading it on demand the first time
36
+ * it's requested rather than bundling every possible grammar up front —
37
+ * shiki supports this incrementally via `Highlighter.loadLanguage()`, which
38
+ * is what keeps this lazy instead of defeating the point of lazy-loading the
39
+ * peer at all. Resolves `false` (and remembers not to retry) when `lang`
40
+ * isn't a shiki-recognized grammar id or alias at all, so a caller can fall
41
+ * back to plain-text rendering instead of retrying an id that can never
42
+ * succeed on every future render.
43
+ */
44
+ export declare function loadShikiLanguage(hl: ShikiHighlighter, lang: string): Promise<boolean>;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The two bundled themes every highlighter instance is seeded with, so a
3
+ * single `codeToHtml()` call can emit a light *and* dark rendering at once
4
+ * (shiki's "dual themes" feature — https://shiki.style/guide/dual-themes —
5
+ * rather than maintaining two separately-highlighted copies). `github-light`/
6
+ * `github-dark` are well-known, reasonably neutral, and already part of
7
+ * shiki's bundled theme set, so picking them costs no extra install. See the
8
+ * `prefers-color-scheme` block in `code-block.styles.ts` for how the dark
9
+ * variant actually activates.
10
+ */
11
+ export const SHIKI_LIGHT_THEME = 'github-light';
12
+ export const SHIKI_DARK_THEME = 'github-dark';
13
+ /** Passed directly as `codeToHtml()`'s `themes` option — see `tokenize()` in `code-block.ts`. */
14
+ export const SHIKI_THEMES = {
15
+ light: SHIKI_LIGHT_THEME,
16
+ dark: SHIKI_DARK_THEME,
17
+ };
18
+ let highlighter;
19
+ /** Language ids that have already failed `loadLanguage()` once — avoids
20
+ * retrying (and re-throwing on) the same unrecognized `language` value on
21
+ * every re-render of every `<lyra-code-block>` that requests it. Shared
22
+ * across every highlighter instance the page ever creates (there's only
23
+ * ever one, see `loadShikiHighlighter()` below), so this never needs
24
+ * resetting alongside it. */
25
+ const unsupportedLanguages = new Set();
26
+ /**
27
+ * Lazily loads the optional peer dependency `shiki` once per page and builds
28
+ * (and caches) a single `Highlighter` instance seeded with `SHIKI_THEMES` and
29
+ * *zero* language grammars. Creating the highlighter — compiling its regex
30
+ * engine, parsing the seed themes — is the expensive part, not the dynamic
31
+ * `import()` itself, so the created instance is what's cached here rather
32
+ * than just the resolved module (one level deeper than `map-loader.ts`'s
33
+ * single-dependency cached-promise shape, which this otherwise mirrors).
34
+ * Resolves to `null` (with a one-time `console.warn`) if shiki isn't
35
+ * installed — `<lyra-code-block>` falls back to plain unhighlighted text in
36
+ * that case, which is a fully supported default, not a degraded mode. No
37
+ * language grammar is loaded up front; `loadShikiLanguage()` below loads each
38
+ * one incrementally the first time a `language` value actually requests it.
39
+ */
40
+ export function loadShikiHighlighter() {
41
+ if (!highlighter) {
42
+ highlighter = import('shiki')
43
+ .then((mod) => mod.createHighlighter({ themes: [SHIKI_LIGHT_THEME, SHIKI_DARK_THEME], langs: [] }))
44
+ .catch((err) => {
45
+ console.warn('<lyra-code-block> needs the optional peer dependency `shiki` for syntax highlighting — install it ' +
46
+ 'with `pnpm add shiki`. Code still renders, just unhighlighted, without it:', err);
47
+ return null;
48
+ });
49
+ }
50
+ return highlighter;
51
+ }
52
+ /**
53
+ * Ensures `lang` is loaded into `hl`, loading it on demand the first time
54
+ * it's requested rather than bundling every possible grammar up front —
55
+ * shiki supports this incrementally via `Highlighter.loadLanguage()`, which
56
+ * is what keeps this lazy instead of defeating the point of lazy-loading the
57
+ * peer at all. Resolves `false` (and remembers not to retry) when `lang`
58
+ * isn't a shiki-recognized grammar id or alias at all, so a caller can fall
59
+ * back to plain-text rendering instead of retrying an id that can never
60
+ * succeed on every future render.
61
+ */
62
+ export async function loadShikiLanguage(hl, lang) {
63
+ if (hl.getLoadedLanguages().includes(lang))
64
+ return true;
65
+ if (unsupportedLanguages.has(lang))
66
+ return false;
67
+ try {
68
+ await hl.loadLanguage(lang);
69
+ return true;
70
+ }
71
+ catch {
72
+ // Not a shiki-recognized grammar id/alias, or the grammar failed to
73
+ // load for some other reason — either way, <lyra-code-block> treats an
74
+ // unrecognized language the same as an unset one (plain text), and
75
+ // there's nothing more specific a caller could do with the reason.
76
+ unsupportedLanguages.add(lang);
77
+ return false;
78
+ }
79
+ }
@@ -54,12 +54,15 @@ export declare class LyraCombobox extends LyraElement {
54
54
  value: {
55
55
  noAccessor: boolean;
56
56
  };
57
+ name: {
58
+ reflect: boolean;
59
+ noAccessor: boolean;
60
+ };
57
61
  };
58
62
  multiple: boolean;
59
63
  placeholder: string;
60
64
  disabled: boolean;
61
65
  required: boolean;
62
- name: string;
63
66
  label: string;
64
67
  hint: string;
65
68
  errorText: string;
@@ -84,6 +87,7 @@ export declare class LyraCombobox extends LyraElement {
84
87
  private _selectedLabelCache;
85
88
  private _rowsByValue;
86
89
  private internals;
90
+ private _fieldsetDisabled;
87
91
  private listId;
88
92
  private inputId;
89
93
  private cleanup?;
@@ -91,20 +95,34 @@ export declare class LyraCombobox extends LyraElement {
91
95
  private _selected;
92
96
  private _defaultSelected;
93
97
  private _defaultCaptured;
98
+ private _name;
94
99
  constructor();
95
100
  connectedCallback(): void;
96
101
  protected willUpdate(): void;
102
+ get name(): string;
103
+ set name(next: string);
97
104
  /** The selected value(s): a string in single mode, a string[] in `multiple` mode. */
98
105
  get value(): string | string[];
99
106
  set value(next: string | string[]);
100
107
  private updateValidity;
101
108
  private syncFormValue;
109
+ /** Effective disabled state: this element's own `disabled` OR an ancestor
110
+ * `<fieldset disabled>`'s inherited state -- mirrors native `<input>`, whose
111
+ * own `disabled` IDL property/attribute is never mutated by a fieldset. */
112
+ get effectiveDisabled(): boolean;
102
113
  formResetCallback(): void;
114
+ /**
115
+ * Called by the browser when an ancestor `<fieldset disabled>` toggles.
116
+ * Tracked separately from the consumer's own `disabled` (see
117
+ * `effectiveDisabled`) so a consumer's explicit `disabled` survives the
118
+ * fieldset re-enabling instead of being permanently overwritten.
119
+ */
103
120
  formDisabledCallback(disabled: boolean): void;
104
121
  checkValidity(): boolean;
105
122
  reportValidity(): boolean;
106
123
  disconnectedCallback(): void;
107
124
  private collectOptions;
125
+ private onOptionChange;
108
126
  private reflectSelected;
109
127
  private labelFor;
110
128
  /** The current row set in a source-agnostic shape, before capping. */
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { html } from 'lit';
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
10
  import { defineElement } from '../../internal/prefix.js';
@@ -54,6 +54,7 @@ export class LyraCombobox extends LyraElement {
54
54
  static { this.styles = [LyraElement.styles, styles]; }
55
55
  static { this.properties = {
56
56
  value: { noAccessor: true },
57
+ name: { reflect: true, noAccessor: true },
57
58
  }; }
58
59
  constructor() {
59
60
  super();
@@ -61,7 +62,6 @@ export class LyraCombobox extends LyraElement {
61
62
  this.placeholder = '';
62
63
  this.disabled = false;
63
64
  this.required = false;
64
- this.name = '';
65
65
  this.label = '';
66
66
  this.hint = '';
67
67
  this.errorText = '';
@@ -97,6 +97,11 @@ export class LyraCombobox extends LyraElement {
97
97
  // handlers' data-value lookup below, instead of each option row closing
98
98
  // over its own row object.
99
99
  this._rowsByValue = new Map();
100
+ // Tracked separately from the consumer's own `disabled` -- a native
101
+ // `<input>`'s own `disabled` IDL property/attribute is never mutated by
102
+ // fieldset cascading, so a consumer's explicit `disabled` must survive the
103
+ // fieldset re-enabling (see `formDisabledCallback` below).
104
+ this._fieldsetDisabled = false;
100
105
  this.listId = nextId('combobox-list');
101
106
  this.inputId = nextId('combobox-input');
102
107
  this._isFirstUpdate = true;
@@ -111,6 +116,15 @@ export class LyraCombobox extends LyraElement {
111
116
  // property assignment never does).
112
117
  this._defaultSelected = [];
113
118
  this._defaultCaptured = false;
119
+ // Hand-written accessor (mirrors the `value` accessor below, and Task 2's
120
+ // `FormAssociated.name` in `../../internal/form-associated.ts`): a
121
+ // form-associated custom element's submitted entry name is resolved by the
122
+ // browser from the live `name` *content attribute*, read synchronously at
123
+ // FormData-construction/submit time (see `syncFormValue()` below) -- Lit's
124
+ // async (microtask-deferred) `reflect: true` alone would leave a
125
+ // property-only assignment like `el.name = 'b'` invisible to a same-tick
126
+ // `new FormData(form)`/submit, so the attribute write happens here instead.
127
+ this._name = '';
114
128
  this.collectOptions = (e) => {
115
129
  const slot = e.target;
116
130
  const previous = new Set(this.options);
@@ -149,6 +163,14 @@ export class LyraCombobox extends LyraElement {
149
163
  }
150
164
  this.reflectSelected();
151
165
  };
166
+ this.onOptionChange = () => {
167
+ // Touch the `options` array reference so Lit's change-detection sees a
168
+ // "new" value and re-renders `renderRows()`/`filtered`/`labelFor()` off
169
+ // the options' now-current data -- the *set* of options is unchanged,
170
+ // only one member's own properties are, so this skips
171
+ // collectOptions()'s selection-seeding logic entirely.
172
+ this.options = [...this.options];
173
+ };
152
174
  this.onDocPointer = (e) => {
153
175
  if (!e.composedPath().includes(this))
154
176
  this.hide();
@@ -226,7 +248,7 @@ export class LyraCombobox extends LyraElement {
226
248
  }
227
249
  };
228
250
  this.onComboMouseDown = (e) => {
229
- if (this.disabled)
251
+ if (this.effectiveDisabled)
230
252
  return;
231
253
  if (e.target.closest('button'))
232
254
  return;
@@ -268,6 +290,20 @@ export class LyraCombobox extends LyraElement {
268
290
  this.hasLabelSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'label');
269
291
  }
270
292
  }
293
+ get name() {
294
+ return this._name;
295
+ }
296
+ set name(next) {
297
+ const old = this._name;
298
+ this._name = next ?? '';
299
+ if (this._name) {
300
+ this.setAttribute('name', this._name);
301
+ }
302
+ else {
303
+ this.removeAttribute('name');
304
+ }
305
+ this.requestUpdate('name', old);
306
+ }
271
307
  /** The selected value(s): a string in single mode, a string[] in `multiple` mode. */
272
308
  get value() {
273
309
  return this.multiple ? [...this._selected] : (this._selected[0] ?? '');
@@ -309,12 +345,25 @@ export class LyraCombobox extends LyraElement {
309
345
  this.internals.setFormValue(this._selected[0] ?? '');
310
346
  }
311
347
  }
348
+ /** Effective disabled state: this element's own `disabled` OR an ancestor
349
+ * `<fieldset disabled>`'s inherited state -- mirrors native `<input>`, whose
350
+ * own `disabled` IDL property/attribute is never mutated by a fieldset. */
351
+ get effectiveDisabled() {
352
+ return this.disabled || this._fieldsetDisabled;
353
+ }
312
354
  formResetCallback() {
313
355
  this.value = [...this._defaultSelected];
314
356
  this.query = '';
315
357
  }
358
+ /**
359
+ * Called by the browser when an ancestor `<fieldset disabled>` toggles.
360
+ * Tracked separately from the consumer's own `disabled` (see
361
+ * `effectiveDisabled`) so a consumer's explicit `disabled` survives the
362
+ * fieldset re-enabling instead of being permanently overwritten.
363
+ */
316
364
  formDisabledCallback(disabled) {
317
- this.disabled = disabled;
365
+ this._fieldsetDisabled = disabled;
366
+ this.requestUpdate();
318
367
  }
319
368
  checkValidity() {
320
369
  return this.internals.checkValidity();
@@ -325,8 +374,15 @@ export class LyraCombobox extends LyraElement {
325
374
  disconnectedCallback() {
326
375
  super.disconnectedCallback();
327
376
  this.cleanup?.();
377
+ this.cleanup = undefined;
328
378
  clearTimeout(this.sourceTimer);
329
379
  document.removeEventListener('pointerdown', this.onDocPointer);
380
+ // Reset so a reconnect (e.g. a drag-drop reparent) re-triggers
381
+ // `updated()`'s `open`-driven branch -- without this, `open` stays
382
+ // `true` across the disconnect/reconnect and `changed.has('open')` never
383
+ // fires again, leaving the listbox rendered open with no positioning and
384
+ // no outside-click listener.
385
+ this.open = false;
330
386
  }
331
387
  reflectSelected() {
332
388
  const sel = new Set(this._selected);
@@ -381,7 +437,7 @@ export class LyraCombobox extends LyraElement {
381
437
  return this._selected[0] ? this.labelFor(this._selected[0]) : '';
382
438
  }
383
439
  show() {
384
- if (this.open || this.disabled)
440
+ if (this.open || this.effectiveDisabled)
385
441
  return;
386
442
  this.open = true;
387
443
  }
@@ -422,6 +478,8 @@ export class LyraCombobox extends LyraElement {
422
478
  }
423
479
  if (changed.has('required'))
424
480
  this.updateValidity();
481
+ if (changed.has('name') || changed.has('multiple'))
482
+ this.syncFormValue();
425
483
  if (changed.has('touched') || changed.has('required') || changed.has('value')) {
426
484
  this.toggleAttribute('data-invalid', this.touched && !this.internals.validity.valid);
427
485
  }
@@ -469,11 +527,22 @@ export class LyraCombobox extends LyraElement {
469
527
  this.sourceTimer = setTimeout(() => {
470
528
  const token = ++this.sourceToken;
471
529
  this.loading = true;
472
- this.source(query)
530
+ // `Promise.resolve().then(() => this.source!(query))` moves the call
531
+ // itself inside a `.then()` callback, so a *synchronous* throw from
532
+ // `this.source(query)` becomes a normal promise rejection the
533
+ // following `.catch()` handles, instead of escaping this `setTimeout`
534
+ // callback as an uncaught exception.
535
+ Promise.resolve()
536
+ .then(() => this.source(query))
473
537
  .then((rows) => {
474
538
  if (token !== this.sourceToken || !this.isConnected)
475
539
  return;
476
540
  this.asyncRows = rows;
541
+ })
542
+ .catch((err) => {
543
+ if (token !== this.sourceToken || !this.isConnected)
544
+ return;
545
+ console.warn('<lyra-combobox> source() rejected:', err);
477
546
  })
478
547
  .finally(() => {
479
548
  if (token === this.sourceToken)
@@ -523,6 +592,7 @@ export class LyraCombobox extends LyraElement {
523
592
  const hasHint = this.hasHintSlot || this.hint.length > 0;
524
593
  const hasError = this.hasErrorSlot || this.errorText.length > 0;
525
594
  const hasLabel = this.hasLabelSlot || this.label.length > 0;
595
+ const describedBy = [hasError ? 'combobox-error' : '', hasHint ? 'combobox-hint' : ''].filter(Boolean).join(' ');
526
596
  return html `
527
597
  <div part="form-control">
528
598
  <label part="form-control-label" for=${this.inputId} ?hidden=${!hasLabel}>
@@ -534,6 +604,7 @@ export class LyraCombobox extends LyraElement {
534
604
  >${this.labelFor(v)}<button
535
605
  part="tag__remove-button"
536
606
  type="button"
607
+ ?disabled=${this.effectiveDisabled}
537
608
  aria-label="Remove ${this.labelFor(v)}"
538
609
  @click=${(e) => {
539
610
  e.stopPropagation();
@@ -549,7 +620,8 @@ export class LyraCombobox extends LyraElement {
549
620
  id=${this.inputId}
550
621
  part="combobox-input"
551
622
  role="combobox"
552
- aria-label=${this.label || this.placeholder || 'Combobox'}
623
+ aria-label=${this.getAttribute('aria-label') || (hasLabel ? nothing : this.placeholder || 'Combobox')}
624
+ aria-describedby=${describedBy || nothing}
553
625
  aria-expanded=${this.open ? 'true' : 'false'}
554
626
  aria-controls=${this.listId}
555
627
  aria-activedescendant=${activeId}
@@ -559,7 +631,7 @@ export class LyraCombobox extends LyraElement {
559
631
  autocomplete="off"
560
632
  .value=${this.displayValue}
561
633
  placeholder=${hasValue && !this.multiple ? '' : this.placeholder}
562
- ?disabled=${this.disabled}
634
+ ?disabled=${this.effectiveDisabled}
563
635
  @input=${this.onInput}
564
636
  @keydown=${this.onKeyDown}
565
637
  @focus=${() => this.show()}
@@ -569,6 +641,7 @@ export class LyraCombobox extends LyraElement {
569
641
  ? html `<button
570
642
  part="clear-button"
571
643
  type="button"
644
+ ?disabled=${this.effectiveDisabled}
572
645
  aria-label="Clear"
573
646
  @click=${(e) => {
574
647
  e.stopPropagation();
@@ -597,14 +670,14 @@ export class LyraCombobox extends LyraElement {
597
670
  ? html `<div part="option-overflow">+${overflow} more — refine your search</div>`
598
671
  : ''}`}
599
672
  </div>
600
- <div part="error" ?hidden=${!hasError}>
673
+ <div id="combobox-error" part="error" ?hidden=${!hasError}>
601
674
  ${this.errorText}<slot name="error" @slotchange=${this.onErrorSlotChange}></slot>
602
675
  </div>
603
- <div part="hint" ?hidden=${!hasHint}>
676
+ <div id="combobox-hint" part="hint" ?hidden=${!hasHint}>
604
677
  ${this.hint}<slot name="hint" @slotchange=${this.onHintSlotChange}></slot>
605
678
  </div>
606
679
  </div>
607
- <slot @slotchange=${this.collectOptions} hidden></slot>
680
+ <slot @slotchange=${this.collectOptions} @lyra-option-change=${this.onOptionChange} hidden></slot>
608
681
  `;
609
682
  }
610
683
  }
@@ -620,9 +693,6 @@ __decorate([
620
693
  __decorate([
621
694
  property({ type: Boolean, reflect: true })
622
695
  ], LyraCombobox.prototype, "required", void 0);
623
- __decorate([
624
- property()
625
- ], LyraCombobox.prototype, "name", void 0);
626
696
  __decorate([
627
697
  property()
628
698
  ], LyraCombobox.prototype, "label", void 0);
@@ -1,4 +1,4 @@
1
- import { type TemplateResult } from 'lit';
1
+ import { type TemplateResult, type PropertyValues } from 'lit';
2
2
  import { LyraElement } from '../../internal/lyra-element.js';
3
3
  /**
4
4
  * `<lyra-option>` — a selectable option for `<lyra-combobox>`.
@@ -27,6 +27,10 @@ export declare class LyraOption extends LyraElement {
27
27
  dotColor: string;
28
28
  /** Resolved label: explicit non-empty `label` attribute wins, else trimmed text content. */
29
29
  get label(): string;
30
+ private labelObserver?;
31
+ connectedCallback(): void;
32
+ disconnectedCallback(): void;
33
+ protected updated(changed: PropertyValues): void;
30
34
  render(): TemplateResult;
31
35
  }
32
36
  declare global {
@@ -48,6 +48,41 @@ export class LyraOption extends LyraElement {
48
48
  const attr = this.getAttribute('label');
49
49
  return (attr ? attr : (this.textContent ?? '')).trim();
50
50
  }
51
+ connectedCallback() {
52
+ super.connectedCallback();
53
+ // `label` is derived from either the `label` attribute or `textContent` --
54
+ // neither is a Lit reactive property, so a direct mutation of either
55
+ // (e.g. `option.textContent = 'New label'`) needs its own observer to
56
+ // notify the parent combobox/select that its cached row data is stale.
57
+ this.labelObserver = new MutationObserver(() => this.emit('lyra-option-change'));
58
+ this.labelObserver.observe(this, {
59
+ attributes: true,
60
+ attributeFilter: ['label'],
61
+ childList: true,
62
+ characterData: true,
63
+ subtree: true,
64
+ });
65
+ }
66
+ disconnectedCallback() {
67
+ super.disconnectedCallback();
68
+ this.labelObserver?.disconnect();
69
+ this.labelObserver = undefined;
70
+ }
71
+ updated(changed) {
72
+ // `selected` is deliberately excluded -- the parent combobox/select
73
+ // already sets `selected` itself as *part of* rendering the current
74
+ // selection, so echoing that back as a `lyra-option-change` notification
75
+ // would trigger a redundant re-render on every selection change, rather
76
+ // than signal a genuine "this option's own data changed externally".
77
+ if (changed.has('value') ||
78
+ changed.has('disabled') ||
79
+ changed.has('group') ||
80
+ changed.has('searchText') ||
81
+ changed.has('sub') ||
82
+ changed.has('dotColor')) {
83
+ this.emit('lyra-option-change');
84
+ }
85
+ }
51
86
  render() {
52
87
  return html `<slot></slot>`;
53
88
  }