@hypoth-ui/cli 0.0.1 → 0.1.1

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,159 @@
1
+ /**
2
+ * Combobox Input component - text input with autocomplete.
3
+ */
4
+
5
+ import { type InputHTMLAttributes, forwardRef, useCallback, useRef } from "react";
6
+ import { useComboboxContext } from "./combobox-context.js";
7
+
8
+ export interface ComboboxInputProps
9
+ extends Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "onChange"> {
10
+ /** Render as child element (polymorphic) */
11
+ asChild?: boolean;
12
+ }
13
+
14
+ /**
15
+ * Text input for the combobox.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <Combobox.Input placeholder="Search..." />
20
+ * ```
21
+ */
22
+ export const ComboboxInput = forwardRef<HTMLInputElement, ComboboxInputProps>(
23
+ ({ onKeyDown, onFocus, ...restProps }, ref) => {
24
+ const {
25
+ behavior,
26
+ open,
27
+ setOpen,
28
+ inputValue,
29
+ setInputValue,
30
+ highlightedValue,
31
+ setHighlightedValue,
32
+ } = useComboboxContext("Combobox.Input");
33
+ const internalRef = useRef<HTMLInputElement>(null);
34
+
35
+ // Handle input change
36
+ const handleChange = useCallback(
37
+ (event: React.ChangeEvent<HTMLInputElement>) => {
38
+ const value = event.target.value;
39
+ behavior.setInputValue(value);
40
+ setInputValue(value);
41
+
42
+ // Auto-open on input
43
+ if (value && !open) {
44
+ behavior.open();
45
+ setOpen(true);
46
+ }
47
+ },
48
+ [behavior, open, setOpen, setInputValue]
49
+ );
50
+
51
+ // Handle keyboard navigation
52
+ const handleKeyDown = useCallback(
53
+ (event: React.KeyboardEvent<HTMLInputElement>) => {
54
+ if (!open) {
55
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
56
+ event.preventDefault();
57
+ behavior.open();
58
+ setOpen(true);
59
+ }
60
+ onKeyDown?.(event);
61
+ return;
62
+ }
63
+
64
+ switch (event.key) {
65
+ case "Enter":
66
+ event.preventDefault();
67
+ if (highlightedValue) {
68
+ behavior.select(highlightedValue);
69
+ }
70
+ break;
71
+ case "Escape":
72
+ event.preventDefault();
73
+ behavior.close();
74
+ setOpen(false);
75
+ break;
76
+ case "ArrowDown":
77
+ event.preventDefault();
78
+ behavior.highlightNext();
79
+ setHighlightedValue(behavior.state.highlightedValue);
80
+ break;
81
+ case "ArrowUp":
82
+ event.preventDefault();
83
+ behavior.highlightPrev();
84
+ setHighlightedValue(behavior.state.highlightedValue);
85
+ break;
86
+ case "Home":
87
+ if (event.currentTarget.selectionStart === 0) {
88
+ event.preventDefault();
89
+ behavior.highlightFirst();
90
+ setHighlightedValue(behavior.state.highlightedValue);
91
+ }
92
+ break;
93
+ case "End":
94
+ if (event.currentTarget.selectionEnd === event.currentTarget.value.length) {
95
+ event.preventDefault();
96
+ behavior.highlightLast();
97
+ setHighlightedValue(behavior.state.highlightedValue);
98
+ }
99
+ break;
100
+ case "Tab":
101
+ behavior.close();
102
+ setOpen(false);
103
+ break;
104
+ }
105
+
106
+ onKeyDown?.(event);
107
+ },
108
+ [behavior, open, setOpen, highlightedValue, setHighlightedValue, onKeyDown]
109
+ );
110
+
111
+ // Handle focus
112
+ const handleFocus = useCallback(
113
+ (event: React.FocusEvent<HTMLInputElement>) => {
114
+ onFocus?.(event);
115
+ },
116
+ [onFocus]
117
+ );
118
+
119
+ // Get input props from behavior
120
+ const inputProps = behavior.getInputProps();
121
+
122
+ // Merge refs
123
+ const mergedRef = useCallback(
124
+ (element: HTMLInputElement | null) => {
125
+ (internalRef as React.MutableRefObject<HTMLInputElement | null>).current = element;
126
+ if (typeof ref === "function") {
127
+ ref(element);
128
+ } else if (ref) {
129
+ (ref as React.MutableRefObject<HTMLInputElement | null>).current = element;
130
+ }
131
+ },
132
+ [ref]
133
+ );
134
+
135
+ return (
136
+ <input
137
+ ref={mergedRef}
138
+ type="text"
139
+ role={inputProps.role}
140
+ aria-expanded={open}
141
+ aria-haspopup={inputProps["aria-haspopup"]}
142
+ aria-controls={inputProps["aria-controls"]}
143
+ aria-activedescendant={
144
+ open && highlightedValue ? `combobox-option-${highlightedValue}` : undefined
145
+ }
146
+ aria-autocomplete={inputProps["aria-autocomplete"]}
147
+ aria-busy={inputProps["aria-busy"]}
148
+ value={inputValue}
149
+ onChange={handleChange}
150
+ onKeyDown={handleKeyDown}
151
+ onFocus={handleFocus}
152
+ data-state={open ? "open" : "closed"}
153
+ {...restProps}
154
+ />
155
+ );
156
+ }
157
+ );
158
+
159
+ ComboboxInput.displayName = "Combobox.Input";
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Combobox Loading component - shown during async loading.
3
+ */
4
+
5
+ import { type HTMLAttributes, type ReactNode, forwardRef } from "react";
6
+ import { useComboboxContext } from "./combobox-context.js";
7
+
8
+ export interface ComboboxLoadingProps extends HTMLAttributes<HTMLOutputElement> {
9
+ /** Loading indicator content */
10
+ children?: ReactNode;
11
+ }
12
+
13
+ /**
14
+ * Loading state shown during async search.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <Combobox.Loading>Searching...</Combobox.Loading>
19
+ * ```
20
+ */
21
+ export const ComboboxLoading = forwardRef<HTMLOutputElement, ComboboxLoadingProps>(
22
+ ({ children, className, ...restProps }, ref) => {
23
+ const { loading } = useComboboxContext("Combobox.Loading");
24
+
25
+ // Only show if loading
26
+ if (!loading) {
27
+ return null;
28
+ }
29
+
30
+ return (
31
+ <output ref={ref} aria-live="polite" className={className} {...restProps}>
32
+ {children}
33
+ </output>
34
+ );
35
+ }
36
+ );
37
+
38
+ ComboboxLoading.displayName = "Combobox.Loading";
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Combobox Option component - individual option in the combobox.
3
+ */
4
+
5
+ import { type HTMLAttributes, type ReactNode, forwardRef, useCallback } from "react";
6
+ import { useComboboxContext } from "./combobox-context.js";
7
+
8
+ export interface ComboboxOptionProps 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 combobox.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * <Combobox.Option value="apple">Apple</Combobox.Option>
25
+ * <Combobox.Option value="banana" disabled>Banana</Combobox.Option>
26
+ * ```
27
+ */
28
+ export const ComboboxOption = forwardRef<HTMLDivElement, ComboboxOptionProps>(
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, multiple } =
43
+ useComboboxContext("Combobox.Option");
44
+
45
+ const isSelected = multiple ? (value as string[]).includes(optionValue) : 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
+ if (!multiple) {
54
+ behavior.close();
55
+ setOpen(false);
56
+ }
57
+ onClick?.(event);
58
+ },
59
+ [behavior, optionValue, disabled, multiple, setOpen, onClick]
60
+ );
61
+
62
+ // Handle mouse enter to highlight
63
+ const handleMouseEnter = useCallback(
64
+ (event: React.MouseEvent<HTMLDivElement>) => {
65
+ if (disabled) return;
66
+ setHighlightedValue(optionValue);
67
+ onMouseEnter?.(event);
68
+ },
69
+ [optionValue, disabled, setHighlightedValue, onMouseEnter]
70
+ );
71
+
72
+ const optionProps = behavior.getOptionProps(
73
+ optionValue,
74
+ label || String(children) || optionValue
75
+ );
76
+
77
+ return (
78
+ <div
79
+ ref={ref}
80
+ role={optionProps.role}
81
+ id={optionProps.id}
82
+ aria-selected={isSelected}
83
+ aria-disabled={disabled || undefined}
84
+ data-value={optionValue}
85
+ data-selected={isSelected || undefined}
86
+ data-highlighted={isHighlighted || undefined}
87
+ data-disabled={disabled || undefined}
88
+ className={className}
89
+ onClick={handleClick}
90
+ onMouseEnter={handleMouseEnter}
91
+ {...restProps}
92
+ >
93
+ {children}
94
+ </div>
95
+ );
96
+ }
97
+ );
98
+
99
+ ComboboxOption.displayName = "Combobox.Option";
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Combobox Root component - provides context to all Combobox compound components.
3
+ */
4
+
5
+ import { type Option, type Placement, createComboboxBehavior } from "@hypoth-ui/primitives-dom";
6
+ import { type ReactNode, useCallback, useMemo, useState } from "react";
7
+ import { ComboboxProvider } from "./combobox-context.js";
8
+
9
+ export interface ComboboxRootProps<Multi extends boolean = false> {
10
+ /** Combobox content */
11
+ children?: ReactNode;
12
+ /** Controlled open state */
13
+ open?: boolean;
14
+ /** Default open state (uncontrolled) */
15
+ defaultOpen?: boolean;
16
+ /** Called when open state changes */
17
+ onOpenChange?: (open: boolean) => void;
18
+ /** Controlled value (single-select) */
19
+ value?: Multi extends true ? string[] : string | null;
20
+ /** Default value (uncontrolled) */
21
+ defaultValue?: Multi extends true ? string[] : string | null;
22
+ /** Called when value changes */
23
+ onValueChange?: (value: Multi extends true ? string[] : string | null) => void;
24
+ /** Called when input value changes */
25
+ onInputChange?: (query: string) => void;
26
+ /** Enable multi-select mode */
27
+ multiple?: Multi;
28
+ /** Allow creating new values */
29
+ creatable?: boolean;
30
+ /** Called when new value is created */
31
+ onCreateValue?: (value: string) => void;
32
+ /** Async item loader */
33
+ loadItems?: (query: string) => Promise<Option<string>[]>;
34
+ /** Static items */
35
+ items?: Option<string>[];
36
+ /** Debounce delay for async (ms) */
37
+ debounce?: number;
38
+ /** Virtualization threshold */
39
+ virtualizationThreshold?: number;
40
+ /** Placement relative to input */
41
+ placement?: Placement;
42
+ /** Offset from input in pixels */
43
+ offset?: number;
44
+ /** Whether to flip placement on viewport edge */
45
+ flip?: boolean;
46
+ /** Whether combobox is disabled */
47
+ disabled?: boolean;
48
+ }
49
+
50
+ /**
51
+ * Root component for Combobox compound pattern.
52
+ * Provides context to Input, Content, Option, and Tag.
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * <Combobox.Root onValueChange={(value) => console.log(value)}>
57
+ * <Combobox.Input placeholder="Search..." />
58
+ * <Combobox.Content>
59
+ * <Combobox.Option value="apple">Apple</Combobox.Option>
60
+ * <Combobox.Option value="banana">Banana</Combobox.Option>
61
+ * </Combobox.Content>
62
+ * </Combobox.Root>
63
+ * ```
64
+ */
65
+ export function ComboboxRoot<Multi extends boolean = false>({
66
+ children,
67
+ open: controlledOpen,
68
+ defaultOpen = false,
69
+ onOpenChange,
70
+ value: controlledValue,
71
+ defaultValue,
72
+ onValueChange,
73
+ onInputChange,
74
+ multiple = false as Multi,
75
+ creatable = false,
76
+ onCreateValue,
77
+ loadItems,
78
+ items: staticItems = [],
79
+ debounce = 300,
80
+ virtualizationThreshold = 100,
81
+ placement: _placement = "bottom-start",
82
+ offset: _offset = 4,
83
+ flip: _flip = true,
84
+ disabled = false,
85
+ }: ComboboxRootProps<Multi>) {
86
+ // Compute default based on multiple mode
87
+ const computedDefaultValue = useMemo(() => {
88
+ if (defaultValue !== undefined) return defaultValue;
89
+ return (multiple ? [] : null) as Multi extends true ? string[] : string | null;
90
+ }, [defaultValue, multiple]);
91
+
92
+ // Support both controlled and uncontrolled modes for open
93
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
94
+ const isOpenControlled = controlledOpen !== undefined;
95
+ const open = isOpenControlled ? controlledOpen : internalOpen;
96
+
97
+ // Support both controlled and uncontrolled modes for value
98
+ const [internalValue, setInternalValue] =
99
+ useState<Multi extends true ? string[] : string | null>(computedDefaultValue);
100
+ const isValueControlled = controlledValue !== undefined;
101
+ const value = isValueControlled ? controlledValue : internalValue;
102
+
103
+ // Input value
104
+ const [inputValue, setInputValueState] = useState("");
105
+
106
+ // Highlighted value for keyboard navigation
107
+ const [highlightedValue, setHighlightedValue] = useState<string | null>(null);
108
+
109
+ // Filtered options
110
+ const [filteredOptions, setFilteredOptions] = useState<Option<string>[]>(staticItems);
111
+
112
+ // Loading state
113
+ const [loading, _setLoading] = useState(false);
114
+
115
+ const setOpen = useCallback(
116
+ (nextOpen: boolean) => {
117
+ if (!isOpenControlled) {
118
+ setInternalOpen(nextOpen);
119
+ }
120
+ onOpenChange?.(nextOpen);
121
+ },
122
+ [isOpenControlled, onOpenChange]
123
+ );
124
+
125
+ const setValue = useCallback(
126
+ (nextValue: Multi extends true ? string[] : string | null) => {
127
+ if (!isValueControlled) {
128
+ setInternalValue(nextValue);
129
+ }
130
+ onValueChange?.(nextValue);
131
+ },
132
+ [isValueControlled, onValueChange]
133
+ );
134
+
135
+ const setInputValue = useCallback(
136
+ (nextValue: string) => {
137
+ setInputValueState(nextValue);
138
+ onInputChange?.(nextValue);
139
+ },
140
+ [onInputChange]
141
+ );
142
+
143
+ // Create behavior instance
144
+ // biome-ignore lint/correctness/useExhaustiveDependencies: behavior is created once
145
+ const behavior = useMemo(
146
+ () =>
147
+ createComboboxBehavior<string, Multi>({
148
+ defaultValue: value as Multi extends true ? string[] : string | null,
149
+ multiple,
150
+ creatable,
151
+ onCreateValue,
152
+ loadItems,
153
+ items: staticItems,
154
+ debounce,
155
+ virtualizationThreshold,
156
+ disabled,
157
+ onValueChange: (v) => setValue(v as Multi extends true ? string[] : string | null),
158
+ onInputChange: (query) => {
159
+ setInputValue(query);
160
+ // Filter static items if no async loader
161
+ if (!loadItems) {
162
+ const lowerQuery = query.toLowerCase();
163
+ const filtered = staticItems.filter((item) =>
164
+ item.label.toLowerCase().includes(lowerQuery)
165
+ );
166
+ setFilteredOptions(filtered);
167
+ }
168
+ },
169
+ }),
170
+ []
171
+ );
172
+
173
+ const contextValue = useMemo(
174
+ () => ({
175
+ behavior: behavior as unknown as typeof behavior,
176
+ open,
177
+ setOpen,
178
+ value,
179
+ setValue,
180
+ inputValue,
181
+ setInputValue,
182
+ highlightedValue,
183
+ setHighlightedValue,
184
+ multiple,
185
+ filteredOptions,
186
+ loading,
187
+ }),
188
+ [
189
+ behavior,
190
+ open,
191
+ setOpen,
192
+ value,
193
+ setValue,
194
+ inputValue,
195
+ setInputValue,
196
+ highlightedValue,
197
+ filteredOptions,
198
+ loading,
199
+ multiple,
200
+ ]
201
+ );
202
+
203
+ // biome-ignore lint/suspicious/noExplicitAny: Generic context type requires cast for conditional Multi type
204
+ return <ComboboxProvider value={contextValue as any}>{children}</ComboboxProvider>;
205
+ }
206
+
207
+ ComboboxRoot.displayName = "Combobox.Root";
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Combobox Tag component - selected value tag for multi-select.
3
+ */
4
+
5
+ import { type HTMLAttributes, type ReactNode, forwardRef, useCallback } from "react";
6
+ import { useComboboxContext } from "./combobox-context.js";
7
+
8
+ export interface ComboboxTagProps extends Omit<HTMLAttributes<HTMLDivElement>, "value"> {
9
+ /** Tag value */
10
+ value: string;
11
+ /** Display label */
12
+ label?: string;
13
+ /** Tag content */
14
+ children?: ReactNode;
15
+ }
16
+
17
+ /**
18
+ * Tag for displaying selected value in multi-select mode.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <Combobox.Tag value="apple">
23
+ * Apple
24
+ * <button onClick={() => remove("apple")}>×</button>
25
+ * </Combobox.Tag>
26
+ * ```
27
+ */
28
+ export const ComboboxTag = forwardRef<HTMLDivElement, ComboboxTagProps>(
29
+ ({ value: tagValue, label, children, className, onKeyDown, ...restProps }, ref) => {
30
+ const { behavior } = useComboboxContext("Combobox.Tag");
31
+
32
+ // Handle keyboard to remove
33
+ const handleKeyDown = useCallback(
34
+ (event: React.KeyboardEvent<HTMLDivElement>) => {
35
+ if (event.key === "Delete" || event.key === "Backspace") {
36
+ event.preventDefault();
37
+ behavior.remove(tagValue);
38
+ }
39
+ onKeyDown?.(event);
40
+ },
41
+ [behavior, tagValue, onKeyDown]
42
+ );
43
+
44
+ const tagProps = behavior.getTagProps(tagValue, label || String(children) || tagValue);
45
+
46
+ return (
47
+ <div
48
+ ref={ref}
49
+ role={tagProps.role}
50
+ aria-label={tagProps["aria-label"]}
51
+ data-value={tagValue}
52
+ className={className}
53
+ onKeyDown={handleKeyDown}
54
+ {...restProps}
55
+ >
56
+ {children}
57
+ </div>
58
+ );
59
+ }
60
+ );
61
+
62
+ ComboboxTag.displayName = "Combobox.Tag";
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Combobox compound component exports.
3
+ *
4
+ * @example
5
+ * ```tsx
6
+ * import { Combobox } from "@/components/ui";
7
+ *
8
+ * <Combobox.Root onValueChange={(value) => console.log(value)}>
9
+ * <Combobox.Input placeholder="Search fruits..." />
10
+ * <Combobox.Content>
11
+ * <Combobox.Option value="apple">Apple</Combobox.Option>
12
+ * <Combobox.Option value="banana">Banana</Combobox.Option>
13
+ * <Combobox.Empty>No results found</Combobox.Empty>
14
+ * </Combobox.Content>
15
+ * </Combobox.Root>
16
+ *
17
+ * // Multi-select with tags
18
+ * <Combobox.Root multiple onValueChange={(values) => console.log(values)}>
19
+ * {values.map(v => (
20
+ * <Combobox.Tag key={v} value={v}>{v}</Combobox.Tag>
21
+ * ))}
22
+ * <Combobox.Input placeholder="Add tags..." />
23
+ * <Combobox.Content>
24
+ * <Combobox.Option value="react">React</Combobox.Option>
25
+ * <Combobox.Option value="vue">Vue</Combobox.Option>
26
+ * </Combobox.Content>
27
+ * </Combobox.Root>
28
+ * ```
29
+ */
30
+
31
+ import { ComboboxContent, type ComboboxContentProps } from "./combobox-content.js";
32
+ import { ComboboxEmpty, type ComboboxEmptyProps } from "./combobox-empty.js";
33
+ import { ComboboxInput, type ComboboxInputProps } from "./combobox-input.js";
34
+ import { ComboboxLoading, type ComboboxLoadingProps } from "./combobox-loading.js";
35
+ import { ComboboxOption, type ComboboxOptionProps } from "./combobox-option.js";
36
+ import { ComboboxRoot, type ComboboxRootProps } from "./combobox-root.js";
37
+ import { ComboboxTag, type ComboboxTagProps } from "./combobox-tag.js";
38
+
39
+ // Compound component
40
+ export const Combobox = {
41
+ Root: ComboboxRoot,
42
+ Input: ComboboxInput,
43
+ Content: ComboboxContent,
44
+ Option: ComboboxOption,
45
+ Tag: ComboboxTag,
46
+ Empty: ComboboxEmpty,
47
+ Loading: ComboboxLoading,
48
+ };
49
+
50
+ // Type exports
51
+ export type {
52
+ ComboboxContentProps,
53
+ ComboboxEmptyProps,
54
+ ComboboxInputProps,
55
+ ComboboxLoadingProps,
56
+ ComboboxOptionProps,
57
+ ComboboxRootProps,
58
+ ComboboxTagProps,
59
+ };
60
+
61
+ // Re-export Placement and Option from primitives-dom
62
+ export type { Placement, Option } from "@hypoth-ui/primitives-dom";