@ds-mo/ui 9.0.0 → 9.2.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 (385) hide show
  1. package/README.md +28 -0
  2. package/dist/.build-stamp +1 -1
  3. package/dist/agent-patterns.json +397 -0
  4. package/dist/agent.json +2347 -735
  5. package/dist/angular/ds-agent-activity.d.ts +12 -0
  6. package/dist/angular/ds-agent-activity.js +38 -0
  7. package/dist/angular/ds-agent-response.d.ts +12 -0
  8. package/dist/angular/ds-agent-response.js +38 -0
  9. package/dist/angular/ds-agent-source-list.d.ts +12 -0
  10. package/dist/angular/ds-agent-source-list.js +38 -0
  11. package/dist/angular/ds-agent-tool-call.d.ts +12 -0
  12. package/dist/angular/ds-agent-tool-call.js +38 -0
  13. package/dist/angular/ds-attachment-list.d.ts +12 -0
  14. package/dist/angular/ds-attachment-list.js +38 -0
  15. package/dist/angular/ds-avatar.d.ts +12 -0
  16. package/dist/angular/ds-avatar.js +38 -0
  17. package/dist/angular/ds-code-block.d.ts +12 -0
  18. package/dist/angular/ds-code-block.js +38 -0
  19. package/dist/angular/ds-conversation-list-item.d.ts +19 -0
  20. package/dist/angular/ds-conversation-list-item.js +42 -0
  21. package/dist/angular/ds-conversation-list-section.d.ts +12 -0
  22. package/dist/angular/ds-conversation-list-section.js +38 -0
  23. package/dist/angular/ds-conversation-list.d.ts +12 -0
  24. package/dist/angular/ds-conversation-list.js +37 -0
  25. package/dist/angular/ds-markdown.d.ts +12 -0
  26. package/dist/angular/ds-markdown.js +38 -0
  27. package/dist/angular/ds-menu.d.ts +6 -1
  28. package/dist/angular/ds-menu.js +7 -4
  29. package/dist/angular/ds-message-bubble.d.ts +12 -0
  30. package/dist/angular/ds-message-bubble.js +38 -0
  31. package/dist/angular/ds-message-composer.d.ts +23 -0
  32. package/dist/angular/ds-message-composer.js +49 -0
  33. package/dist/angular/ds-message-scroller.d.ts +15 -0
  34. package/dist/angular/ds-message-scroller.js +43 -0
  35. package/dist/angular/ds-message.d.ts +12 -0
  36. package/dist/angular/ds-message.js +38 -0
  37. package/dist/angular/ds-panel-tool-header.d.ts +25 -0
  38. package/dist/angular/ds-panel-tool-header.js +49 -0
  39. package/dist/angular/ds-panel-tool-search.d.ts +19 -0
  40. package/dist/angular/ds-panel-tool-search.js +49 -0
  41. package/dist/angular/ds-panel-tools.d.ts +30 -1
  42. package/dist/angular/ds-panel-tools.js +14 -5
  43. package/dist/angular/ds-swatch-picker.d.ts +15 -0
  44. package/dist/angular/ds-swatch-picker.js +42 -0
  45. package/dist/angular/index.d.ts +1 -1
  46. package/dist/angular/index.js +18 -0
  47. package/dist/angular/proxies.d.ts +18 -0
  48. package/dist/angular/proxies.js +18 -0
  49. package/dist/components/ds-agent-activity.d.ts +11 -0
  50. package/dist/components/ds-agent-activity.js +2 -0
  51. package/dist/components/ds-agent-activity.js.map +1 -0
  52. package/dist/components/ds-agent-response.d.ts +11 -0
  53. package/dist/components/ds-agent-response.js +2 -0
  54. package/dist/components/ds-agent-response.js.map +1 -0
  55. package/dist/components/ds-agent-source-list.d.ts +11 -0
  56. package/dist/components/ds-agent-source-list.js +2 -0
  57. package/dist/components/ds-agent-source-list.js.map +1 -0
  58. package/dist/components/ds-agent-tool-call.d.ts +11 -0
  59. package/dist/components/ds-agent-tool-call.js +2 -0
  60. package/dist/components/ds-agent-tool-call.js.map +1 -0
  61. package/dist/components/ds-app-shell.js +1 -1
  62. package/dist/components/ds-app-shell.js.map +1 -1
  63. package/dist/components/ds-attachment-list.d.ts +11 -0
  64. package/dist/components/ds-attachment-list.js +2 -0
  65. package/dist/components/ds-attachment-list.js.map +1 -0
  66. package/dist/components/ds-avatar.d.ts +11 -0
  67. package/dist/components/ds-avatar.js +2 -0
  68. package/dist/components/ds-avatar.js.map +1 -0
  69. package/dist/components/ds-badge.js +1 -1
  70. package/dist/components/ds-banner.js +1 -1
  71. package/dist/components/ds-bar-nav.js +1 -1
  72. package/dist/components/ds-bar-nav.js.map +1 -1
  73. package/dist/components/ds-button-filled.js +1 -1
  74. package/dist/components/ds-button-unfilled.js +1 -1
  75. package/dist/components/ds-card-data-viz-donut.js +1 -1
  76. package/dist/components/ds-card-setting.js +1 -1
  77. package/dist/components/ds-card-shell-data-viz.js +1 -1
  78. package/dist/components/ds-card.js +1 -1
  79. package/dist/components/ds-chart-bar.js +1 -1
  80. package/dist/components/ds-chart-bar.js.map +1 -1
  81. package/dist/components/ds-chart-donut.js +1 -1
  82. package/dist/components/ds-chart-legend.js +1 -1
  83. package/dist/components/ds-chart-line.js +1 -1
  84. package/dist/components/ds-checkbox.js +1 -1
  85. package/dist/components/ds-chip.js +1 -1
  86. package/dist/components/ds-code-block.d.ts +11 -0
  87. package/dist/components/ds-code-block.js +2 -0
  88. package/dist/components/ds-code-block.js.map +1 -0
  89. package/dist/components/ds-conversation-list-item.d.ts +11 -0
  90. package/dist/components/ds-conversation-list-item.js +2 -0
  91. package/dist/components/ds-conversation-list-item.js.map +1 -0
  92. package/dist/components/ds-conversation-list-section.d.ts +11 -0
  93. package/dist/components/ds-conversation-list-section.js +2 -0
  94. package/dist/components/ds-conversation-list-section.js.map +1 -0
  95. package/dist/components/ds-conversation-list.d.ts +11 -0
  96. package/dist/components/ds-conversation-list.js +2 -0
  97. package/dist/components/ds-conversation-list.js.map +1 -0
  98. package/dist/components/ds-divider.js +1 -1
  99. package/dist/components/ds-divider.js.map +1 -1
  100. package/dist/components/ds-empty-state.js +1 -1
  101. package/dist/components/ds-field.js +1 -1
  102. package/dist/components/ds-icon.js +1 -1
  103. package/dist/components/ds-input.js +1 -1
  104. package/dist/components/ds-markdown.d.ts +11 -0
  105. package/dist/components/ds-markdown.js +2 -0
  106. package/dist/components/ds-markdown.js.map +1 -0
  107. package/dist/components/ds-menu.js +1 -1
  108. package/dist/components/ds-message-bubble.d.ts +11 -0
  109. package/dist/components/ds-message-bubble.js +2 -0
  110. package/dist/components/ds-message-bubble.js.map +1 -0
  111. package/dist/components/ds-message-composer.d.ts +11 -0
  112. package/dist/components/ds-message-composer.js +2 -0
  113. package/dist/components/ds-message-composer.js.map +1 -0
  114. package/dist/components/ds-message-scroller.d.ts +11 -0
  115. package/dist/components/ds-message-scroller.js +2 -0
  116. package/dist/components/ds-message-scroller.js.map +1 -0
  117. package/dist/components/ds-message.d.ts +11 -0
  118. package/dist/components/ds-message.js +2 -0
  119. package/dist/components/ds-message.js.map +1 -0
  120. package/dist/components/ds-modal.js +1 -1
  121. package/dist/components/ds-panel-nav.js +1 -1
  122. package/dist/components/ds-panel-nav.js.map +1 -1
  123. package/dist/components/ds-panel-sub-nav.js +1 -1
  124. package/dist/components/ds-panel-tool-header.d.ts +11 -0
  125. package/dist/components/ds-panel-tool-header.js +2 -0
  126. package/dist/components/ds-panel-tool-header.js.map +1 -0
  127. package/dist/components/ds-panel-tool-search.d.ts +11 -0
  128. package/dist/components/ds-panel-tool-search.js +2 -0
  129. package/dist/components/ds-panel-tool-search.js.map +1 -0
  130. package/dist/components/ds-panel-tools.js +1 -1
  131. package/dist/components/ds-panel-tools.js.map +1 -1
  132. package/dist/components/ds-radio.js +1 -1
  133. package/dist/components/ds-select-multi.js +1 -1
  134. package/dist/components/ds-select-multi.js.map +1 -1
  135. package/dist/components/ds-select.js +1 -1
  136. package/dist/components/ds-select.js.map +1 -1
  137. package/dist/components/ds-shell-gradient-picker.js +1 -1
  138. package/dist/components/ds-shell-gradient-picker.js.map +1 -1
  139. package/dist/components/ds-shell-gradient-swatch.js +1 -1
  140. package/dist/components/ds-shell-gradient-swatch.js.map +1 -1
  141. package/dist/components/ds-skeleton.js +1 -1
  142. package/dist/components/ds-slider.js +1 -1
  143. package/dist/components/ds-slider.js.map +1 -1
  144. package/dist/components/ds-swatch-picker.d.ts +11 -0
  145. package/dist/components/ds-swatch-picker.js +2 -0
  146. package/dist/components/ds-swatch-picker.js.map +1 -0
  147. package/dist/components/ds-switch.js +1 -1
  148. package/dist/components/ds-tab-group.js +1 -1
  149. package/dist/components/ds-tab-group.js.map +1 -1
  150. package/dist/components/ds-tag.js +1 -1
  151. package/dist/components/ds-text.js +1 -1
  152. package/dist/components/ds-tooltip-data-viz.js +1 -1
  153. package/dist/components/ds-tooltip.js +1 -1
  154. package/dist/components/index.d.ts +14 -0
  155. package/dist/components/p--KbMQblZ.js +2 -0
  156. package/dist/components/p--KbMQblZ.js.map +1 -0
  157. package/dist/components/p-2br9YDbG.js +2 -0
  158. package/dist/components/p-2br9YDbG.js.map +1 -0
  159. package/dist/components/p-41UAx2eq.js +2 -0
  160. package/dist/components/p-41UAx2eq.js.map +1 -0
  161. package/dist/components/p-B1pWGQn1.js +2 -0
  162. package/dist/components/p-B1pWGQn1.js.map +1 -0
  163. package/dist/components/p-B7NbIYjS.js +2 -0
  164. package/dist/components/p-B7NbIYjS.js.map +1 -0
  165. package/dist/components/p-BBu_Svz7.js +2 -0
  166. package/dist/components/p-BBu_Svz7.js.map +1 -0
  167. package/dist/components/p-BEQB8EnB.js +2 -0
  168. package/dist/components/p-BEQB8EnB.js.map +1 -0
  169. package/dist/components/{p-CZ9wemOA.js → p-BFWC17em.js} +2 -2
  170. package/dist/components/{p-KRGBGTu5.js → p-BO6C8abO.js} +2 -2
  171. package/dist/components/{p-CbS_WWs2.js → p-BSOZXagj.js} +2 -2
  172. package/dist/components/p-BSOZXagj.js.map +1 -0
  173. package/dist/components/{p-DT2MK8Kt.js → p-BZAEZENv.js} +2 -2
  174. package/dist/components/p-BhC1YyId.js +2 -0
  175. package/dist/components/p-BhC1YyId.js.map +1 -0
  176. package/dist/components/p-BjtXYFhw.js +2 -0
  177. package/dist/components/p-BjtXYFhw.js.map +1 -0
  178. package/dist/components/{p-B-zhgAvL.js → p-Bo5wikia.js} +2 -2
  179. package/dist/components/p-Bx1G7P6W.js +2 -0
  180. package/dist/components/p-Bx1G7P6W.js.map +1 -0
  181. package/dist/components/p-C0sq948W.js +2 -0
  182. package/dist/components/p-C0sq948W.js.map +1 -0
  183. package/dist/components/p-CC1C8s6m.js +2 -0
  184. package/dist/components/p-CC1C8s6m.js.map +1 -0
  185. package/dist/components/p-CKaJx0IX.js +2 -0
  186. package/dist/components/p-CKaJx0IX.js.map +1 -0
  187. package/dist/components/{p-DyZj3k9S.js → p-CZMEhdlA.js} +2 -2
  188. package/dist/components/{p-BbV68F23.js → p-CiwdnKKp.js} +2 -2
  189. package/dist/components/{p-BLzivrE3.js → p-CnM9SW_8.js} +2 -2
  190. package/dist/components/{p-C7UFYvsO.js → p-CuKn9I5f.js} +2 -2
  191. package/dist/components/p-D1HFMTdC.js +2 -0
  192. package/dist/components/p-D1HFMTdC.js.map +1 -0
  193. package/dist/components/p-DFMM60My.js +2 -0
  194. package/dist/components/p-DFMM60My.js.map +1 -0
  195. package/dist/components/p-DIsDiGcp.js +2 -0
  196. package/dist/components/p-DIsDiGcp.js.map +1 -0
  197. package/dist/components/p-DVsje4AY.js +2 -0
  198. package/dist/components/p-DVsje4AY.js.map +1 -0
  199. package/dist/components/p-Di-ThR90.js +2 -0
  200. package/dist/components/p-Di-ThR90.js.map +1 -0
  201. package/dist/components/{p-C7RObioO.js → p-Di4HBckb.js} +2 -2
  202. package/dist/components/p-a9nGf1s6.js +2 -0
  203. package/dist/components/p-a9nGf1s6.js.map +1 -0
  204. package/dist/components/p-gidVv1FX.js +2 -0
  205. package/dist/components/p-gidVv1FX.js.map +1 -0
  206. package/dist/components/p-l6PmnW_P.js +2 -0
  207. package/dist/components/p-l6PmnW_P.js.map +1 -0
  208. package/dist/components/p-rEe-3KR_.js +2 -0
  209. package/dist/components/p-rEe-3KR_.js.map +1 -0
  210. package/dist/components/p-t9Ei1kHP.js +2 -0
  211. package/dist/components/p-t9Ei1kHP.js.map +1 -0
  212. package/dist/docs/components.json +8097 -3924
  213. package/dist/lib/components/Menu/menu-placement.d.ts +19 -3
  214. package/dist/lib/shell/index.d.ts +3 -3
  215. package/dist/lib/shell/index.js +48 -39
  216. package/dist/lib/shell/index.js.map +3 -3
  217. package/dist/lib/shell/shell-gradient-presets.d.ts +15 -0
  218. package/dist/lib/utils/choice-popup-alignment.d.ts +20 -0
  219. package/dist/lib/utils/index.d.ts +2 -0
  220. package/dist/lib/utils/index.js +16 -0
  221. package/dist/lib/utils/index.js.map +3 -3
  222. package/dist/mcp/cli.js +31409 -0
  223. package/dist/mcp-data/registry/agent-activity.json +158 -0
  224. package/dist/mcp-data/registry/agent-response.json +211 -0
  225. package/dist/mcp-data/registry/agent-source-list.json +153 -0
  226. package/dist/mcp-data/registry/agent-tool-call.json +213 -0
  227. package/dist/mcp-data/registry/app-shell.json +210 -0
  228. package/dist/mcp-data/registry/attachment-list.json +137 -0
  229. package/dist/mcp-data/registry/avatar.json +136 -0
  230. package/dist/mcp-data/registry/badge.json +289 -0
  231. package/dist/mcp-data/registry/banner.json +206 -0
  232. package/dist/mcp-data/registry/bar-nav.json +341 -0
  233. package/dist/mcp-data/registry/button-filled.json +386 -0
  234. package/dist/mcp-data/registry/button-unfilled.json +537 -0
  235. package/dist/mcp-data/registry/card-data-viz-donut.json +143 -0
  236. package/dist/mcp-data/registry/card-setting.json +194 -0
  237. package/dist/mcp-data/registry/card-shell-data-viz.json +173 -0
  238. package/dist/mcp-data/registry/card.json +126 -0
  239. package/dist/mcp-data/registry/chart-bar.json +121 -0
  240. package/dist/mcp-data/registry/chart-donut.json +257 -0
  241. package/dist/mcp-data/registry/chart-legend.json +209 -0
  242. package/dist/mcp-data/registry/chart-line.json +153 -0
  243. package/dist/mcp-data/registry/checkbox.json +361 -0
  244. package/dist/mcp-data/registry/chip.json +276 -0
  245. package/dist/mcp-data/registry/code-block.json +150 -0
  246. package/dist/mcp-data/registry/conversation-list-item.json +265 -0
  247. package/dist/mcp-data/registry/conversation-list-section.json +139 -0
  248. package/dist/mcp-data/registry/conversation-list.json +101 -0
  249. package/dist/mcp-data/registry/divider.json +225 -0
  250. package/dist/mcp-data/registry/empty-state.json +197 -0
  251. package/dist/mcp-data/registry/field.json +222 -0
  252. package/dist/mcp-data/registry/icon.json +242 -0
  253. package/dist/mcp-data/registry/input.json +597 -0
  254. package/dist/mcp-data/registry/loader.json +192 -0
  255. package/dist/mcp-data/registry/markdown.json +141 -0
  256. package/dist/mcp-data/registry/menu.json +479 -0
  257. package/dist/mcp-data/registry/message-bubble.json +119 -0
  258. package/dist/mcp-data/registry/message-composer.json +265 -0
  259. package/dist/mcp-data/registry/message-scroller.json +217 -0
  260. package/dist/mcp-data/registry/message.json +255 -0
  261. package/dist/mcp-data/registry/modal.json +150 -0
  262. package/dist/mcp-data/registry/panel-nav.json +622 -0
  263. package/dist/mcp-data/registry/panel-sub-nav.json +249 -0
  264. package/dist/mcp-data/registry/panel-tool-header.json +342 -0
  265. package/dist/mcp-data/registry/panel-tool-search.json +387 -0
  266. package/dist/mcp-data/registry/panel-tools.json +514 -0
  267. package/dist/mcp-data/registry/radio.json +374 -0
  268. package/dist/mcp-data/registry/registry.json +6916 -0
  269. package/dist/mcp-data/registry/select-multi.json +755 -0
  270. package/dist/mcp-data/registry/select.json +740 -0
  271. package/dist/mcp-data/registry/shell-gradient-picker.json +195 -0
  272. package/dist/mcp-data/registry/shell-gradient-swatch.json +215 -0
  273. package/dist/mcp-data/registry/skeleton.json +282 -0
  274. package/dist/mcp-data/registry/slider.json +657 -0
  275. package/dist/mcp-data/registry/swatch-picker.json +231 -0
  276. package/dist/mcp-data/registry/switch.json +361 -0
  277. package/dist/mcp-data/registry/tab-group.json +255 -0
  278. package/dist/mcp-data/registry/tag.json +352 -0
  279. package/dist/mcp-data/registry/text.json +371 -0
  280. package/dist/mcp-data/registry/tooltip-data-viz.json +158 -0
  281. package/dist/mcp-data/registry/tooltip.json +311 -0
  282. package/dist/react/components.d.ts +18 -0
  283. package/dist/react/components.js +18 -0
  284. package/dist/react/ds-agent-activity.d.ts +9 -0
  285. package/dist/react/ds-agent-activity.js +12 -0
  286. package/dist/react/ds-agent-response.d.ts +9 -0
  287. package/dist/react/ds-agent-response.js +12 -0
  288. package/dist/react/ds-agent-source-list.d.ts +9 -0
  289. package/dist/react/ds-agent-source-list.js +12 -0
  290. package/dist/react/ds-agent-tool-call.d.ts +9 -0
  291. package/dist/react/ds-agent-tool-call.js +12 -0
  292. package/dist/react/ds-attachment-list.d.ts +9 -0
  293. package/dist/react/ds-attachment-list.js +12 -0
  294. package/dist/react/ds-avatar.d.ts +9 -0
  295. package/dist/react/ds-avatar.js +12 -0
  296. package/dist/react/ds-code-block.d.ts +9 -0
  297. package/dist/react/ds-code-block.js +12 -0
  298. package/dist/react/ds-conversation-list-item.d.ts +14 -0
  299. package/dist/react/ds-conversation-list-item.js +12 -0
  300. package/dist/react/ds-conversation-list-section.d.ts +9 -0
  301. package/dist/react/ds-conversation-list-section.js +12 -0
  302. package/dist/react/ds-conversation-list.d.ts +9 -0
  303. package/dist/react/ds-conversation-list.js +12 -0
  304. package/dist/react/ds-markdown.d.ts +9 -0
  305. package/dist/react/ds-markdown.js +12 -0
  306. package/dist/react/ds-menu.d.ts +1 -0
  307. package/dist/react/ds-menu.js +2 -1
  308. package/dist/react/ds-message-bubble.d.ts +9 -0
  309. package/dist/react/ds-message-bubble.js +12 -0
  310. package/dist/react/ds-message-composer.d.ts +16 -0
  311. package/dist/react/ds-message-composer.js +16 -0
  312. package/dist/react/ds-message-scroller.d.ts +12 -0
  313. package/dist/react/ds-message-scroller.js +12 -0
  314. package/dist/react/ds-message.d.ts +9 -0
  315. package/dist/react/ds-message.js +12 -0
  316. package/dist/react/ds-panel-tool-header.d.ts +17 -0
  317. package/dist/react/ds-panel-tool-header.js +16 -0
  318. package/dist/react/ds-panel-tool-search.d.ts +14 -0
  319. package/dist/react/ds-panel-tool-search.js +16 -0
  320. package/dist/react/ds-panel-tools.d.ts +10 -0
  321. package/dist/react/ds-panel-tools.js +3 -0
  322. package/dist/react/ds-swatch-picker.d.ts +12 -0
  323. package/dist/react/ds-swatch-picker.js +12 -0
  324. package/dist/types/components/AgentActivity/AgentActivity.d.ts +14 -0
  325. package/dist/types/components/AgentResponse/AgentResponse.d.ts +12 -0
  326. package/dist/types/components/AgentSourceList/AgentSourceList.d.ts +9 -0
  327. package/dist/types/components/AgentToolCall/AgentToolCall.d.ts +13 -0
  328. package/dist/types/components/AppShell/AppShell.d.ts +4 -0
  329. package/dist/types/components/AttachmentList/AttachmentList.d.ts +8 -0
  330. package/dist/types/components/Avatar/Avatar.d.ts +8 -0
  331. package/dist/types/components/CodeBlock/CodeBlock.d.ts +11 -0
  332. package/dist/types/components/ConversationList/ConversationList.d.ts +4 -0
  333. package/dist/types/components/ConversationListItem/ConversationListItem.d.ts +22 -0
  334. package/dist/types/components/ConversationListSection/ConversationListSection.d.ts +9 -0
  335. package/dist/types/components/Markdown/Markdown.d.ts +15 -0
  336. package/dist/types/components/Menu/Menu.d.ts +10 -1
  337. package/dist/types/components/Menu/menu-placement.d.ts +19 -3
  338. package/dist/types/components/Menu/menu-types.d.ts +15 -2
  339. package/dist/types/components/Message/Message.d.ts +17 -0
  340. package/dist/types/components/MessageBubble/MessageBubble.d.ts +6 -0
  341. package/dist/types/components/MessageComposer/MessageComposer.d.ts +29 -0
  342. package/dist/types/components/MessageScroller/MessageScroller.d.ts +37 -0
  343. package/dist/types/components/PanelNav/PanelNav.d.ts +3 -0
  344. package/dist/types/components/PanelToolHeader/PanelToolHeader.d.ts +34 -0
  345. package/dist/types/components/PanelToolSearch/PanelToolSearch.d.ts +35 -0
  346. package/dist/types/components/PanelTools/PanelTools.d.ts +40 -1
  347. package/dist/types/components/PanelTools/panel-tools-types.d.ts +20 -0
  348. package/dist/types/components/PanelTools/panel-tools-utils.d.ts +2 -0
  349. package/dist/types/components/ShellGradientPicker/ShellGradientPicker.d.ts +2 -5
  350. package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +1 -0
  351. package/dist/types/components/Slider/Slider.d.ts +1 -1
  352. package/dist/types/components/SwatchPicker/SwatchPicker.d.ts +21 -0
  353. package/dist/types/components/SwatchPicker/swatch-picker-types.d.ts +26 -0
  354. package/dist/types/components/conversation-types.d.ts +55 -0
  355. package/dist/types/components.d.ts +1298 -4
  356. package/dist/types/shell/index.d.ts +3 -3
  357. package/dist/types/shell/shell-gradient-presets.d.ts +15 -0
  358. package/dist/types/utils/choice-list-parts.d.ts +4 -1
  359. package/dist/types/utils/choice-popup-alignment.d.ts +21 -0
  360. package/dist/types/utils/index.d.ts +2 -0
  361. package/package.json +9 -2
  362. package/dist/components/p-Bafp65bw.js +0 -2
  363. package/dist/components/p-Bafp65bw.js.map +0 -1
  364. package/dist/components/p-BdnR3jxi.js +0 -2
  365. package/dist/components/p-BdnR3jxi.js.map +0 -1
  366. package/dist/components/p-CXF8yd-g.js +0 -2
  367. package/dist/components/p-CXF8yd-g.js.map +0 -1
  368. package/dist/components/p-C_cu-HIT.js +0 -2
  369. package/dist/components/p-C_cu-HIT.js.map +0 -1
  370. package/dist/components/p-CbS_WWs2.js.map +0 -1
  371. package/dist/components/p-D0B9uDTP.js +0 -2
  372. package/dist/components/p-D0B9uDTP.js.map +0 -1
  373. package/dist/components/p-DF0yLZG_.js +0 -2
  374. package/dist/components/p-DF0yLZG_.js.map +0 -1
  375. package/dist/components/p-VKIsOVza.js +0 -2
  376. package/dist/components/p-VKIsOVza.js.map +0 -1
  377. /package/dist/components/{p-CZ9wemOA.js.map → p-BFWC17em.js.map} +0 -0
  378. /package/dist/components/{p-KRGBGTu5.js.map → p-BO6C8abO.js.map} +0 -0
  379. /package/dist/components/{p-DT2MK8Kt.js.map → p-BZAEZENv.js.map} +0 -0
  380. /package/dist/components/{p-B-zhgAvL.js.map → p-Bo5wikia.js.map} +0 -0
  381. /package/dist/components/{p-DyZj3k9S.js.map → p-CZMEhdlA.js.map} +0 -0
  382. /package/dist/components/{p-BbV68F23.js.map → p-CiwdnKKp.js.map} +0 -0
  383. /package/dist/components/{p-BLzivrE3.js.map → p-CnM9SW_8.js.map} +0 -0
  384. /package/dist/components/{p-C7UFYvsO.js.map → p-CuKn9I5f.js.map} +0 -0
  385. /package/dist/components/{p-C7RObioO.js.map → p-Di4HBckb.js.map} +0 -0
@@ -0,0 +1,740 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "select",
4
+ "title": "Select",
5
+ "description": "Form-associated single-value select with listbox semantics, local search, rich flat options, grouped sections, loading, clearing, and surface-aware trigger chrome.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@ds-mo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/compomo/?path=/story/select",
11
+ "source": "src/wc/components/Select/Select.tsx",
12
+ "intentStatus": "complete",
13
+ "intent": {
14
+ "audience": "general",
15
+ "status": "stable",
16
+ "summary": "Form-associated single-value select with listbox semantics, local search, rich flat options, grouped sections, loading, clearing, and surface-aware trigger chrome.",
17
+ "useWhen": [
18
+ "The user must choose one value from a finite set.",
19
+ "The option set benefits from local search, subtext, prefix icons, grouping, or disabled choices.",
20
+ "The choice set has more than roughly 20 options, comes from a user-managed listing, or represents a large domain such as addresses where search materially improves retrieval.",
21
+ "The selected value must participate in native, Angular, or React form state."
22
+ ],
23
+ "avoidWhen": [
24
+ "Several values may be selected at once.",
25
+ "The rows perform commands rather than choosing a form value.",
26
+ "The choices form a hierarchy with expandable parents."
27
+ ],
28
+ "alternatives": [
29
+ {
30
+ "when": "Several independent values may be selected.",
31
+ "component": "component:ds-select-multi",
32
+ "reason": "SelectMulti owns array values, multi-selection semantics, and count presentation."
33
+ },
34
+ {
35
+ "when": "The popup contains commands or state-changing actions.",
36
+ "component": "component:ds-menu",
37
+ "reason": "Menu uses action-menu roles and command-focused keyboard behavior."
38
+ },
39
+ {
40
+ "when": "A small set of choices should remain visible.",
41
+ "component": "component:ds-radio",
42
+ "reason": "Prefer Radio for roughly two to five mutually exclusive choices when the available space allows all choices to remain visible."
43
+ }
44
+ ],
45
+ "commonlyComposedWith": [
46
+ "component:ds-text",
47
+ "component:ds-icon",
48
+ "component:ds-empty-state",
49
+ "component:ds-loader"
50
+ ],
51
+ "accessibility": [
52
+ "In forms, provide a persistent visible external field label; placeholder text is guidance and must not be the field's only label. In a compact filter bar, the trigger's visible text may supply the accessible name.",
53
+ "The trigger uses combobox semantics and the popup uses listbox and option semantics; do not replace them with menu roles.",
54
+ "Disabled options remain visible, expose aria-disabled, and are skipped by keyboard navigation and typeahead.",
55
+ "Keyboard navigation keeps the aria-activedescendant option scrolled into the visible listbox viewport.",
56
+ "Selected options rely on active fill and foreground treatment without a redundant trailing check icon.",
57
+ "Local search moves focus into the search field while preserving the active option through aria-activedescendant.",
58
+ "Use errorMessage with error so the trigger is described by the rendered alert."
59
+ ],
60
+ "states": [
61
+ "Value is controlled through the mutable value property; dsChange reports user selection and clearing.",
62
+ "Required Selects begin without an automatic selection and require the user to make an explicit choice; do not preselect the first option merely to satisfy validity.",
63
+ "When allowClear is enabled, the clear affordance appears only after a value exists. Clearing is valid for optional and required fields; a required field becomes invalid until the user selects again.",
64
+ "Clearing emits dsChange with an empty string and dsClear, keeps the popup open, and restores useful focus.",
65
+ "Loading keeps the trigger visible, replaces its prefix icon, marks the control busy, and makes selection interaction temporarily unavailable without presenting the control as inactive.",
66
+ "The trigger label stays left-aligned at every width. The default size is md in both forms and filter bars; smaller sizes require an explicit density need.",
67
+ "Use option icons only when they help users differentiate choices. Icons render only when every option in the complete list provides one; mixed icon data falls back to the text-only row layout.",
68
+ "Create sections only for categories that are meaningful to customers, not merely to break a long list into arbitrary chunks.",
69
+ "When any option supplies subtext, every row uses the same subtext structure and missing values render an em dash. Subtext should disambiguate or add decision-helpful information.",
70
+ "Option labels and the selected trigger label stay on one line and truncate when constrained. Option subtext may wrap to at most two lines.",
71
+ "The optional prefix icon and chevron always use the parent surface's secondary foreground color, including when a selected value promotes the label to primary.",
72
+ "The shared popup search control stays md at every trigger size, using body-medium text, a 20px icon, and the same internal spacing as a borderless Select trigger. Its container uses menu-item padding on every side and owns a 1px bottom divider that becomes a 1.5px bold-brand stroke while search has focus. Search placeholder text is secondary at rest and quaternary while focused because it becomes decorative once the editable field is active.",
73
+ "When search contains text, the shared control shows a rounded sm icon-only ButtonUnfilled with the CrossCircle icon and no border. It clears the local term, stays hidden for an empty term, and returns focus to search.",
74
+ "The shared clear footer mirrors the search region's sizing: menu-item padding surrounds an md-height borderless row, and the Clear label uses the same row and label insets as option text. The outer footer owns a 1px top divider.",
75
+ "An empty filtered list composes the message-only body variant of EmptyState. Keep the default neutral no-results message unless localized product guidance makes the outcome clearer.",
76
+ "Enable searchable for more than roughly 20 options, user-managed listings, large domains such as addresses, or sets users cannot efficiently scan. Local matching includes option labels, subtext, and section headings; the owner resolves remote data before assigning options.",
77
+ "Validation timing belongs to the form owner and may be immediate or deferred until blur or submit; the Select exposes validity and error presentation without imposing that policy.",
78
+ "The error trigger uses a 1.5px bold-negative inset stroke so invalid state remains distinguishable from the normal 1px border without changing control geometry.",
79
+ "An initially empty option set is not an expected Select use case. The no-results state describes a search with no matches, not a source with no choices.",
80
+ "Use options for a flat list or sections for grouped choices; when sections are present they take precedence.",
81
+ "The background prop describes the actual parent surface and uses the same surface set as ButtonUnfilled."
82
+ ],
83
+ "responsiveBehavior": [
84
+ "Use width fill for form fields and width hug for compact filter bars. Override those defaults only when the owning layout has a clear constraint.",
85
+ "The popup matches the trigger minimum width, may grow for content, and clamps to the viewport.",
86
+ "Long option collections scroll inside the popup; virtualization and remote search are not part of this component."
87
+ ],
88
+ "frameworkCaveats": {
89
+ "customElements": [
90
+ "Assign options and sections through JavaScript properties because arrays and objects cannot be represented safely as attributes."
91
+ ],
92
+ "react": [
93
+ "Pass options or sections as wrapper props and handle onDsChange, onDsClear, and onDsOpenChange."
94
+ ],
95
+ "angular": [
96
+ "Import DsSelect and SelectValueAccessor when integrating with Angular Forms; bind options and sections as properties."
97
+ ]
98
+ },
99
+ "references": [
100
+ {
101
+ "label": "Storybook examples",
102
+ "path": "src/wc/components/Select/Select.stories.ts"
103
+ },
104
+ {
105
+ "label": "Selection patterns",
106
+ "path": "src/docs/SelectionPatterns.mdx"
107
+ }
108
+ ]
109
+ },
110
+ "api": {
111
+ "props": {
112
+ "activeFill": {
113
+ "type": "boolean",
114
+ "resolvedType": "boolean",
115
+ "attribute": "active-fill",
116
+ "default": "true",
117
+ "required": false,
118
+ "mutable": false,
119
+ "description": "Show the selected interaction fill when a valid value exists."
120
+ },
121
+ "allowClear": {
122
+ "type": "boolean",
123
+ "resolvedType": "boolean",
124
+ "attribute": "allow-clear",
125
+ "default": "true",
126
+ "required": false,
127
+ "mutable": false,
128
+ "description": "Show the clear footer action when a value exists."
129
+ },
130
+ "ariaDescribedby": {
131
+ "type": "string | undefined",
132
+ "resolvedType": "string | undefined",
133
+ "attribute": "aria-describedby",
134
+ "required": false,
135
+ "mutable": false,
136
+ "description": "Additional IDs that describe the combobox."
137
+ },
138
+ "ariaLabel": {
139
+ "type": "string | null",
140
+ "resolvedType": "null | string",
141
+ "attribute": "aria-label",
142
+ "default": "null",
143
+ "required": false,
144
+ "mutable": false,
145
+ "description": "Direct accessible name when no external label is available."
146
+ },
147
+ "ariaLabelledby": {
148
+ "type": "string | undefined",
149
+ "resolvedType": "string | undefined",
150
+ "attribute": "aria-labelledby",
151
+ "required": false,
152
+ "mutable": false,
153
+ "description": "IDs of elements that label the combobox."
154
+ },
155
+ "background": {
156
+ "type": "SelectBackground | undefined",
157
+ "resolvedType": "\"always-dark\" | \"bold\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
158
+ "attribute": "background",
159
+ "required": false,
160
+ "mutable": false,
161
+ "description": "Actual parent surface context; omit on primary and secondary surfaces."
162
+ },
163
+ "clearLabel": {
164
+ "type": "string",
165
+ "resolvedType": "string",
166
+ "attribute": "clear-label",
167
+ "default": "'Clear'",
168
+ "required": false,
169
+ "mutable": false,
170
+ "description": "Localized clear action label."
171
+ },
172
+ "disabled": {
173
+ "type": "boolean",
174
+ "resolvedType": "boolean",
175
+ "attribute": "disabled",
176
+ "default": "false",
177
+ "required": false,
178
+ "mutable": false,
179
+ "description": "Native disabled state."
180
+ },
181
+ "error": {
182
+ "type": "boolean",
183
+ "resolvedType": "boolean",
184
+ "attribute": "error",
185
+ "default": "false",
186
+ "required": false,
187
+ "mutable": false,
188
+ "description": "Show invalid visual state."
189
+ },
190
+ "errorMessage": {
191
+ "type": "string | undefined",
192
+ "resolvedType": "string | undefined",
193
+ "attribute": "error-message",
194
+ "required": false,
195
+ "mutable": false,
196
+ "description": "Error text rendered below the trigger when error is true."
197
+ },
198
+ "hasBorder": {
199
+ "type": "boolean",
200
+ "resolvedType": "boolean",
201
+ "attribute": "has-border",
202
+ "default": "true",
203
+ "required": false,
204
+ "mutable": false,
205
+ "description": "Show the surface-aware inset border."
206
+ },
207
+ "icon": {
208
+ "type": "string | undefined",
209
+ "resolvedType": "string | undefined",
210
+ "attribute": "icon",
211
+ "required": false,
212
+ "mutable": false,
213
+ "description": "Optional trigger prefix icon name."
214
+ },
215
+ "inputId": {
216
+ "type": "string | undefined",
217
+ "resolvedType": "string | undefined",
218
+ "attribute": "input-id",
219
+ "required": false,
220
+ "mutable": false,
221
+ "description": "ID applied to the internal combobox trigger for external labels."
222
+ },
223
+ "isInactive": {
224
+ "type": "boolean",
225
+ "resolvedType": "boolean",
226
+ "attribute": "is-inactive",
227
+ "default": "false",
228
+ "required": false,
229
+ "mutable": false,
230
+ "description": "Shared inactive treatment; removes interaction and form submission."
231
+ },
232
+ "isLoading": {
233
+ "type": "boolean",
234
+ "resolvedType": "boolean",
235
+ "attribute": "is-loading",
236
+ "default": "false",
237
+ "required": false,
238
+ "mutable": false,
239
+ "description": "Replace the prefix with a loader and disable option interaction."
240
+ },
241
+ "loadingLabel": {
242
+ "type": "string",
243
+ "resolvedType": "string",
244
+ "attribute": "loading-label",
245
+ "default": "'Loading'",
246
+ "required": false,
247
+ "mutable": false,
248
+ "description": "Accessible loading status label."
249
+ },
250
+ "name": {
251
+ "type": "string | undefined",
252
+ "resolvedType": "string | undefined",
253
+ "attribute": "name",
254
+ "required": false,
255
+ "mutable": false,
256
+ "description": "Native form field name."
257
+ },
258
+ "noResultsText": {
259
+ "type": "string",
260
+ "resolvedType": "string",
261
+ "attribute": "no-results-text",
262
+ "default": "'No results found'",
263
+ "required": false,
264
+ "mutable": false,
265
+ "description": "Localized empty-filter result text."
266
+ },
267
+ "open": {
268
+ "type": "boolean",
269
+ "resolvedType": "boolean",
270
+ "attribute": "open",
271
+ "default": "false",
272
+ "required": false,
273
+ "mutable": true,
274
+ "description": "Controlled popup visibility."
275
+ },
276
+ "options": {
277
+ "type": "SelectOption[]",
278
+ "resolvedType": "ChoiceOption[]",
279
+ "default": "[]",
280
+ "required": false,
281
+ "mutable": false,
282
+ "description": "Flat choices. Assign arrays through the JavaScript property."
283
+ },
284
+ "placeholder": {
285
+ "type": "string",
286
+ "resolvedType": "string",
287
+ "attribute": "placeholder",
288
+ "default": "'Select'",
289
+ "required": false,
290
+ "mutable": false,
291
+ "description": "Trigger text shown when no valid value is selected."
292
+ },
293
+ "required": {
294
+ "type": "boolean",
295
+ "resolvedType": "boolean",
296
+ "attribute": "required",
297
+ "default": "false",
298
+ "required": false,
299
+ "mutable": false,
300
+ "description": "Require one valid selected value."
301
+ },
302
+ "requiredMessage": {
303
+ "type": "string",
304
+ "resolvedType": "string",
305
+ "attribute": "required-message",
306
+ "default": "'This field is required.'",
307
+ "required": false,
308
+ "mutable": false,
309
+ "description": "Validation message used when required is missing."
310
+ },
311
+ "searchPlaceholder": {
312
+ "type": "string",
313
+ "resolvedType": "string",
314
+ "attribute": "search-placeholder",
315
+ "default": "'Search'",
316
+ "required": false,
317
+ "mutable": false,
318
+ "description": "Localized search-field placeholder and accessible name."
319
+ },
320
+ "searchable": {
321
+ "type": "boolean",
322
+ "resolvedType": "boolean",
323
+ "attribute": "searchable",
324
+ "default": "false",
325
+ "required": false,
326
+ "mutable": false,
327
+ "description": "Show immediate local filtering over option labels, subtext, and section headings."
328
+ },
329
+ "sections": {
330
+ "type": "SelectSection[]",
331
+ "resolvedType": "ChoiceSection[]",
332
+ "default": "[]",
333
+ "required": false,
334
+ "mutable": false,
335
+ "description": "Grouped choices; takes precedence over options. Assign through JavaScript."
336
+ },
337
+ "size": {
338
+ "type": "SelectSize",
339
+ "resolvedType": "\"md\" | \"sm\" | \"xs\"",
340
+ "attribute": "size",
341
+ "default": "'md'",
342
+ "required": false,
343
+ "mutable": false,
344
+ "description": "Control density."
345
+ },
346
+ "value": {
347
+ "type": "string",
348
+ "resolvedType": "string",
349
+ "attribute": "value",
350
+ "default": "''",
351
+ "required": false,
352
+ "mutable": true,
353
+ "description": "Selected string value. Unknown values render the placeholder and are not submitted."
354
+ },
355
+ "width": {
356
+ "type": "SelectWidth",
357
+ "resolvedType": "\"fill\" | \"hug\"",
358
+ "attribute": "width",
359
+ "default": "'hug'",
360
+ "required": false,
361
+ "mutable": false,
362
+ "description": "Width fit — hug content (default) or fill the parent."
363
+ }
364
+ },
365
+ "events": [
366
+ {
367
+ "name": "dsChange",
368
+ "detail": "string",
369
+ "bubbles": true,
370
+ "cancelable": true,
371
+ "composed": true,
372
+ "description": "Emitted after user selection or clearing with the next scalar value."
373
+ },
374
+ {
375
+ "name": "dsClear",
376
+ "detail": "void",
377
+ "bubbles": true,
378
+ "cancelable": true,
379
+ "composed": true,
380
+ "description": "Emitted after the footer clear action."
381
+ },
382
+ {
383
+ "name": "dsOpenChange",
384
+ "detail": "boolean",
385
+ "bubbles": true,
386
+ "cancelable": true,
387
+ "composed": true,
388
+ "description": "Emitted whenever popup visibility changes."
389
+ }
390
+ ],
391
+ "methods": [
392
+ {
393
+ "name": "setFocus",
394
+ "signature": "setFocus() => Promise<void>"
395
+ }
396
+ ],
397
+ "slots": []
398
+ },
399
+ "props": {
400
+ "activeFill": {
401
+ "type": "boolean",
402
+ "resolvedType": "boolean",
403
+ "attribute": "active-fill",
404
+ "default": "true",
405
+ "required": false,
406
+ "mutable": false,
407
+ "description": "Show the selected interaction fill when a valid value exists."
408
+ },
409
+ "allowClear": {
410
+ "type": "boolean",
411
+ "resolvedType": "boolean",
412
+ "attribute": "allow-clear",
413
+ "default": "true",
414
+ "required": false,
415
+ "mutable": false,
416
+ "description": "Show the clear footer action when a value exists."
417
+ },
418
+ "ariaDescribedby": {
419
+ "type": "string | undefined",
420
+ "resolvedType": "string | undefined",
421
+ "attribute": "aria-describedby",
422
+ "required": false,
423
+ "mutable": false,
424
+ "description": "Additional IDs that describe the combobox."
425
+ },
426
+ "ariaLabel": {
427
+ "type": "string | null",
428
+ "resolvedType": "null | string",
429
+ "attribute": "aria-label",
430
+ "default": "null",
431
+ "required": false,
432
+ "mutable": false,
433
+ "description": "Direct accessible name when no external label is available."
434
+ },
435
+ "ariaLabelledby": {
436
+ "type": "string | undefined",
437
+ "resolvedType": "string | undefined",
438
+ "attribute": "aria-labelledby",
439
+ "required": false,
440
+ "mutable": false,
441
+ "description": "IDs of elements that label the combobox."
442
+ },
443
+ "background": {
444
+ "type": "SelectBackground | undefined",
445
+ "resolvedType": "\"always-dark\" | \"bold\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
446
+ "attribute": "background",
447
+ "required": false,
448
+ "mutable": false,
449
+ "description": "Actual parent surface context; omit on primary and secondary surfaces."
450
+ },
451
+ "clearLabel": {
452
+ "type": "string",
453
+ "resolvedType": "string",
454
+ "attribute": "clear-label",
455
+ "default": "'Clear'",
456
+ "required": false,
457
+ "mutable": false,
458
+ "description": "Localized clear action label."
459
+ },
460
+ "disabled": {
461
+ "type": "boolean",
462
+ "resolvedType": "boolean",
463
+ "attribute": "disabled",
464
+ "default": "false",
465
+ "required": false,
466
+ "mutable": false,
467
+ "description": "Native disabled state."
468
+ },
469
+ "error": {
470
+ "type": "boolean",
471
+ "resolvedType": "boolean",
472
+ "attribute": "error",
473
+ "default": "false",
474
+ "required": false,
475
+ "mutable": false,
476
+ "description": "Show invalid visual state."
477
+ },
478
+ "errorMessage": {
479
+ "type": "string | undefined",
480
+ "resolvedType": "string | undefined",
481
+ "attribute": "error-message",
482
+ "required": false,
483
+ "mutable": false,
484
+ "description": "Error text rendered below the trigger when error is true."
485
+ },
486
+ "hasBorder": {
487
+ "type": "boolean",
488
+ "resolvedType": "boolean",
489
+ "attribute": "has-border",
490
+ "default": "true",
491
+ "required": false,
492
+ "mutable": false,
493
+ "description": "Show the surface-aware inset border."
494
+ },
495
+ "icon": {
496
+ "type": "string | undefined",
497
+ "resolvedType": "string | undefined",
498
+ "attribute": "icon",
499
+ "required": false,
500
+ "mutable": false,
501
+ "description": "Optional trigger prefix icon name."
502
+ },
503
+ "inputId": {
504
+ "type": "string | undefined",
505
+ "resolvedType": "string | undefined",
506
+ "attribute": "input-id",
507
+ "required": false,
508
+ "mutable": false,
509
+ "description": "ID applied to the internal combobox trigger for external labels."
510
+ },
511
+ "isInactive": {
512
+ "type": "boolean",
513
+ "resolvedType": "boolean",
514
+ "attribute": "is-inactive",
515
+ "default": "false",
516
+ "required": false,
517
+ "mutable": false,
518
+ "description": "Shared inactive treatment; removes interaction and form submission."
519
+ },
520
+ "isLoading": {
521
+ "type": "boolean",
522
+ "resolvedType": "boolean",
523
+ "attribute": "is-loading",
524
+ "default": "false",
525
+ "required": false,
526
+ "mutable": false,
527
+ "description": "Replace the prefix with a loader and disable option interaction."
528
+ },
529
+ "loadingLabel": {
530
+ "type": "string",
531
+ "resolvedType": "string",
532
+ "attribute": "loading-label",
533
+ "default": "'Loading'",
534
+ "required": false,
535
+ "mutable": false,
536
+ "description": "Accessible loading status label."
537
+ },
538
+ "name": {
539
+ "type": "string | undefined",
540
+ "resolvedType": "string | undefined",
541
+ "attribute": "name",
542
+ "required": false,
543
+ "mutable": false,
544
+ "description": "Native form field name."
545
+ },
546
+ "noResultsText": {
547
+ "type": "string",
548
+ "resolvedType": "string",
549
+ "attribute": "no-results-text",
550
+ "default": "'No results found'",
551
+ "required": false,
552
+ "mutable": false,
553
+ "description": "Localized empty-filter result text."
554
+ },
555
+ "open": {
556
+ "type": "boolean",
557
+ "resolvedType": "boolean",
558
+ "attribute": "open",
559
+ "default": "false",
560
+ "required": false,
561
+ "mutable": true,
562
+ "description": "Controlled popup visibility."
563
+ },
564
+ "options": {
565
+ "type": "SelectOption[]",
566
+ "resolvedType": "ChoiceOption[]",
567
+ "default": "[]",
568
+ "required": false,
569
+ "mutable": false,
570
+ "description": "Flat choices. Assign arrays through the JavaScript property."
571
+ },
572
+ "placeholder": {
573
+ "type": "string",
574
+ "resolvedType": "string",
575
+ "attribute": "placeholder",
576
+ "default": "'Select'",
577
+ "required": false,
578
+ "mutable": false,
579
+ "description": "Trigger text shown when no valid value is selected."
580
+ },
581
+ "required": {
582
+ "type": "boolean",
583
+ "resolvedType": "boolean",
584
+ "attribute": "required",
585
+ "default": "false",
586
+ "required": false,
587
+ "mutable": false,
588
+ "description": "Require one valid selected value."
589
+ },
590
+ "requiredMessage": {
591
+ "type": "string",
592
+ "resolvedType": "string",
593
+ "attribute": "required-message",
594
+ "default": "'This field is required.'",
595
+ "required": false,
596
+ "mutable": false,
597
+ "description": "Validation message used when required is missing."
598
+ },
599
+ "searchPlaceholder": {
600
+ "type": "string",
601
+ "resolvedType": "string",
602
+ "attribute": "search-placeholder",
603
+ "default": "'Search'",
604
+ "required": false,
605
+ "mutable": false,
606
+ "description": "Localized search-field placeholder and accessible name."
607
+ },
608
+ "searchable": {
609
+ "type": "boolean",
610
+ "resolvedType": "boolean",
611
+ "attribute": "searchable",
612
+ "default": "false",
613
+ "required": false,
614
+ "mutable": false,
615
+ "description": "Show immediate local filtering over option labels, subtext, and section headings."
616
+ },
617
+ "sections": {
618
+ "type": "SelectSection[]",
619
+ "resolvedType": "ChoiceSection[]",
620
+ "default": "[]",
621
+ "required": false,
622
+ "mutable": false,
623
+ "description": "Grouped choices; takes precedence over options. Assign through JavaScript."
624
+ },
625
+ "size": {
626
+ "type": "SelectSize",
627
+ "resolvedType": "\"md\" | \"sm\" | \"xs\"",
628
+ "attribute": "size",
629
+ "default": "'md'",
630
+ "required": false,
631
+ "mutable": false,
632
+ "description": "Control density."
633
+ },
634
+ "value": {
635
+ "type": "string",
636
+ "resolvedType": "string",
637
+ "attribute": "value",
638
+ "default": "''",
639
+ "required": false,
640
+ "mutable": true,
641
+ "description": "Selected string value. Unknown values render the placeholder and are not submitted."
642
+ },
643
+ "width": {
644
+ "type": "SelectWidth",
645
+ "resolvedType": "\"fill\" | \"hug\"",
646
+ "attribute": "width",
647
+ "default": "'hug'",
648
+ "required": false,
649
+ "mutable": false,
650
+ "description": "Width fit — hug content (default) or fill the parent."
651
+ }
652
+ },
653
+ "events": [
654
+ {
655
+ "name": "dsChange",
656
+ "detail": "string",
657
+ "bubbles": true,
658
+ "cancelable": true,
659
+ "composed": true,
660
+ "description": "Emitted after user selection or clearing with the next scalar value."
661
+ },
662
+ {
663
+ "name": "dsClear",
664
+ "detail": "void",
665
+ "bubbles": true,
666
+ "cancelable": true,
667
+ "composed": true,
668
+ "description": "Emitted after the footer clear action."
669
+ },
670
+ {
671
+ "name": "dsOpenChange",
672
+ "detail": "boolean",
673
+ "bubbles": true,
674
+ "cancelable": true,
675
+ "composed": true,
676
+ "description": "Emitted whenever popup visibility changes."
677
+ }
678
+ ],
679
+ "methods": [
680
+ {
681
+ "name": "setFocus",
682
+ "signature": "setFocus() => Promise<void>"
683
+ }
684
+ ],
685
+ "slots": [],
686
+ "exports": {
687
+ "customElement": "ds-select",
688
+ "react": "DsSelect",
689
+ "angular": "DsSelect"
690
+ },
691
+ "consumption": {
692
+ "install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
693
+ "cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
694
+ "customElements": {
695
+ "import": "import '@ds-mo/ui/dist/components/ds-select.js';",
696
+ "example": "<ds-select></ds-select>"
697
+ },
698
+ "react": {
699
+ "import": "import { DsSelect } from '@ds-mo/ui/react';",
700
+ "example": "<DsSelect />"
701
+ },
702
+ "angular": {
703
+ "import": "import { DsSelect } from '@ds-mo/ui/angular/ds-select';",
704
+ "example": "<ds-select></ds-select>"
705
+ },
706
+ "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: options, sections.",
707
+ "peerDependencies": {
708
+ "required": [
709
+ "@ds-mo/tokens ^3.1.1",
710
+ "@ds-mo/icons ^6.2.0"
711
+ ],
712
+ "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
713
+ }
714
+ }
715
+ },
716
+ "dependencies": [
717
+ "@ds-mo/ui",
718
+ "@ds-mo/tokens",
719
+ "@ds-mo/icons"
720
+ ],
721
+ "registryDependencies": [
722
+ "button-unfilled",
723
+ "empty-state",
724
+ "icon",
725
+ "loader",
726
+ "text"
727
+ ],
728
+ "files": [
729
+ {
730
+ "path": "src/wc/components/Select/Select.css",
731
+ "content": "@import '../../utils/choice-list.css';\n@import '../../utils/control-width.css';\n@import '../../utils/search-control.css';\n@import '../../utils/typography.css';\n\n:host(.select-host) {\n display: inline-flex;\n flex-direction: column;\n gap: var(--dimension-space-050);\n position: relative;\n outline: none;\n --ds-select-fg: var(--color-foreground-secondary);\n --ds-select-fg-active: var(--color-foreground-primary);\n --ds-select-prefix-fg: var(--ds-select-fg);\n --ds-select-chevron-fg: var(--ds-select-fg);\n --ds-select-border: var(--color-border-secondary);\n}\n\n:host(.ds-control-width--fill),\n:host(.ds-control-width--fill) .trigger {\n width: 100%;\n}\n\n.trigger {\n display: inline-flex;\n align-items: center;\n justify-content: flex-start;\n box-sizing: border-box;\n height: var(--ds-control-height, var(--dimension-size-400));\n padding: 0 var(--ds-control-padding-inline, var(--dimension-space-075));\n gap: var(--ds-control-gap, var(--dimension-space-050));\n background: transparent;\n border: none;\n border-radius: var(--ds-control-radius, var(--dimension-radius-025));\n color: var(--ds-select-fg);\n cursor: pointer;\n font-family: inherit;\n -webkit-user-select: none;\n user-select: none;\n overflow: hidden;\n transition: color var(--effect-motion-short-2);\n}\n\n.trigger--bordered {\n --ds-interaction-border-width: var(--dimension-stroke-width-012);\n --ds-interaction-border-color: var(--ds-select-border);\n}\n\n.trigger--has-value .trigger__label {\n color: var(--ds-select-fg-active);\n}\n\n.wrapper--error {\n --ds-interaction-border-width: var(--dimension-stroke-width-018);\n --ds-interaction-border-color: var(--color-border-bold-negative);\n}\n\n.trigger__prefix,\n.trigger__chevron {\n position: relative;\n z-index: 2;\n flex-shrink: 0;\n width: var(--ds-control-icon, var(--dimension-iconography-md));\n height: var(--ds-control-icon, var(--dimension-iconography-md));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.trigger__prefix {\n color: var(--ds-select-prefix-fg);\n}\n\n.trigger__chevron {\n color: var(--ds-select-chevron-fg);\n}\n\n.trigger__label {\n position: relative;\n z-index: 2;\n flex: 1 1 auto;\n min-width: 0;\n padding: 0 var(--ds-control-label-inset, var(--dimension-space-025));\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n color: inherit;\n transition: color var(--effect-motion-short-2);\n}\n\n.select-popup {\n color: var(--color-foreground-secondary);\n}\n\n.select-option[aria-selected='true'] .ds-choice-item__icon {\n color: var(--color-foreground-primary);\n}\n\n.error-text {\n width: 100%;\n}\n\n:host(.select-host--background-medium) {\n --ds-select-fg: var(--color-foreground-on-medium-background-secondary);\n --ds-select-fg-active: var(--color-foreground-on-medium-background-primary);\n --ds-select-border: var(--color-border-on-medium-background-secondary);\n}\n\n:host(.select-host--background-bold) {\n --ds-select-fg: var(--color-foreground-on-bold-background-secondary);\n --ds-select-fg-active: var(--color-foreground-on-bold-background-primary);\n --ds-select-border: var(--color-border-on-bold-background-secondary);\n}\n\n:host(.select-host--background-strong) {\n --ds-select-fg: var(--color-foreground-on-strong-background-secondary);\n --ds-select-fg-active: var(--color-foreground-on-strong-background-primary);\n --ds-select-border: var(--color-border-on-strong-background-secondary);\n}\n\n:host(.select-host--background-translucent) {\n --ds-select-fg: var(--color-translucent-foreground-secondary);\n --ds-select-fg-active: var(--color-translucent-foreground-primary);\n --ds-select-border: var(--color-translucent-border-secondary);\n}\n\n:host(.select-host--background-inverted) {\n --ds-select-fg: var(--color-inverted-foreground-secondary);\n --ds-select-fg-active: var(--color-inverted-foreground-primary);\n --ds-select-border: var(--color-inverted-border-secondary);\n}\n\n:host(.select-host--background-media) {\n --ds-select-fg: var(--color-media-foreground-secondary);\n --ds-select-fg-active: var(--color-media-foreground-primary);\n --ds-select-border: var(--color-media-border-secondary);\n}\n\n:host(.select-host--background-always-dark) {\n --ds-select-fg: var(--color-always-dark-foreground-secondary);\n --ds-select-fg-active: var(--color-always-dark-foreground-primary);\n --ds-select-border: var(--color-always-dark-border-secondary);\n}\n",
732
+ "type": "registry:ui"
733
+ },
734
+ {
735
+ "path": "src/wc/components/Select/Select.tsx",
736
+ "content": "import {\n AttachInternals,\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Method,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport {\n controlWidthClass,\n CONTROL_TEXT_VARIANT,\n choicePopupMinWidth,\n resolveCssLengthPx,\n resolveCssTimeMs,\n resolveChoicePopupAlignOffset,\n TOKEN_DEFAULTS,\n type ControlWidth,\n} from '../../utils';\nimport { computeAnchoredPopupPosition } from '../../utils/anchored-popup';\nimport { ChoiceFooter, ChoiceOptionRow, ChoiceSearch } from '../../utils/choice-list-parts';\nimport {\n choiceBackgroundClassMap,\n choiceListUsesIcons,\n choiceListUsesSubtext,\n enabledChoiceIndexes,\n filterChoiceSections,\n findChoiceTypeaheadMatch,\n flattenChoiceSections,\n moveChoiceIndex,\n resolveChoiceSections,\n type ChoiceBackground,\n type ChoiceOption,\n type ChoiceSection,\n} from '../../utils/choice-list';\n\nexport type SelectOption = ChoiceOption;\nexport type SelectSection = ChoiceSection;\nexport type SelectBackground = ChoiceBackground;\nexport type SelectSize = 'md' | 'sm' | 'xs';\nexport type SelectWidth = ControlWidth;\n\nconst ICON_SIZE: Record<SelectSize, 'md' | 'sm' | 'xs'> = {\n md: 'md',\n sm: 'sm',\n xs: 'xs',\n};\n\nlet selectId = 0;\n/** rAF retries while the conditionally rendered popup mounts. */\nconst POSITION_RETRY_BUDGET = 8;\n\n@Component({\n tag: 'ds-select',\n styleUrl: 'Select.css',\n scoped: true,\n formAssociated: true,\n})\nexport class Select {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n /** Flat choices. Assign arrays through the JavaScript property. */\n @Prop() options: SelectOption[] = [];\n /** Grouped choices; takes precedence over options. Assign through JavaScript. */\n @Prop() sections: SelectSection[] = [];\n /** Selected string value. Unknown values render the placeholder and are not submitted. */\n @Prop({ mutable: true }) value: string = '';\n /** Controlled popup visibility. */\n @Prop({ mutable: true, reflect: true }) open: boolean = false;\n /** Native form field name. */\n @Prop({ reflect: true }) name: string | undefined;\n /** Native disabled state. */\n @Prop({ reflect: true }) disabled: boolean = false;\n /** Require one valid selected value. */\n @Prop({ reflect: true }) required: boolean = false;\n /** Validation message used when required is missing. */\n @Prop() requiredMessage: string = 'This field is required.';\n /** Trigger text shown when no valid value is selected. */\n @Prop() placeholder: string = 'Select';\n /** Control density. */\n @Prop() size: SelectSize = 'md';\n /** Width fit — hug content (default) or fill the parent. */\n @Prop() width: SelectWidth = 'hug';\n /** Shared inactive treatment; removes interaction and form submission. */\n @Prop() isInactive: boolean = false;\n /** Replace the prefix with a loader and disable option interaction. */\n @Prop() isLoading: boolean = false;\n /** Show the selected interaction fill when a valid value exists. */\n @Prop() activeFill: boolean = true;\n /** Show the surface-aware inset border. */\n @Prop() hasBorder: boolean = true;\n /** Optional trigger prefix icon name. */\n @Prop() icon: string | undefined;\n /** Show the clear footer action when a value exists. */\n @Prop() allowClear: boolean = true;\n /** Localized clear action label. */\n @Prop() clearLabel: string = 'Clear';\n /** Show immediate local filtering over option labels, subtext, and section headings. */\n @Prop() searchable: boolean = false;\n /** Localized search-field placeholder and accessible name. */\n @Prop() searchPlaceholder: string = 'Search';\n /** Localized empty-filter result text. */\n @Prop() noResultsText: string = 'No results found';\n /** Accessible loading status label. */\n @Prop() loadingLabel: string = 'Loading';\n /** Actual parent surface context; omit on primary and secondary surfaces. */\n @Prop() background: SelectBackground | undefined;\n /** Show invalid visual state. */\n @Prop() error: boolean = false;\n /** Error text rendered below the trigger when error is true. */\n @Prop() errorMessage: string | undefined;\n /** ID applied to the internal combobox trigger for external labels. */\n @Prop() inputId: string | undefined;\n /** Direct accessible name when no external label is available. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n /** IDs of elements that label the combobox. */\n @Prop({ attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined;\n /** Additional IDs that describe the combobox. */\n @Prop({ attribute: 'aria-describedby' }) ariaDescribedby: string | undefined;\n\n /** Emitted after user selection or clearing with the next scalar value. */\n @Event() dsChange!: EventEmitter<string>;\n /** Emitted after the footer clear action. */\n @Event() dsClear!: EventEmitter<void>;\n /** Emitted whenever popup visibility changes. */\n @Event() dsOpenChange!: EventEmitter<boolean>;\n\n @State() private activeIndex = -1;\n @State() private searchTerm = '';\n @State() private formDisabled = false;\n @State() private position = { x: 0, y: 0 };\n @State() private positionReady = false;\n @State() private focusRingVisible = false;\n\n private readonly generatedId = `ds-select-${++selectId}`;\n private readonly listboxId = `${this.generatedId}-listbox`;\n private readonly errorId = `${this.generatedId}-error`;\n private triggerEl: HTMLButtonElement | null = null;\n private popupEl: HTMLDivElement | null = null;\n private searchEl: HTMLInputElement | null = null;\n private initialValue = '';\n private typeahead = '';\n private typeaheadTimer: ReturnType<typeof setTimeout> | null = null;\n private outsideHandler: ((event: MouseEvent) => void) | null = null;\n private repositionHandler: (() => void) | null = null;\n private positionRetryRaf: number | null = null;\n\n componentWillLoad() {\n this.initialValue = this.value;\n this.syncFormValue();\n }\n\n componentDidLoad() {\n if (this.open) this.onOpenChange(true);\n }\n\n disconnectedCallback() {\n this.cancelPositionRetry();\n this.unbindPopupListeners();\n if (this.typeaheadTimer) clearTimeout(this.typeaheadTimer);\n }\n\n @Watch('value')\n @Watch('disabled')\n @Watch('isInactive')\n @Watch('required')\n @Watch('options')\n @Watch('sections')\n syncFormValue() {\n const inactive = this.isDisabled;\n const resolvedValue = this.hasSelection ? this.value : '';\n this.internals.setFormValue(inactive ? null : resolvedValue);\n const missing = this.required && !inactive && !resolvedValue;\n this.internals.setValidity(missing ? { valueMissing: true } : {}, missing ? this.requiredMessage : '');\n if (this.open) {\n const enabled = enabledChoiceIndexes(this.visibleOptions);\n if (!enabled.includes(this.activeIndex)) this.activeIndex = enabled[0] ?? -1;\n requestAnimationFrame(() => this.updatePosition());\n }\n }\n\n @Watch('isLoading')\n onLoadingChange() {\n if (this.open) requestAnimationFrame(() => this.updatePosition());\n }\n\n @Watch('open')\n onOpenChange(open: boolean) {\n this.dsOpenChange.emit(open);\n if (open) {\n this.bindPopupListeners();\n this.schedulePositionUpdate(() => {\n this.scrollActiveOptionIntoView();\n if (this.searchable) this.searchEl?.focus();\n });\n } else {\n this.cancelPositionRetry();\n this.unbindPopupListeners();\n this.searchTerm = '';\n this.positionReady = false;\n }\n }\n\n @Watch('searchTerm')\n onSearchTermChange() {\n const enabled = enabledChoiceIndexes(this.visibleOptions);\n this.activeIndex = enabled[0] ?? -1;\n requestAnimationFrame(() => {\n this.updatePosition();\n this.scrollActiveOptionIntoView();\n });\n }\n\n @Watch('activeIndex')\n onActiveIndexChange() {\n requestAnimationFrame(() => this.scrollActiveOptionIntoView());\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.syncFormValue();\n }\n\n formResetCallback() {\n this.value = this.initialValue;\n this.closePopup();\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n this.value = typeof state === 'string' ? state : '';\n }\n\n @Method()\n async setFocus() {\n this.triggerEl?.focus();\n }\n\n private get isDisabled(): boolean {\n return this.disabled || this.isInactive || this.formDisabled;\n }\n\n private get allSections(): SelectSection[] {\n return resolveChoiceSections(this.options, this.sections);\n }\n\n private get allOptions(): SelectOption[] {\n return flattenChoiceSections(this.allSections);\n }\n\n private get visibleSections(): SelectSection[] {\n return this.searchable\n ? filterChoiceSections(this.allSections, this.searchTerm)\n : this.allSections;\n }\n\n private get visibleOptions(): SelectOption[] {\n return flattenChoiceSections(this.visibleSections);\n }\n\n private get selectedOption(): SelectOption | undefined {\n return this.allOptions.find(option => option.value === this.value);\n }\n\n private get hasSelection(): boolean {\n return Boolean(this.selectedOption);\n }\n\n private get activeOptionId(): string | undefined {\n return !this.isLoading && this.activeIndex >= 0\n ? `${this.generatedId}-option-${this.activeIndex}`\n : undefined;\n }\n\n private scrollActiveOptionIntoView() {\n if (!this.open || !this.activeOptionId) return;\n this.el\n .querySelector<HTMLElement>(`#${this.activeOptionId}`)\n ?.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n }\n\n private bindPopupListeners() {\n this.unbindPopupListeners();\n this.outsideHandler = event => {\n const target = event.target as Node;\n if (this.el.contains(target)) return;\n this.closePopup();\n };\n this.repositionHandler = () => this.updatePosition();\n document.addEventListener('mousedown', this.outsideHandler, true);\n window.addEventListener('scroll', this.repositionHandler, true);\n window.addEventListener('resize', this.repositionHandler);\n }\n\n private unbindPopupListeners() {\n if (this.outsideHandler) {\n document.removeEventListener('mousedown', this.outsideHandler, true);\n this.outsideHandler = null;\n }\n if (this.repositionHandler) {\n window.removeEventListener('scroll', this.repositionHandler, true);\n window.removeEventListener('resize', this.repositionHandler);\n this.repositionHandler = null;\n }\n }\n\n private cancelPositionRetry() {\n if (this.positionRetryRaf !== null) {\n cancelAnimationFrame(this.positionRetryRaf);\n this.positionRetryRaf = null;\n }\n }\n\n /** Retry until the conditionally rendered popup is mounted and measurable. */\n private schedulePositionUpdate(onReady?: () => void) {\n if (!this.open) return;\n\n this.cancelPositionRetry();\n this.positionReady = false;\n let remaining = POSITION_RETRY_BUDGET;\n\n const attempt = () => {\n this.positionRetryRaf = null;\n if (!this.open) return;\n\n if (this.updatePosition()) {\n onReady?.();\n return;\n }\n\n if (remaining > 0) {\n remaining -= 1;\n this.positionRetryRaf = requestAnimationFrame(attempt);\n }\n };\n\n this.positionRetryRaf = requestAnimationFrame(attempt);\n }\n\n /** @returns `true` when the current popup was found and positioned. */\n private updatePosition(): boolean {\n if (\n !this.open ||\n !this.triggerEl ||\n !this.popupEl ||\n !this.popupEl.isConnected ||\n !this.el.contains(this.popupEl)\n ) return false;\n const sectionPadding = resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050);\n this.popupEl.style.minWidth = `${choicePopupMinWidth(this.triggerEl.offsetWidth, sectionPadding)}px`;\n this.position = computeAnchoredPopupPosition({\n anchorRect: this.triggerEl.getBoundingClientRect(),\n popupWidth: this.popupEl.offsetWidth,\n popupHeight: this.popupEl.offsetHeight,\n side: 'bottom',\n align: 'start',\n sideOffsetPx: sectionPadding,\n alignOffsetPx: resolveChoicePopupAlignOffset({\n align: 'start',\n alignOffsetPx: 0,\n sectionInsetPx: sectionPadding,\n }),\n viewportPadPx: sectionPadding,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n });\n this.positionReady = true;\n return true;\n }\n\n private openPopup(focusVisible: boolean, edge?: 'first' | 'last') {\n if (this.isDisabled || (!this.allOptions.length && !this.isLoading)) return;\n const enabled = enabledChoiceIndexes(this.visibleOptions);\n const selectedIndex = this.visibleOptions.findIndex(\n option => option.value === this.value && !option.isInactive,\n );\n this.activeIndex =\n edge === 'last'\n ? (enabled[enabled.length - 1] ?? -1)\n : selectedIndex >= 0\n ? selectedIndex\n : (enabled[0] ?? -1);\n this.focusRingVisible = focusVisible;\n this.open = true;\n }\n\n private closePopup(restoreFocus = false) {\n if (!this.open) return;\n this.open = false;\n if (restoreFocus) requestAnimationFrame(() => this.triggerEl?.focus());\n }\n\n private selectOption(option: SelectOption) {\n if (option.isInactive || this.isLoading) return;\n this.value = option.value;\n this.dsChange.emit(this.value);\n this.closePopup(true);\n }\n\n private clearSelection = (event: Event) => {\n event.preventDefault();\n event.stopPropagation();\n this.value = '';\n this.dsChange.emit('');\n this.dsClear.emit();\n const enabled = enabledChoiceIndexes(this.visibleOptions);\n this.activeIndex = enabled[0] ?? -1;\n requestAnimationFrame(() => (this.searchable ? this.searchEl?.focus() : this.triggerEl?.focus()));\n };\n\n private moveActive(direction: 1 | -1) {\n this.activeIndex = moveChoiceIndex(this.visibleOptions, this.activeIndex, direction);\n }\n\n private setActiveEdge(edge: 'first' | 'last') {\n const enabled = enabledChoiceIndexes(this.visibleOptions);\n this.activeIndex =\n edge === 'first' ? (enabled[0] ?? -1) : (enabled[enabled.length - 1] ?? -1);\n }\n\n private handleTypeahead(key: string) {\n if (this.typeaheadTimer) clearTimeout(this.typeaheadTimer);\n this.focusRingVisible = true;\n const normalized = key.toLocaleLowerCase();\n const repeatedCharacter =\n this.typeahead.length > 0 &&\n [...this.typeahead].every(character => character === normalized);\n this.typeahead = repeatedCharacter ? normalized : `${this.typeahead}${normalized}`;\n const match = findChoiceTypeaheadMatch(this.visibleOptions, this.typeahead, this.activeIndex);\n if (match >= 0) this.activeIndex = match;\n const resetMs = resolveCssTimeMs(\n TOKEN_DEFAULTS.animationDurationMedium1,\n TOKEN_DEFAULTS.animationDurationMedium1,\n );\n this.typeaheadTimer = setTimeout(() => {\n this.typeahead = '';\n this.typeaheadTimer = null;\n }, resetMs);\n }\n\n private handleListKeyDown(event: KeyboardEvent) {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.focusRingVisible = true;\n this.moveActive(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.focusRingVisible = true;\n this.moveActive(-1);\n break;\n case 'Home':\n event.preventDefault();\n this.focusRingVisible = true;\n this.setActiveEdge('first');\n break;\n case 'End':\n event.preventDefault();\n this.focusRingVisible = true;\n this.setActiveEdge('last');\n break;\n case 'Enter':\n case ' ': {\n if (event.key === ' ' && this.searchable && event.target === this.searchEl) break;\n event.preventDefault();\n const option = this.visibleOptions[this.activeIndex];\n if (option) this.selectOption(option);\n break;\n }\n case 'Escape':\n event.preventDefault();\n this.closePopup(true);\n break;\n case 'Tab':\n this.closePopup();\n break;\n default:\n if (!this.searchable && event.key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\n this.handleTypeahead(event.key);\n }\n }\n }\n\n private handleTriggerKeyDown = (event: KeyboardEvent) => {\n if (!this.open) {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) {\n event.preventDefault();\n this.openPopup(true, event.key === 'ArrowUp' ? 'last' : 'first');\n } else if (event.key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\n event.preventDefault();\n this.openPopup(true);\n if (this.searchable) {\n this.searchTerm = event.key;\n } else {\n this.handleTypeahead(event.key);\n }\n }\n return;\n }\n this.handleListKeyDown(event);\n };\n\n private renderOption(\n option: SelectOption,\n index: number,\n usesIcons: boolean,\n usesSubtext: boolean,\n ) {\n const selected = option.value === this.value;\n const active = index === this.activeIndex;\n return (\n <ChoiceOptionRow\n id={`${this.generatedId}-option-${index}`}\n option={option}\n selected={selected}\n active={active}\n focusRingVisible={this.focusRingVisible}\n usesSubtext={usesSubtext}\n leading={usesIcons && option.icon ? (\n <span class=\"ds-choice-item__icon ds-interaction-fill__content\" aria-hidden=\"true\">\n <ds-icon name={option.icon} size=\"md\" color=\"inherit\" />\n </span>\n ) : undefined}\n onHover={() => {\n this.focusRingVisible = false;\n this.activeIndex = index;\n }}\n onSelect={() => this.selectOption(option)}\n />\n );\n }\n\n render() {\n const inactive = this.isDisabled;\n const showPlaceholder = !this.hasSelection;\n const label = showPlaceholder ? this.placeholder : this.selectedOption?.label;\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const iconSize = ICON_SIZE[this.size];\n const usesOptionIcons = choiceListUsesIcons(this.allOptions);\n const usesOptionSubtext = choiceListUsesSubtext(this.allOptions);\n const showError = this.error && Boolean(this.errorMessage);\n const describedBy = [this.ariaDescribedby, showError ? this.errorId : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n const popupStyle = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.position.x)}px, ${Math.round(this.position.y)}px)`,\n zIndex: 'var(--dimension-z-index-floating)',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n let flatIndex = 0;\n\n return (\n <Host\n class={{\n 'select-host': true,\n 'ds-control-inactive': inactive,\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n ...controlWidthClass(this.width),\n [`select-host--background-${this.background}`]: !!this.background,\n }}\n >\n <button\n ref={element => {\n this.triggerEl = (element as HTMLButtonElement) ?? null;\n }}\n id={this.inputId ?? this.generatedId}\n type=\"button\"\n class={{\n trigger: true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n 'ds-interaction-fill--selected':\n !inactive && this.activeFill && this.hasSelection,\n 'trigger--bordered': this.hasBorder || this.error,\n 'trigger--placeholder': showPlaceholder,\n 'trigger--has-value': this.hasSelection,\n 'wrapper--error': this.error,\n [`ds-control--${this.size}`]: true,\n ...choiceBackgroundClassMap(this.background),\n }}\n disabled={inactive}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={String(this.open)}\n aria-controls={this.open ? this.listboxId : undefined}\n aria-activedescendant={this.open && !this.searchable ? this.activeOptionId : undefined}\n aria-label={this.ariaLabel}\n aria-labelledby={this.ariaLabelledby}\n aria-describedby={describedBy}\n aria-invalid={this.error ? 'true' : undefined}\n aria-required={this.required || undefined}\n aria-busy={this.isLoading ? 'true' : undefined}\n onClick={() => (this.open ? this.closePopup() : this.openPopup(false))}\n onKeyDown={this.handleTriggerKeyDown}\n >\n {(this.icon || this.isLoading) && (\n <span class=\"trigger__prefix ds-interaction-fill__content\" aria-hidden=\"true\">\n {this.isLoading ? (\n <ds-loader size={iconSize} color=\"inherit\" />\n ) : (\n <ds-icon name={this.icon} size={iconSize} color=\"inherit\" />\n )}\n </span>\n )}\n <ds-text\n class=\"trigger__label ds-interaction-fill__content\"\n as=\"span\"\n variant={textVariant}\n color=\"inherit\"\n lineTruncation={1}\n >\n {label}\n </ds-text>\n <span class=\"trigger__chevron ds-interaction-fill__content\" aria-hidden=\"true\">\n <ds-icon name=\"ChevronDown\" size={iconSize} color=\"inherit\" />\n </span>\n </button>\n\n {this.open && (\n <div\n ref={element => {\n this.popupEl = (element as HTMLDivElement) ?? null;\n }}\n class=\"select-popup ds-choice-popup\"\n style={popupStyle}\n >\n {this.searchable && (\n <ChoiceSearch\n value={this.searchTerm}\n placeholder={this.searchPlaceholder}\n controls={this.listboxId}\n activeDescendant={this.activeOptionId}\n inputRef={element => {\n this.searchEl = element;\n }}\n clearLabel={this.clearLabel}\n onValueChange={value => {\n this.searchTerm = value;\n }}\n onKeyDown={event => this.handleListKeyDown(event)}\n />\n )}\n <div\n id={this.listboxId}\n class=\"ds-choice-list\"\n role=\"listbox\"\n aria-label={this.ariaLabel ?? this.placeholder}\n aria-busy={this.isLoading ? 'true' : undefined}\n >\n {this.isLoading ? (\n <div\n class=\"ds-choice-loading\"\n role=\"option\"\n aria-selected=\"false\"\n aria-disabled=\"true\"\n aria-label={this.loadingLabel}\n aria-live=\"polite\"\n >\n <ds-loader size=\"md\" color=\"inherit\" />\n </div>\n ) : this.visibleOptions.length === 0 ? (\n <div\n class=\"ds-choice-empty\"\n role=\"option\"\n aria-selected=\"false\"\n aria-disabled=\"true\"\n aria-label={this.noResultsText}\n aria-live=\"polite\"\n >\n <ds-empty-state body={this.noResultsText} />\n </div>\n ) : (\n this.visibleSections.map(section => (\n <div\n class={{\n 'ds-choice-section': true,\n 'ds-choice-section--divided': !!section.divider,\n }}\n role={section.header ? 'group' : undefined}\n aria-label={section.header}\n >\n {section.header && (\n <ds-text\n class=\"ds-choice-section__header ds-control--md\"\n as=\"span\"\n variant=\"text-body-small\"\n emphasis\n color=\"primary\"\n aria-hidden=\"true\"\n >\n {section.header}\n </ds-text>\n )}\n {section.options.map(option => this.renderOption(\n option,\n flatIndex++,\n usesOptionIcons,\n usesOptionSubtext,\n ))}\n </div>\n ))\n )}\n </div>\n {this.allowClear && this.hasSelection && !this.isLoading && (\n <ChoiceFooter clearLabel={this.clearLabel} onClear={this.clearSelection} />\n )}\n </div>\n )}\n\n {showError && (\n <ds-text\n class=\"error-text\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </Host>\n );\n }\n}\n",
737
+ "type": "registry:ui"
738
+ }
739
+ ]
740
+ }