@hypoth-ui/cli 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -115
  3. package/dist/{add-PDBC4JTE.js → add-V5PW73GC.js} +29 -17
  4. package/dist/{chunk-5LTQ2XVL.js → chunk-27CLUUVC.js} +0 -2
  5. package/dist/{chunk-YPKFYE45.js → chunk-NWIRSZUQ.js} +6 -13
  6. package/dist/{chunk-GJ6JOQ3Q.js → chunk-PBK72SJJ.js} +1 -1
  7. package/dist/{diff-BQEXG7HU.js → diff-776UATCA.js} +2 -2
  8. package/dist/index.js +5 -5
  9. package/dist/{init-7AZXYAPJ.js → init-GDU2PW7K.js} +10 -13
  10. package/dist/{list-X6ZLM2NQ.js → list-XDP5I537.js} +3 -3
  11. package/package.json +16 -12
  12. package/registry/components.json +1820 -206
  13. package/templates/accordion/index.tsx +266 -0
  14. package/templates/accordion/wc/accordion-content.ts +113 -0
  15. package/templates/accordion/wc/accordion-item.ts +111 -0
  16. package/templates/accordion/wc/accordion-trigger.ts +105 -0
  17. package/templates/accordion/wc/accordion.ts +213 -0
  18. package/templates/accordion/wc/index.ts +12 -0
  19. package/templates/alert/index.tsx +177 -0
  20. package/templates/alert/wc/alert.ts +167 -0
  21. package/templates/alert/wc/index.ts +1 -0
  22. package/templates/alert-dialog/index.tsx +360 -0
  23. package/templates/alert-dialog/wc/alert-dialog-action.ts +43 -0
  24. package/templates/alert-dialog/wc/alert-dialog-cancel.ts +43 -0
  25. package/templates/alert-dialog/wc/alert-dialog-content.ts +42 -0
  26. package/templates/alert-dialog/wc/alert-dialog-description.ts +34 -0
  27. package/templates/alert-dialog/wc/alert-dialog-footer.ts +25 -0
  28. package/templates/alert-dialog/wc/alert-dialog-header.ts +25 -0
  29. package/templates/alert-dialog/wc/alert-dialog-title.ts +34 -0
  30. package/templates/alert-dialog/wc/alert-dialog-trigger.ts +46 -0
  31. package/templates/alert-dialog/wc/alert-dialog.ts +302 -0
  32. package/templates/alert-dialog/wc/index.ts +13 -0
  33. package/templates/aspect-ratio/index.tsx +50 -0
  34. package/templates/aspect-ratio/wc/aspect-ratio.ts +78 -0
  35. package/templates/aspect-ratio/wc/index.ts +5 -0
  36. package/templates/avatar/avatar-group.tsx +88 -0
  37. package/templates/avatar/avatar.tsx +124 -0
  38. package/templates/avatar/index.tsx +33 -0
  39. package/templates/avatar/wc/avatar-group.ts +112 -0
  40. package/templates/avatar/wc/avatar.ts +184 -0
  41. package/templates/avatar/wc/index.ts +5 -0
  42. package/templates/badge/index.tsx +140 -0
  43. package/templates/badge/wc/badge.ts +119 -0
  44. package/templates/badge/wc/index.ts +9 -0
  45. package/templates/breadcrumb/index.tsx +157 -0
  46. package/templates/breadcrumb/wc/breadcrumb-item.ts +30 -0
  47. package/templates/breadcrumb/wc/breadcrumb-link.ts +70 -0
  48. package/templates/breadcrumb/wc/breadcrumb-list.ts +30 -0
  49. package/templates/breadcrumb/wc/breadcrumb-page.ts +32 -0
  50. package/templates/breadcrumb/wc/breadcrumb-separator.ts +31 -0
  51. package/templates/breadcrumb/wc/breadcrumb.ts +55 -0
  52. package/templates/breadcrumb/wc/index.ts +10 -0
  53. package/templates/button/button.tsx +119 -0
  54. package/templates/button/index.ts +1 -0
  55. package/templates/button/wc/button.ts +169 -0
  56. package/templates/calendar/index.tsx +149 -0
  57. package/templates/calendar/wc/calendar.ts +316 -0
  58. package/templates/calendar/wc/index.ts +4 -0
  59. package/templates/card/index.tsx +108 -0
  60. package/templates/card/wc/card-content.ts +25 -0
  61. package/templates/card/wc/card-footer.ts +25 -0
  62. package/templates/card/wc/card-header.ts +25 -0
  63. package/templates/card/wc/card.ts +43 -0
  64. package/templates/card/wc/index.ts +8 -0
  65. package/templates/checkbox/checkbox.tsx +85 -0
  66. package/templates/checkbox/wc/checkbox.ts +247 -0
  67. package/templates/collapsible/index.tsx +172 -0
  68. package/templates/collapsible/wc/collapsible-content.ts +97 -0
  69. package/templates/collapsible/wc/collapsible-trigger.ts +39 -0
  70. package/templates/collapsible/wc/collapsible.ts +143 -0
  71. package/templates/collapsible/wc/index.ts +7 -0
  72. package/templates/combobox/combobox-content.tsx +141 -0
  73. package/templates/combobox/combobox-context.ts +36 -0
  74. package/templates/combobox/combobox-empty.tsx +38 -0
  75. package/templates/combobox/combobox-input.tsx +159 -0
  76. package/templates/combobox/combobox-loading.tsx +38 -0
  77. package/templates/combobox/combobox-option.tsx +99 -0
  78. package/templates/combobox/combobox-root.tsx +207 -0
  79. package/templates/combobox/combobox-tag.tsx +62 -0
  80. package/templates/combobox/index.ts +62 -0
  81. package/templates/combobox/wc/combobox-content.ts +97 -0
  82. package/templates/combobox/wc/combobox-input.ts +134 -0
  83. package/templates/combobox/wc/combobox-option.ts +111 -0
  84. package/templates/combobox/wc/combobox-tag.ts +103 -0
  85. package/templates/combobox/wc/combobox.ts +981 -0
  86. package/templates/combobox/wc/index.ts +5 -0
  87. package/templates/command/index.tsx +279 -0
  88. package/templates/command/wc/command-empty.ts +24 -0
  89. package/templates/command/wc/command-group.ts +60 -0
  90. package/templates/command/wc/command-input.ts +136 -0
  91. package/templates/command/wc/command-item.ts +78 -0
  92. package/templates/command/wc/command-list.ts +103 -0
  93. package/templates/command/wc/command-loading.ts +24 -0
  94. package/templates/command/wc/command-separator.ts +23 -0
  95. package/templates/command/wc/command.ts +176 -0
  96. package/templates/context-menu/index.tsx +262 -0
  97. package/templates/context-menu/wc/context-menu-content.ts +41 -0
  98. package/templates/context-menu/wc/context-menu-item.ts +83 -0
  99. package/templates/context-menu/wc/context-menu-label.ts +30 -0
  100. package/templates/context-menu/wc/context-menu-separator.ts +28 -0
  101. package/templates/context-menu/wc/context-menu.ts +324 -0
  102. package/templates/context-menu/wc/index.ts +9 -0
  103. package/templates/data-table/index.tsx +263 -0
  104. package/templates/data-table/wc/data-table.ts +405 -0
  105. package/templates/data-table/wc/index.ts +10 -0
  106. package/templates/date-picker/date-picker-calendar.tsx +352 -0
  107. package/templates/date-picker/date-picker-content.tsx +121 -0
  108. package/templates/date-picker/date-picker-context.ts +46 -0
  109. package/templates/date-picker/date-picker-root.tsx +201 -0
  110. package/templates/date-picker/date-picker-trigger.tsx +95 -0
  111. package/templates/date-picker/index.ts +44 -0
  112. package/templates/date-picker/wc/date-picker-calendar.ts +457 -0
  113. package/templates/date-picker/wc/date-picker.ts +592 -0
  114. package/templates/date-picker/wc/date-utils.ts +467 -0
  115. package/templates/date-picker/wc/index.ts +3 -0
  116. package/templates/dialog/dialog-close.tsx +57 -0
  117. package/templates/dialog/dialog-content.tsx +106 -0
  118. package/templates/dialog/dialog-context.ts +24 -0
  119. package/templates/dialog/dialog-description.tsx +51 -0
  120. package/templates/dialog/dialog-root.tsx +104 -0
  121. package/templates/dialog/dialog-title.tsx +38 -0
  122. package/templates/dialog/dialog-trigger.tsx +94 -0
  123. package/templates/dialog/index.ts +52 -0
  124. package/templates/dialog/wc/dialog-content.ts +59 -0
  125. package/templates/dialog/wc/dialog-description.ts +58 -0
  126. package/templates/dialog/wc/dialog-title.ts +56 -0
  127. package/templates/dialog/wc/dialog.ts +411 -0
  128. package/templates/drawer/index.tsx +263 -0
  129. package/templates/drawer/wc/drawer-content.ts +150 -0
  130. package/templates/drawer/wc/drawer-description.ts +34 -0
  131. package/templates/drawer/wc/drawer-footer.ts +25 -0
  132. package/templates/drawer/wc/drawer-header.ts +25 -0
  133. package/templates/drawer/wc/drawer-title.ts +34 -0
  134. package/templates/drawer/wc/drawer.ts +348 -0
  135. package/templates/drawer/wc/index.ts +10 -0
  136. package/templates/dropdown-menu/index.tsx +454 -0
  137. package/templates/dropdown-menu/wc/dropdown-menu-checkbox-item.ts +93 -0
  138. package/templates/dropdown-menu/wc/dropdown-menu-content.ts +43 -0
  139. package/templates/dropdown-menu/wc/dropdown-menu-item.ts +85 -0
  140. package/templates/dropdown-menu/wc/dropdown-menu-label.ts +31 -0
  141. package/templates/dropdown-menu/wc/dropdown-menu-radio-group.ts +80 -0
  142. package/templates/dropdown-menu/wc/dropdown-menu-radio-item.ts +101 -0
  143. package/templates/dropdown-menu/wc/dropdown-menu-separator.ts +28 -0
  144. package/templates/dropdown-menu/wc/dropdown-menu.ts +358 -0
  145. package/templates/dropdown-menu/wc/index.ts +12 -0
  146. package/templates/field/field-description.tsx +39 -0
  147. package/templates/field/field-error.tsx +37 -0
  148. package/templates/field/field.tsx +46 -0
  149. package/templates/field/index.ts +4 -0
  150. package/templates/field/label.tsx +40 -0
  151. package/templates/field/wc/field-description.ts +42 -0
  152. package/templates/field/wc/field-error.ts +46 -0
  153. package/templates/field/wc/field.ts +210 -0
  154. package/templates/field/wc/label.ts +54 -0
  155. package/templates/file-upload/file-upload-context.ts +26 -0
  156. package/templates/file-upload/file-upload-dropzone.tsx +111 -0
  157. package/templates/file-upload/file-upload-input.tsx +86 -0
  158. package/templates/file-upload/file-upload-item.tsx +105 -0
  159. package/templates/file-upload/file-upload-root.tsx +115 -0
  160. package/templates/file-upload/index.ts +50 -0
  161. package/templates/file-upload/wc/file-upload.ts +380 -0
  162. package/templates/file-upload/wc/index.ts +1 -0
  163. package/templates/hover-card/index.tsx +203 -0
  164. package/templates/hover-card/wc/hover-card-content.ts +50 -0
  165. package/templates/hover-card/wc/hover-card.ts +382 -0
  166. package/templates/hover-card/wc/index.ts +6 -0
  167. package/templates/icon/icon.tsx +76 -0
  168. package/templates/icon/wc/icon-adapter.ts +108 -0
  169. package/templates/icon/wc/icon.ts +161 -0
  170. package/templates/input/input.tsx +130 -0
  171. package/templates/input/wc/input.ts +216 -0
  172. package/templates/layout/app-shell.tsx +177 -0
  173. package/templates/layout/box.tsx +53 -0
  174. package/templates/layout/center.tsx +42 -0
  175. package/templates/layout/container.tsx +43 -0
  176. package/templates/layout/flow.tsx +83 -0
  177. package/templates/layout/grid.tsx +79 -0
  178. package/templates/layout/index.ts +33 -0
  179. package/templates/layout/inline.tsx +16 -0
  180. package/templates/layout/page.tsx +43 -0
  181. package/templates/layout/section.tsx +39 -0
  182. package/templates/layout/spacer.tsx +30 -0
  183. package/templates/layout/split.tsx +47 -0
  184. package/templates/layout/stack.tsx +16 -0
  185. package/templates/layout/wc/app-shell.ts +58 -0
  186. package/templates/layout/wc/box.ts +117 -0
  187. package/templates/layout/wc/center.ts +78 -0
  188. package/templates/layout/wc/container.ts +77 -0
  189. package/templates/layout/wc/flow.ts +149 -0
  190. package/templates/layout/wc/footer.ts +57 -0
  191. package/templates/layout/wc/grid.ts +142 -0
  192. package/templates/layout/wc/header.ts +57 -0
  193. package/templates/layout/wc/index.ts +41 -0
  194. package/templates/layout/wc/main.ts +46 -0
  195. package/templates/layout/wc/page.ts +81 -0
  196. package/templates/layout/wc/section.ts +65 -0
  197. package/templates/layout/wc/spacer.ts +77 -0
  198. package/templates/layout/wc/split.ts +94 -0
  199. package/templates/layout/wc/wrap.ts +93 -0
  200. package/templates/layout/wrap.tsx +46 -0
  201. package/templates/link/link.tsx +109 -0
  202. package/templates/link/wc/link.ts +124 -0
  203. package/templates/list/index.tsx +55 -0
  204. package/templates/list/list-item.tsx +117 -0
  205. package/templates/list/list.tsx +115 -0
  206. package/templates/list/wc/index.ts +5 -0
  207. package/templates/list/wc/list-item.ts +127 -0
  208. package/templates/list/wc/list.ts +114 -0
  209. package/templates/menu/index.ts +49 -0
  210. package/templates/menu/menu-content.tsx +109 -0
  211. package/templates/menu/menu-context.ts +17 -0
  212. package/templates/menu/menu-item.tsx +108 -0
  213. package/templates/menu/menu-label.tsx +32 -0
  214. package/templates/menu/menu-root.tsx +108 -0
  215. package/templates/menu/menu-separator.tsx +24 -0
  216. package/templates/menu/menu-trigger.tsx +104 -0
  217. package/templates/menu/wc/menu-content.ts +67 -0
  218. package/templates/menu/wc/menu-item.ts +109 -0
  219. package/templates/menu/wc/menu.ts +449 -0
  220. package/templates/navigation-menu/index.tsx +328 -0
  221. package/templates/navigation-menu/wc/index.ts +12 -0
  222. package/templates/navigation-menu/wc/navigation-menu-content.ts +30 -0
  223. package/templates/navigation-menu/wc/navigation-menu-indicator.ts +30 -0
  224. package/templates/navigation-menu/wc/navigation-menu-item.ts +60 -0
  225. package/templates/navigation-menu/wc/navigation-menu-link.ts +97 -0
  226. package/templates/navigation-menu/wc/navigation-menu-list.ts +30 -0
  227. package/templates/navigation-menu/wc/navigation-menu-trigger.ts +110 -0
  228. package/templates/navigation-menu/wc/navigation-menu-viewport.ts +85 -0
  229. package/templates/navigation-menu/wc/navigation-menu.ts +272 -0
  230. package/templates/number-input/index.ts +46 -0
  231. package/templates/number-input/number-input-context.ts +38 -0
  232. package/templates/number-input/number-input-decrement.tsx +53 -0
  233. package/templates/number-input/number-input-field.tsx +93 -0
  234. package/templates/number-input/number-input-increment.tsx +53 -0
  235. package/templates/number-input/number-input-root.tsx +137 -0
  236. package/templates/number-input/wc/index.ts +1 -0
  237. package/templates/number-input/wc/number-input.ts +283 -0
  238. package/templates/pagination/index.tsx +198 -0
  239. package/templates/pagination/wc/index.ts +11 -0
  240. package/templates/pagination/wc/pagination-content.ts +30 -0
  241. package/templates/pagination/wc/pagination-ellipsis.ts +28 -0
  242. package/templates/pagination/wc/pagination-item.ts +30 -0
  243. package/templates/pagination/wc/pagination-link.ts +76 -0
  244. package/templates/pagination/wc/pagination-next.ts +69 -0
  245. package/templates/pagination/wc/pagination-previous.ts +69 -0
  246. package/templates/pagination/wc/pagination.ts +156 -0
  247. package/templates/pin-input/index.ts +39 -0
  248. package/templates/pin-input/pin-input-context.ts +30 -0
  249. package/templates/pin-input/pin-input-field.tsx +186 -0
  250. package/templates/pin-input/pin-input-root.tsx +120 -0
  251. package/templates/pin-input/wc/index.ts +1 -0
  252. package/templates/pin-input/wc/pin-input.ts +259 -0
  253. package/templates/popover/popover.tsx +121 -0
  254. package/templates/popover/wc/popover-content.ts +66 -0
  255. package/templates/popover/wc/popover.ts +343 -0
  256. package/templates/progress/index.tsx +117 -0
  257. package/templates/progress/wc/index.ts +4 -0
  258. package/templates/progress/wc/progress.ts +174 -0
  259. package/templates/radio/radio.tsx +43 -0
  260. package/templates/radio/wc/radio-group.ts +261 -0
  261. package/templates/radio/wc/radio.ts +145 -0
  262. package/templates/scroll-area/index.tsx +144 -0
  263. package/templates/scroll-area/wc/index.ts +8 -0
  264. package/templates/scroll-area/wc/scroll-area-scrollbar.ts +143 -0
  265. package/templates/scroll-area/wc/scroll-area-thumb.ts +225 -0
  266. package/templates/scroll-area/wc/scroll-area-viewport.ts +120 -0
  267. package/templates/scroll-area/wc/scroll-area.ts +63 -0
  268. package/templates/select/index.ts +57 -0
  269. package/templates/select/select-content.tsx +243 -0
  270. package/templates/select/select-context.ts +30 -0
  271. package/templates/select/select-group.tsx +53 -0
  272. package/templates/select/select-label.tsx +34 -0
  273. package/templates/select/select-option.tsx +97 -0
  274. package/templates/select/select-root.tsx +153 -0
  275. package/templates/select/select-separator.tsx +27 -0
  276. package/templates/select/select-trigger.tsx +112 -0
  277. package/templates/select/select-value.tsx +48 -0
  278. package/templates/select/wc/index.ts +6 -0
  279. package/templates/select/wc/select-content.ts +89 -0
  280. package/templates/select/wc/select-group.ts +82 -0
  281. package/templates/select/wc/select-label.ts +49 -0
  282. package/templates/select/wc/select-option.ts +111 -0
  283. package/templates/select/wc/select-trigger.ts +101 -0
  284. package/templates/select/wc/select.ts +840 -0
  285. package/templates/separator/index.tsx +49 -0
  286. package/templates/separator/wc/index.ts +5 -0
  287. package/templates/separator/wc/separator.ts +60 -0
  288. package/templates/sheet/index.tsx +291 -0
  289. package/templates/sheet/wc/index.ts +12 -0
  290. package/templates/sheet/wc/sheet-close.ts +43 -0
  291. package/templates/sheet/wc/sheet-content.ts +47 -0
  292. package/templates/sheet/wc/sheet-description.ts +34 -0
  293. package/templates/sheet/wc/sheet-footer.ts +25 -0
  294. package/templates/sheet/wc/sheet-header.ts +25 -0
  295. package/templates/sheet/wc/sheet-overlay.ts +23 -0
  296. package/templates/sheet/wc/sheet-title.ts +34 -0
  297. package/templates/sheet/wc/sheet.ts +336 -0
  298. package/templates/skeleton/index.tsx +131 -0
  299. package/templates/skeleton/wc/index.ts +10 -0
  300. package/templates/skeleton/wc/skeleton.ts +107 -0
  301. package/templates/slider/index.ts +41 -0
  302. package/templates/slider/slider-context.ts +36 -0
  303. package/templates/slider/slider-range.tsx +59 -0
  304. package/templates/slider/slider-root.tsx +166 -0
  305. package/templates/slider/slider-thumb.tsx +213 -0
  306. package/templates/slider/slider-track.tsx +113 -0
  307. package/templates/slider/wc/index.ts +1 -0
  308. package/templates/slider/wc/slider.ts +465 -0
  309. package/templates/spinner/spinner.tsx +64 -0
  310. package/templates/spinner/wc/spinner.ts +70 -0
  311. package/templates/stepper/index.tsx +230 -0
  312. package/templates/stepper/wc/index.ts +12 -0
  313. package/templates/stepper/wc/stepper-content.ts +30 -0
  314. package/templates/stepper/wc/stepper-description.ts +25 -0
  315. package/templates/stepper/wc/stepper-indicator.ts +30 -0
  316. package/templates/stepper/wc/stepper-item.ts +55 -0
  317. package/templates/stepper/wc/stepper-separator.ts +29 -0
  318. package/templates/stepper/wc/stepper-title.ts +25 -0
  319. package/templates/stepper/wc/stepper-trigger.ts +67 -0
  320. package/templates/stepper/wc/stepper.ts +164 -0
  321. package/templates/switch/switch.tsx +90 -0
  322. package/templates/switch/wc/switch.ts +228 -0
  323. package/templates/table/body.tsx +21 -0
  324. package/templates/table/cell.tsx +44 -0
  325. package/templates/table/head.tsx +112 -0
  326. package/templates/table/header.tsx +21 -0
  327. package/templates/table/index.tsx +93 -0
  328. package/templates/table/root.tsx +82 -0
  329. package/templates/table/row.tsx +36 -0
  330. package/templates/table/wc/index.ts +9 -0
  331. package/templates/table/wc/table-body.ts +32 -0
  332. package/templates/table/wc/table-cell.ts +58 -0
  333. package/templates/table/wc/table-head.ts +129 -0
  334. package/templates/table/wc/table-header.ts +32 -0
  335. package/templates/table/wc/table-row.ts +50 -0
  336. package/templates/table/wc/table.ts +93 -0
  337. package/templates/tabs/index.tsx +222 -0
  338. package/templates/tabs/wc/index.ts +8 -0
  339. package/templates/tabs/wc/tabs-content.ts +82 -0
  340. package/templates/tabs/wc/tabs-list.ts +56 -0
  341. package/templates/tabs/wc/tabs-trigger.ts +136 -0
  342. package/templates/tabs/wc/tabs.ts +202 -0
  343. package/templates/tag/index.tsx +186 -0
  344. package/templates/tag/wc/index.ts +4 -0
  345. package/templates/tag/wc/tag.ts +166 -0
  346. package/templates/text/text.tsx +100 -0
  347. package/templates/text/wc/text.ts +94 -0
  348. package/templates/textarea/textarea.tsx +134 -0
  349. package/templates/textarea/wc/textarea.ts +280 -0
  350. package/templates/time-picker/index.ts +42 -0
  351. package/templates/time-picker/time-picker-context.ts +28 -0
  352. package/templates/time-picker/time-picker-root.tsx +113 -0
  353. package/templates/time-picker/time-picker-segment.tsx +91 -0
  354. package/templates/time-picker/wc/index.ts +1 -0
  355. package/templates/time-picker/wc/time-picker.ts +221 -0
  356. package/templates/toast/index.tsx +71 -0
  357. package/templates/toast/provider.tsx +228 -0
  358. package/templates/toast/toast.tsx +142 -0
  359. package/templates/toast/use-toast.ts +89 -0
  360. package/templates/toast/wc/index.ts +15 -0
  361. package/templates/toast/wc/toast-controller.ts +282 -0
  362. package/templates/toast/wc/toast-provider.ts +161 -0
  363. package/templates/toast/wc/toast.ts +165 -0
  364. package/templates/tooltip/tooltip.tsx +62 -0
  365. package/templates/tooltip/wc/tooltip-content.ts +64 -0
  366. package/templates/tooltip/wc/tooltip.ts +289 -0
  367. package/templates/tree/index.tsx +60 -0
  368. package/templates/tree/tree-item.tsx +131 -0
  369. package/templates/tree/tree.tsx +138 -0
  370. package/templates/tree/wc/index.ts +11 -0
  371. package/templates/tree/wc/tree-item.ts +273 -0
  372. package/templates/tree/wc/tree-utils.ts +143 -0
  373. package/templates/tree/wc/tree.ts +139 -0
  374. package/templates/visually-hidden/visually-hidden.tsx +45 -0
  375. package/templates/visually-hidden/wc/visually-hidden.ts +64 -0
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Select context for compound component pattern.
3
+ */
4
+
5
+ import type { SelectBehavior } from "@hypoth-ui/primitives-dom";
6
+ import { createCompoundContext } from "../../utils/create-context.js";
7
+
8
+ export interface SelectContextValue {
9
+ /** Select behavior instance */
10
+ behavior: SelectBehavior<string>;
11
+ /** Whether select is open */
12
+ open: boolean;
13
+ /** Set open state */
14
+ setOpen: (open: boolean) => void;
15
+ /** Current value */
16
+ value: string | null;
17
+ /** Set value */
18
+ setValue: (value: string | null) => void;
19
+ /** Highlighted value for keyboard navigation */
20
+ highlightedValue: string | null;
21
+ /** Set highlighted value */
22
+ setHighlightedValue: (value: string | null) => void;
23
+ /** Whether the select is in a loading state */
24
+ loading: boolean;
25
+ /** Text to display during loading */
26
+ loadingText: string;
27
+ }
28
+
29
+ export const [SelectProvider, useSelectContext] =
30
+ createCompoundContext<SelectContextValue>("Select");
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Select Group component - groups options with an optional label.
3
+ */
4
+
5
+ import { type HTMLAttributes, type ReactNode, forwardRef, useId } from "react";
6
+
7
+ export interface SelectGroupProps extends HTMLAttributes<HTMLFieldSetElement> {
8
+ /** Group content (Label and Options) */
9
+ children?: ReactNode;
10
+ /** Optional label text (alternative to using Select.Label as child) */
11
+ label?: string;
12
+ }
13
+
14
+ /**
15
+ * Group for organizing select options.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <Select.Content>
20
+ * <Select.Group>
21
+ * <Select.Label>Fruits</Select.Label>
22
+ * <Select.Option value="apple">Apple</Select.Option>
23
+ * <Select.Option value="banana">Banana</Select.Option>
24
+ * </Select.Group>
25
+ * <Select.Group label="Vegetables">
26
+ * <Select.Option value="carrot">Carrot</Select.Option>
27
+ * <Select.Option value="potato">Potato</Select.Option>
28
+ * </Select.Group>
29
+ * </Select.Content>
30
+ * ```
31
+ */
32
+ export const SelectGroup = forwardRef<HTMLFieldSetElement, SelectGroupProps>(
33
+ ({ children, className, label, ...restProps }, ref) => {
34
+ const groupId = useId();
35
+ const labelId = `${groupId}-label`;
36
+
37
+ return (
38
+ <fieldset
39
+ ref={ref}
40
+ aria-label={label}
41
+ aria-labelledby={!label ? labelId : undefined}
42
+ className={className}
43
+ data-group-label-id={labelId}
44
+ {...restProps}
45
+ >
46
+ {label && <legend className="sr-only">{label}</legend>}
47
+ {children}
48
+ </fieldset>
49
+ );
50
+ }
51
+ );
52
+
53
+ SelectGroup.displayName = "Select.Group";
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Select Label component - label for option groups.
3
+ */
4
+
5
+ import { type HTMLAttributes, type ReactNode, forwardRef } from "react";
6
+
7
+ export interface SelectLabelProps extends HTMLAttributes<HTMLDivElement> {
8
+ /** Label content */
9
+ children?: ReactNode;
10
+ }
11
+
12
+ /**
13
+ * Label for grouping options.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * <Select.Content>
18
+ * <Select.Label>Fruits</Select.Label>
19
+ * <Select.Option value="apple">Apple</Select.Option>
20
+ * <Select.Option value="banana">Banana</Select.Option>
21
+ * </Select.Content>
22
+ * ```
23
+ */
24
+ export const SelectLabel = forwardRef<HTMLDivElement, SelectLabelProps>(
25
+ ({ children, className, ...restProps }, ref) => {
26
+ return (
27
+ <div ref={ref} role="presentation" aria-hidden="true" className={className} {...restProps}>
28
+ {children}
29
+ </div>
30
+ );
31
+ }
32
+ );
33
+
34
+ SelectLabel.displayName = "Select.Label";
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Select Option component - individual option in the select.
3
+ */
4
+
5
+ import { type HTMLAttributes, type ReactNode, forwardRef, useCallback } from "react";
6
+ import { useSelectContext } from "./select-context.js";
7
+
8
+ export interface SelectOptionProps extends Omit<HTMLAttributes<HTMLDivElement>, "value"> {
9
+ /** Option value */
10
+ value: string;
11
+ /** Display label (uses children if not specified) */
12
+ label?: string;
13
+ /** Whether the option is disabled */
14
+ disabled?: boolean;
15
+ /** Option content */
16
+ children?: ReactNode;
17
+ }
18
+
19
+ /**
20
+ * Individual option in the select.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * <Select.Option value="apple">Apple</Select.Option>
25
+ * <Select.Option value="banana" disabled>Banana</Select.Option>
26
+ * ```
27
+ */
28
+ export const SelectOption = forwardRef<HTMLDivElement, SelectOptionProps>(
29
+ (
30
+ {
31
+ value: optionValue,
32
+ label,
33
+ disabled = false,
34
+ children,
35
+ className,
36
+ onClick,
37
+ onMouseEnter,
38
+ ...restProps
39
+ },
40
+ ref
41
+ ) => {
42
+ const { behavior, value, highlightedValue, setHighlightedValue, setOpen } =
43
+ useSelectContext("Select.Option");
44
+
45
+ const isSelected = value === optionValue;
46
+ const isHighlighted = highlightedValue === optionValue;
47
+
48
+ // Handle click to select
49
+ const handleClick = useCallback(
50
+ (event: React.MouseEvent<HTMLDivElement>) => {
51
+ if (disabled) return;
52
+ behavior.select(optionValue);
53
+ setOpen(false);
54
+ onClick?.(event);
55
+ },
56
+ [behavior, optionValue, disabled, setOpen, onClick]
57
+ );
58
+
59
+ // Handle mouse enter to highlight
60
+ const handleMouseEnter = useCallback(
61
+ (event: React.MouseEvent<HTMLDivElement>) => {
62
+ if (disabled) return;
63
+ behavior.highlight(optionValue);
64
+ setHighlightedValue(optionValue);
65
+ onMouseEnter?.(event);
66
+ },
67
+ [behavior, optionValue, disabled, setHighlightedValue, onMouseEnter]
68
+ );
69
+
70
+ const optionProps = behavior.getOptionProps(
71
+ optionValue,
72
+ label || String(children) || optionValue
73
+ );
74
+
75
+ return (
76
+ <div
77
+ ref={ref}
78
+ role={optionProps.role}
79
+ id={optionProps.id}
80
+ aria-selected={isSelected}
81
+ aria-disabled={disabled || undefined}
82
+ data-value={optionValue}
83
+ data-selected={isSelected || undefined}
84
+ data-highlighted={isHighlighted || undefined}
85
+ data-disabled={disabled || undefined}
86
+ className={className}
87
+ onClick={handleClick}
88
+ onMouseEnter={handleMouseEnter}
89
+ {...restProps}
90
+ >
91
+ {children}
92
+ </div>
93
+ );
94
+ }
95
+ );
96
+
97
+ SelectOption.displayName = "Select.Option";
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Select Root component - provides context to all Select compound components.
3
+ */
4
+
5
+ import { type Placement, createSelectBehavior } from "@hypoth-ui/primitives-dom";
6
+ import { type ReactNode, useCallback, useMemo, useState } from "react";
7
+ import { useStableId } from "../../hooks/use-stable-id.js";
8
+ import { SelectProvider } from "./select-context.js";
9
+
10
+ export interface SelectRootProps {
11
+ /** Select content */
12
+ children?: ReactNode;
13
+ /** Custom ID for the select (SSR-safe auto-generated if not provided) */
14
+ id?: string;
15
+ /** Controlled open state */
16
+ open?: boolean;
17
+ /** Default open state (uncontrolled) */
18
+ defaultOpen?: boolean;
19
+ /** Called when open state changes */
20
+ onOpenChange?: (open: boolean) => void;
21
+ /** Controlled value */
22
+ value?: string | null;
23
+ /** Default value (uncontrolled) */
24
+ defaultValue?: string | null;
25
+ /** Called when value changes */
26
+ onValueChange?: (value: string | null) => void;
27
+ /** Placement relative to trigger */
28
+ placement?: Placement;
29
+ /** Offset from trigger in pixels */
30
+ offset?: number;
31
+ /** Whether to flip placement on viewport edge */
32
+ flip?: boolean;
33
+ /** Whether select is disabled */
34
+ disabled?: boolean;
35
+ /** Whether select is read-only */
36
+ readOnly?: boolean;
37
+ /** Enable typeahead search */
38
+ searchable?: boolean;
39
+ /** Allow clearing the selection */
40
+ clearable?: boolean;
41
+ /** Whether the select is in a loading state (e.g., fetching options) */
42
+ loading?: boolean;
43
+ /** Text to display/announce during loading */
44
+ loadingText?: string;
45
+ }
46
+
47
+ /**
48
+ * Root component for Select compound pattern.
49
+ * Provides context to Trigger, Content, and Option.
50
+ *
51
+ * @example
52
+ * ```tsx
53
+ * <Select.Root onValueChange={(value) => console.log(value)}>
54
+ * <Select.Trigger>Select a fruit</Select.Trigger>
55
+ * <Select.Content>
56
+ * <Select.Option value="apple">Apple</Select.Option>
57
+ * <Select.Option value="banana">Banana</Select.Option>
58
+ * </Select.Content>
59
+ * </Select.Root>
60
+ * ```
61
+ */
62
+ export function SelectRoot({
63
+ children,
64
+ id,
65
+ open: controlledOpen,
66
+ defaultOpen = false,
67
+ onOpenChange,
68
+ value: controlledValue,
69
+ defaultValue = null,
70
+ onValueChange,
71
+ placement: _placement = "bottom-start",
72
+ offset: _offset = 4,
73
+ flip: _flip = true,
74
+ disabled = false,
75
+ readOnly = false,
76
+ searchable = true,
77
+ clearable = false,
78
+ loading = false,
79
+ loadingText = "Loading...",
80
+ }: SelectRootProps) {
81
+ // Generate SSR-safe stable ID using React 18's useId under the hood
82
+ const stableId = useStableId({ id, prefix: "select" });
83
+
84
+ // Support both controlled and uncontrolled modes for open
85
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
86
+ const isOpenControlled = controlledOpen !== undefined;
87
+ const open = isOpenControlled ? controlledOpen : internalOpen;
88
+
89
+ // Support both controlled and uncontrolled modes for value
90
+ const [internalValue, setInternalValue] = useState<string | null>(defaultValue);
91
+ const isValueControlled = controlledValue !== undefined;
92
+ const value = isValueControlled ? controlledValue : internalValue;
93
+
94
+ // Highlighted value for keyboard navigation
95
+ const [highlightedValue, setHighlightedValue] = useState<string | null>(value);
96
+
97
+ const setOpen = useCallback(
98
+ (nextOpen: boolean) => {
99
+ if (!isOpenControlled) {
100
+ setInternalOpen(nextOpen);
101
+ }
102
+ onOpenChange?.(nextOpen);
103
+ },
104
+ [isOpenControlled, onOpenChange]
105
+ );
106
+
107
+ const setValue = useCallback(
108
+ (nextValue: string | null) => {
109
+ if (!isValueControlled) {
110
+ setInternalValue(nextValue);
111
+ }
112
+ onValueChange?.(nextValue);
113
+ },
114
+ [isValueControlled, onValueChange]
115
+ );
116
+
117
+ // Create behavior instance - intentionally created once with initial values
118
+ // biome-ignore lint/correctness/useExhaustiveDependencies: behavior is created once, state synced via callbacks
119
+ const behavior = useMemo(
120
+ () =>
121
+ createSelectBehavior({
122
+ defaultValue: value,
123
+ disabled,
124
+ readOnly,
125
+ searchable,
126
+ clearable,
127
+ onValueChange: (v) => setValue(v),
128
+ onOpenChange: (o) => setOpen(o),
129
+ // Use SSR-safe stable ID generator
130
+ generateId: () => stableId,
131
+ }),
132
+ [stableId]
133
+ );
134
+
135
+ const contextValue = useMemo(
136
+ () => ({
137
+ behavior,
138
+ open,
139
+ setOpen,
140
+ value,
141
+ setValue,
142
+ highlightedValue,
143
+ setHighlightedValue,
144
+ loading,
145
+ loadingText,
146
+ }),
147
+ [behavior, open, setOpen, value, setValue, highlightedValue, loading, loadingText]
148
+ );
149
+
150
+ return <SelectProvider value={contextValue}>{children}</SelectProvider>;
151
+ }
152
+
153
+ SelectRoot.displayName = "Select.Root";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Select Separator component - visual separator between groups.
3
+ */
4
+
5
+ import { type HTMLAttributes, forwardRef } from "react";
6
+
7
+ export interface SelectSeparatorProps extends HTMLAttributes<HTMLHRElement> {}
8
+
9
+ /**
10
+ * Visual separator for grouping options.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <Select.Content>
15
+ * <Select.Option value="apple">Apple</Select.Option>
16
+ * <Select.Separator />
17
+ * <Select.Option value="banana">Banana</Select.Option>
18
+ * </Select.Content>
19
+ * ```
20
+ */
21
+ export const SelectSeparator = forwardRef<HTMLHRElement, SelectSeparatorProps>(
22
+ ({ className, ...restProps }, ref) => {
23
+ return <hr ref={ref} className={className} {...restProps} />;
24
+ }
25
+ );
26
+
27
+ SelectSeparator.displayName = "Select.Separator";
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Select Trigger component - opens the select when activated.
3
+ */
4
+
5
+ import { type ButtonHTMLAttributes, type ReactNode, forwardRef, useCallback, useRef } from "react";
6
+ import { Slot } from "../../primitives/slot.js";
7
+ import { useSelectContext } from "./select-context.js";
8
+
9
+ export interface SelectTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
10
+ /** Trigger content */
11
+ children?: ReactNode;
12
+ /** Render as child element (polymorphic) */
13
+ asChild?: boolean;
14
+ }
15
+
16
+ /**
17
+ * Trigger button that opens the select.
18
+ * Supports asChild for custom trigger elements.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <Select.Trigger>Select a fruit</Select.Trigger>
23
+ *
24
+ * <Select.Trigger asChild>
25
+ * <button className="custom-button">Custom Trigger</button>
26
+ * </Select.Trigger>
27
+ * ```
28
+ */
29
+ export const SelectTrigger = forwardRef<HTMLButtonElement, SelectTriggerProps>(
30
+ ({ children, asChild = false, onClick, onKeyDown, ...restProps }, ref) => {
31
+ const { behavior, open, highlightedValue } = useSelectContext("Select.Trigger");
32
+ const internalRef = useRef<HTMLButtonElement>(null);
33
+
34
+ // Handle click to toggle select
35
+ const handleClick = useCallback(
36
+ (event: React.MouseEvent<HTMLButtonElement>) => {
37
+ behavior.toggle();
38
+ onClick?.(event);
39
+ },
40
+ [behavior, onClick]
41
+ );
42
+
43
+ // Handle keyboard navigation
44
+ const handleKeyDown = useCallback(
45
+ (event: React.KeyboardEvent<HTMLButtonElement>) => {
46
+ switch (event.key) {
47
+ case "Enter":
48
+ case " ":
49
+ event.preventDefault();
50
+ behavior.toggle();
51
+ break;
52
+ case "ArrowDown":
53
+ event.preventDefault();
54
+ if (!open) {
55
+ behavior.open();
56
+ behavior.highlightFirst();
57
+ }
58
+ break;
59
+ case "ArrowUp":
60
+ event.preventDefault();
61
+ if (!open) {
62
+ behavior.open();
63
+ behavior.highlightLast();
64
+ }
65
+ break;
66
+ }
67
+ onKeyDown?.(event);
68
+ },
69
+ [behavior, open, onKeyDown]
70
+ );
71
+
72
+ // Get trigger props from behavior
73
+ const triggerProps = behavior.getTriggerProps();
74
+
75
+ const Component = asChild ? Slot : "button";
76
+
77
+ // Merge refs
78
+ const mergedRef = useCallback(
79
+ (element: HTMLButtonElement | null) => {
80
+ (internalRef as React.MutableRefObject<HTMLButtonElement | null>).current = element;
81
+ if (typeof ref === "function") {
82
+ ref(element);
83
+ } else if (ref) {
84
+ (ref as React.MutableRefObject<HTMLButtonElement | null>).current = element;
85
+ }
86
+ },
87
+ [ref]
88
+ );
89
+
90
+ return (
91
+ <Component
92
+ ref={mergedRef}
93
+ type={asChild ? undefined : "button"}
94
+ role={triggerProps.role}
95
+ aria-haspopup={triggerProps["aria-haspopup"]}
96
+ aria-expanded={open}
97
+ aria-controls={behavior.contentId}
98
+ aria-activedescendant={
99
+ open && highlightedValue ? `select-option-${highlightedValue}` : undefined
100
+ }
101
+ onClick={handleClick}
102
+ onKeyDown={handleKeyDown}
103
+ data-state={open ? "open" : "closed"}
104
+ {...restProps}
105
+ >
106
+ {children}
107
+ </Component>
108
+ );
109
+ }
110
+ );
111
+
112
+ SelectTrigger.displayName = "Select.Trigger";
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Select Value component - displays the selected value.
3
+ */
4
+
5
+ import { type HTMLAttributes, type ReactNode, forwardRef } from "react";
6
+ import { useSelectContext } from "./select-context.js";
7
+
8
+ export interface SelectValueProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {
9
+ /** Placeholder text when no value is selected */
10
+ placeholder?: string;
11
+ /** Custom render function for the value */
12
+ children?: ReactNode | ((value: string | null) => ReactNode);
13
+ }
14
+
15
+ /**
16
+ * Displays the currently selected value.
17
+ * Used inside Select.Trigger.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * <Select.Trigger>
22
+ * <Select.Value placeholder="Select a fruit" />
23
+ * </Select.Trigger>
24
+ * ```
25
+ */
26
+ export const SelectValue = forwardRef<HTMLSpanElement, SelectValueProps>(
27
+ ({ placeholder, children, className, ...restProps }, ref) => {
28
+ const { value } = useSelectContext("Select.Value");
29
+
30
+ let displayContent: ReactNode;
31
+
32
+ if (typeof children === "function") {
33
+ displayContent = children(value);
34
+ } else if (children) {
35
+ displayContent = value ? children : placeholder;
36
+ } else {
37
+ displayContent = value || placeholder;
38
+ }
39
+
40
+ return (
41
+ <span ref={ref} className={className} data-placeholder={!value || undefined} {...restProps}>
42
+ {displayContent}
43
+ </span>
44
+ );
45
+ }
46
+ );
47
+
48
+ SelectValue.displayName = "Select.Value";
@@ -0,0 +1,6 @@
1
+ export { DsSelect } from "./select.js";
2
+ export { DsSelectTrigger } from "./select-trigger.js";
3
+ export { DsSelectContent, type SelectContentState } from "./select-content.js";
4
+ export { DsSelectOption } from "./select-option.js";
5
+ export { DsSelectGroup } from "./select-group.js";
6
+ export { DsSelectLabel } from "./select-label.js";
@@ -0,0 +1,89 @@
1
+ import { html } from "lit";
2
+ import { property } from "lit/decorators.js";
3
+ import { DSElement } from "../../base/ds-element.js";
4
+ import { define } from "../../registry/define.js";
5
+
6
+ export type SelectContentState = "open" | "closed";
7
+
8
+ /**
9
+ * Select content container with role="listbox".
10
+ *
11
+ * @element ds-select-content
12
+ *
13
+ * @slot - Select options (ds-select-option elements)
14
+ *
15
+ * @attr {string} data-state - Animation state ("open" or "closed")
16
+ * @attr {string} data-placement - Current anchor position placement
17
+ *
18
+ * @example
19
+ * ```html
20
+ * <ds-select>
21
+ * <button slot="trigger">Select fruit</button>
22
+ * <ds-select-content>
23
+ * <ds-select-option value="apple">Apple</ds-select-option>
24
+ * <ds-select-option value="banana">Banana</ds-select-option>
25
+ * </ds-select-content>
26
+ * </ds-select>
27
+ * ```
28
+ */
29
+ export class DsSelectContent extends DSElement {
30
+ /** Unique ID for ARIA association */
31
+ @property({ type: String, reflect: true })
32
+ override id = "";
33
+
34
+ /** Animation state (open or closed) - set by parent ds-select */
35
+ @property({ type: String, reflect: true, attribute: "data-state" })
36
+ dataState: SelectContentState = "closed";
37
+
38
+ /** Optional label for the listbox */
39
+ @property({ type: String })
40
+ label = "";
41
+
42
+ override connectedCallback(): void {
43
+ super.connectedCallback();
44
+
45
+ // Generate ID if not set
46
+ if (!this.id) {
47
+ this.id = `select-content-${crypto.randomUUID().slice(0, 8)}`;
48
+ }
49
+
50
+ // Set ARIA role for listbox
51
+ this.setAttribute("role", "listbox");
52
+
53
+ // Set label if provided
54
+ if (this.label) {
55
+ this.setAttribute("aria-label", this.label);
56
+ }
57
+
58
+ // Hidden by default (parent select controls visibility)
59
+ this.setAttribute("hidden", "");
60
+ }
61
+
62
+ override updated(changedProperties: Map<string, unknown>): void {
63
+ super.updated(changedProperties);
64
+
65
+ if (changedProperties.has("label")) {
66
+ if (this.label) {
67
+ this.setAttribute("aria-label", this.label);
68
+ } else {
69
+ this.removeAttribute("aria-label");
70
+ }
71
+ }
72
+ }
73
+
74
+ override render() {
75
+ return html`
76
+ <div class="ds-select-content" part="container">
77
+ <slot></slot>
78
+ </div>
79
+ `;
80
+ }
81
+ }
82
+
83
+ define("ds-select-content", DsSelectContent);
84
+
85
+ declare global {
86
+ interface HTMLElementTagNameMap {
87
+ "ds-select-content": DsSelectContent;
88
+ }
89
+ }