@webjsdev/ui 0.3.17 → 0.4.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 (358) hide show
  1. package/README.md +66 -7
  2. package/THIRD_PARTY_NOTICES.md +349 -0
  3. package/package.json +4 -2
  4. package/packages/registry/blocks/_shared/placeholder.svg +1 -0
  5. package/packages/registry/blocks/charts/chart-area-axes.ts +72 -0
  6. package/packages/registry/blocks/charts/chart-area-default.ts +64 -0
  7. package/packages/registry/blocks/charts/chart-area-gradient.ts +82 -0
  8. package/packages/registry/blocks/charts/chart-area-icons.ts +77 -0
  9. package/packages/registry/blocks/charts/chart-area-interactive.ts +204 -0
  10. package/packages/registry/blocks/charts/chart-area-legend.ts +72 -0
  11. package/packages/registry/blocks/charts/chart-area-linear.ts +64 -0
  12. package/packages/registry/blocks/charts/chart-area-stacked-expand.ts +77 -0
  13. package/packages/registry/blocks/charts/chart-area-stacked.ts +71 -0
  14. package/packages/registry/blocks/charts/chart-area-step.ts +68 -0
  15. package/packages/registry/blocks/charts/chart-bar-active.ts +93 -0
  16. package/packages/registry/blocks/charts/chart-bar-default.ts +60 -0
  17. package/packages/registry/blocks/charts/chart-bar-horizontal.ts +62 -0
  18. package/packages/registry/blocks/charts/chart-bar-interactive.ts +185 -0
  19. package/packages/registry/blocks/charts/chart-bar-label-custom.ts +78 -0
  20. package/packages/registry/blocks/charts/chart-bar-label.ts +66 -0
  21. package/packages/registry/blocks/charts/chart-bar-mixed.ts +87 -0
  22. package/packages/registry/blocks/charts/chart-bar-multiple.ts +67 -0
  23. package/packages/registry/blocks/charts/chart-bar-negative.ts +61 -0
  24. package/packages/registry/blocks/charts/chart-bar-stacked.ts +68 -0
  25. package/packages/registry/blocks/charts/chart-line-default.ts +61 -0
  26. package/packages/registry/blocks/charts/chart-line-dots-colors.ts +86 -0
  27. package/packages/registry/blocks/charts/chart-line-dots-custom.ts +75 -0
  28. package/packages/registry/blocks/charts/chart-line-dots.ts +65 -0
  29. package/packages/registry/blocks/charts/chart-line-interactive.ts +185 -0
  30. package/packages/registry/blocks/charts/chart-line-label-custom.ts +94 -0
  31. package/packages/registry/blocks/charts/chart-line-label.ts +73 -0
  32. package/packages/registry/blocks/charts/chart-line-linear.ts +61 -0
  33. package/packages/registry/blocks/charts/chart-line-multiple.ts +71 -0
  34. package/packages/registry/blocks/charts/chart-line-step.ts +61 -0
  35. package/packages/registry/blocks/charts/chart-pie-donut-active.ts +86 -0
  36. package/packages/registry/blocks/charts/chart-pie-donut-text.ts +89 -0
  37. package/packages/registry/blocks/charts/chart-pie-donut.ts +77 -0
  38. package/packages/registry/blocks/charts/chart-pie-interactive.ts +120 -0
  39. package/packages/registry/blocks/charts/chart-pie-label-custom.ts +82 -0
  40. package/packages/registry/blocks/charts/chart-pie-label-list.ts +86 -0
  41. package/packages/registry/blocks/charts/chart-pie-label.ts +77 -0
  42. package/packages/registry/blocks/charts/chart-pie-legend.ts +79 -0
  43. package/packages/registry/blocks/charts/chart-pie-separator-none.ts +77 -0
  44. package/packages/registry/blocks/charts/chart-pie-simple.ts +77 -0
  45. package/packages/registry/blocks/charts/chart-pie-stacked.ts +99 -0
  46. package/packages/registry/blocks/charts/chart-radar-default.ts +61 -0
  47. package/packages/registry/blocks/charts/chart-radar-dots.ts +61 -0
  48. package/packages/registry/blocks/charts/chart-radar-grid-circle-fill.ts +61 -0
  49. package/packages/registry/blocks/charts/chart-radar-grid-circle-no-lines.ts +61 -0
  50. package/packages/registry/blocks/charts/chart-radar-grid-circle.ts +61 -0
  51. package/packages/registry/blocks/charts/chart-radar-grid-custom.ts +61 -0
  52. package/packages/registry/blocks/charts/chart-radar-grid-fill.ts +61 -0
  53. package/packages/registry/blocks/charts/chart-radar-grid-none.ts +60 -0
  54. package/packages/registry/blocks/charts/chart-radar-icons.ts +76 -0
  55. package/packages/registry/blocks/charts/chart-radar-label-custom.ts +77 -0
  56. package/packages/registry/blocks/charts/chart-radar-legend.ts +70 -0
  57. package/packages/registry/blocks/charts/chart-radar-lines-only.ts +68 -0
  58. package/packages/registry/blocks/charts/chart-radar-multiple.ts +68 -0
  59. package/packages/registry/blocks/charts/chart-radar-radius.ts +68 -0
  60. package/packages/registry/blocks/charts/chart-radial-grid.ts +80 -0
  61. package/packages/registry/blocks/charts/chart-radial-label.ts +85 -0
  62. package/packages/registry/blocks/charts/chart-radial-shape.ts +81 -0
  63. package/packages/registry/blocks/charts/chart-radial-simple.ts +79 -0
  64. package/packages/registry/blocks/charts/chart-radial-stacked.ts +69 -0
  65. package/packages/registry/blocks/charts/chart-radial-text.ts +82 -0
  66. package/packages/registry/blocks/charts/chart-tooltip-advanced.ts +84 -0
  67. package/packages/registry/blocks/charts/chart-tooltip-default.ts +62 -0
  68. package/packages/registry/blocks/charts/chart-tooltip-formatter.ts +75 -0
  69. package/packages/registry/blocks/charts/chart-tooltip-icons.ts +68 -0
  70. package/packages/registry/blocks/charts/chart-tooltip-indicator-line.ts +62 -0
  71. package/packages/registry/blocks/charts/chart-tooltip-indicator-none.ts +62 -0
  72. package/packages/registry/blocks/charts/chart-tooltip-label-custom.ts +65 -0
  73. package/packages/registry/blocks/charts/chart-tooltip-label-formatter.ts +66 -0
  74. package/packages/registry/blocks/charts/chart-tooltip-label-none.ts +62 -0
  75. package/packages/registry/blocks/dashboard-01/components/app-sidebar.ts +108 -0
  76. package/packages/registry/blocks/dashboard-01/components/chart-area-interactive.ts +276 -0
  77. package/packages/registry/blocks/dashboard-01/components/dashboard-data.ts +89 -0
  78. package/packages/registry/blocks/dashboard-01/components/data-table.ts +637 -0
  79. package/packages/registry/blocks/dashboard-01/components/nav-documents.ts +65 -0
  80. package/packages/registry/blocks/dashboard-01/components/nav-main.ts +61 -0
  81. package/packages/registry/blocks/dashboard-01/components/nav-secondary.ts +40 -0
  82. package/packages/registry/blocks/dashboard-01/components/nav-user.ts +66 -0
  83. package/packages/registry/blocks/dashboard-01/components/section-cards.ts +59 -0
  84. package/packages/registry/blocks/dashboard-01/components/site-header.ts +52 -0
  85. package/packages/registry/blocks/dashboard-01/page.ts +39 -0
  86. package/packages/registry/blocks/login-01/components/login-form.ts +70 -0
  87. package/packages/registry/blocks/login-01/page.ts +19 -0
  88. package/packages/registry/blocks/login-02/components/login-form.ts +68 -0
  89. package/packages/registry/blocks/login-02/page.ts +36 -0
  90. package/packages/registry/blocks/login-03/components/login-form.ts +89 -0
  91. package/packages/registry/blocks/login-03/page.ts +28 -0
  92. package/packages/registry/blocks/login-04/components/login-form.ts +91 -0
  93. package/packages/registry/blocks/login-04/page.ts +20 -0
  94. package/packages/registry/blocks/login-05/components/login-form.ts +75 -0
  95. package/packages/registry/blocks/login-05/page.ts +19 -0
  96. package/packages/registry/blocks/preview/cards/activate-agent-dialog.ts +77 -0
  97. package/packages/registry/blocks/preview/cards/analytics-card.ts +64 -0
  98. package/packages/registry/blocks/preview/cards/anomaly-alert.ts +35 -0
  99. package/packages/registry/blocks/preview/cards/bar-chart-card.ts +91 -0
  100. package/packages/registry/blocks/preview/cards/book-appointment.ts +51 -0
  101. package/packages/registry/blocks/preview/cards/codespaces-card.ts +172 -0
  102. package/packages/registry/blocks/preview/cards/contributions-activity.ts +63 -0
  103. package/packages/registry/blocks/preview/cards/contributors.ts +51 -0
  104. package/packages/registry/blocks/preview/cards/environment-variables.ts +47 -0
  105. package/packages/registry/blocks/preview/cards/feedback-form.ts +61 -0
  106. package/packages/registry/blocks/preview/cards/file-upload.ts +51 -0
  107. package/packages/registry/blocks/preview/cards/github-profile.ts +66 -0
  108. package/packages/registry/blocks/preview/cards/icon-preview-grid.ts +47 -0
  109. package/packages/registry/blocks/preview/cards/invite-team.ts +78 -0
  110. package/packages/registry/blocks/preview/cards/invoice.ts +91 -0
  111. package/packages/registry/blocks/preview/cards/live-waveform.ts +330 -0
  112. package/packages/registry/blocks/preview/cards/no-team-members.ts +61 -0
  113. package/packages/registry/blocks/preview/cards/not-found.ts +46 -0
  114. package/packages/registry/blocks/preview/cards/observability-card.ts +44 -0
  115. package/packages/registry/blocks/preview/cards/pie-chart-card.ts +84 -0
  116. package/packages/registry/blocks/preview/cards/report-bug.ts +71 -0
  117. package/packages/registry/blocks/preview/cards/shipping-address.ts +79 -0
  118. package/packages/registry/blocks/preview/cards/shortcuts.ts +57 -0
  119. package/packages/registry/blocks/preview/cards/skeleton-loading.ts +37 -0
  120. package/packages/registry/blocks/preview/cards/sleep-report.ts +85 -0
  121. package/packages/registry/blocks/preview/cards/style-overview.ts +64 -0
  122. package/packages/registry/blocks/preview/cards/typography-specimen.ts +107 -0
  123. package/packages/registry/blocks/preview/cards/ui-elements.ts +164 -0
  124. package/packages/registry/blocks/preview/cards/usage-card.ts +63 -0
  125. package/packages/registry/blocks/preview/cards/visitors.ts +71 -0
  126. package/packages/registry/blocks/preview/cards/weekly-fitness-summary.ts +54 -0
  127. package/packages/registry/blocks/preview/page.ts +103 -0
  128. package/packages/registry/blocks/preview-02/cards/account-access.ts +70 -0
  129. package/packages/registry/blocks/preview-02/cards/card-overview.ts +75 -0
  130. package/packages/registry/blocks/preview-02/cards/claimable-balance.ts +54 -0
  131. package/packages/registry/blocks/preview-02/cards/contribution-history.ts +80 -0
  132. package/packages/registry/blocks/preview-02/cards/cover-art.ts +41 -0
  133. package/packages/registry/blocks/preview-02/cards/dividend-income.ts +76 -0
  134. package/packages/registry/blocks/preview-02/cards/empty-connect-bank.ts +38 -0
  135. package/packages/registry/blocks/preview-02/cards/empty-distribute-track.ts +38 -0
  136. package/packages/registry/blocks/preview-02/cards/empty-explore-catalog.ts +39 -0
  137. package/packages/registry/blocks/preview-02/cards/faq.ts +79 -0
  138. package/packages/registry/blocks/preview-02/cards/front-door.ts +40 -0
  139. package/packages/registry/blocks/preview-02/cards/index-investing.ts +31 -0
  140. package/packages/registry/blocks/preview-02/cards/kitchen-island.ts +90 -0
  141. package/packages/registry/blocks/preview-02/cards/loading-card.ts +34 -0
  142. package/packages/registry/blocks/preview-02/cards/new-milestone.ts +53 -0
  143. package/packages/registry/blocks/preview-02/cards/notification-settings.ts +126 -0
  144. package/packages/registry/blocks/preview-02/cards/payments.ts +88 -0
  145. package/packages/registry/blocks/preview-02/cards/payout-threshold.ts +92 -0
  146. package/packages/registry/blocks/preview-02/cards/power-usage.ts +84 -0
  147. package/packages/registry/blocks/preview-02/cards/preferences.ts +89 -0
  148. package/packages/registry/blocks/preview-02/cards/qr-connect.ts +54 -0
  149. package/packages/registry/blocks/preview-02/cards/receiving-method.ts +89 -0
  150. package/packages/registry/blocks/preview-02/cards/recent-transactions.ts +101 -0
  151. package/packages/registry/blocks/preview-02/cards/release-catalog.ts +73 -0
  152. package/packages/registry/blocks/preview-02/cards/roller-shades.ts +110 -0
  153. package/packages/registry/blocks/preview-02/cards/savings-progress.ts +68 -0
  154. package/packages/registry/blocks/preview-02/cards/savings-targets.ts +132 -0
  155. package/packages/registry/blocks/preview-02/cards/sidebar-nav.ts +88 -0
  156. package/packages/registry/blocks/preview-02/cards/social-links.ts +57 -0
  157. package/packages/registry/blocks/preview-02/cards/stock-performance.ts +106 -0
  158. package/packages/registry/blocks/preview-02/cards/syncing-state.ts +37 -0
  159. package/packages/registry/blocks/preview-02/cards/transfer-funds.ts +111 -0
  160. package/packages/registry/blocks/preview-02/cards/upcoming-payments.ts +69 -0
  161. package/packages/registry/blocks/preview-02/page.ts +111 -0
  162. package/packages/registry/blocks/preview-03/cards/files-chat.ts +75 -0
  163. package/packages/registry/blocks/preview-03/cards/group-chat.ts +114 -0
  164. package/packages/registry/blocks/preview-03/cards/reasoning-chat.ts +88 -0
  165. package/packages/registry/blocks/preview-03/cards/simple-chat.ts +53 -0
  166. package/packages/registry/blocks/preview-03/components/chat-card.ts +126 -0
  167. package/packages/registry/blocks/preview-03/components/chat-player.ts +174 -0
  168. package/packages/registry/blocks/preview-03/components/part-file.ts +77 -0
  169. package/packages/registry/blocks/preview-03/components/part-reasoning.ts +25 -0
  170. package/packages/registry/blocks/preview-03/components/part-source.ts +48 -0
  171. package/packages/registry/blocks/preview-03/components/part-text.ts +69 -0
  172. package/packages/registry/blocks/preview-03/components/part-tool.ts +71 -0
  173. package/packages/registry/blocks/preview-03/components/prompt-input.ts +86 -0
  174. package/packages/registry/blocks/preview-03/page.ts +39 -0
  175. package/packages/registry/blocks/sidebar-01/components/app-sidebar.ts +113 -0
  176. package/packages/registry/blocks/sidebar-01/components/search-form.ts +33 -0
  177. package/packages/registry/blocks/sidebar-01/components/version-switcher.ts +50 -0
  178. package/packages/registry/blocks/sidebar-01/page.ts +58 -0
  179. package/packages/registry/blocks/sidebar-02/components/app-sidebar.ts +131 -0
  180. package/packages/registry/blocks/sidebar-02/components/search-form.ts +33 -0
  181. package/packages/registry/blocks/sidebar-02/components/version-switcher.ts +50 -0
  182. package/packages/registry/blocks/sidebar-02/page.ts +53 -0
  183. package/packages/registry/blocks/sidebar-03/components/app-sidebar.ts +134 -0
  184. package/packages/registry/blocks/sidebar-03/page.ts +60 -0
  185. package/packages/registry/blocks/sidebar-04/components/app-sidebar.ts +136 -0
  186. package/packages/registry/blocks/sidebar-04/page.ts +58 -0
  187. package/packages/registry/blocks/sidebar-05/components/app-sidebar.ts +147 -0
  188. package/packages/registry/blocks/sidebar-05/components/search-form.ts +33 -0
  189. package/packages/registry/blocks/sidebar-05/page.ts +58 -0
  190. package/packages/registry/blocks/sidebar-06/components/app-sidebar.ts +105 -0
  191. package/packages/registry/blocks/sidebar-06/components/nav-main.ts +56 -0
  192. package/packages/registry/blocks/sidebar-06/components/sidebar-opt-in-form.ts +44 -0
  193. package/packages/registry/blocks/sidebar-06/page.ts +57 -0
  194. package/packages/registry/blocks/sidebar-07/components/app-sidebar.ts +108 -0
  195. package/packages/registry/blocks/sidebar-07/components/nav-main.ts +61 -0
  196. package/packages/registry/blocks/sidebar-07/components/nav-projects.ts +65 -0
  197. package/packages/registry/blocks/sidebar-07/components/nav-user.ts +70 -0
  198. package/packages/registry/blocks/sidebar-07/components/team-switcher.ts +66 -0
  199. package/packages/registry/blocks/sidebar-07/page.ts +59 -0
  200. package/packages/registry/blocks/sidebar-08/components/app-sidebar.ts +122 -0
  201. package/packages/registry/blocks/sidebar-08/components/nav-main.ts +68 -0
  202. package/packages/registry/blocks/sidebar-08/components/nav-projects.ts +65 -0
  203. package/packages/registry/blocks/sidebar-08/components/nav-secondary.ts +40 -0
  204. package/packages/registry/blocks/sidebar-08/components/nav-user.ts +70 -0
  205. package/packages/registry/blocks/sidebar-08/page.ts +59 -0
  206. package/packages/registry/blocks/sidebar-09/components/app-sidebar.ts +213 -0
  207. package/packages/registry/blocks/sidebar-09/components/nav-user.ts +70 -0
  208. package/packages/registry/blocks/sidebar-09/page.ts +52 -0
  209. package/packages/registry/blocks/sidebar-10/components/app-sidebar.ts +125 -0
  210. package/packages/registry/blocks/sidebar-10/components/nav-actions.ts +84 -0
  211. package/packages/registry/blocks/sidebar-10/components/nav-favorites.ts +66 -0
  212. package/packages/registry/blocks/sidebar-10/components/nav-main.ts +37 -0
  213. package/packages/registry/blocks/sidebar-10/components/nav-secondary.ts +43 -0
  214. package/packages/registry/blocks/sidebar-10/components/nav-workspaces.ts +78 -0
  215. package/packages/registry/blocks/sidebar-10/components/team-switcher.ts +63 -0
  216. package/packages/registry/blocks/sidebar-10/page.ts +46 -0
  217. package/packages/registry/blocks/sidebar-11/components/app-sidebar.ts +114 -0
  218. package/packages/registry/blocks/sidebar-11/page.ts +63 -0
  219. package/packages/registry/blocks/sidebar-12/components/app-sidebar.ts +63 -0
  220. package/packages/registry/blocks/sidebar-12/components/calendars.ts +53 -0
  221. package/packages/registry/blocks/sidebar-12/components/date-picker.ts +26 -0
  222. package/packages/registry/blocks/sidebar-12/components/nav-user.ts +70 -0
  223. package/packages/registry/blocks/sidebar-12/page.ts +43 -0
  224. package/packages/registry/blocks/sidebar-13/components/settings-dialog.ts +114 -0
  225. package/packages/registry/blocks/sidebar-13/page.ts +21 -0
  226. package/packages/registry/blocks/sidebar-14/components/app-sidebar.ts +120 -0
  227. package/packages/registry/blocks/sidebar-14/page.ts +55 -0
  228. package/packages/registry/blocks/sidebar-15/components/calendars.ts +53 -0
  229. package/packages/registry/blocks/sidebar-15/components/date-picker.ts +26 -0
  230. package/packages/registry/blocks/sidebar-15/components/nav-favorites.ts +66 -0
  231. package/packages/registry/blocks/sidebar-15/components/nav-main.ts +35 -0
  232. package/packages/registry/blocks/sidebar-15/components/nav-secondary.ts +43 -0
  233. package/packages/registry/blocks/sidebar-15/components/nav-user.ts +70 -0
  234. package/packages/registry/blocks/sidebar-15/components/nav-workspaces.ts +75 -0
  235. package/packages/registry/blocks/sidebar-15/components/sidebar-left.ts +126 -0
  236. package/packages/registry/blocks/sidebar-15/components/sidebar-right.ts +62 -0
  237. package/packages/registry/blocks/sidebar-15/components/team-switcher.ts +63 -0
  238. package/packages/registry/blocks/sidebar-15/page.ts +47 -0
  239. package/packages/registry/blocks/sidebar-16/components/app-sidebar.ts +124 -0
  240. package/packages/registry/blocks/sidebar-16/components/nav-main.ts +67 -0
  241. package/packages/registry/blocks/sidebar-16/components/nav-projects.ts +65 -0
  242. package/packages/registry/blocks/sidebar-16/components/nav-secondary.ts +40 -0
  243. package/packages/registry/blocks/sidebar-16/components/nav-user.ts +70 -0
  244. package/packages/registry/blocks/sidebar-16/components/search-form.ts +27 -0
  245. package/packages/registry/blocks/sidebar-16/components/site-header.ts +42 -0
  246. package/packages/registry/blocks/sidebar-16/page.ts +38 -0
  247. package/packages/registry/blocks/signup-01/components/signup-form.ts +78 -0
  248. package/packages/registry/blocks/signup-01/page.ts +19 -0
  249. package/packages/registry/blocks/signup-02/components/signup-form.ts +78 -0
  250. package/packages/registry/blocks/signup-02/page.ts +36 -0
  251. package/packages/registry/blocks/signup-03/components/signup-form.ts +79 -0
  252. package/packages/registry/blocks/signup-03/page.ts +28 -0
  253. package/packages/registry/blocks/signup-04/components/signup-form.ts +100 -0
  254. package/packages/registry/blocks/signup-04/page.ts +20 -0
  255. package/packages/registry/blocks/signup-05/components/signup-form.ts +75 -0
  256. package/packages/registry/blocks/signup-05/page.ts +20 -0
  257. package/packages/registry/components/accordion.ts +20 -7
  258. package/packages/registry/components/alert-dialog.ts +58 -13
  259. package/packages/registry/components/alert.ts +11 -6
  260. package/packages/registry/components/attachment.ts +119 -0
  261. package/packages/registry/components/avatar.ts +17 -8
  262. package/packages/registry/components/badge.ts +16 -9
  263. package/packages/registry/components/breadcrumb.ts +6 -6
  264. package/packages/registry/components/bubble.ts +95 -0
  265. package/packages/registry/components/button-group.ts +73 -0
  266. package/packages/registry/components/button.ts +35 -25
  267. package/packages/registry/components/calendar.ts +566 -0
  268. package/packages/registry/components/card.ts +8 -8
  269. package/packages/registry/components/carousel.ts +352 -0
  270. package/packages/registry/components/chart-element.ts +547 -0
  271. package/packages/registry/components/chart-geometry.ts +457 -0
  272. package/packages/registry/components/chart.ts +932 -0
  273. package/packages/registry/components/checkbox.ts +22 -84
  274. package/packages/registry/components/code-block.ts +191 -0
  275. package/packages/registry/components/collapsible.ts +5 -2
  276. package/packages/registry/components/combobox.ts +802 -0
  277. package/packages/registry/components/command.ts +618 -0
  278. package/packages/registry/components/context-menu.ts +302 -0
  279. package/packages/registry/components/dialog.ts +156 -45
  280. package/packages/registry/components/direction.ts +43 -0
  281. package/packages/registry/components/drawer.ts +226 -0
  282. package/packages/registry/components/dropdown-menu.ts +262 -83
  283. package/packages/registry/components/empty.ts +8 -8
  284. package/packages/registry/components/field.ts +20 -18
  285. package/packages/registry/components/floating.ts +124 -0
  286. package/packages/registry/components/hover-card.ts +19 -8
  287. package/packages/registry/components/input-group.ts +118 -0
  288. package/packages/registry/components/input-otp.ts +365 -0
  289. package/packages/registry/components/input.ts +3 -3
  290. package/packages/registry/components/item.ts +134 -0
  291. package/packages/registry/components/kbd.ts +2 -2
  292. package/packages/registry/components/label.ts +1 -1
  293. package/packages/registry/components/marker.ts +63 -0
  294. package/packages/registry/components/menubar.ts +388 -0
  295. package/packages/registry/components/message-scroller.ts +470 -0
  296. package/packages/registry/components/message.ts +69 -0
  297. package/packages/registry/components/native-select.ts +5 -5
  298. package/packages/registry/components/navigation-menu.ts +564 -0
  299. package/packages/registry/components/pagination.ts +5 -5
  300. package/packages/registry/components/popover.ts +30 -84
  301. package/packages/registry/components/progress.ts +7 -3
  302. package/packages/registry/components/questionnaire.ts +840 -0
  303. package/packages/registry/components/radio-group.ts +18 -73
  304. package/packages/registry/components/resizable.ts +330 -0
  305. package/packages/registry/components/scroll-area.ts +46 -0
  306. package/packages/registry/components/select.ts +650 -0
  307. package/packages/registry/components/separator.ts +1 -1
  308. package/packages/registry/components/sheet.ts +128 -0
  309. package/packages/registry/components/sidebar.ts +457 -0
  310. package/packages/registry/components/skeleton.ts +1 -1
  311. package/packages/registry/components/slider.ts +333 -0
  312. package/packages/registry/components/sonner.ts +74 -7
  313. package/packages/registry/components/spinner.ts +7 -4
  314. package/packages/registry/components/switch.ts +117 -9
  315. package/packages/registry/components/table.ts +11 -9
  316. package/packages/registry/components/tabs.ts +76 -25
  317. package/packages/registry/components/textarea.ts +1 -1
  318. package/packages/registry/components/toggle-group.ts +30 -11
  319. package/packages/registry/components/toggle.ts +20 -13
  320. package/packages/registry/components/tooltip.ts +68 -7
  321. package/packages/registry/components/trace.ts +75 -0
  322. package/packages/registry/lib/icons-hugeicons.ts +955 -0
  323. package/packages/registry/lib/icons-phosphor.ts +955 -0
  324. package/packages/registry/lib/icons-remixicon.ts +955 -0
  325. package/packages/registry/lib/icons-tabler.ts +955 -0
  326. package/packages/registry/lib/icons.ts +768 -0
  327. package/packages/registry/lib/utils.ts +49 -4
  328. package/packages/registry/registry.json +4056 -72
  329. package/packages/registry/styles/shadcn-tailwind.css +654 -0
  330. package/packages/registry/styles/style-luma.css +1987 -0
  331. package/packages/registry/styles/style-lyra.css +1965 -0
  332. package/packages/registry/styles/style-maia.css +1987 -0
  333. package/packages/registry/styles/style-mira.css +1992 -0
  334. package/packages/registry/styles/style-new-york.css +1597 -0
  335. package/packages/registry/styles/style-nova.css +1990 -0
  336. package/packages/registry/styles/style-rhea.css +1987 -0
  337. package/packages/registry/styles/style-sera.css +1977 -0
  338. package/packages/registry/styles/style-vega.css +1990 -0
  339. package/packages/registry/styles/supplement.json +54 -0
  340. package/packages/registry/styles/tw-animate.css +6 -0
  341. package/packages/registry/themes/base-colors.js +8 -2
  342. package/packages/registry/themes/fonts.js +120 -0
  343. package/packages/registry/themes/index.css +2 -0
  344. package/packages/registry/themes/items.js +61 -0
  345. package/packages/registry/themes/preset.js +302 -0
  346. package/packages/registry/themes/themes.js +1193 -0
  347. package/src/commands/add.js +236 -12
  348. package/src/commands/diff.js +34 -20
  349. package/src/commands/info.js +7 -0
  350. package/src/commands/init.js +125 -8
  351. package/src/commands/list.js +43 -11
  352. package/src/commands/view.js +33 -5
  353. package/src/registry/extract.js +192 -2
  354. package/src/registry/icons.js +31 -0
  355. package/src/registry/local.js +15 -1
  356. package/src/registry/schema.js +13 -0
  357. package/src/registry/style-bake.js +506 -0
  358. package/src/utils/theme.js +110 -21
@@ -31,37 +31,38 @@
31
31
  */
32
32
  import { cn } from '../lib/utils.ts';
33
33
 
34
- // cursor-pointer is on the BASE so every variant (default, outline,
35
- // ghost, link, …) gets the right hover affordance. Native <button>
36
- // defaults to the OS arrow cursor in Chromium and Firefox: fine for
37
- // native chrome but unusual for app buttons; shadcn's modern Button
38
- // has long since gravitated toward an explicit cursor-pointer in the
39
- // real world (see the open issue shadcn-ui/ui#1791). disabled:pointer-
40
- // events-none below already suppresses cursor on disabled buttons by
41
- // virtue of the element not receiving pointer events at all.
34
+ // Base form (#1666): the semantic `cn-button*` names carry the look, and
35
+ // the style named in components.json supplies it when the file is installed
36
+ // (styles/style-<name>.css, baked by `add`). What stays inline is the layout
37
+ // shadcn's base form keeps inline in every style.
38
+ //
39
+ // The default new-york style puts cursor-pointer on `cn-button`, so every
40
+ // variant gets the right hover affordance. Native <button> defaults to the OS
41
+ // arrow cursor in Chromium and Firefox, and shadcn's modern Button has
42
+ // gravitated toward an explicit cursor-pointer in the real world (see the open
43
+ // issue shadcn-ui/ui#1791). disabled:pointer-events-none below already
44
+ // suppresses the cursor on a disabled button.
42
45
  const BASE =
43
- "inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
46
+ 'cn-button group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0';
44
47
 
45
48
  const VARIANTS = {
46
- default: 'bg-primary text-primary-foreground hover:bg-primary/90',
47
- destructive:
48
- 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40',
49
- outline:
50
- 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',
51
- secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
52
- ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
53
- link: 'text-primary underline-offset-4 hover:underline',
49
+ default: 'cn-button-variant-default',
50
+ destructive: 'cn-button-variant-destructive',
51
+ outline: 'cn-button-variant-outline',
52
+ secondary: 'cn-button-variant-secondary',
53
+ ghost: 'cn-button-variant-ghost',
54
+ link: 'cn-button-variant-link',
54
55
  } as const;
55
56
 
56
57
  const SIZES = {
57
- default: 'h-9 px-4 py-2 has-[>svg]:px-3',
58
- xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
59
- sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5',
60
- lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
61
- icon: 'size-9',
62
- 'icon-xs': "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
63
- 'icon-sm': 'size-8',
64
- 'icon-lg': 'size-10',
58
+ default: 'cn-button-size-default',
59
+ xs: 'cn-button-size-xs',
60
+ sm: 'cn-button-size-sm',
61
+ lg: 'cn-button-size-lg',
62
+ icon: 'cn-button-size-icon',
63
+ 'icon-xs': 'cn-button-size-icon-xs',
64
+ 'icon-sm': 'cn-button-size-icon-sm',
65
+ 'icon-lg': 'cn-button-size-icon-lg',
65
66
  } as const;
66
67
 
67
68
  export type ButtonVariant = keyof typeof VARIANTS;
@@ -78,3 +79,12 @@ export function buttonClass(opts: ButtonClassOptions = {}): string {
78
79
  const size = opts.size ?? 'default';
79
80
  return cn(BASE, VARIANTS[variant], SIZES[size]);
80
81
  }
82
+
83
+ /**
84
+ * shadcn's name for {@link buttonClass}, so shadcn code ports verbatim
85
+ * (`buttonVariants({ ... })` is shadcn's `cva` export for `Button`). Like cva, it
86
+ * merges a `className` into the result.
87
+ */
88
+ export function buttonVariants(opts: ButtonClassOptions & { className?: string } = {}): string {
89
+ return cn(buttonClass(opts), opts.className);
90
+ }
@@ -0,0 +1,566 @@
1
+ /**
2
+ * Calendar: a month grid for picking a date, several dates, or a range.
3
+ * Tier-2. shadcn's is react-day-picker; this is the same grid hand-rolled on
4
+ * `Intl.DateTimeFormat`, with no dependency. The server renders the month, so
5
+ * the grid is in the first paint; picking needs JavaScript.
6
+ *
7
+ * shadcn parity:
8
+ * Calendar mode="single" | "multiple" | "range"
9
+ * → <ui-calendar mode value>
10
+ * selected → `value`: "2025-06-12"; for multiple a comma list;
11
+ * for range "2025-06-12/2025-06-20"
12
+ * month / defaultMonth → `month`: "2025-06" (the first month shown)
13
+ * numberOfMonths → `number-of-months`
14
+ * showOutsideDays → `show-outside-days="false"` hides them (shown by default)
15
+ * weekStartsOn → `week-starts-on` (0 is Sunday, the default)
16
+ * showWeekNumber → `show-week-number` (a leading column of week numbers)
17
+ * ISOWeek → `iso-week` (ISO 8601 weeks: Monday first, ISO numbers)
18
+ * captionLayout="dropdown" → `caption-layout="dropdown"` (month and year selects)
19
+ * disabled / startMonth / endMonth
20
+ * → `min` / `max` ("2025-01-01"), and `disabled` for the whole grid
21
+ * locale → `locale` (a BCP 47 tag), else the page's `lang`
22
+ * onSelect → `ui-value-change` ({ detail: { value } }): a date string, a
23
+ * string array, or { from, to } for a range
24
+ * onMonthChange → `ui-month-change` ({ detail: { month } })
25
+ *
26
+ * With `name`, the value also rides hidden inputs, so a form submits it: one
27
+ * input for a single date, one per date for multiple, and `name[from]` /
28
+ * `name[to]` for a range.
29
+ *
30
+ * Keyboard (the WAI-ARIA date grid): one day is in the tab order. The arrows
31
+ * move a day or a week (left and right swap under `dir="rtl"`), Home / End go
32
+ * to the week's ends, PageUp / PageDown change the month and with Shift the
33
+ * year, and Enter or Space picks. Moving past the shown months turns the page.
34
+ *
35
+ * A11y (handled by the element): each month is a `role="grid"` labelled by its
36
+ * caption, every day button is named by its full date (and says "Today" and
37
+ * "selected"), days outside `min` / `max` are disabled, and the previous and
38
+ * next buttons are named.
39
+ *
40
+ * @example
41
+ * ```html
42
+ * <ui-calendar mode="single" value="2025-06-12" class="rounded-lg border"></ui-calendar>
43
+ *
44
+ * <ui-calendar mode="range" value="2025-06-12/2025-06-20" number-of-months="2" name="stay"></ui-calendar>
45
+ * ```
46
+ */
47
+ import { WebComponent, html, prop, signal, nothing } from '@webjsdev/core';
48
+ import { cn } from '../lib/utils.ts';
49
+ import { buttonClass } from './button.ts';
50
+
51
+ // --------------------------------------------------------------------------
52
+ // Date maths, all on UTC calendar dates written as YYYY-MM-DD, so a timezone
53
+ // can never move a day.
54
+ // --------------------------------------------------------------------------
55
+
56
+ /** A date-only value: the calendar's unit. */
57
+ export type CalendarDate = { y: number; m: number; d: number };
58
+
59
+ /** Parse "YYYY-MM-DD" (or "YYYY-MM", day 1); null when it is not a date. */
60
+ export function parseDate(s: string | null | undefined): CalendarDate | null {
61
+ const m = /^(\d{4})-(\d{2})(?:-(\d{2}))?$/.exec((s ?? '').trim());
62
+ if (!m) return null;
63
+ const y = Number(m[1]);
64
+ const mo = Number(m[2]) - 1;
65
+ const d = m[3] ? Number(m[3]) : 1;
66
+ const t = new Date(Date.UTC(y, mo, d));
67
+ if (t.getUTCFullYear() !== y || t.getUTCMonth() !== mo || t.getUTCDate() !== d) return null;
68
+ return { y, m: mo, d };
69
+ }
70
+
71
+ /** Format as "YYYY-MM-DD". */
72
+ export function formatDate(c: CalendarDate): string {
73
+ return `${String(c.y).padStart(4, '0')}-${String(c.m + 1).padStart(2, '0')}-${String(c.d).padStart(2, '0')}`;
74
+ }
75
+
76
+ function toUTC(c: CalendarDate): Date {
77
+ return new Date(Date.UTC(c.y, c.m, c.d));
78
+ }
79
+
80
+ function fromUTC(t: Date): CalendarDate {
81
+ return { y: t.getUTCFullYear(), m: t.getUTCMonth(), d: t.getUTCDate() };
82
+ }
83
+
84
+ /** `c` moved by `days`. */
85
+ export function addDays(c: CalendarDate, days: number): CalendarDate {
86
+ const t = toUTC(c);
87
+ t.setUTCDate(t.getUTCDate() + days);
88
+ return fromUTC(t);
89
+ }
90
+
91
+ /** `c` moved by `months`, clamped to the last day of the target month. */
92
+ export function addMonths(c: CalendarDate, months: number): CalendarDate {
93
+ const first = new Date(Date.UTC(c.y, c.m + months, 1));
94
+ const last = new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth() + 1, 0)).getUTCDate();
95
+ return { y: first.getUTCFullYear(), m: first.getUTCMonth(), d: Math.min(c.d, last) };
96
+ }
97
+
98
+ /** -1, 0 or 1. */
99
+ export function compareDates(a: CalendarDate, b: CalendarDate): number {
100
+ return a.y - b.y || a.m - b.m || a.d - b.d;
101
+ }
102
+
103
+ /** Whether `a` and `b` are the same day. */
104
+ export function sameDay(a: CalendarDate | null, b: CalendarDate | null): boolean {
105
+ return !!a && !!b && compareDates(a, b) === 0;
106
+ }
107
+
108
+ /**
109
+ * The weeks of a month as rows of seven days, starting on `weekStartsOn`
110
+ * (0 Sunday). Days of the neighbouring months fill the first and last rows;
111
+ * there are only as many rows as the month needs.
112
+ */
113
+ export function monthWeeks(y: number, m: number, weekStartsOn = 0): CalendarDate[][] {
114
+ const first = { y, m, d: 1 };
115
+ const lead = (toUTC(first).getUTCDay() - weekStartsOn + 7) % 7;
116
+ const daysIn = new Date(Date.UTC(y, m + 1, 0)).getUTCDate();
117
+ const total = Math.ceil((lead + daysIn) / 7) * 7;
118
+ const start = addDays(first, -lead);
119
+ const weeks: CalendarDate[][] = [];
120
+ for (let i = 0; i < total; i += 7) {
121
+ weeks.push(Array.from({ length: 7 }, (_, j) => addDays(start, i + j)));
122
+ }
123
+ return weeks;
124
+ }
125
+
126
+ /**
127
+ * The number of the week `date` falls in, as the calendar labels a row, the
128
+ * way react-day-picker numbers it. By default week 1 is the week holding
129
+ * January 1, with weeks counted from `weekStartsOn` (date-fns getWeek, with
130
+ * the en-US first week). With `iso` the week is ISO 8601's: weeks start on
131
+ * Monday and week 1 holds the year's first Thursday (date-fns getISOWeek),
132
+ * whatever `weekStartsOn` says.
133
+ */
134
+ export function weekNumber(date: CalendarDate, weekStartsOn = 0, iso = false): number {
135
+ const DAY = 86400000;
136
+ const start = iso ? 1 : weekStartsOn;
137
+ // The day of January that week 1 must contain.
138
+ const anchor = iso ? 4 : 1;
139
+ const startOfWeek = (ms: number): number => ms - ((new Date(ms).getUTCDay() - start + 7) % 7) * DAY;
140
+ const at = Date.UTC(date.y, date.m, date.d);
141
+ const firstOf = (y: number): number => startOfWeek(Date.UTC(y, 0, anchor));
142
+ const year = at >= firstOf(date.y + 1) ? date.y + 1 : at >= firstOf(date.y) ? date.y : date.y - 1;
143
+ return Math.round((startOfWeek(at) - firstOf(year)) / (7 * DAY)) + 1;
144
+ }
145
+
146
+ /** A range in progress or complete. */
147
+ export type CalendarRange = { from: CalendarDate | null; to: CalendarDate | null };
148
+
149
+ /**
150
+ * The range after picking `day`: the first pick starts it, the second ends
151
+ * it (swapping if it lies before the start), and a pick on a complete range
152
+ * starts a new one.
153
+ */
154
+ export function addToRange(range: CalendarRange, day: CalendarDate): CalendarRange {
155
+ const { from, to } = range;
156
+ if (!from || (from && to)) return { from: day, to: null };
157
+ if (compareDates(day, from) < 0) return { from: day, to: from };
158
+ return { from, to: day };
159
+ }
160
+
161
+ // --------------------------------------------------------------------------
162
+ // Classes
163
+ // --------------------------------------------------------------------------
164
+
165
+ /** The root's classes (the element applies them). */
166
+ export function calendarClass(): string {
167
+ return 'cn-calendar group/calendar bg-background in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent rtl:**:[.rdp-button-next>svg]:rotate-180 rtl:**:[.rdp-button-previous>svg]:rotate-180';
168
+ }
169
+ /** A month caption's label. */
170
+ export const calendarCaptionClass = (): string => 'cn-calendar-caption text-sm';
171
+ // shadcn names the dropdown caption's box and label `cn-calendar-dropdown-root`
172
+ // and `cn-calendar-caption-label`, but its build bakes only the first name of
173
+ // each component file, so `shadcn add` leaves both unstyled in every style and
174
+ // ui.shadcn.com draws neither a border nor a padded label. The kit gives them
175
+ // names only new-york maps, which keeps new-york's bordered dropdowns and
176
+ // matches shadcn's output in the other styles.
177
+ /** A dropdown caption's visible label. */
178
+ export const calendarCaptionLabelClass = (): string =>
179
+ 'cn-calendar-dropdown-label flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground';
180
+ /** A caption dropdown's box. */
181
+ export const calendarDropdownRootClass = (): string => 'cn-calendar-dropdown-box relative rounded-(--cell-radius)';
182
+ /** A day button's classes (the element applies them). */
183
+ export const calendarDayButtonClass = (): string =>
184
+ 'cn-calendar-day-button relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-e-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-s-(--cell-radius) data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70';
185
+
186
+ const NAV_BUTTON = 'size-(--cell-size) p-0 select-none aria-disabled:opacity-50';
187
+
188
+ // --------------------------------------------------------------------------
189
+ // <ui-calendar>
190
+ // --------------------------------------------------------------------------
191
+
192
+ let uid = 0;
193
+
194
+ export class UiCalendar extends WebComponent({
195
+ mode: prop<'single' | 'multiple' | 'range'>(String),
196
+ value: String,
197
+ name: String,
198
+ month: String,
199
+ numberOfMonths: prop(Number, { attribute: 'number-of-months' }),
200
+ showOutsideDays: prop(String, { attribute: 'show-outside-days' }),
201
+ weekStartsOn: prop(Number, { attribute: 'week-starts-on' }),
202
+ showWeekNumber: prop(Boolean, { attribute: 'show-week-number' }),
203
+ isoWeek: prop(Boolean, { attribute: 'iso-week' }),
204
+ captionLayout: prop<'label' | 'dropdown'>(String, { attribute: 'caption-layout' }),
205
+ min: String,
206
+ max: String,
207
+ disabled: Boolean,
208
+ locale: String,
209
+ }) {
210
+ // The live state: what is chosen, which month is shown, which day has focus.
211
+ readonly #selection = signal<{ days: string[]; from: string; to: string }>({ days: [], from: '', to: '' });
212
+ readonly #shown = signal('');
213
+ readonly #focused = signal('');
214
+ _id = '';
215
+ _parsed = false;
216
+
217
+ constructor() {
218
+ super();
219
+ this.mode = 'single';
220
+ this.value = '';
221
+ this.name = '';
222
+ this.month = '';
223
+ this.numberOfMonths = 1;
224
+ this.showOutsideDays = 'true';
225
+ this.weekStartsOn = 0;
226
+ this.showWeekNumber = false;
227
+ this.isoWeek = false;
228
+ this.captionLayout = 'label';
229
+ this.min = '';
230
+ this.max = '';
231
+ this.disabled = false;
232
+ this.locale = '';
233
+ }
234
+
235
+ connectedCallback(): void {
236
+ super.connectedCallback?.();
237
+ this._id ||= `ui-calendar-${++uid}`;
238
+ }
239
+
240
+ // Read the attributes into state once, on the first render (server or client).
241
+ willUpdate(changedProperties: Map<string, unknown>): void {
242
+ super.willUpdate?.(changedProperties);
243
+ if (this._parsed) return;
244
+ this._parsed = true;
245
+ const v = this.value ?? '';
246
+ if (this.mode === 'range') {
247
+ const [a, b] = v.split('/');
248
+ const from = parseDate(a);
249
+ const to = parseDate(b);
250
+ this.#selection.set({ days: [], from: from ? formatDate(from) : '', to: to ? formatDate(to) : '' });
251
+ } else {
252
+ const days = (this.mode === 'multiple' ? v.split(',') : [v]).map(parseDate).filter((d): d is CalendarDate => !!d).map(formatDate);
253
+ this.#selection.set({ days, from: '', to: '' });
254
+ }
255
+ const picked = this.#selection.get();
256
+ const anchor = parseDate(this.month) ?? parseDate(picked.from || picked.days[0]) ?? this._today();
257
+ this.#shown.set(formatDate({ y: anchor.y, m: anchor.m, d: 1 }));
258
+ }
259
+
260
+ _today(): CalendarDate {
261
+ const n = new Date();
262
+ return { y: n.getFullYear(), m: n.getMonth(), d: n.getDate() };
263
+ }
264
+
265
+ _locale(): string {
266
+ if (this.locale) return this.locale;
267
+ const lang = typeof document !== 'undefined' ? document.documentElement?.lang : '';
268
+ return lang || 'en-US';
269
+ }
270
+
271
+ _fmt(opts: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {
272
+ return new Intl.DateTimeFormat(this._locale(), { ...opts, timeZone: 'UTC' });
273
+ }
274
+
275
+ _min(): CalendarDate | null {
276
+ return parseDate(this.min);
277
+ }
278
+
279
+ _max(): CalendarDate | null {
280
+ return parseDate(this.max);
281
+ }
282
+
283
+ _isDisabled(day: CalendarDate): boolean {
284
+ if (this.disabled) return true;
285
+ const lo = this._min();
286
+ const hi = this._max();
287
+ return (!!lo && compareDates(day, lo) < 0) || (!!hi && compareDates(day, hi) > 0);
288
+ }
289
+
290
+ _first(): CalendarDate {
291
+ return parseDate(this.#shown.get()) ?? this._today();
292
+ }
293
+
294
+ /** The value in the shape `ui-value-change` reports. */
295
+ get selected(): string | string[] | { from: string; to: string } {
296
+ const s = this.#selection.get();
297
+ if (this.mode === 'range') return { from: s.from, to: s.to };
298
+ if (this.mode === 'multiple') return [...s.days];
299
+ return s.days[0] ?? '';
300
+ }
301
+
302
+ /** Pick `iso`, as a click or Enter does. */
303
+ pick(iso: string): void {
304
+ const day = parseDate(iso);
305
+ if (!day || this._isDisabled(day)) return;
306
+ const s = this.#selection.get();
307
+ if (this.mode === 'range') {
308
+ const next = addToRange({ from: parseDate(s.from), to: parseDate(s.to) }, day);
309
+ this.#selection.set({ days: [], from: next.from ? formatDate(next.from) : '', to: next.to ? formatDate(next.to) : '' });
310
+ } else if (this.mode === 'multiple') {
311
+ const days = s.days.includes(iso) ? s.days.filter((d) => d !== iso) : [...s.days, iso].sort();
312
+ this.#selection.set({ days, from: '', to: '' });
313
+ } else {
314
+ this.#selection.set({ days: s.days[0] === iso ? [] : [iso], from: '', to: '' });
315
+ }
316
+ this.#focused.set(iso);
317
+ this.dispatchEvent(new CustomEvent('ui-value-change', { bubbles: true, detail: { value: this.selected } }));
318
+ }
319
+
320
+ /** Show the month containing `iso` first. */
321
+ goToMonth(iso: string): void {
322
+ const day = parseDate(iso);
323
+ if (!day) return;
324
+ const next = formatDate({ y: day.y, m: day.m, d: 1 });
325
+ if (next === this.#shown.get()) return;
326
+ this.#shown.set(next);
327
+ this.dispatchEvent(new CustomEvent('ui-month-change', { bubbles: true, detail: { month: next.slice(0, 7) } }));
328
+ }
329
+
330
+ _canGo(by: number): boolean {
331
+ const first = this._first();
332
+ const lo = this._min();
333
+ const hi = this._max();
334
+ if (by < 0 && lo) return compareDates(addMonths(first, -1), { y: lo.y, m: lo.m, d: 1 }) >= 0;
335
+ if (by > 0 && hi) {
336
+ const lastShown = addMonths(first, (this.numberOfMonths || 1) - 1);
337
+ return compareDates(addMonths(lastShown, 1), { y: hi.y, m: hi.m, d: 1 }) <= 0;
338
+ }
339
+ return true;
340
+ }
341
+
342
+ _turn(by: number): void {
343
+ if (!this._canGo(by)) return;
344
+ this.goToMonth(formatDate(addMonths(this._first(), by)));
345
+ }
346
+
347
+ // The state a day is drawn in.
348
+ _dayState(day: CalendarDate): { selected: boolean; single: boolean; start: boolean; end: boolean; middle: boolean } {
349
+ const s = this.#selection.get();
350
+ const iso = formatDate(day);
351
+ if (this.mode === 'range') {
352
+ const from = parseDate(s.from);
353
+ const to = parseDate(s.to);
354
+ const start = sameDay(day, from);
355
+ const end = sameDay(day, to);
356
+ const middle = !!from && !!to && compareDates(day, from) > 0 && compareDates(day, to) < 0;
357
+ // A range of one day (or one not yet ended) draws its start as a single pick.
358
+ const lone = start && (!to || sameDay(from, to));
359
+ return { selected: start || end || middle, single: lone, start: start && !lone, end: end && !lone, middle };
360
+ }
361
+ const on = s.days.includes(iso);
362
+ return { selected: on, single: on, start: false, end: false, middle: false };
363
+ }
364
+
365
+ // The day that owns the tab stop: the focused one, else the first chosen
366
+ // day shown, else today if shown, else the first day of the first month.
367
+ _tabDay(months: CalendarDate[]): string {
368
+ const inShown = (iso: string) => {
369
+ const d = parseDate(iso);
370
+ return !!d && months.some((m) => m.y === d.y && m.m === d.m);
371
+ };
372
+ const focused = this.#focused.get();
373
+ if (focused && inShown(focused)) return focused;
374
+ const s = this.#selection.get();
375
+ const chosen = [s.from, ...s.days].find((d) => d && inShown(d));
376
+ if (chosen) return chosen;
377
+ const today = formatDate(this._today());
378
+ if (inShown(today)) return today;
379
+ return formatDate(months[0]);
380
+ }
381
+
382
+ render() {
383
+ const months = Array.from({ length: Math.max(1, this.numberOfMonths || 1) }, (_, i) => addMonths(this._first(), i));
384
+ const tab = this._tabDay(months);
385
+ const today = formatDate(this._today());
386
+ const outside = this.showOutsideDays !== 'false';
387
+ const weekday = this._fmt({ weekday: 'short' });
388
+ const weekdayLong = this._fmt({ weekday: 'long' });
389
+ const caption = this._fmt({ month: 'long', year: 'numeric' });
390
+ const full = this._fmt({ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
391
+ const en = this._locale().toLowerCase().startsWith('en');
392
+ const headerDays = monthWeeks(2024, 0, this._weekStart())[1];
393
+ const dropdown = this.captionLayout === 'dropdown';
394
+ const weeks = !!this.showWeekNumber;
395
+ const hidden = this.name ? this._hiddenInputs() : '';
396
+ return html`<div
397
+ data-slot="calendar"
398
+ class=${cn('w-fit', calendarClass())}
399
+ @keydown=${this._onKeyDown}
400
+ ><div class="relative flex flex-col gap-4 md:flex-row"><nav aria-label="Navigation" class="absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1"><button
401
+ type="button"
402
+ aria-label="Go to the Previous Month"
403
+ aria-disabled=${this._canGo(-1) ? nothing : 'true'}
404
+ class=${cn(buttonClass({ variant: 'ghost' }), NAV_BUTTON, 'rdp-button-previous')}
405
+ @click=${() => this._turn(-1)}
406
+ ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="cn-rtl-flip size-4 rtl:rotate-180"><path d="m15 18-6-6 6-6"></path></svg></button><button
407
+ type="button"
408
+ aria-label="Go to the Next Month"
409
+ aria-disabled=${this._canGo(1) ? nothing : 'true'}
410
+ class=${cn(buttonClass({ variant: 'ghost' }), NAV_BUTTON, 'rdp-button-next')}
411
+ @click=${() => this._turn(1)}
412
+ ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="cn-rtl-flip size-4 rtl:rotate-180"><path d="m9 18 6-6-6-6"></path></svg></button></nav>${months.map((mo, mi) => {
413
+ // No id before connect (the server never connects an element): a served
414
+ // `-caption-0` would be shared by every calendar on the page.
415
+ const captionId = this._id ? `${this._id}-caption-${mi}` : nothing;
416
+ return html`<div class="flex w-full flex-col gap-4"><div class="flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)">${dropdown && mi === 0
417
+ ? this._dropdowns(mo, captionId)
418
+ : html`<span id=${captionId} role="status" aria-live="polite" class=${cn('font-medium select-none', calendarCaptionClass())}>${caption.format(toUTC(mo))}</span>`}</div><table
419
+ role="grid"
420
+ aria-labelledby=${captionId}
421
+ aria-multiselectable=${this.mode === 'single' ? nothing : 'true'}
422
+ class="w-full border-collapse"
423
+ ><thead aria-hidden="true"><tr class="flex">${weeks
424
+ ? html`<th scope="col" aria-label="Week Number" class="w-(--cell-size) select-none"></th>`
425
+ : ''}${headerDays.map((d) => {
426
+ const short = weekday.format(toUTC(d));
427
+ return html`<th scope="col" aria-label=${weekdayLong.format(toUTC(d))} class="flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none">${en ? short.slice(0, 2) : short}</th>`;
428
+ })}</tr></thead><tbody>${monthWeeks(mo.y, mo.m, this._weekStart()).map((week) => html`<tr class="mt-2 flex w-full">${weeks
429
+ ? this._weekNumberCell(week)
430
+ : ''}${week.map((day) => {
431
+ const iso = formatDate(day);
432
+ const isOutside = day.m !== mo.m;
433
+ if (isOutside && !outside) {
434
+ return html`<td role="gridcell" class="group/day relative aspect-square h-full w-full p-0 invisible"></td>`;
435
+ }
436
+ const st = this._dayState(day);
437
+ const off = this._isDisabled(day);
438
+ const isToday = iso === today;
439
+ const label = `${isToday ? 'Today, ' : ''}${full.format(toUTC(day))}${st.selected ? ', selected' : ''}`;
440
+ return html`<td
441
+ role="gridcell"
442
+ data-day=${iso}
443
+ aria-selected=${st.selected ? 'true' : nothing}
444
+ data-selected=${st.selected ? 'true' : nothing}
445
+ data-today=${isToday ? 'true' : nothing}
446
+ data-outside=${isOutside ? 'true' : nothing}
447
+ data-disabled=${off ? 'true' : nothing}
448
+ data-focused=${this.#focused.get() === iso ? 'true' : nothing}
449
+ class=${cn(
450
+ 'group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-e-(--cell-radius) [&:first-child[data-selected=true]_button]:rounded-s-(--cell-radius)',
451
+ // A week-number column makes the row's first day its second cell,
452
+ // which takes the first day's corner instead.
453
+ weeks ? '[&:nth-child(2)[data-selected=true]_button]:rounded-s-(--cell-radius)' : '',
454
+ st.start ? 'relative isolate z-0 rounded-s-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:end-0 after:w-4 after:bg-muted' : '',
455
+ st.middle ? 'rounded-none' : '',
456
+ st.end ? 'relative isolate z-0 rounded-e-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:start-0 after:w-4 after:bg-muted' : '',
457
+ isToday ? 'rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none' : '',
458
+ isOutside ? 'text-muted-foreground aria-selected:text-muted-foreground' : '',
459
+ off ? 'text-muted-foreground opacity-50' : '',
460
+ )}
461
+ ><button
462
+ type="button"
463
+ tabindex=${iso === tab ? '0' : '-1'}
464
+ aria-label=${label}
465
+ ?disabled=${off}
466
+ data-day=${iso}
467
+ data-selected-single=${st.single ? 'true' : 'false'}
468
+ data-range-start=${st.start ? 'true' : 'false'}
469
+ data-range-end=${st.end ? 'true' : 'false'}
470
+ data-range-middle=${st.middle ? 'true' : 'false'}
471
+ class=${cn(buttonClass({ variant: 'ghost', size: 'icon' }), calendarDayButtonClass())}
472
+ @click=${() => this.pick(iso)}
473
+ @focus=${() => { this.#focused.set(iso); }}
474
+ >${day.d}</button></td>`;
475
+ })}</tr>`)}</tbody></table></div>`;
476
+ })}</div>${hidden}</div>`;
477
+ }
478
+
479
+ // The first day of a week: Monday for ISO weeks, as react-day-picker's
480
+ // ISOWeek lays them out, else `week-starts-on`.
481
+ _weekStart(): number {
482
+ return this.isoWeek ? 1 : this.weekStartsOn || 0;
483
+ }
484
+
485
+ // A row's week number, a header cell for the row as react-day-picker draws
486
+ // it: named "Week N" and shown two digits wide.
487
+ _weekNumberCell(week: CalendarDate[]): unknown {
488
+ const n = weekNumber(week[0], this._weekStart(), !!this.isoWeek);
489
+ return html`<td role="rowheader" scope="row" aria-label=${`Week ${n}`} class="text-[0.8rem] text-muted-foreground select-none"><div class="flex size-(--cell-size) items-center justify-center text-center">${String(n).padStart(2, '0')}</div></td>`;
490
+ }
491
+
492
+ _hiddenInputs(): unknown {
493
+ const s = this.#selection.get();
494
+ if (this.mode === 'range') {
495
+ return html`<input type="hidden" name=${`${this.name}[from]`} value=${s.from}><input type="hidden" name=${`${this.name}[to]`} value=${s.to}>`;
496
+ }
497
+ return s.days.map((d) => html`<input type="hidden" name=${this.name} value=${d}>`);
498
+ }
499
+
500
+ // Month and year selects over the caption, as react-day-picker draws them.
501
+ _dropdowns(mo: CalendarDate, captionId: string | typeof nothing): unknown {
502
+ const monthName = this._fmt({ month: 'short' });
503
+ const lo = this._min() ?? { y: mo.y - 100, m: 0, d: 1 };
504
+ const hi = this._max() ?? { y: mo.y + 10, m: 11, d: 31 };
505
+ const years: number[] = [];
506
+ for (let y = lo.y; y <= hi.y; y++) years.push(y);
507
+ const months = Array.from({ length: 12 }, (_, i) => i);
508
+ const chevron = html`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg>`;
509
+ return html`<div id=${captionId} class="flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium"><span class=${calendarDropdownRootClass()}><select
510
+ aria-label="Choose the Month"
511
+ class="absolute inset-0 bg-popover opacity-0"
512
+ @change=${(e: Event) => this.goToMonth(formatDate({ y: mo.y, m: Number((e.target as HTMLSelectElement).value), d: 1 }))}
513
+ >${months.map((m) => html`<option value=${String(m)} ?selected=${m === mo.m}>${monthName.format(toUTC({ y: mo.y, m, d: 1 }))}</option>`)}</select><span
514
+ aria-hidden="true" class=${cn('font-medium select-none', calendarCaptionLabelClass())}>${monthName.format(toUTC(mo))}${chevron}</span></span><span class=${calendarDropdownRootClass()}><select
515
+ aria-label="Choose the Year"
516
+ class="absolute inset-0 bg-popover opacity-0"
517
+ @change=${(e: Event) => this.goToMonth(formatDate({ y: Number((e.target as HTMLSelectElement).value), m: mo.m, d: 1 }))}
518
+ >${years.map((y) => html`<option value=${String(y)} ?selected=${y === mo.y}>${y}</option>`)}</select><span
519
+ aria-hidden="true" class=${cn('font-medium select-none', calendarCaptionLabelClass())}>${mo.y}${chevron}</span></span></div>`;
520
+ }
521
+
522
+ _onKeyDown = (e: KeyboardEvent): void => {
523
+ const target = e.target as HTMLElement;
524
+ const iso = target.getAttribute?.('data-day');
525
+ if (!iso || target.tagName !== 'BUTTON') return;
526
+ const day = parseDate(iso);
527
+ if (!day) return;
528
+ const rtl = typeof getComputedStyle === 'function' && getComputedStyle(this).direction === 'rtl';
529
+ const w = this._weekStart();
530
+ let next: CalendarDate | null = null;
531
+ switch (e.key) {
532
+ case 'ArrowLeft': next = addDays(day, rtl ? 1 : -1); break;
533
+ case 'ArrowRight': next = addDays(day, rtl ? -1 : 1); break;
534
+ case 'ArrowUp': next = addDays(day, -7); break;
535
+ case 'ArrowDown': next = addDays(day, 7); break;
536
+ case 'Home': next = addDays(day, -((toUTC(day).getUTCDay() - w + 7) % 7)); break;
537
+ case 'End': next = addDays(day, 6 - ((toUTC(day).getUTCDay() - w + 7) % 7)); break;
538
+ case 'PageUp': next = e.shiftKey ? addMonths(day, -12) : addMonths(day, -1); break;
539
+ case 'PageDown': next = e.shiftKey ? addMonths(day, 12) : addMonths(day, 1); break;
540
+ case 'Enter':
541
+ case ' ':
542
+ e.preventDefault();
543
+ this.pick(iso);
544
+ return;
545
+ default:
546
+ return;
547
+ }
548
+ e.preventDefault();
549
+ this.focusDay(formatDate(next));
550
+ };
551
+
552
+ /** Move focus to `iso`, turning the page when it is not shown. */
553
+ focusDay(iso: string): void {
554
+ const day = parseDate(iso);
555
+ if (!day) return;
556
+ const first = this._first();
557
+ const last = addMonths(first, (this.numberOfMonths || 1) - 1);
558
+ if (compareDates({ ...day, d: 1 }, { ...first, d: 1 }) < 0) this.goToMonth(iso);
559
+ else if (compareDates({ ...day, d: 1 }, { ...last, d: 1 }) > 0) this.goToMonth(formatDate(addMonths(day, -((this.numberOfMonths || 1) - 1))));
560
+ this.#focused.set(iso);
561
+ this.updateComplete.then(() => {
562
+ this.querySelector<HTMLButtonElement>(`button[data-day="${iso}"]`)?.focus();
563
+ });
564
+ }
565
+ }
566
+ UiCalendar.register('ui-calendar');