@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,261 @@
1
+ import { type RovingFocus, createRovingFocus } from "@hypoth-ui/primitives-dom";
2
+ import { html } from "lit";
3
+ import type { PropertyValues } from "lit";
4
+ import { property } from "lit/decorators.js";
5
+ import { DSElement } from "../../base/ds-element.js";
6
+ import { FormAssociatedMixin } from "../../base/form-associated.js";
7
+ import type { ValidationFlags } from "../../base/form-associated.js";
8
+ import { StandardEvents, emitEvent } from "../../events/emit.js";
9
+ import { define } from "../../registry/define.js";
10
+ import type { DsRadio } from "./radio.js";
11
+
12
+ // Import radio component
13
+ import "./radio.js";
14
+
15
+ export type RadioOrientation = "horizontal" | "vertical";
16
+
17
+ /**
18
+ * Container for radio button group with roving tabindex and native form participation.
19
+ *
20
+ * Uses ElementInternals for form association - the selected value is submitted with the form
21
+ * and the group participates in constraint validation.
22
+ *
23
+ * @element ds-radio-group
24
+ * @fires ds:change - Fired when selection changes with { value }
25
+ * @fires ds:invalid - Fired when customValidation is true and validation fails
26
+ *
27
+ * @slot - ds-radio children
28
+ *
29
+ * @example
30
+ * ```html
31
+ * <form>
32
+ * <ds-field>
33
+ * <ds-label>Size</ds-label>
34
+ * <ds-radio-group name="size" required>
35
+ * <ds-radio value="sm">Small</ds-radio>
36
+ * <ds-radio value="md">Medium</ds-radio>
37
+ * <ds-radio value="lg">Large</ds-radio>
38
+ * </ds-radio-group>
39
+ * <ds-field-error></ds-field-error>
40
+ * </ds-field>
41
+ * <button type="submit">Submit</button>
42
+ * </form>
43
+ * ```
44
+ */
45
+ export class DsRadioGroup extends FormAssociatedMixin(DSElement) {
46
+ /** Layout and navigation axis */
47
+ @property({ type: String, reflect: true })
48
+ orientation: RadioOrientation = "vertical";
49
+
50
+ /** Default value for form reset */
51
+ private _defaultValue = "";
52
+
53
+ private rovingFocus: RovingFocus | null = null;
54
+ private childObserver: MutationObserver | null = null;
55
+
56
+ override connectedCallback(): void {
57
+ // Store default value for form reset
58
+ this._defaultValue = this.value;
59
+
60
+ super.connectedCallback();
61
+
62
+ // Set role on the group
63
+ this.setAttribute("role", "radiogroup");
64
+
65
+ // Observe child changes
66
+ this.childObserver = new MutationObserver(() => {
67
+ this.setupRadios();
68
+ });
69
+ this.childObserver.observe(this, { childList: true, subtree: true });
70
+
71
+ // Listen for radio selection events
72
+ this.addEventListener("ds:radio-select", this.handleRadioSelect as EventListener);
73
+
74
+ // Setup after first render
75
+ this.updateComplete.then(() => {
76
+ this.setupRadios();
77
+ this.setupRovingFocus();
78
+ });
79
+ }
80
+
81
+ override disconnectedCallback(): void {
82
+ super.disconnectedCallback();
83
+ this.childObserver?.disconnect();
84
+ this.childObserver = null;
85
+ this.rovingFocus?.destroy();
86
+ this.rovingFocus = null;
87
+ this.removeEventListener("ds:radio-select", this.handleRadioSelect as EventListener);
88
+ }
89
+
90
+ /**
91
+ * Sets up the radio items with correct checked state and disabled state.
92
+ */
93
+ private setupRadios(): void {
94
+ const radios = this.getRadioItems();
95
+
96
+ radios.forEach((radio) => {
97
+ // Set checked state based on group value
98
+ radio.setChecked(radio.value === this.value);
99
+
100
+ // Propagate disabled state from group
101
+ if (this.disabled) {
102
+ radio.disabled = true;
103
+ }
104
+ });
105
+
106
+ // Update roving focus tabindex
107
+ this.updateTabIndices();
108
+ }
109
+
110
+ /**
111
+ * Updates tabindex values for roving focus.
112
+ */
113
+ private updateTabIndices(): void {
114
+ const radios = this.getRadioItems();
115
+ const selectedIndex = radios.findIndex((r) => r.value === this.value);
116
+ const focusIndex = selectedIndex >= 0 ? selectedIndex : 0;
117
+
118
+ radios.forEach((radio, index) => {
119
+ radio.setTabIndex(index === focusIndex ? 0 : -1);
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Sets up roving focus for keyboard navigation.
125
+ */
126
+ private setupRovingFocus(): void {
127
+ this.rovingFocus?.destroy();
128
+
129
+ const direction = this.orientation === "horizontal" ? "horizontal" : "vertical";
130
+
131
+ this.rovingFocus = createRovingFocus({
132
+ container: this,
133
+ selector: "[role='radio']",
134
+ direction,
135
+ loop: true,
136
+ skipDisabled: true,
137
+ onFocus: (element, _index) => {
138
+ // Find the parent ds-radio and select it (selection follows focus)
139
+ const radio = element.closest("ds-radio") as DsRadio | null;
140
+ if (radio && !radio.disabled && !this.disabled) {
141
+ this.selectValue(radio.value);
142
+ }
143
+ },
144
+ });
145
+ }
146
+
147
+ /**
148
+ * Gets all radio items in the group.
149
+ */
150
+ private getRadioItems(): DsRadio[] {
151
+ return Array.from(this.querySelectorAll("ds-radio")) as DsRadio[];
152
+ }
153
+
154
+ /**
155
+ * Handles radio selection from click or keyboard.
156
+ */
157
+ private handleRadioSelect = (event: CustomEvent<{ value: string }>): void => {
158
+ if (this.disabled) return;
159
+
160
+ const { value } = event.detail;
161
+ this.selectValue(value);
162
+ };
163
+
164
+ /**
165
+ * Selects a value and updates state.
166
+ */
167
+ private selectValue(value: string): void {
168
+ if (value === this.value) return;
169
+
170
+ this.value = value;
171
+ this.setupRadios();
172
+
173
+ emitEvent(this, StandardEvents.CHANGE, {
174
+ detail: { value: this.value },
175
+ });
176
+ }
177
+
178
+ override updated(changedProperties: Map<string, unknown>): void {
179
+ super.updated(changedProperties);
180
+
181
+ if (changedProperties.has("value")) {
182
+ this.setupRadios();
183
+ }
184
+
185
+ if (changedProperties.has("orientation")) {
186
+ this.setupRovingFocus();
187
+ }
188
+
189
+ if (changedProperties.has("disabled")) {
190
+ this.setupRadios();
191
+ }
192
+ }
193
+
194
+ // Form association implementation
195
+
196
+ protected getFormValue(): string | null {
197
+ return this.value || null;
198
+ }
199
+
200
+ protected getValidationAnchor(): HTMLElement | undefined {
201
+ // Use the first radio control as validation anchor
202
+ return this.querySelector("ds-radio [role='radio']") as HTMLElement | undefined;
203
+ }
204
+
205
+ protected getValidationFlags(): ValidationFlags {
206
+ if (this.required && !this.value) {
207
+ return { valueMissing: true };
208
+ }
209
+ return {};
210
+ }
211
+
212
+ protected getValidationMessage(flags: ValidationFlags): string {
213
+ if (flags.valueMissing) {
214
+ return "Please select an option";
215
+ }
216
+ return "";
217
+ }
218
+
219
+ protected shouldUpdateFormValue(changedProperties: PropertyValues): boolean {
220
+ return changedProperties.has("value");
221
+ }
222
+
223
+ protected shouldUpdateValidity(changedProperties: PropertyValues): boolean {
224
+ return changedProperties.has("value");
225
+ }
226
+
227
+ protected onFormReset(): void {
228
+ this.value = this._defaultValue;
229
+ this.setupRadios();
230
+ }
231
+
232
+ protected onFormStateRestore(
233
+ state: string | File | FormData | null,
234
+ _mode: "restore" | "autocomplete"
235
+ ): void {
236
+ if (typeof state === "string") {
237
+ this.value = state;
238
+ this.setupRadios();
239
+ }
240
+ }
241
+
242
+ override render() {
243
+ return html`
244
+ <div
245
+ class="ds-radio-group"
246
+ part="container"
247
+ data-orientation=${this.orientation}
248
+ >
249
+ <slot></slot>
250
+ </div>
251
+ `;
252
+ }
253
+ }
254
+
255
+ define("ds-radio-group", DsRadioGroup);
256
+
257
+ declare global {
258
+ interface HTMLElementTagNameMap {
259
+ "ds-radio-group": DsRadioGroup;
260
+ }
261
+ }
@@ -0,0 +1,145 @@
1
+ import { html } from "lit";
2
+ import { property, state } from "lit/decorators.js";
3
+ import { DSElement } from "../../base/ds-element.js";
4
+ import { define } from "../../registry/define.js";
5
+
6
+ /**
7
+ * Individual radio button within a group.
8
+ *
9
+ * @element ds-radio
10
+ *
11
+ * @slot - Radio label
12
+ *
13
+ * @example
14
+ * ```html
15
+ * <ds-radio-group name="size">
16
+ * <ds-radio value="sm">Small</ds-radio>
17
+ * <ds-radio value="md">Medium</ds-radio>
18
+ * <ds-radio value="lg">Large</ds-radio>
19
+ * </ds-radio-group>
20
+ * ```
21
+ */
22
+ export class DsRadio extends DSElement {
23
+ /** Radio value */
24
+ @property({ type: String, reflect: true })
25
+ value = "";
26
+
27
+ /** Selected state (managed by group) */
28
+ @property({ type: Boolean, reflect: true })
29
+ checked = false;
30
+
31
+ /** Disabled state */
32
+ @property({ type: Boolean, reflect: true })
33
+ disabled = false;
34
+
35
+ /** Label text captured from slot */
36
+ @state()
37
+ private labelText = "";
38
+
39
+ /** Unique ID for label association */
40
+ @state()
41
+ private labelId = "";
42
+
43
+ /** Whether this radio is focusable (managed by group) */
44
+ @state()
45
+ private _tabIndexValue: number | undefined = undefined;
46
+
47
+ get tabIndexValue(): number {
48
+ return this._tabIndexValue ?? -1;
49
+ }
50
+
51
+ override connectedCallback(): void {
52
+ // Capture label text before Lit renders
53
+ this.labelText = this.textContent?.trim() ?? "";
54
+ // Generate unique ID for label
55
+ this.labelId = `radio-label-${crypto.randomUUID().slice(0, 8)}`;
56
+ super.connectedCallback();
57
+ }
58
+
59
+ /**
60
+ * Sets the checked state (called by RadioGroup).
61
+ */
62
+ setChecked(checked: boolean): void {
63
+ this.checked = checked;
64
+ }
65
+
66
+ /**
67
+ * Sets the tabindex (called by RadioGroup for roving focus).
68
+ */
69
+ setTabIndex(index: number): void {
70
+ this._tabIndexValue = index;
71
+ this.requestUpdate();
72
+ }
73
+
74
+ /**
75
+ * Focus the control element.
76
+ */
77
+ focusControl(): void {
78
+ const control = this.querySelector("[role='radio']") as HTMLElement | null;
79
+ control?.focus();
80
+ }
81
+
82
+ private handleClick = (event: Event): void => {
83
+ if (this.disabled) return;
84
+ event.preventDefault();
85
+
86
+ // Dispatch custom event for parent to handle
87
+ this.dispatchEvent(
88
+ new CustomEvent("ds:radio-select", {
89
+ detail: { value: this.value },
90
+ bubbles: true,
91
+ composed: true,
92
+ })
93
+ );
94
+ };
95
+
96
+ private handleKeyDown = (event: KeyboardEvent): void => {
97
+ // Space key selects the radio
98
+ if (event.key === " " && !this.disabled) {
99
+ event.preventDefault();
100
+ this.dispatchEvent(
101
+ new CustomEvent("ds:radio-select", {
102
+ detail: { value: this.value },
103
+ bubbles: true,
104
+ composed: true,
105
+ })
106
+ );
107
+ }
108
+ };
109
+
110
+ override render() {
111
+ return html`
112
+ <div
113
+ class="ds-radio"
114
+ part="container"
115
+ @click=${this.handleClick}
116
+ >
117
+ <div
118
+ role="radio"
119
+ part="control"
120
+ class="ds-radio__control"
121
+ .tabIndex=${this.tabIndexValue}
122
+ aria-checked=${this.checked ? "true" : "false"}
123
+ aria-disabled=${this.disabled ? "true" : "false"}
124
+ aria-labelledby=${this.labelId}
125
+ @keydown=${this.handleKeyDown}
126
+ >
127
+ <span class="ds-radio__indicator" part="indicator">
128
+ ${this.checked ? html`<span class="ds-radio__dot"></span>` : null}
129
+ </span>
130
+ </div>
131
+ <span id=${this.labelId} class="ds-radio__label" part="label">
132
+ ${this.labelText}
133
+ </span>
134
+ </div>
135
+ `;
136
+ }
137
+ }
138
+
139
+ define("ds-radio", DsRadio);
140
+
141
+ declare global {
142
+ interface HTMLElementTagNameMap {
143
+ "ds-radio": DsRadio;
144
+ }
145
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * ScrollArea compound component exports.
3
+ *
4
+ * ScrollArea provides custom styled scrollbars for content containers.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { ScrollArea } from "@/components/ui";
9
+ *
10
+ * <ScrollArea.Root style={{ height: "200px" }}>
11
+ * <ScrollArea.Viewport>
12
+ * <!-- Long content here -->
13
+ * </ScrollArea.Viewport>
14
+ * <ScrollArea.Scrollbar orientation="vertical">
15
+ * <ScrollArea.Thumb />
16
+ * </ScrollArea.Scrollbar>
17
+ * </ScrollArea.Root>
18
+ * ```
19
+ */
20
+
21
+ import {
22
+ type CSSProperties,
23
+ type HTMLAttributes,
24
+ type ReactNode,
25
+ createElement,
26
+ forwardRef,
27
+ } from "react";
28
+
29
+ // ============================================================================
30
+ // Types
31
+ // ============================================================================
32
+
33
+ export type ScrollAreaType = "auto" | "always" | "scroll" | "hover";
34
+
35
+ export interface ScrollAreaRootProps extends HTMLAttributes<HTMLElement> {
36
+ /** Content */
37
+ children?: ReactNode;
38
+ /** When scrollbars are visible */
39
+ type?: ScrollAreaType;
40
+ /** Scroll hide delay in ms (for hover type) */
41
+ scrollHideDelay?: number;
42
+ /** Orientation for which to show scrollbar */
43
+ orientation?: "vertical" | "horizontal" | "both";
44
+ /** Custom styles */
45
+ style?: CSSProperties;
46
+ }
47
+
48
+ export interface ScrollAreaViewportProps extends HTMLAttributes<HTMLElement> {
49
+ /** Scrollable content */
50
+ children?: ReactNode;
51
+ }
52
+
53
+ export interface ScrollAreaScrollbarProps extends HTMLAttributes<HTMLElement> {
54
+ /** Scrollbar content (typically a thumb) */
55
+ children?: ReactNode;
56
+ /** Scrollbar orientation */
57
+ orientation?: "vertical" | "horizontal";
58
+ }
59
+
60
+ export interface ScrollAreaThumbProps extends HTMLAttributes<HTMLElement> {}
61
+
62
+ // ============================================================================
63
+ // Components
64
+ // ============================================================================
65
+
66
+ /**
67
+ * ScrollArea root component.
68
+ */
69
+ const ScrollAreaRoot = forwardRef<HTMLElement, ScrollAreaRootProps>(function ScrollAreaRoot(
70
+ {
71
+ children,
72
+ className,
73
+ type = "hover",
74
+ scrollHideDelay = 600,
75
+ orientation = "vertical",
76
+ style,
77
+ ...props
78
+ },
79
+ ref
80
+ ) {
81
+ return createElement(
82
+ "ds-scroll-area",
83
+ {
84
+ ref,
85
+ class: className,
86
+ type,
87
+ "scroll-hide-delay": scrollHideDelay,
88
+ orientation,
89
+ style,
90
+ ...props,
91
+ },
92
+ children
93
+ );
94
+ });
95
+ ScrollAreaRoot.displayName = "ScrollArea.Root";
96
+
97
+ /**
98
+ * ScrollArea viewport component.
99
+ */
100
+ const ScrollAreaViewport = forwardRef<HTMLElement, ScrollAreaViewportProps>(
101
+ function ScrollAreaViewport({ children, className, ...props }, ref) {
102
+ return createElement("ds-scroll-area-viewport", { ref, class: className, ...props }, children);
103
+ }
104
+ );
105
+ ScrollAreaViewport.displayName = "ScrollArea.Viewport";
106
+
107
+ /**
108
+ * ScrollArea scrollbar component.
109
+ */
110
+ const ScrollAreaScrollbar = forwardRef<HTMLElement, ScrollAreaScrollbarProps>(
111
+ function ScrollAreaScrollbar({ children, className, orientation = "vertical", ...props }, ref) {
112
+ return createElement(
113
+ "ds-scroll-area-scrollbar",
114
+ { ref, class: className, orientation, ...props },
115
+ children
116
+ );
117
+ }
118
+ );
119
+ ScrollAreaScrollbar.displayName = "ScrollArea.Scrollbar";
120
+
121
+ /**
122
+ * ScrollArea thumb component.
123
+ */
124
+ const ScrollAreaThumb = forwardRef<HTMLElement, ScrollAreaThumbProps>(function ScrollAreaThumb(
125
+ { className, ...props },
126
+ ref
127
+ ) {
128
+ return createElement("ds-scroll-area-thumb", { ref, class: className, ...props });
129
+ });
130
+ ScrollAreaThumb.displayName = "ScrollArea.Thumb";
131
+
132
+ // ============================================================================
133
+ // Compound Component
134
+ // ============================================================================
135
+
136
+ export const ScrollArea = {
137
+ Root: ScrollAreaRoot,
138
+ Viewport: ScrollAreaViewport,
139
+ Scrollbar: ScrollAreaScrollbar,
140
+ Thumb: ScrollAreaThumb,
141
+ };
142
+
143
+ // Also export individual components
144
+ export { ScrollAreaRoot, ScrollAreaViewport, ScrollAreaScrollbar, ScrollAreaThumb };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * ScrollArea component exports.
3
+ */
4
+
5
+ export { DsScrollArea, type ScrollAreaType } from "./scroll-area.js";
6
+ export { DsScrollAreaViewport } from "./scroll-area-viewport.js";
7
+ export { DsScrollAreaScrollbar } from "./scroll-area-scrollbar.js";
8
+ export { DsScrollAreaThumb } from "./scroll-area-thumb.js";
@@ -0,0 +1,143 @@
1
+ /**
2
+ * ScrollAreaScrollbar component - scrollbar track.
3
+ *
4
+ * @element ds-scroll-area-scrollbar
5
+ *
6
+ * @slot - Scrollbar thumb
7
+ */
8
+
9
+ import { html } from "lit";
10
+ import { property } from "lit/decorators.js";
11
+ import { DSElement } from "../../base/ds-element.js";
12
+ import { define } from "../../registry/define.js";
13
+
14
+ export class DsScrollAreaScrollbar extends DSElement {
15
+ /** Scrollbar orientation */
16
+ @property({ type: String, reflect: true })
17
+ orientation: "vertical" | "horizontal" = "vertical";
18
+
19
+ private hideTimer: ReturnType<typeof setTimeout> | null = null;
20
+ private isHovered = false;
21
+
22
+ override connectedCallback(): void {
23
+ super.connectedCallback();
24
+
25
+ this.setAttribute("role", "scrollbar");
26
+ this.setAttribute("aria-orientation", this.orientation);
27
+
28
+ // Handle track click
29
+ this.addEventListener("mousedown", this.handleTrackClick);
30
+ this.addEventListener("mouseenter", this.handleMouseEnter);
31
+ this.addEventListener("mouseleave", this.handleMouseLeave);
32
+
33
+ // Listen for viewport scroll
34
+ const scrollArea = this.closest("ds-scroll-area");
35
+ const viewport = scrollArea?.querySelector("ds-scroll-area-viewport");
36
+ if (viewport) {
37
+ viewport.addEventListener("scroll", this.handleViewportScroll);
38
+ }
39
+ }
40
+
41
+ override disconnectedCallback(): void {
42
+ super.disconnectedCallback();
43
+ this.removeEventListener("mousedown", this.handleTrackClick);
44
+ this.removeEventListener("mouseenter", this.handleMouseEnter);
45
+ this.removeEventListener("mouseleave", this.handleMouseLeave);
46
+
47
+ if (this.hideTimer) {
48
+ clearTimeout(this.hideTimer);
49
+ }
50
+
51
+ const scrollArea = this.closest("ds-scroll-area");
52
+ const viewport = scrollArea?.querySelector("ds-scroll-area-viewport");
53
+ if (viewport) {
54
+ viewport.removeEventListener("scroll", this.handleViewportScroll);
55
+ }
56
+ }
57
+
58
+ private handleTrackClick = (event: MouseEvent): void => {
59
+ // Ignore if clicking on thumb
60
+ const thumb = event.target as HTMLElement;
61
+ if (thumb.tagName === "DS-SCROLL-AREA-THUMB") return;
62
+
63
+ const scrollArea = this.closest("ds-scroll-area");
64
+ const viewport = scrollArea?.querySelector("ds-scroll-area-viewport");
65
+ if (!viewport) return;
66
+
67
+ const rect = this.getBoundingClientRect();
68
+
69
+ if (this.orientation === "vertical") {
70
+ const clickRatio = (event.clientY - rect.top) / rect.height;
71
+ const scrollHeight = viewport.scrollHeight - viewport.clientHeight;
72
+ viewport.scrollTo({
73
+ top: clickRatio * scrollHeight,
74
+ behavior: "smooth",
75
+ });
76
+ } else {
77
+ const clickRatio = (event.clientX - rect.left) / rect.width;
78
+ const scrollWidth = viewport.scrollWidth - viewport.clientWidth;
79
+ viewport.scrollTo({
80
+ left: clickRatio * scrollWidth,
81
+ behavior: "smooth",
82
+ });
83
+ }
84
+ };
85
+
86
+ private handleViewportScroll = (): void => {
87
+ // Show scrollbar
88
+ this.setAttribute("data-state", "visible");
89
+
90
+ // Schedule hide (for hover type)
91
+ this.scheduleHide();
92
+ };
93
+
94
+ private handleMouseEnter = (): void => {
95
+ this.isHovered = true;
96
+ if (this.hideTimer) {
97
+ clearTimeout(this.hideTimer);
98
+ this.hideTimer = null;
99
+ }
100
+ };
101
+
102
+ private handleMouseLeave = (): void => {
103
+ this.isHovered = false;
104
+ this.scheduleHide();
105
+ };
106
+
107
+ private scheduleHide(): void {
108
+ const scrollArea = this.closest("ds-scroll-area");
109
+ const type = scrollArea?.getAttribute("type") || "hover";
110
+
111
+ if (type !== "hover") return;
112
+
113
+ if (this.hideTimer) {
114
+ clearTimeout(this.hideTimer);
115
+ }
116
+
117
+ const delay = Number(scrollArea?.getAttribute("scroll-hide-delay")) || 600;
118
+
119
+ this.hideTimer = setTimeout(() => {
120
+ if (!this.isHovered) {
121
+ this.setAttribute("data-state", "hidden");
122
+ }
123
+ }, delay);
124
+ }
125
+
126
+ override updated(changedProperties: Map<string, unknown>): void {
127
+ if (changedProperties.has("orientation")) {
128
+ this.setAttribute("aria-orientation", this.orientation);
129
+ }
130
+ }
131
+
132
+ override render() {
133
+ return html`<slot></slot>`;
134
+ }
135
+ }
136
+
137
+ define("ds-scroll-area-scrollbar", DsScrollAreaScrollbar);
138
+
139
+ declare global {
140
+ interface HTMLElementTagNameMap {
141
+ "ds-scroll-area-scrollbar": DsScrollAreaScrollbar;
142
+ }
143
+ }