@aceshooting/lyra-ui 1.2.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 (330) hide show
  1. package/README.md +11 -0
  2. package/custom-elements.json +23341 -11202
  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 +1 -2
  19. package/dist/components/chart/chart.js +67 -12
  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 +54 -0
  23. package/dist/components/chart/lite-chart.js +140 -22
  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 +29 -13
  88. package/dist/components/flag/flag.js +39 -13
  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 +74 -0
  99. package/dist/components/heatmap/heatmap.js +135 -23
  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 +43 -2
  159. package/dist/components/select/select.js +150 -17
  160. package/dist/components/slider/slider.d.ts +89 -0
  161. package/dist/components/slider/slider.js +352 -0
  162. package/dist/components/slider/slider.styles.d.ts +1 -0
  163. package/dist/components/slider/slider.styles.js +87 -0
  164. package/dist/components/source-card/source-card.d.ts +92 -0
  165. package/dist/components/source-card/source-card.js +148 -0
  166. package/dist/components/source-card/source-card.styles.d.ts +1 -0
  167. package/dist/components/source-card/source-card.styles.js +69 -0
  168. package/dist/components/source-list/source-list.d.ts +63 -0
  169. package/dist/components/source-list/source-list.js +122 -0
  170. package/dist/components/source-list/source-list.styles.d.ts +1 -0
  171. package/dist/components/source-list/source-list.styles.js +59 -0
  172. package/dist/components/sparkline/sparkline.js +27 -13
  173. package/dist/components/split/split.d.ts +93 -1
  174. package/dist/components/split/split.js +284 -15
  175. package/dist/components/split/split.styles.js +30 -0
  176. package/dist/components/stat/stat.d.ts +6 -1
  177. package/dist/components/stat/stat.js +8 -2
  178. package/dist/components/stream-status/stream-status.d.ts +110 -0
  179. package/dist/components/stream-status/stream-status.js +210 -0
  180. package/dist/components/stream-status/stream-status.styles.d.ts +1 -0
  181. package/dist/components/stream-status/stream-status.styles.js +103 -0
  182. package/dist/components/streaming-text/streaming-text.d.ts +98 -0
  183. package/dist/components/streaming-text/streaming-text.js +209 -0
  184. package/dist/components/streaming-text/streaming-text.styles.d.ts +1 -0
  185. package/dist/components/streaming-text/streaming-text.styles.js +62 -0
  186. package/dist/components/switch/switch.d.ts +58 -0
  187. package/dist/components/switch/switch.js +179 -0
  188. package/dist/components/switch/switch.styles.d.ts +1 -0
  189. package/dist/components/switch/switch.styles.js +75 -0
  190. package/dist/components/table/table.d.ts +73 -4
  191. package/dist/components/table/table.js +169 -20
  192. package/dist/components/table/table.styles.js +6 -1
  193. package/dist/components/tabs/tabs.d.ts +51 -0
  194. package/dist/components/tabs/tabs.js +190 -0
  195. package/dist/components/tabs/tabs.styles.d.ts +1 -0
  196. package/dist/components/tabs/tabs.styles.js +63 -0
  197. package/dist/components/thinking-panel/thinking-panel.d.ts +121 -0
  198. package/dist/components/thinking-panel/thinking-panel.js +235 -0
  199. package/dist/components/thinking-panel/thinking-panel.styles.d.ts +1 -0
  200. package/dist/components/thinking-panel/thinking-panel.styles.js +117 -0
  201. package/dist/components/toast/toast-item.d.ts +1 -0
  202. package/dist/components/toast/toast-item.js +31 -6
  203. package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +130 -0
  204. package/dist/components/tool-approval-dialog/tool-approval-dialog.js +403 -0
  205. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.d.ts +1 -0
  206. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +160 -0
  207. package/dist/components/tool-call-chip/tool-call-chip.d.ts +89 -0
  208. package/dist/components/tool-call-chip/tool-call-chip.js +288 -0
  209. package/dist/components/tool-call-chip/tool-call-chip.styles.d.ts +1 -0
  210. package/dist/components/tool-call-chip/tool-call-chip.styles.js +203 -0
  211. package/dist/components/tool-param-form/tool-param-form.d.ts +145 -0
  212. package/dist/components/tool-param-form/tool-param-form.js +366 -0
  213. package/dist/components/tool-param-form/tool-param-form.styles.d.ts +1 -0
  214. package/dist/components/tool-param-form/tool-param-form.styles.js +75 -0
  215. package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +102 -0
  216. package/dist/components/tool-result-dialog/tool-result-dialog.js +393 -0
  217. package/dist/components/tool-result-dialog/tool-result-dialog.styles.d.ts +1 -0
  218. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +176 -0
  219. package/dist/components/tool-result-view/registry.d.ts +81 -0
  220. package/dist/components/tool-result-view/registry.js +84 -0
  221. package/dist/components/tool-result-view/tool-result-view.d.ts +55 -0
  222. package/dist/components/tool-result-view/tool-result-view.js +138 -0
  223. package/dist/components/tool-result-view/tool-result-view.styles.d.ts +1 -0
  224. package/dist/components/tool-result-view/tool-result-view.styles.js +13 -0
  225. package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +151 -0
  226. package/dist/components/tool-select-dialog/tool-select-dialog.js +439 -0
  227. package/dist/components/tool-select-dialog/tool-select-dialog.styles.d.ts +1 -0
  228. package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +182 -0
  229. package/dist/components/tree/tree-node.d.ts +11 -2
  230. package/dist/components/tree/tree-node.js +16 -6
  231. package/dist/components/tree/tree.d.ts +8 -2
  232. package/dist/components/tree/tree.js +18 -11
  233. package/dist/components/typing-indicator/typing-indicator.d.ts +60 -0
  234. package/dist/components/typing-indicator/typing-indicator.js +96 -0
  235. package/dist/components/typing-indicator/typing-indicator.styles.d.ts +1 -0
  236. package/dist/components/typing-indicator/typing-indicator.styles.js +132 -0
  237. package/dist/components/virtual-list/virtual-list.d.ts +173 -0
  238. package/dist/components/virtual-list/virtual-list.js +461 -0
  239. package/dist/components/virtual-list/virtual-list.styles.d.ts +1 -0
  240. package/dist/components/virtual-list/virtual-list.styles.js +44 -0
  241. package/dist/components/word-cloud/word-cloud-layout.js +14 -1
  242. package/dist/components/word-cloud/word-cloud.d.ts +6 -0
  243. package/dist/components/word-cloud/word-cloud.js +25 -14
  244. package/dist/components/word-cloud/word-cloud.styles.js +3 -2
  245. package/dist/internal/announcer.d.ts +57 -0
  246. package/dist/internal/announcer.js +71 -0
  247. package/dist/internal/form-associated.d.ts +1 -0
  248. package/dist/internal/form-associated.js +55 -11
  249. package/dist/internal/group-by-recency.d.ts +50 -0
  250. package/dist/internal/group-by-recency.js +80 -0
  251. package/dist/internal/rtl.d.ts +23 -0
  252. package/dist/internal/rtl.js +28 -0
  253. package/dist/internal/scroll-lock.d.ts +10 -5
  254. package/dist/internal/scroll-lock.js +30 -14
  255. package/dist/internal/tokens.styles.js +6 -0
  256. package/dist/lyra.d.ts +130 -31
  257. package/dist/lyra.js +94 -26
  258. package/llms-full.txt +3836 -17
  259. package/llms.txt +16 -1
  260. package/package.json +23 -5
  261. package/dist/components/chart/bar-chart.stories.d.ts +0 -5
  262. package/dist/components/chart/bar-chart.stories.js +0 -20
  263. package/dist/components/chart/box-plot.stories.d.ts +0 -5
  264. package/dist/components/chart/box-plot.stories.js +0 -29
  265. package/dist/components/chart/bubble-chart.stories.d.ts +0 -5
  266. package/dist/components/chart/bubble-chart.stories.js +0 -26
  267. package/dist/components/chart/chart.stories.d.ts +0 -32
  268. package/dist/components/chart/chart.stories.js +0 -141
  269. package/dist/components/chart/doughnut-chart.stories.d.ts +0 -5
  270. package/dist/components/chart/doughnut-chart.stories.js +0 -26
  271. package/dist/components/chart/histogram.stories.d.ts +0 -5
  272. package/dist/components/chart/histogram.stories.js +0 -17
  273. package/dist/components/chart/line-chart.stories.d.ts +0 -22
  274. package/dist/components/chart/line-chart.stories.js +0 -99
  275. package/dist/components/chart/lite-chart.stories.d.ts +0 -14
  276. package/dist/components/chart/lite-chart.stories.js +0 -114
  277. package/dist/components/chart/pie-chart.stories.d.ts +0 -5
  278. package/dist/components/chart/pie-chart.stories.js +0 -26
  279. package/dist/components/chart/polar-area-chart.stories.d.ts +0 -5
  280. package/dist/components/chart/polar-area-chart.stories.js +0 -20
  281. package/dist/components/chart/radar-chart.stories.d.ts +0 -5
  282. package/dist/components/chart/radar-chart.stories.js +0 -20
  283. package/dist/components/chart/scatter-chart.stories.d.ts +0 -5
  284. package/dist/components/chart/scatter-chart.stories.js +0 -31
  285. package/dist/components/combobox/combobox.stories.d.ts +0 -24
  286. package/dist/components/combobox/combobox.stories.js +0 -102
  287. package/dist/components/date-picker/date-input.stories.d.ts +0 -10
  288. package/dist/components/date-picker/date-input.stories.js +0 -48
  289. package/dist/components/date-picker/date-picker.stories.d.ts +0 -10
  290. package/dist/components/date-picker/date-picker.stories.js +0 -25
  291. package/dist/components/empty/empty.stories.d.ts +0 -7
  292. package/dist/components/empty/empty.stories.js +0 -34
  293. package/dist/components/export-button/export-button.stories.d.ts +0 -7
  294. package/dist/components/export-button/export-button.stories.js +0 -37
  295. package/dist/components/file-input/file-input.stories.d.ts +0 -7
  296. package/dist/components/file-input/file-input.stories.js +0 -19
  297. package/dist/components/flag/flag.stories.d.ts +0 -6
  298. package/dist/components/flag/flag.stories.js +0 -31
  299. package/dist/components/gauge/gauge.stories.d.ts +0 -8
  300. package/dist/components/gauge/gauge.stories.js +0 -19
  301. package/dist/components/graph/graph.stories.d.ts +0 -8
  302. package/dist/components/graph/graph.stories.js +0 -68
  303. package/dist/components/heatmap/heatmap.stories.d.ts +0 -27
  304. package/dist/components/heatmap/heatmap.stories.js +0 -179
  305. package/dist/components/map/map.stories.d.ts +0 -15
  306. package/dist/components/map/map.stories.js +0 -135
  307. package/dist/components/playback/playback.stories.d.ts +0 -7
  308. package/dist/components/playback/playback.stories.js +0 -16
  309. package/dist/components/select/select.stories.d.ts +0 -21
  310. package/dist/components/select/select.stories.js +0 -91
  311. package/dist/components/skeleton/skeleton.stories.d.ts +0 -5
  312. package/dist/components/skeleton/skeleton.stories.js +0 -16
  313. package/dist/components/sparkline/sparkline.stories.d.ts +0 -11
  314. package/dist/components/sparkline/sparkline.stories.js +0 -39
  315. package/dist/components/split/split.stories.d.ts +0 -7
  316. package/dist/components/split/split.stories.js +0 -36
  317. package/dist/components/stat/stat.stories.d.ts +0 -9
  318. package/dist/components/stat/stat.stories.js +0 -81
  319. package/dist/components/table/table.stories.d.ts +0 -12
  320. package/dist/components/table/table.stories.js +0 -67
  321. package/dist/components/time-range/time-range.stories.d.ts +0 -8
  322. package/dist/components/time-range/time-range.stories.js +0 -26
  323. package/dist/components/toast/toast.stories.d.ts +0 -8
  324. package/dist/components/toast/toast.stories.js +0 -72
  325. package/dist/components/tree/tree.stories.d.ts +0 -9
  326. package/dist/components/tree/tree.stories.js +0 -52
  327. package/dist/components/widget/widget.stories.d.ts +0 -9
  328. package/dist/components/widget/widget.stories.js +0 -74
  329. package/dist/components/word-cloud/word-cloud.stories.d.ts +0 -10
  330. package/dist/components/word-cloud/word-cloud.stories.js +0 -55
@@ -0,0 +1,490 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html } from 'lit';
8
+ import { property, state } from 'lit/decorators.js';
9
+ import { LyraElement } from '../../internal/lyra-element.js';
10
+ import { defineElement } from '../../internal/prefix.js';
11
+ import { place } from '../../internal/positioner.js';
12
+ import { nextId } from '../../internal/a11y.js';
13
+ import { chevronIcon } from '../../internal/icons.js';
14
+ import { styles } from './model-select.styles.js';
15
+ /**
16
+ * `<lyra-model-select>` — a provider/model picker that renders as a closed
17
+ * dropdown when a fixed `catalog` is available, or as a filterable free-text
18
+ * combobox when it isn't (or when `allow-custom` explicitly permits typing
19
+ * something outside the catalog). Built directly on the shared
20
+ * trigger-button/aria-activedescendant listbox technique `<lyra-select>` uses
21
+ * and the filter-as-you-type suggestion-popup technique `<lyra-combobox>`
22
+ * uses — not by composing either element, since the mode switch and the
23
+ * stale-value handling below are specific to this control.
24
+ *
25
+ * A `value` that isn't present in `catalog` (e.g. a model id saved from a
26
+ * provider whose live catalog has since changed) is never silently dropped:
27
+ * `effectiveEntries` appends it to the rendered option list as a synthetic,
28
+ * visually-distinct row (dashed border, italic label, "not in catalog"
29
+ * badge — see `model-select.styles.ts`) computed fresh from `catalog` +
30
+ * `value` on every render, without ever mutating the `catalog` property
31
+ * itself.
32
+ *
33
+ * @customElement lyra-model-select
34
+ * @event lyra-change - The selected/typed value changed. `detail: { value: string; inCatalog: boolean }`.
35
+ * @csspart trigger - The trigger button (closed-dropdown mode's positioning anchor).
36
+ * @csspart combobox - The text-input container (free-text mode's positioning anchor).
37
+ * @csspart combobox-input - The free-text mode's text input.
38
+ * @csspart provider-badge - The optional leading `provider` label.
39
+ * @csspart listbox - The options popover (shared by both modes).
40
+ * @csspart option - An option row.
41
+ * @csspart option-label - An option row's label.
42
+ * @csspart option-badge - The "not in catalog" badge on a synthetic stale-value row.
43
+ * @csspart expand-icon - The dropdown indicator.
44
+ */
45
+ export class LyraModelSelect extends LyraElement {
46
+ static { this.formAssociated = true; }
47
+ static { this.styles = [LyraElement.styles, styles]; }
48
+ static { this.properties = {
49
+ value: { noAccessor: true },
50
+ }; }
51
+ constructor() {
52
+ super();
53
+ /** Informational only — e.g. `'ollama'`. Rendered as a small leading badge for display grouping. */
54
+ this.provider = '';
55
+ /** Let the user type/commit a value that isn't in `catalog`, even when `catalog` is non-empty. */
56
+ this.allowCustom = false;
57
+ this.placeholder = '';
58
+ this.name = '';
59
+ this.disabled = false;
60
+ this.required = false;
61
+ this.open = false;
62
+ this.activeIndex = -1;
63
+ // Free-text mode's live input text. Only meaningful while `open` — the
64
+ // input is otherwise controlled by the committed value's label (see
65
+ // `renderFreeText`), so this never needs resetting on commit/hide.
66
+ this.query = '';
67
+ // Set on first blur; gates the `data-invalid` reflection below so
68
+ // validity styling never flashes on first render (matches lyra-select).
69
+ this.touched = false;
70
+ this.listId = nextId('model-select-list');
71
+ this.controlId = nextId('model-select-control');
72
+ this._value = '';
73
+ // What `form.reset()` restores to — captured from the `value` *content
74
+ // attribute* only, mirroring native `<input>`/`FormAssociated`'s
75
+ // `_defaultValue` (see internal/form-associated.ts). There's no child
76
+ // markup here to seed a declarative default from (unlike lyra-select's
77
+ // `<lyra-option selected>`), so the initial attribute is the only source.
78
+ this._defaultValue = '';
79
+ this.onDocPointer = (e) => {
80
+ if (!e.composedPath().includes(this))
81
+ this.hide();
82
+ };
83
+ // -- Closed-dropdown mode (trigger button) --------------------------------
84
+ this.onTriggerClick = () => {
85
+ if (this.disabled)
86
+ return;
87
+ this.open ? this.hide() : this.show();
88
+ };
89
+ this.onTriggerBlur = () => {
90
+ this.touched = true;
91
+ this.hide();
92
+ };
93
+ this.onTriggerKeyDown = (e) => {
94
+ const rows = this.effectiveEntries;
95
+ switch (e.key) {
96
+ case 'ArrowDown':
97
+ e.preventDefault();
98
+ if (!this.open)
99
+ return this.show();
100
+ this.activeIndex = Math.min(rows.length - 1, this.activeIndex + 1);
101
+ break;
102
+ case 'ArrowUp':
103
+ e.preventDefault();
104
+ if (!this.open)
105
+ return this.show();
106
+ this.activeIndex = Math.max(0, this.activeIndex - 1);
107
+ break;
108
+ case 'Enter':
109
+ case ' ':
110
+ if (this.open) {
111
+ e.preventDefault();
112
+ if (this.activeIndex >= 0 && rows[this.activeIndex]) {
113
+ this.selectEntry(rows[this.activeIndex]);
114
+ }
115
+ else {
116
+ this.hide();
117
+ }
118
+ }
119
+ break;
120
+ case 'Escape':
121
+ if (this.open) {
122
+ e.preventDefault();
123
+ this.hide();
124
+ }
125
+ break;
126
+ case 'Home':
127
+ if (this.open) {
128
+ e.preventDefault();
129
+ this.activeIndex = 0;
130
+ }
131
+ break;
132
+ case 'End':
133
+ if (this.open) {
134
+ e.preventDefault();
135
+ this.activeIndex = rows.length - 1;
136
+ }
137
+ break;
138
+ }
139
+ };
140
+ // -- Free-text mode (text input) ------------------------------------------
141
+ this.onComboMouseDown = (e) => {
142
+ if (this.disabled)
143
+ return;
144
+ e.preventDefault();
145
+ this.renderRoot.querySelector('[part="combobox-input"]')?.focus();
146
+ };
147
+ this.onInputFocus = () => {
148
+ // Seed the editable text from the *current* value each time a fresh
149
+ // editing session starts, not on every keystroke (onInput overwrites
150
+ // `query` directly) — otherwise a same-session reopen via ArrowDown
151
+ // after Escape would clobber the just-reverted text right back to
152
+ // whatever the user had typed before Escape.
153
+ if (!this.open)
154
+ this.query = this.labelFor(this.value);
155
+ this.show();
156
+ };
157
+ this.onInput = (e) => {
158
+ this.query = e.target.value;
159
+ this.activeIndex = -1;
160
+ this.show();
161
+ };
162
+ this.onInputBlur = () => {
163
+ this.touched = true;
164
+ this.hide();
165
+ };
166
+ this.onInputKeyDown = (e) => {
167
+ const rows = this.filteredEntries;
168
+ switch (e.key) {
169
+ case 'ArrowDown':
170
+ e.preventDefault();
171
+ if (!this.open)
172
+ return this.show();
173
+ this.activeIndex = Math.min(rows.length - 1, this.activeIndex + 1);
174
+ break;
175
+ case 'ArrowUp':
176
+ e.preventDefault();
177
+ if (!this.open)
178
+ return this.show();
179
+ this.activeIndex = Math.max(0, this.activeIndex - 1);
180
+ break;
181
+ case 'Enter':
182
+ if (this.open) {
183
+ e.preventDefault();
184
+ this.commitFreeText();
185
+ }
186
+ break;
187
+ case 'Escape':
188
+ if (this.open) {
189
+ e.preventDefault();
190
+ this.query = this.labelFor(this.value);
191
+ this.hide();
192
+ }
193
+ break;
194
+ case 'Home':
195
+ if (this.open) {
196
+ e.preventDefault();
197
+ this.activeIndex = 0;
198
+ }
199
+ break;
200
+ case 'End':
201
+ if (this.open) {
202
+ e.preventDefault();
203
+ this.activeIndex = rows.length - 1;
204
+ }
205
+ break;
206
+ }
207
+ };
208
+ // -- Shared listbox ---------------------------------------------------
209
+ // Delegated onto [part="listbox"] rather than one closure pair allocated
210
+ // per row per render — resolves the target row via closest('[part="option"]')
211
+ // + a data-value lookup, mirroring lyra-select/lyra-combobox.
212
+ this.onListboxMouseDown = (e) => {
213
+ if (e.target.closest('[part="option"]'))
214
+ e.preventDefault();
215
+ };
216
+ this.onListboxClick = (e) => {
217
+ const optionEl = e.target.closest('[part="option"]');
218
+ const value = optionEl?.dataset.value;
219
+ if (value === undefined)
220
+ return;
221
+ const entry = (this.closedMode ? this.effectiveEntries : this.filteredEntries).find((e2) => e2.id === value);
222
+ if (entry)
223
+ this.selectEntry(entry);
224
+ };
225
+ this.internals = this.attachInternals();
226
+ }
227
+ connectedCallback() {
228
+ super.connectedCallback();
229
+ this.updateValidity();
230
+ }
231
+ disconnectedCallback() {
232
+ super.disconnectedCallback();
233
+ this.cleanup?.();
234
+ document.removeEventListener('pointerdown', this.onDocPointer);
235
+ }
236
+ attributeChangedCallback(name, old, val) {
237
+ super.attributeChangedCallback(name, old, val);
238
+ if (name === 'value')
239
+ this._defaultValue = this._value;
240
+ }
241
+ /** The current model id (empty string when nothing is selected). */
242
+ get value() {
243
+ return this._value;
244
+ }
245
+ set value(next) {
246
+ const old = this._value;
247
+ this._value = next ?? '';
248
+ this.internals.setFormValue(this._value);
249
+ this.updateValidity();
250
+ this.requestUpdate('value', old);
251
+ }
252
+ updateValidity() {
253
+ if (this.required && !this._value) {
254
+ this.internals.setValidity({ valueMissing: true }, 'Please choose a model.');
255
+ }
256
+ else {
257
+ this.internals.setValidity({});
258
+ }
259
+ }
260
+ formResetCallback() {
261
+ this.value = this._defaultValue;
262
+ }
263
+ formDisabledCallback(disabled) {
264
+ this.disabled = disabled;
265
+ }
266
+ checkValidity() {
267
+ return this.internals.checkValidity();
268
+ }
269
+ reportValidity() {
270
+ return this.internals.reportValidity();
271
+ }
272
+ /** `catalog`, normalized to `{ id, label }[]` regardless of the plain-string-array shorthand. */
273
+ get normalizedCatalog() {
274
+ const raw = this.catalog;
275
+ if (!raw || raw.length === 0)
276
+ return [];
277
+ return raw.map((item) => (typeof item === 'string' ? { id: item, label: item } : item));
278
+ }
279
+ /** Closed-dropdown-with-listbox mode vs. free-text filterable mode — see class doc. */
280
+ get closedMode() {
281
+ return this.normalizedCatalog.length > 0 && !this.allowCustom;
282
+ }
283
+ /**
284
+ * `normalizedCatalog` plus, when `value` isn't one of its ids, a synthetic
285
+ * trailing row for it — recomputed from scratch on every access so it
286
+ * always reflects the *current* `catalog`/`value`, never a snapshot from
287
+ * whenever `value` happened to be assigned.
288
+ */
289
+ get effectiveEntries() {
290
+ const catalog = this.normalizedCatalog;
291
+ const entries = catalog.map((e) => ({ ...e, synthetic: false }));
292
+ if (catalog.length > 0 && this._value && !catalog.some((e) => e.id === this._value)) {
293
+ entries.push({ id: this._value, label: this._value, synthetic: true });
294
+ }
295
+ return entries;
296
+ }
297
+ /** `effectiveEntries` filtered by the typed `query` (free-text mode only; id or label substring, case-insensitive). */
298
+ get filteredEntries() {
299
+ const q = this.query.trim().toLowerCase();
300
+ if (!q)
301
+ return this.effectiveEntries;
302
+ return this.effectiveEntries.filter((e) => e.id.toLowerCase().includes(q) || e.label.toLowerCase().includes(q));
303
+ }
304
+ labelFor(id) {
305
+ if (!id)
306
+ return '';
307
+ return this.effectiveEntries.find((e) => e.id === id)?.label ?? id;
308
+ }
309
+ show() {
310
+ if (this.open || this.disabled)
311
+ return;
312
+ this.open = true;
313
+ }
314
+ hide() {
315
+ if (!this.open)
316
+ return;
317
+ this.open = false;
318
+ this.activeIndex = -1;
319
+ }
320
+ updated(changed) {
321
+ const reposition = changed.has('open') || (this.open && (changed.has('catalog') || changed.has('allowCustom')));
322
+ if (reposition) {
323
+ this.cleanup?.();
324
+ this.cleanup = undefined;
325
+ if (this.open) {
326
+ document.addEventListener('pointerdown', this.onDocPointer);
327
+ const anchor = this.renderRoot.querySelector(this.closedMode ? '[part="trigger"]' : '[part="combobox"]');
328
+ const listbox = this.renderRoot.querySelector('[part="listbox"]');
329
+ if (anchor && listbox)
330
+ this.cleanup = place(anchor, listbox);
331
+ }
332
+ else {
333
+ document.removeEventListener('pointerdown', this.onDocPointer);
334
+ }
335
+ }
336
+ if (changed.has('required') || changed.has('touched') || changed.has('value')) {
337
+ this.toggleAttribute('data-invalid', this.touched && !this.internals.validity.valid);
338
+ }
339
+ }
340
+ commitValue(next) {
341
+ const inCatalog = this.normalizedCatalog.some((e) => e.id === next);
342
+ this.value = next;
343
+ this.hide();
344
+ this.emit('lyra-change', { value: next, inCatalog });
345
+ }
346
+ selectEntry(entry) {
347
+ this.commitValue(entry.id);
348
+ }
349
+ /** Enter in free-text mode: commit the highlighted suggestion, else the raw typed text. */
350
+ commitFreeText() {
351
+ const rows = this.filteredEntries;
352
+ if (this.activeIndex >= 0 && rows[this.activeIndex]) {
353
+ this.commitValue(rows[this.activeIndex].id);
354
+ return;
355
+ }
356
+ this.commitValue(this.query.trim());
357
+ }
358
+ renderRows(rows, activeId) {
359
+ return rows.map((entry, i) => {
360
+ const id = `${this.listId}-opt-${i}`;
361
+ const selected = entry.id === this._value;
362
+ return html `<div
363
+ part="option"
364
+ id=${id}
365
+ role="option"
366
+ data-value=${entry.id}
367
+ ?data-synthetic=${entry.synthetic}
368
+ aria-selected=${selected ? 'true' : 'false'}
369
+ ?data-active=${id === activeId}
370
+ >
371
+ <span part="option-label">${entry.label}</span>
372
+ ${entry.synthetic ? html `<span part="option-badge">not in catalog</span>` : ''}
373
+ </div>`;
374
+ });
375
+ }
376
+ renderListbox(rows, activeId, emptyText) {
377
+ return html `
378
+ <div
379
+ part="listbox"
380
+ id=${this.listId}
381
+ role="listbox"
382
+ @mousedown=${this.onListboxMouseDown}
383
+ @click=${this.onListboxClick}
384
+ >
385
+ ${rows.length === 0
386
+ ? html `<div class="empty" role="option" aria-selected="false" aria-disabled="true">${emptyText}</div>`
387
+ : this.renderRows(rows, activeId)}
388
+ </div>
389
+ `;
390
+ }
391
+ renderClosed() {
392
+ const rows = this.effectiveEntries;
393
+ const activeId = this.activeIndex >= 0 && rows[this.activeIndex] ? `${this.listId}-opt-${this.activeIndex}` : '';
394
+ const hasValue = this._value.length > 0;
395
+ return html `
396
+ <button
397
+ id=${this.controlId}
398
+ part="trigger"
399
+ type="button"
400
+ role="combobox"
401
+ aria-haspopup="listbox"
402
+ aria-expanded=${this.open ? 'true' : 'false'}
403
+ aria-controls=${this.listId}
404
+ aria-activedescendant=${activeId}
405
+ aria-label=${this.getAttribute('aria-label') || this.placeholder || 'Model'}
406
+ aria-required=${this.required ? 'true' : 'false'}
407
+ aria-invalid=${this.touched && !this.internals.validity.valid ? 'true' : 'false'}
408
+ ?disabled=${this.disabled}
409
+ @click=${this.onTriggerClick}
410
+ @keydown=${this.onTriggerKeyDown}
411
+ @blur=${this.onTriggerBlur}
412
+ >
413
+ ${this.provider ? html `<span part="provider-badge">${this.provider}</span>` : ''}
414
+ <span class="trigger-label" ?data-placeholder=${!hasValue}
415
+ >${hasValue ? this.labelFor(this._value) : this.placeholder}</span
416
+ >
417
+ <span part="expand-icon" aria-hidden="true">${chevronIcon()}</span>
418
+ </button>
419
+ ${this.renderListbox(rows, activeId, 'No models')}
420
+ `;
421
+ }
422
+ renderFreeText() {
423
+ const rows = this.filteredEntries;
424
+ const activeId = this.activeIndex >= 0 && rows[this.activeIndex] ? `${this.listId}-opt-${this.activeIndex}` : '';
425
+ return html `
426
+ <div part="combobox" @mousedown=${this.onComboMouseDown}>
427
+ ${this.provider ? html `<span part="provider-badge">${this.provider}</span>` : ''}
428
+ <input
429
+ id=${this.controlId}
430
+ part="combobox-input"
431
+ role="combobox"
432
+ aria-label=${this.getAttribute('aria-label') || this.placeholder || 'Model'}
433
+ aria-expanded=${this.open ? 'true' : 'false'}
434
+ aria-controls=${this.listId}
435
+ aria-activedescendant=${activeId}
436
+ aria-autocomplete="list"
437
+ aria-required=${this.required ? 'true' : 'false'}
438
+ aria-invalid=${this.touched && !this.internals.validity.valid ? 'true' : 'false'}
439
+ autocomplete="off"
440
+ .value=${this.open ? this.query : this.labelFor(this._value)}
441
+ placeholder=${this.placeholder}
442
+ ?disabled=${this.disabled}
443
+ @input=${this.onInput}
444
+ @keydown=${this.onInputKeyDown}
445
+ @focus=${this.onInputFocus}
446
+ @blur=${this.onInputBlur}
447
+ />
448
+ <span part="expand-icon" aria-hidden="true">${chevronIcon()}</span>
449
+ </div>
450
+ ${this.renderListbox(rows, activeId, 'No matches')}
451
+ `;
452
+ }
453
+ render() {
454
+ return this.closedMode ? this.renderClosed() : this.renderFreeText();
455
+ }
456
+ }
457
+ __decorate([
458
+ property()
459
+ ], LyraModelSelect.prototype, "provider", void 0);
460
+ __decorate([
461
+ property({ attribute: false })
462
+ ], LyraModelSelect.prototype, "catalog", void 0);
463
+ __decorate([
464
+ property({ type: Boolean, reflect: true, attribute: 'allow-custom' })
465
+ ], LyraModelSelect.prototype, "allowCustom", void 0);
466
+ __decorate([
467
+ property()
468
+ ], LyraModelSelect.prototype, "placeholder", void 0);
469
+ __decorate([
470
+ property()
471
+ ], LyraModelSelect.prototype, "name", void 0);
472
+ __decorate([
473
+ property({ type: Boolean, reflect: true })
474
+ ], LyraModelSelect.prototype, "disabled", void 0);
475
+ __decorate([
476
+ property({ type: Boolean, reflect: true })
477
+ ], LyraModelSelect.prototype, "required", void 0);
478
+ __decorate([
479
+ property({ type: Boolean, reflect: true })
480
+ ], LyraModelSelect.prototype, "open", void 0);
481
+ __decorate([
482
+ state()
483
+ ], LyraModelSelect.prototype, "activeIndex", void 0);
484
+ __decorate([
485
+ state()
486
+ ], LyraModelSelect.prototype, "query", void 0);
487
+ __decorate([
488
+ state()
489
+ ], LyraModelSelect.prototype, "touched", void 0);
490
+ defineElement('model-select', LyraModelSelect);
@@ -0,0 +1 @@
1
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,189 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ position: relative;
5
+ display: inline-block;
6
+ inline-size: 100%;
7
+ max-inline-size: 24rem;
8
+ }
9
+ :host([disabled]) {
10
+ cursor: not-allowed;
11
+ }
12
+
13
+ [part='trigger'],
14
+ [part='combobox'] {
15
+ display: flex;
16
+ align-items: center;
17
+ gap: var(--lyra-space-xs);
18
+ inline-size: 100%;
19
+ min-block-size: 2.5rem;
20
+ box-sizing: border-box;
21
+ padding: var(--lyra-space-xs) var(--lyra-space-s);
22
+ border: 1px solid var(--lyra-color-border);
23
+ border-radius: var(--lyra-radius);
24
+ background: var(--lyra-color-surface);
25
+ color: inherit;
26
+ font: inherit;
27
+ }
28
+ [part='trigger'] {
29
+ cursor: pointer;
30
+ text-align: start;
31
+ }
32
+ [part='combobox'] {
33
+ cursor: text;
34
+ }
35
+ [part='trigger']:focus-visible,
36
+ [part='combobox']:focus-within {
37
+ outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
38
+ outline-offset: var(--lyra-focus-ring-offset);
39
+ }
40
+ :host([open]) [part='trigger'] {
41
+ border-color: var(--lyra-color-brand);
42
+ }
43
+ :host([disabled]) [part='trigger'],
44
+ :host([disabled]) [part='combobox'] {
45
+ opacity: var(--lyra-opacity-disabled);
46
+ cursor: not-allowed;
47
+ }
48
+
49
+ [part='provider-badge'] {
50
+ flex: 0 0 auto;
51
+ padding-inline-end: var(--lyra-space-xs);
52
+ margin-inline-end: var(--lyra-space-xs);
53
+ border-inline-end: 1px solid var(--lyra-color-border);
54
+ font-size: 0.6875rem;
55
+ font-weight: 700;
56
+ text-transform: uppercase;
57
+ letter-spacing: 0.04em;
58
+ color: var(--lyra-color-text-quiet);
59
+ white-space: nowrap;
60
+ }
61
+
62
+ .trigger-label {
63
+ flex: 1 1 auto;
64
+ min-inline-size: 0;
65
+ overflow: hidden;
66
+ text-overflow: ellipsis;
67
+ white-space: nowrap;
68
+ }
69
+ .trigger-label[data-placeholder] {
70
+ color: var(--lyra-color-text-quiet);
71
+ }
72
+
73
+ [part='combobox-input'] {
74
+ flex: 1 1 auto;
75
+ min-inline-size: 0;
76
+ border: none;
77
+ outline: none;
78
+ background: transparent;
79
+ color: inherit;
80
+ font: inherit;
81
+ }
82
+
83
+ [part='expand-icon'] {
84
+ flex: 0 0 auto;
85
+ display: inline-flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ color: var(--lyra-color-text-quiet);
89
+ min-inline-size: min(var(--lyra-icon-button-size), 1.75rem);
90
+ min-block-size: min(var(--lyra-icon-button-size), 1.75rem);
91
+ line-height: 1;
92
+ }
93
+ [part='expand-icon'] svg {
94
+ transform: rotate(90deg);
95
+ }
96
+
97
+ [part='listbox'] {
98
+ position: fixed;
99
+ z-index: 900;
100
+ box-sizing: border-box;
101
+ max-block-size: 18rem;
102
+ overflow-y: auto;
103
+ inline-size: max-content;
104
+ min-inline-size: 12rem;
105
+ max-inline-size: min(92vw, 28rem);
106
+ padding: var(--lyra-space-xs);
107
+ background: var(--lyra-color-surface);
108
+ border: 1px solid var(--lyra-color-border);
109
+ border-radius: var(--lyra-radius);
110
+ box-shadow: var(--lyra-shadow);
111
+ /* Closed state: invisible + slightly raised. visibility (not
112
+ display:none) so opacity/transform can actually transition; hit-testing
113
+ and a11y exposure stay off since this part is already position:fixed. */
114
+ visibility: hidden;
115
+ opacity: 0;
116
+ transform: translateY(-0.25rem);
117
+ transition:
118
+ opacity var(--lyra-transition-fast),
119
+ transform var(--lyra-transition-fast),
120
+ visibility var(--lyra-transition-fast);
121
+ }
122
+ :host([open]) [part='listbox'] {
123
+ visibility: visible;
124
+ opacity: 1;
125
+ transform: translateY(0);
126
+ }
127
+ @media (prefers-reduced-motion: reduce) {
128
+ [part='listbox'] {
129
+ transition: none !important;
130
+ }
131
+ }
132
+
133
+ [part='option'] {
134
+ display: flex;
135
+ align-items: center;
136
+ gap: var(--lyra-space-xs);
137
+ inline-size: 100%;
138
+ box-sizing: border-box;
139
+ padding: var(--lyra-space-xs) var(--lyra-space-s);
140
+ border: 1px solid transparent;
141
+ border-radius: var(--lyra-radius);
142
+ background: none;
143
+ color: inherit;
144
+ font: inherit;
145
+ text-align: start;
146
+ cursor: pointer;
147
+ }
148
+ [part='option']:hover,
149
+ [part='option'][data-active] {
150
+ background: var(--lyra-color-brand-quiet);
151
+ }
152
+ [part='option'][aria-selected='true'] {
153
+ border-color: var(--lyra-color-brand);
154
+ color: var(--lyra-color-brand);
155
+ font-weight: 600;
156
+ }
157
+ [part='option-label'] {
158
+ flex: 1 1 auto;
159
+ min-inline-size: 0;
160
+ overflow: hidden;
161
+ text-overflow: ellipsis;
162
+ white-space: nowrap;
163
+ }
164
+ /* Stale-value row: a previously-saved value that no longer appears in the
165
+ catalog. Marked with a dashed border + italic label (instead of the
166
+ solid border every real row uses) so it visually reads as "remembered,
167
+ not offered" rather than a normal selectable catalog entry. */
168
+ [part='option'][data-synthetic] {
169
+ border-style: dashed;
170
+ border-color: var(--lyra-color-border);
171
+ }
172
+ [part='option'][data-synthetic] [part='option-label'] {
173
+ font-style: italic;
174
+ }
175
+ [part='option-badge'] {
176
+ flex: 0 0 auto;
177
+ font-size: 0.6875rem;
178
+ font-style: normal;
179
+ font-weight: 400;
180
+ color: var(--lyra-color-text-quiet);
181
+ white-space: nowrap;
182
+ }
183
+
184
+ .empty {
185
+ padding: var(--lyra-space-m);
186
+ color: var(--lyra-color-text-quiet);
187
+ font-size: 0.875rem;
188
+ }
189
+ `;