@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,592 @@
1
+ import {
2
+ type AnchorPosition,
3
+ type DismissableLayer,
4
+ type Placement,
5
+ type Presence,
6
+ createAnchorPosition,
7
+ createDismissableLayer,
8
+ createPresence,
9
+ prefersReducedMotion,
10
+ } from "@hypoth-ui/primitives-dom";
11
+ import { html } from "lit";
12
+ import { property, state } from "lit/decorators.js";
13
+ import { DSElement } from "../../base/ds-element.js";
14
+ import { StandardEvents, emitEvent } from "../../events/emit.js";
15
+ import { define } from "../../registry/define.js";
16
+
17
+ // Import child components
18
+ import type { DsDatePickerCalendar } from "./date-picker-calendar.js";
19
+ import "./date-picker-calendar.js";
20
+ import {
21
+ type DateParseResult,
22
+ formatTypedDate,
23
+ getDateFormatPlaceholder,
24
+ parseTypedDate,
25
+ validateTypedDate,
26
+ } from "./date-utils.js";
27
+
28
+ export type DatePickerMode = "single" | "range";
29
+
30
+ /**
31
+ * DatePicker component with calendar dropdown.
32
+ *
33
+ * Implements WAI-ARIA DatePicker pattern with:
34
+ * - Arrow key navigation within calendar grid
35
+ * - Page Up/Down for month navigation
36
+ * - Enter/Space to select date
37
+ * - Escape to close
38
+ *
39
+ * @element ds-date-picker
40
+ *
41
+ * @slot trigger - Trigger element (button or input)
42
+ * @slot - Calendar content (ds-date-picker-calendar)
43
+ *
44
+ * @fires ds:open - Fired when calendar opens
45
+ * @fires ds:close - Fired when calendar closes
46
+ * @fires ds:change - Fired when date changes (detail: { date } or { start, end })
47
+ *
48
+ * @example
49
+ * ```html
50
+ * <ds-date-picker value="2026-01-15">
51
+ * <button slot="trigger">Select date</button>
52
+ * <ds-date-picker-calendar></ds-date-picker-calendar>
53
+ * </ds-date-picker>
54
+ * ```
55
+ */
56
+ export class DsDatePicker extends DSElement {
57
+ /** Whether the calendar is open */
58
+ @property({ type: Boolean, reflect: true })
59
+ open = false;
60
+
61
+ /** Selection mode: single date or date range */
62
+ @property({ type: String, reflect: true })
63
+ mode: DatePickerMode = "single";
64
+
65
+ /** Selected date in ISO format (YYYY-MM-DD) */
66
+ @property({ type: String, reflect: true })
67
+ value = "";
68
+
69
+ /** Range start date in ISO format */
70
+ @property({ type: String, attribute: "range-start" })
71
+ rangeStart = "";
72
+
73
+ /** Range end date in ISO format */
74
+ @property({ type: String, attribute: "range-end" })
75
+ rangeEnd = "";
76
+
77
+ /** Minimum selectable date in ISO format */
78
+ @property({ type: String, attribute: "min-date" })
79
+ minDate = "";
80
+
81
+ /** Maximum selectable date in ISO format */
82
+ @property({ type: String, attribute: "max-date" })
83
+ maxDate = "";
84
+
85
+ /** Locale for date formatting */
86
+ @property({ type: String })
87
+ locale = "en-US";
88
+
89
+ /** First day of week (0=Sunday, 1=Monday) */
90
+ @property({ type: Number, attribute: "first-day-of-week" })
91
+ firstDayOfWeek: 0 | 1 | 2 | 3 | 4 | 5 | 6 = 0;
92
+
93
+ /** Placement relative to trigger */
94
+ @property({ type: String, reflect: true })
95
+ placement: Placement = "bottom-start";
96
+
97
+ /** Offset distance from trigger in pixels */
98
+ @property({ type: Number })
99
+ offset = 4;
100
+
101
+ /** Whether to flip placement when near viewport edge */
102
+ @property({ type: Boolean })
103
+ flip = true;
104
+
105
+ /** Whether to animate open/close transitions */
106
+ @property({ type: Boolean })
107
+ animated = true;
108
+
109
+ /** Whether the date picker is disabled */
110
+ @property({ type: Boolean, reflect: true })
111
+ disabled = false;
112
+
113
+ /** Whether the date picker is read-only */
114
+ @property({ type: Boolean, reflect: true })
115
+ readonly = false;
116
+
117
+ /** Whether to allow typed date input (when using input trigger) */
118
+ @property({ type: Boolean, attribute: "typed-input" })
119
+ typedInput = false;
120
+
121
+ /** Current text value of the input (for typed input mode) */
122
+ @state()
123
+ inputValue = "";
124
+
125
+ /** Current validation error message */
126
+ @state()
127
+ inputError: string | null = null;
128
+
129
+ private anchorPosition: AnchorPosition | null = null;
130
+ private dismissLayer: DismissableLayer | null = null;
131
+ private presence: Presence | null = null;
132
+ private resizeObserver: ResizeObserver | null = null;
133
+ private scrollHandler: (() => void) | null = null;
134
+ private isSelectingRange = false;
135
+
136
+ override connectedCallback(): void {
137
+ super.connectedCallback();
138
+
139
+ // Listen for trigger interactions
140
+ this.addEventListener("click", this.handleTriggerClick);
141
+ this.addEventListener("keydown", this.handleTriggerKeyDown);
142
+
143
+ // Listen for date selection from calendar
144
+ this.addEventListener("ds:date-select", this.handleDateSelect);
145
+
146
+ // Listen for input events (typed input mode)
147
+ this.addEventListener("input", this.handleTypedInput);
148
+ this.addEventListener("blur", this.handleInputBlur, true);
149
+
150
+ // Initialize input value from date value
151
+ if (this.value) {
152
+ this.inputValue = formatTypedDate(this.value, this.locale);
153
+ }
154
+ }
155
+
156
+ override disconnectedCallback(): void {
157
+ super.disconnectedCallback();
158
+ this.removeEventListener("click", this.handleTriggerClick);
159
+ this.removeEventListener("keydown", this.handleTriggerKeyDown);
160
+ this.removeEventListener("ds:date-select", this.handleDateSelect);
161
+ this.removeEventListener("input", this.handleTypedInput);
162
+ this.removeEventListener("blur", this.handleInputBlur, true);
163
+ this.cleanup();
164
+ }
165
+
166
+ /**
167
+ * Opens the calendar.
168
+ */
169
+ public show(): void {
170
+ if (this.open || this.disabled) return;
171
+ this.open = true;
172
+ emitEvent(this, StandardEvents.OPEN);
173
+ }
174
+
175
+ /**
176
+ * Closes the calendar.
177
+ */
178
+ public close(): void {
179
+ if (!this.open) return;
180
+
181
+ const calendar = this.querySelector("ds-date-picker-calendar") as DsDatePickerCalendar | null;
182
+
183
+ if (this.animated && calendar && !prefersReducedMotion()) {
184
+ this.dismissLayer?.deactivate();
185
+ this.dismissLayer = null;
186
+
187
+ this.presence = createPresence({
188
+ onExitComplete: () => {
189
+ this.completeClose();
190
+ },
191
+ });
192
+ this.presence.hide(calendar);
193
+ } else {
194
+ this.cleanup();
195
+ this.open = false;
196
+ emitEvent(this, StandardEvents.CLOSE);
197
+ this.getTriggerElement()?.focus();
198
+ }
199
+ }
200
+
201
+ private completeClose(): void {
202
+ this.cleanup();
203
+ this.open = false;
204
+ emitEvent(this, StandardEvents.CLOSE);
205
+ this.getTriggerElement()?.focus();
206
+ }
207
+
208
+ /**
209
+ * Toggles the calendar.
210
+ */
211
+ public toggle(): void {
212
+ if (this.open) {
213
+ this.close();
214
+ } else {
215
+ this.show();
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Sets the selected date programmatically.
221
+ */
222
+ public setDate(date: string): void {
223
+ if (this.disabled || this.readonly) return;
224
+ this.value = date;
225
+ emitEvent(this, StandardEvents.CHANGE, { detail: { date } });
226
+ }
227
+
228
+ /**
229
+ * Sets the date range programmatically.
230
+ */
231
+ public setRange(start: string, end: string): void {
232
+ if (this.disabled || this.readonly || this.mode !== "range") return;
233
+ this.rangeStart = start;
234
+ this.rangeEnd = end;
235
+ emitEvent(this, StandardEvents.CHANGE, { detail: { start, end } });
236
+ }
237
+
238
+ /**
239
+ * Clears the selected date(s).
240
+ */
241
+ public clear(): void {
242
+ if (this.disabled || this.readonly) return;
243
+ this.value = "";
244
+ this.rangeStart = "";
245
+ this.rangeEnd = "";
246
+ this.isSelectingRange = false;
247
+ emitEvent(this, StandardEvents.CHANGE, {
248
+ detail: this.mode === "range" ? { start: "", end: "" } : { date: "" },
249
+ });
250
+ }
251
+
252
+ private getTriggerElement(): HTMLElement | null {
253
+ const triggerSlot = this.querySelector('[slot="trigger"]');
254
+ return triggerSlot as HTMLElement | null;
255
+ }
256
+
257
+ private handleTriggerClick = (event: Event): void => {
258
+ const target = event.target as HTMLElement;
259
+ const trigger = target.closest('[slot="trigger"]');
260
+
261
+ if (trigger && this.contains(trigger)) {
262
+ event.preventDefault();
263
+ if (!this.disabled) {
264
+ this.toggle();
265
+ }
266
+ }
267
+ };
268
+
269
+ private handleTriggerKeyDown = (event: KeyboardEvent): void => {
270
+ const target = event.target as HTMLElement;
271
+ const trigger = target.closest('[slot="trigger"]');
272
+
273
+ if (!trigger || !this.contains(trigger)) return;
274
+ if (this.disabled) return;
275
+
276
+ switch (event.key) {
277
+ case "Enter":
278
+ case " ":
279
+ event.preventDefault();
280
+ this.toggle();
281
+ break;
282
+ case "ArrowDown":
283
+ event.preventDefault();
284
+ if (!this.open) this.show();
285
+ break;
286
+ }
287
+ };
288
+
289
+ private handleDateSelect = (event: Event): void => {
290
+ const customEvent = event as CustomEvent<{ date: string }>;
291
+ const selectedDate = customEvent.detail.date;
292
+
293
+ if (this.mode === "single") {
294
+ this.value = selectedDate;
295
+ emitEvent(this, StandardEvents.CHANGE, { detail: { date: selectedDate } });
296
+ this.close();
297
+ } else {
298
+ // Range mode
299
+ if (!this.isSelectingRange || !this.rangeStart) {
300
+ // Start new range
301
+ this.rangeStart = selectedDate;
302
+ this.rangeEnd = "";
303
+ this.isSelectingRange = true;
304
+ } else {
305
+ // Complete range
306
+ if (selectedDate < this.rangeStart) {
307
+ this.rangeEnd = this.rangeStart;
308
+ this.rangeStart = selectedDate;
309
+ } else {
310
+ this.rangeEnd = selectedDate;
311
+ }
312
+ this.isSelectingRange = false;
313
+ emitEvent(this, StandardEvents.CHANGE, {
314
+ detail: { start: this.rangeStart, end: this.rangeEnd },
315
+ });
316
+ this.close();
317
+ }
318
+ }
319
+ };
320
+
321
+ private handleDismiss = (): void => {
322
+ this.close();
323
+ };
324
+
325
+ /**
326
+ * Handles typed input events.
327
+ */
328
+ private handleTypedInput = (event: Event): void => {
329
+ if (!this.typedInput) return;
330
+
331
+ const target = event.target as HTMLInputElement;
332
+ if (target.tagName !== "INPUT") return;
333
+ if (!this.contains(target)) return;
334
+
335
+ this.inputValue = target.value;
336
+ this.inputError = null;
337
+
338
+ // Parse on each keystroke for real-time feedback
339
+ const result = parseTypedDate(target.value, this.locale);
340
+ if (result.valid && result.date) {
341
+ // Validate against min/max
342
+ const validation = validateTypedDate(result.date, this.minDate, this.maxDate, this.locale);
343
+ if (validation.valid) {
344
+ this.inputError = null;
345
+ } else {
346
+ this.inputError = validation.error;
347
+ }
348
+ }
349
+ };
350
+
351
+ /**
352
+ * Handles input blur to finalize typed input.
353
+ */
354
+ private handleInputBlur = (event: Event): void => {
355
+ if (!this.typedInput) return;
356
+
357
+ const target = event.target as HTMLInputElement;
358
+ if (target.tagName !== "INPUT") return;
359
+ if (!this.contains(target)) return;
360
+
361
+ this.commitTypedInput();
362
+ };
363
+
364
+ /**
365
+ * Commits the typed input value as the selected date.
366
+ */
367
+ private commitTypedInput(): void {
368
+ if (!this.inputValue) {
369
+ // Clear the date if input is empty
370
+ if (this.value) {
371
+ this.value = "";
372
+ this.inputError = null;
373
+ emitEvent(this, StandardEvents.CHANGE, { detail: { date: "" } });
374
+ }
375
+ return;
376
+ }
377
+
378
+ const result = parseTypedDate(this.inputValue, this.locale);
379
+ if (!result.valid || !result.date) {
380
+ this.inputError = result.error;
381
+ return;
382
+ }
383
+
384
+ // Validate against min/max
385
+ const validation = validateTypedDate(result.date, this.minDate, this.maxDate, this.locale);
386
+ if (!validation.valid) {
387
+ this.inputError = validation.error;
388
+ return;
389
+ }
390
+
391
+ // Commit the value
392
+ this.inputError = null;
393
+ this.value = result.date;
394
+ this.inputValue = formatTypedDate(result.date, this.locale);
395
+ emitEvent(this, StandardEvents.CHANGE, { detail: { date: result.date } });
396
+ }
397
+
398
+ /**
399
+ * Gets the expected input format placeholder.
400
+ */
401
+ public getFormatPlaceholder(): string {
402
+ return getDateFormatPlaceholder(this.locale);
403
+ }
404
+
405
+ /**
406
+ * Gets the current validation error.
407
+ */
408
+ public getValidationError(): string | null {
409
+ return this.inputError;
410
+ }
411
+
412
+ /**
413
+ * Parses a typed date string and returns the validation result.
414
+ */
415
+ public parseInput(input: string): DateParseResult {
416
+ const result = parseTypedDate(input, this.locale);
417
+ if (result.valid && result.date) {
418
+ return validateTypedDate(result.date, this.minDate, this.maxDate, this.locale);
419
+ }
420
+ return result;
421
+ }
422
+
423
+ private setupPositioning(): void {
424
+ const trigger = this.getTriggerElement();
425
+ const calendar = this.querySelector("ds-date-picker-calendar") as HTMLElement | null;
426
+
427
+ if (!trigger || !calendar) return;
428
+
429
+ this.anchorPosition = createAnchorPosition({
430
+ anchor: trigger,
431
+ floating: calendar,
432
+ placement: this.placement,
433
+ offset: this.offset,
434
+ flip: this.flip,
435
+ onPositionChange: (pos) => {
436
+ calendar.setAttribute("data-placement", pos.placement);
437
+ },
438
+ });
439
+
440
+ this.resizeObserver = new ResizeObserver(() => {
441
+ this.anchorPosition?.update();
442
+ });
443
+ this.resizeObserver.observe(trigger);
444
+ this.resizeObserver.observe(calendar);
445
+
446
+ this.scrollHandler = () => {
447
+ this.anchorPosition?.update();
448
+ };
449
+ window.addEventListener("scroll", this.scrollHandler, { passive: true });
450
+ window.addEventListener("resize", this.scrollHandler, { passive: true });
451
+ }
452
+
453
+ private setupDismissLayer(): void {
454
+ const calendar = this.querySelector("ds-date-picker-calendar") as HTMLElement | null;
455
+ const trigger = this.getTriggerElement();
456
+
457
+ if (!calendar) return;
458
+
459
+ this.dismissLayer = createDismissableLayer({
460
+ container: calendar,
461
+ excludeElements: trigger ? [trigger] : [],
462
+ onDismiss: this.handleDismiss,
463
+ closeOnEscape: true,
464
+ closeOnOutsideClick: true,
465
+ });
466
+ this.dismissLayer.activate();
467
+ }
468
+
469
+ private cleanup(): void {
470
+ this.anchorPosition?.destroy();
471
+ this.anchorPosition = null;
472
+
473
+ this.dismissLayer?.deactivate();
474
+ this.dismissLayer = null;
475
+
476
+ this.presence?.destroy();
477
+ this.presence = null;
478
+
479
+ this.resizeObserver?.disconnect();
480
+ this.resizeObserver = null;
481
+
482
+ if (this.scrollHandler) {
483
+ window.removeEventListener("scroll", this.scrollHandler);
484
+ window.removeEventListener("resize", this.scrollHandler);
485
+ this.scrollHandler = null;
486
+ }
487
+ }
488
+
489
+ override async updated(changedProperties: Map<string, unknown>): Promise<void> {
490
+ super.updated(changedProperties);
491
+
492
+ if (changedProperties.has("open")) {
493
+ const calendar = this.querySelector("ds-date-picker-calendar") as DsDatePickerCalendar | null;
494
+
495
+ if (this.open) {
496
+ // Update calendar props
497
+ if (calendar) {
498
+ calendar.removeAttribute("hidden");
499
+ calendar.dataState = "open";
500
+ calendar.range = this.mode === "range";
501
+ calendar.locale = this.locale;
502
+ calendar.firstDayOfWeek = this.firstDayOfWeek;
503
+ calendar.minDate = this.minDate;
504
+ calendar.maxDate = this.maxDate;
505
+ calendar.selectedDate = this.value;
506
+ calendar.rangeStart = this.rangeStart;
507
+ calendar.rangeEnd = this.rangeEnd;
508
+
509
+ // Set initial viewing month
510
+ const initialDate =
511
+ this.value || this.rangeStart || new Date().toISOString().split("T")[0];
512
+ if (initialDate) {
513
+ const date = new Date(initialDate);
514
+ calendar.viewingMonth = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
515
+ }
516
+ }
517
+
518
+ await this.updateComplete;
519
+
520
+ this.setupPositioning();
521
+ this.setupDismissLayer();
522
+
523
+ // Focus the calendar
524
+ calendar?.focus();
525
+ } else {
526
+ if (calendar) {
527
+ calendar.dataState = "closed";
528
+ calendar.setAttribute("hidden", "");
529
+ }
530
+ }
531
+ }
532
+
533
+ // Sync typed input value when value changes externally
534
+ if (changedProperties.has("value") && this.typedInput) {
535
+ // Only update inputValue if it wasn't set from typed input
536
+ const expectedInput = formatTypedDate(this.value, this.locale);
537
+ if (this.inputValue !== expectedInput) {
538
+ this.inputValue = expectedInput;
539
+ this.inputError = null;
540
+ }
541
+ }
542
+
543
+ // Sync props to calendar when open
544
+ if (this.open) {
545
+ const calendar = this.querySelector("ds-date-picker-calendar") as DsDatePickerCalendar | null;
546
+ if (calendar) {
547
+ if (changedProperties.has("value")) {
548
+ calendar.selectedDate = this.value;
549
+ }
550
+ if (changedProperties.has("rangeStart")) {
551
+ calendar.rangeStart = this.rangeStart;
552
+ }
553
+ if (changedProperties.has("rangeEnd")) {
554
+ calendar.rangeEnd = this.rangeEnd;
555
+ }
556
+ if (changedProperties.has("locale")) {
557
+ calendar.locale = this.locale;
558
+ }
559
+ if (changedProperties.has("firstDayOfWeek")) {
560
+ calendar.firstDayOfWeek = this.firstDayOfWeek;
561
+ }
562
+ if (changedProperties.has("minDate")) {
563
+ calendar.minDate = this.minDate;
564
+ }
565
+ if (changedProperties.has("maxDate")) {
566
+ calendar.maxDate = this.maxDate;
567
+ }
568
+ }
569
+ }
570
+
571
+ if (this.open && (changedProperties.has("placement") || changedProperties.has("offset"))) {
572
+ this.cleanup();
573
+ this.setupPositioning();
574
+ this.setupDismissLayer();
575
+ }
576
+ }
577
+
578
+ override render() {
579
+ return html`
580
+ <slot name="trigger"></slot>
581
+ <slot></slot>
582
+ `;
583
+ }
584
+ }
585
+
586
+ define("ds-date-picker", DsDatePicker);
587
+
588
+ declare global {
589
+ interface HTMLElementTagNameMap {
590
+ "ds-date-picker": DsDatePicker;
591
+ }
592
+ }