@webjsdev/ui 0.3.17 → 0.5.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 (360) hide show
  1. package/README.md +67 -8
  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 +644 -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/dom.ts +3 -4
  323. package/packages/registry/lib/icons-hugeicons.ts +955 -0
  324. package/packages/registry/lib/icons-phosphor.ts +955 -0
  325. package/packages/registry/lib/icons-remixicon.ts +955 -0
  326. package/packages/registry/lib/icons-tabler.ts +955 -0
  327. package/packages/registry/lib/icons.ts +768 -0
  328. package/packages/registry/lib/utils.ts +52 -8
  329. package/packages/registry/registry.json +4056 -72
  330. package/packages/registry/styles/shadcn-tailwind.css +654 -0
  331. package/packages/registry/styles/style-luma.css +1987 -0
  332. package/packages/registry/styles/style-lyra.css +1965 -0
  333. package/packages/registry/styles/style-maia.css +1987 -0
  334. package/packages/registry/styles/style-mira.css +1992 -0
  335. package/packages/registry/styles/style-new-york.css +1597 -0
  336. package/packages/registry/styles/style-nova.css +1990 -0
  337. package/packages/registry/styles/style-rhea.css +1987 -0
  338. package/packages/registry/styles/style-sera.css +1977 -0
  339. package/packages/registry/styles/style-vega.css +1990 -0
  340. package/packages/registry/styles/supplement.json +54 -0
  341. package/packages/registry/styles/tw-animate.css +6 -0
  342. package/packages/registry/themes/base-colors.js +8 -2
  343. package/packages/registry/themes/fonts.js +120 -0
  344. package/packages/registry/themes/index.css +2 -0
  345. package/packages/registry/themes/items.js +61 -0
  346. package/packages/registry/themes/preset.js +302 -0
  347. package/packages/registry/themes/themes.js +1193 -0
  348. package/src/commands/add.js +266 -14
  349. package/src/commands/diff.js +34 -20
  350. package/src/commands/info.js +7 -0
  351. package/src/commands/init.js +127 -10
  352. package/src/commands/list.js +43 -11
  353. package/src/commands/view.js +33 -5
  354. package/src/lint/rules/no-restyle.js +1 -1
  355. package/src/registry/extract.js +194 -5
  356. package/src/registry/icons.js +31 -0
  357. package/src/registry/local.js +15 -1
  358. package/src/registry/schema.js +13 -0
  359. package/src/registry/style-bake.js +506 -0
  360. package/src/utils/theme.js +110 -21
@@ -1,12 +1,14 @@
1
1
  import { Command } from 'commander';
2
+ import { bakeForStyle } from '../registry/style-bake.js';
2
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
- import { dirname, join, basename, relative as relPath } from 'node:path';
4
+ import { dirname, join, basename, posix, relative as relPath } from 'node:path';
4
5
  import prompts from 'prompts';
5
6
  import { execSync } from 'node:child_process';
6
7
  import { getConfig } from '../utils/get-config.js';
7
8
  import { logger } from '../utils/logger.js';
8
9
  import { resolveTree, collectNpmDeps } from '../registry/resolver.js';
9
- import { DEFAULT_REGISTRY_URL } from '../registry/fetcher.js';
10
+ import { withIconLibrary } from '../registry/icons.js';
11
+ import { DEFAULT_REGISTRY_URL, getRegistryIndex, getRegistryItem } from '../registry/fetcher.js';
10
12
  import { isCustomElementSource } from '../registry/local.js';
11
13
  import { stripExample } from '../registry/example.js';
12
14
  import { ensureTheme } from '../utils/theme.js';
@@ -36,7 +38,8 @@ export const add = new Command()
36
38
  process.exit(1);
37
39
  }
38
40
 
39
- const tree = await resolveTree(components, opts.registry);
41
+ // The icon library is the one components.json names, not always Lucide.
42
+ const tree = await withIconLibrary(await resolveTree(components, opts.registry), config.iconLibrary, opts.registry);
40
43
  logger.info(`Installing ${logger.bold(components.join(', '))}…`);
41
44
 
42
45
  // Self-heal missing theme tokens (#983): the helpers render against CSS
@@ -53,10 +56,42 @@ export const add = new Command()
53
56
  }
54
57
  }
55
58
 
59
+ const written = [];
60
+ // Block files another block already wrote (two families sharing a
61
+ // target, sidebar-07 then dashboard-01), collected for one summary.
62
+ /** @type {{ file: string, item: string, by: string[] }[]} */
63
+ const conflicts = [];
64
+ /** @type {{ blocks?: any[] }} */
65
+ const blockCache = {};
56
66
  for (const item of tree) {
57
67
  for (const file of item.files || []) {
58
- await writeRegistryFile(cwd, config, item, file, opts);
68
+ const out = await writeRegistryFile(cwd, config, item, file, { ...opts, conflicts, blockCache });
69
+ if (out) written.push(out);
59
70
  }
71
+ // A block or a component that needs tokens an existing app may lack
72
+ // (sidebar's --sidebar-*, chart's --chart-*) carries them as cssVars,
73
+ // and the missing ones are added to the app's stylesheet (D18).
74
+ if (item.cssVars && tw.css) {
75
+ const added = mergeCssVars(cwd, tw.css, item.cssVars);
76
+ if (added > 0) logger.success(`Added ${added} theme token${added === 1 ? '' : 's'} for ${item.name} to ${tw.css}`);
77
+ }
78
+ }
79
+ if (written.length) {
80
+ logger.info('Files written:');
81
+ for (const f of written) logger.info(` ${f}`);
82
+ }
83
+ if (conflicts.length) {
84
+ const names = [...new Set(conflicts.map((c) => c.item))];
85
+ const others = [...new Set(conflicts.flatMap((c) => c.by))];
86
+ logger.warn(
87
+ `${conflicts.length} file${conflicts.length === 1 ? '' : 's'} of ${names.join(', ')} ` +
88
+ `${conflicts.length === 1 ? 'was' : 'were'} kept from ${others.join(', ')}, so the app mixes the blocks:`,
89
+ );
90
+ for (const c of conflicts) logger.warn(` ${c.file} (from ${c.by.join(', ')})`);
91
+ logger.warn(
92
+ `Run ${logger.cyan(`npx @webjsdev/ui add ${names.join(' ')} --overwrite`)} to replace them with ${names.join(', ')}'s version ` +
93
+ '(it also replaces every kit component and helper the install writes, so commit your edits first).',
94
+ );
60
95
  }
61
96
 
62
97
  if (opts.deps !== false) {
@@ -64,8 +99,13 @@ export const add = new Command()
64
99
  // @webjsdev/core is always a runtime dep
65
100
  if (!dependencies.includes('@webjsdev/core')) dependencies.push('@webjsdev/core');
66
101
 
67
- if (dependencies.length) await installDeps(cwd, dependencies, false);
68
- if (devDependencies.length) await installDeps(cwd, devDependencies, true);
102
+ // Install only what the app does not already declare. Most components need
103
+ // nothing beyond @webjsdev/core, which every WebJs app has, and re-installing
104
+ // it ran a full install and rewrote the app's version range on every add.
105
+ const missing = undeclaredDeps(cwd, dependencies);
106
+ const missingDev = undeclaredDeps(cwd, devDependencies);
107
+ if (missing.length) await installDeps(cwd, missing, false);
108
+ if (missingDev.length) await installDeps(cwd, missingDev, true);
69
109
  }
70
110
 
71
111
  logger.success('Done.');
@@ -82,7 +122,31 @@ async function writeRegistryFile(cwd, config, item, file, opts) {
82
122
  // replace edited source on every `add`. Only an explicit `--overwrite` may.
83
123
  if (existsSync(target) && !opts.overwrite && helperTarget(config, item, file)) {
84
124
  logger.info(`${relative(cwd, target)} already exists: keeping it.`);
85
- return;
125
+ return null;
126
+ }
127
+
128
+ // A block's files are app code the user owns (a page, a module), so `--yes`
129
+ // does not license replacing one: only `--overwrite` does (D18). Keeping it
130
+ // silently is wrong when ANOTHER block wrote it (two block families share
131
+ // targets such as components/app-sidebar.ts), since the app then mixes the
132
+ // two, so the existing file is compared against what this block and every
133
+ // other block would write there, and a match with another block is a
134
+ // warning that names it.
135
+ if (existsSync(target) && !opts.overwrite && isBlock(item, file)) {
136
+ const rel = relative(cwd, target);
137
+ const local = readFileSync(target, 'utf8');
138
+ if (local === transformForProject(file.content || '', target, config, item, { file, cwd })) {
139
+ logger.info(`${rel} is already ${item.name}'s version: keeping it.`);
140
+ return null;
141
+ }
142
+ const by = await otherBlockWriters(cwd, config, item, target, local, opts);
143
+ if (by.length) {
144
+ logger.warn(`${rel} was written by ${by.join(', ')}, not ${item.name}: keeping it (pass --overwrite to replace it).`);
145
+ opts.conflicts?.push({ file: rel, item: item.name, by });
146
+ } else {
147
+ logger.info(`${rel} already exists and differs from ${item.name}'s version: keeping it (pass --overwrite to replace it).`);
148
+ }
149
+ return null;
86
150
  }
87
151
 
88
152
  if (existsSync(target) && !opts.overwrite && !opts.yes) {
@@ -94,20 +158,67 @@ async function writeRegistryFile(cwd, config, item, file, opts) {
94
158
  });
95
159
  if (!r.overwrite) {
96
160
  logger.info(`Skipped ${basename(target)}`);
97
- return;
161
+ return null;
98
162
  }
99
163
  }
100
164
 
101
- const content = transformForProject(file.content || '', target, config, item);
165
+ const content = transformForProject(file.content || '', target, config, item, { file, cwd });
102
166
  writeFileSync(target, content, 'utf8');
103
167
  logger.success(`Wrote ${relative(cwd, target)}`);
168
+ return relative(cwd, target);
169
+ }
170
+
171
+ /**
172
+ * The OTHER blocks whose file at `target` is exactly `local`, by name: what
173
+ * `add` would have written for each of them there (the same transform, so a
174
+ * baked, import-rewritten file still matches). The registry's blocks are
175
+ * loaded once per `add` run, and only when a block file already exists.
176
+ *
177
+ * @param {string} cwd
178
+ * @param {any} config
179
+ * @param {{ name: string }} item the block being installed
180
+ * @param {string} target absolute path of the existing file
181
+ * @param {string} local its content
182
+ * @param {{ registry?: string, blockCache?: { blocks?: any[] } }} opts
183
+ * @returns {Promise<string[]>}
184
+ */
185
+ async function otherBlockWriters(cwd, config, item, target, local, opts) {
186
+ const cache = opts.blockCache ?? {};
187
+ if (!cache.blocks) {
188
+ cache.blocks = [];
189
+ try {
190
+ const index = await getRegistryIndex(opts.registry);
191
+ for (const entry of index.filter((i) => i.type === 'registry:block')) {
192
+ cache.blocks.push(await getRegistryItem(entry.name, opts.registry));
193
+ }
194
+ } catch {
195
+ // An index that cannot be read only costs the warning its block name.
196
+ }
197
+ }
198
+ const by = [];
199
+ for (const other of cache.blocks) {
200
+ if (other.name === item.name) continue;
201
+ const match = (other.files || []).some((f) =>
202
+ resolveTarget(cwd, config, other, f) === target &&
203
+ transformForProject(f.content || '', target, config, other, { file: f, cwd }) === local);
204
+ if (match) by.push(other.name);
205
+ }
206
+ return by;
207
+ }
208
+
209
+ function isBlock(item, file) {
210
+ return item?.type === 'registry:block' || file?.type === 'registry:block';
104
211
  }
105
212
 
106
213
  /**
107
214
  * The single transform that turns a registry file's raw content into what
108
215
  * lands in the user's project. `add` writes this; `diff` compares against it,
109
- * so the two cannot disagree (#983). Two steps:
216
+ * so the two cannot disagree (#983). Three steps:
110
217
  *
218
+ * 0. Bake the style (#1666): a registry file in base form carries semantic
219
+ * `cn-*` names, which are replaced by the Tailwind classes of the style
220
+ * `components.json` names (`new-york` when it names none), so the file an
221
+ * app owns is plain Tailwind. A file with no `cn-*` name is untouched.
111
222
  * 1. Retarget the registry-relative `../lib/utils.ts` / `../lib/dom.ts` imports
112
223
  * to the project's resolved helper paths (see {@link rewriteUtilsImport}).
113
224
  * 2. For a Tier-1 helper component (a `registry:ui` file that is NOT a custom
@@ -118,12 +229,15 @@ async function writeRegistryFile(cwd, config, item, file, opts) {
118
229
  *
119
230
  * @param {string} content raw registry file content
120
231
  * @param {string} target absolute path where the file will be written
121
- * @param {{ resolvedPaths: { utils: string } }} config parsed components.json
232
+ * @param {{ resolvedPaths: { utils: string }, style?: string }} config parsed components.json
122
233
  * @param {{ name: string, type?: string }} [item] the registry item
123
234
  * @returns {string}
124
235
  */
125
- export function transformForProject(content, target, config, item) {
126
- let out = rewriteUtilsImport(content, target, config);
236
+ export function transformForProject(content, target, config, item, where = {}) {
237
+ let out = bakeForStyle(content, config?.style);
238
+ out = where.file?.path && where.cwd
239
+ ? rewriteRegistryImports(out, where.file.path, target, config, where.cwd, item)
240
+ : rewriteUtilsImport(out, target, config);
127
241
  if (item && item.type === 'registry:ui' && !isCustomElementSource(content)) {
128
242
  out = stripExample(out, item.name);
129
243
  }
@@ -160,6 +274,100 @@ export function rewriteUtilsImport(content, target, config) {
160
274
  return out;
161
275
  }
162
276
 
277
+ /**
278
+ * Rewrite every registry-relative import in a file to the path that resolves
279
+ * from where the file lands in the app (D18). Each relative specifier is
280
+ * resolved against the file's own registry path, then mapped to where THAT
281
+ * registry file lands:
282
+ *
283
+ * - another file of the same item (a block's page importing its own
284
+ * component) lands at its own target;
285
+ * - `lib/utils.ts` and `lib/dom.ts` land at the utils alias and beside it,
286
+ * as {@link rewriteUtilsImport} has always done (and `lib/icons.ts` beside
287
+ * them too);
288
+ * - a component (`components/<name>.ts`) lands in the ui alias directory.
289
+ *
290
+ * Anything else is left as written. This is the general form of the two
291
+ * fixed literals {@link rewriteUtilsImport} rewrites, which a block, whose
292
+ * files sit at other depths and import components and each other, needs.
293
+ *
294
+ * @param {string} content
295
+ * @param {string} fromPath the file's path inside the registry
296
+ * @param {string} target absolute path where the file is written
297
+ * @param {object} config parsed components.json
298
+ * @param {string} cwd the project root
299
+ * @param {{ files?: { path: string }[] }} [item] the item the file belongs to
300
+ */
301
+ export function rewriteRegistryImports(content, fromPath, target, config, cwd, item) {
302
+ const utilsAbs = config?.resolvedPaths?.utils;
303
+ const uiDir = config?.resolvedPaths?.ui ?? join(cwd, (config?.aliases?.ui || 'components/ui').replace(/^@\//, ''));
304
+ const own = new Map((item?.files || []).map((f) => [posix.normalize(f.path), f]));
305
+ const destOf = (regPath) => {
306
+ if (own.has(regPath) && regPath !== posix.normalize(fromPath)) return resolveTarget(cwd, config, item, own.get(regPath));
307
+ if (utilsAbs && regPath === 'lib/utils.ts') return utilsAbs;
308
+ if (utilsAbs && (regPath === 'lib/dom.ts' || regPath === 'lib/icons.ts')) return join(dirname(utilsAbs), posix.basename(regPath));
309
+ if (regPath.startsWith('components/') && !regPath.slice('components/'.length).includes('/')) return join(uiDir, posix.basename(regPath));
310
+ return null;
311
+ };
312
+ return content.replace(/((?:from|import)\s*\(?\s*)(['"])(\.{1,2}\/[^'"]+)\2/g, (whole, lead, q, spec) => {
313
+ const regPath = posix.normalize(posix.join(posix.dirname(fromPath), spec));
314
+ const dest = destOf(regPath);
315
+ if (!dest) return whole;
316
+ let rel = relPath(dirname(target), dest).split(/[\\/]/).join('/');
317
+ if (!rel.startsWith('.')) rel = './' + rel;
318
+ return `${lead}${q}${rel}${q}`;
319
+ });
320
+ }
321
+
322
+ /**
323
+ * Add the CSS variables an item carries to the app's stylesheet, leaving
324
+ * every one the app already defines as it is. `light` goes in the `:root`
325
+ * block, `dark` in `.dark`, and `theme` in `@theme inline`, which is where
326
+ * the kit's theme puts each. A missing block is appended. Returns how many
327
+ * variables were added.
328
+ *
329
+ * @param {string} cwd
330
+ * @param {string} cssPath the app's stylesheet, relative to cwd
331
+ * @param {{ theme?: Record<string, string>, light?: Record<string, string>, dark?: Record<string, string> }} cssVars
332
+ */
333
+ export function mergeCssVars(cwd, cssPath, cssVars) {
334
+ const file = join(cwd, cssPath);
335
+ let css = existsSync(file) ? readFileSync(file, 'utf8') : '';
336
+ let added = 0;
337
+ const groups = [
338
+ ['@theme inline', cssVars.theme],
339
+ [':root', cssVars.light],
340
+ ['.dark', cssVars.dark],
341
+ ];
342
+ for (const [selector, vars] of groups) {
343
+ const entries = Object.entries(vars || {});
344
+ if (!entries.length) continue;
345
+ // A token counts as present only inside ITS block: a light value in
346
+ // :root says nothing about the dark one .dark still needs.
347
+ const open = css.indexOf(`${selector} {`);
348
+ const body = open >= 0 ? css.slice(open, css.indexOf('}', open)) : '';
349
+ const missing = entries.filter(([name]) => !new RegExp(`--${escapeRe(name)}\\s*:`).test(body));
350
+ if (!missing.length) continue;
351
+ const lines = missing.map(([name, value]) => ` --${name}: ${value};`).join('\n');
352
+ if (open >= 0) {
353
+ const close = css.indexOf('}', open);
354
+ css = `${css.slice(0, close).replace(/\s*$/, '')}\n${lines}\n${css.slice(close)}`;
355
+ } else {
356
+ css = `${css.replace(/\s*$/, '')}\n\n${selector} {\n${lines}\n}\n`;
357
+ }
358
+ added += missing.length;
359
+ }
360
+ if (added) {
361
+ ensureDir(dirname(file));
362
+ writeFileSync(file, css, 'utf8');
363
+ }
364
+ return added;
365
+ }
366
+
367
+ function escapeRe(s) {
368
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
369
+ }
370
+
163
371
  /**
164
372
  * Replace a single registry-relative import specifier with the relative path
165
373
  * from `target`'s directory to `destAbs`. No-op when `spec` is absent.
@@ -178,7 +386,19 @@ function replaceImportSpecifier(content, spec, destAbs, target) {
178
386
  .replaceAll(`"${spec}"`, `"${rel}"`);
179
387
  }
180
388
 
181
- function resolveTarget(cwd, config, item, file) {
389
+ /**
390
+ * The absolute path a registry file is written to: the helper alias for the
391
+ * shared helpers, else the file's own `target`, else a folder picked by the
392
+ * file's type. `diff` reads the same answer, so it compares the file `add`
393
+ * would have written.
394
+ *
395
+ * @param {string} cwd
396
+ * @param {any} config parsed components.json
397
+ * @param {any} item the registry item
398
+ * @param {{ path: string, type?: string, target?: string }} file
399
+ * @returns {string}
400
+ */
401
+ export function resolveTarget(cwd, config, item, file) {
182
402
  // The two shared helpers are pinned to `lib/utils.ts` / `lib/dom.ts` by the
183
403
  // registry manifest, but where they actually BELONG is wherever the project's
184
404
  // `utils` alias points, because that is the path `rewriteUtilsImport` writes
@@ -205,6 +425,11 @@ function resolveTarget(cwd, config, item, file) {
205
425
  return join(cwd, (aliases.lib || 'lib').replace(/^@\//, ''), fileName);
206
426
  case 'registry:hook':
207
427
  return join(cwd, 'hooks', fileName);
428
+ case 'registry:block':
429
+ // Every shipped block file names its target (a registry test enforces
430
+ // it). A custom registry's block that does not keeps its path, so two
431
+ // files called page.ts cannot land on one another.
432
+ return join(cwd, file.path);
208
433
  default:
209
434
  return join(cwd, fileName);
210
435
  }
@@ -236,6 +461,10 @@ function helperTarget(config, item, file) {
236
461
  const name = basename(file.path || '');
237
462
  if (item.name === 'lib-utils' && name === 'utils.ts') return utilsAbs;
238
463
  if (item.name === 'lib-dom' && name === 'dom.ts') return join(dirname(utilsAbs), 'dom.ts');
464
+ // Every icon library (lib-icons, lib-icons-tabler, ...) is the SAME file in
465
+ // an app, the utils file's sibling `icons.ts`, which is where a block's
466
+ // `../lib/icons.ts` import is rewritten to (#1666).
467
+ if (/^lib-icons(-|$)/.test(item.name) && /^icons(-[a-z]+)?\.ts$/.test(name)) return join(dirname(utilsAbs), 'icons.ts');
239
468
  return null;
240
469
  }
241
470
 
@@ -247,6 +476,29 @@ function ensureDir(d) {
247
476
  if (!existsSync(d)) mkdirSync(d, { recursive: true });
248
477
  }
249
478
 
479
+ /**
480
+ * The dependency specs (`name` or `name@range`) that the app's package.json does
481
+ * not already declare in any dependency field. A missing or unreadable
482
+ * package.json declares nothing, so every spec is returned.
483
+ * @param {string} cwd
484
+ * @param {string[]} specs
485
+ * @returns {string[]}
486
+ */
487
+ export function undeclaredDeps(cwd, specs) {
488
+ let pkg = {};
489
+ try { pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8')); } catch {}
490
+ const declared = new Set();
491
+ for (const field of ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']) {
492
+ for (const name of Object.keys(pkg?.[field] || {})) declared.add(name);
493
+ }
494
+ // A scoped name starts with @, so the version separator is the LAST @ past it.
495
+ const nameOf = (spec) => {
496
+ const at = spec.lastIndexOf('@');
497
+ return at > 0 ? spec.slice(0, at) : spec;
498
+ };
499
+ return specs.filter((spec) => !declared.has(nameOf(spec)));
500
+ }
501
+
250
502
  async function installDeps(cwd, deps, dev) {
251
503
  const manager = detectAddCommand(cwd);
252
504
  const flag = dev ? '-D' : '';
@@ -1,15 +1,14 @@
1
1
  import { Command } from 'commander';
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
- import { join, basename } from 'node:path';
4
3
  import { getConfig } from '../utils/get-config.js';
5
4
  import { fetchRegistryItem, fetchRegistryIndex, DEFAULT_REGISTRY_URL } from '../registry/fetcher.js';
6
- import { transformForProject } from './add.js';
5
+ import { transformForProject, resolveTarget } from './add.js';
7
6
  import { logger } from '../utils/logger.js';
8
7
 
9
8
  export const diff = new Command()
10
9
  .name('diff')
11
- .description('Show differences between local components and the registry')
12
- .argument('[name]', 'component to diff (omit to show all out-of-date)')
10
+ .description('Show differences between local components or blocks and the registry')
11
+ .argument('[name]', 'component or block to diff (omit to show all out-of-date)')
13
12
  .option('-c, --cwd <cwd>', 'the working directory', process.cwd())
14
13
  .option('--registry <url>', 'registry base URL', DEFAULT_REGISTRY_URL)
15
14
  .action(async (name, opts) => {
@@ -22,35 +21,50 @@ export const diff = new Command()
22
21
  // diff compares local files against the LIVE upstream, so it stays on the
23
22
  // network path (NOT local-first): local-first would compare the package
24
23
  // against itself. Resolve the names to compare, then fetch each item's full
25
- // content (the index is metadata-only).
24
+ // content (the index is metadata-only). Installed blocks are compared too
25
+ // (D18).
26
26
  let names;
27
27
  if (name) {
28
28
  names = [name];
29
29
  } else {
30
30
  const index = await fetchRegistryIndex(opts.registry);
31
- names = index.filter((i) => i.type === 'registry:ui').map((i) => i.name);
31
+ names = index.filter((i) => i.type === 'registry:ui' || i.type === 'registry:block').map((i) => i.name);
32
32
  }
33
33
 
34
- const uiDir = config.resolvedPaths.ui;
35
- let changed = 0;
36
-
34
+ // Grouped by the file on disk, not by item: several blocks can write the
35
+ // same target (every login block writes app/login/page.ts), so a file is
36
+ // up to date when it matches ANY item that writes it, and is reported
37
+ // once otherwise.
38
+ /** @type {Map<string, { items: string[], expected: string[] }>} */
39
+ const byTarget = new Map();
37
40
  for (const n of names) {
38
41
  const item = await fetchRegistryItem(n, opts.registry);
39
42
  for (const file of item.files || []) {
40
- const target = join(uiDir, basename(file.path));
43
+ // The path `add` writes, so the two cannot disagree (#983).
44
+ const target = resolveTarget(opts.cwd, config, item, file);
41
45
  if (!existsSync(target)) continue;
42
- const local = readFileSync(target, 'utf8');
43
- // Compare against what `add` WOULD write (import-rewrite + example
44
- // strip), not the raw registry content: otherwise a pristine install
45
- // reports every import-rewritten component as differing (#983).
46
- const expected = transformForProject(file.content || '', target, config, item);
47
- if (local !== expected) {
48
- logger.info(`${logger.bold(item.name)}: ${basename(file.path)} differs from registry`);
49
- changed++;
50
- }
46
+ // Compare against what `add` WOULD write (bake, import rewrite and
47
+ // example strip), not the raw registry content: otherwise a pristine
48
+ // install reports every import-rewritten file as differing (#983).
49
+ const expected = transformForProject(file.content || '', target, config, item, { file, cwd: opts.cwd });
50
+ const entry = byTarget.get(target) ?? { items: [], expected: [] };
51
+ entry.items.push(item.name);
52
+ entry.expected.push(expected);
53
+ byTarget.set(target, entry);
51
54
  }
52
55
  }
53
56
 
54
- if (changed === 0) logger.success('All local components match the registry.');
57
+ let changed = 0;
58
+ for (const [target, { items, expected }] of byTarget) {
59
+ const local = readFileSync(target, 'utf8');
60
+ if (expected.includes(local)) continue;
61
+ const rel = target.startsWith(opts.cwd) ? target.slice(opts.cwd.length + 1) : target;
62
+ logger.info(items.length === 1
63
+ ? `${logger.bold(items[0])}: ${rel} differs from registry`
64
+ : `${rel} differs from every item that writes it (${items.join(', ')})`);
65
+ changed++;
66
+ }
67
+
68
+ if (changed === 0) logger.success('All local components and blocks match the registry.');
55
69
  else logger.info(`\n${changed} file${changed === 1 ? '' : 's'} differ. Re-add with ${logger.cyan('npx @webjsdev/ui add <name> -o')} to overwrite.`);
56
70
  });
@@ -3,6 +3,8 @@ import { existsSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { getConfig } from '../utils/get-config.js';
5
5
  import { DEFAULT_REGISTRY_URL } from '../registry/fetcher.js';
6
+ import { loadRegistryIndex } from '../registry/local.js';
7
+ import { itemKind } from '../registry/extract.js';
6
8
  import { logger } from '../utils/logger.js';
7
9
 
8
10
  export const info = new Command()
@@ -15,6 +17,11 @@ export const info = new Command()
15
17
 
16
18
  logger.info(`${logger.bold('cwd')} ${cwd}`);
17
19
  logger.info(`${logger.bold('Registry')} ${DEFAULT_REGISTRY_URL}`);
20
+ // What the installed kit ships (the packaged registry `add` reads), with
21
+ // the blocks and charts counted beside the components (D18).
22
+ const kinds = loadRegistryIndex().map(itemKind);
23
+ const count = (k) => kinds.filter((x) => x === k).length;
24
+ logger.info(`${logger.bold('Kit')} ${count('ui')} components, ${count('block')} blocks, ${count('chart')} charts`);
18
25
  logger.info(`${logger.bold('Config')} ${config ? 'components.json ✔' : 'components.json ✖ (run `npx @webjsdev/ui init`)'}`);
19
26
  if (config) {
20
27
  logger.info(`${logger.bold('Base color')} ${config.tailwind.baseColor}`);