makersclaw 0.2.0 → 0.3.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 (473) hide show
  1. package/THIRD-PARTY-NOTICES.md +180 -0
  2. package/package.json +3 -2
  3. package/r/annotate.json +62 -0
  4. package/r/approval-request.json +52 -0
  5. package/r/audio-player.json +74 -0
  6. package/r/auth-form.json +55 -0
  7. package/r/board.json +10 -6
  8. package/r/calendar-view.json +105 -0
  9. package/r/cart.json +62 -0
  10. package/r/chart.json +83 -0
  11. package/r/chat.json +95 -0
  12. package/r/code-editor.json +94 -0
  13. package/r/comment-box.json +64 -0
  14. package/r/contact-section.json +53 -0
  15. package/r/core.json +205 -8
  16. package/r/csv-import.json +63 -0
  17. package/r/data-table.json +69 -0
  18. package/r/diagram.json +74 -0
  19. package/r/doc-editor.json +82 -0
  20. package/r/doc-page.json +61 -0
  21. package/r/email-render.json +73 -0
  22. package/r/faq.json +50 -0
  23. package/r/file-upload.json +54 -0
  24. package/r/flow-canvas.json +93 -0
  25. package/r/footer.json +52 -0
  26. package/r/gantt.json +70 -0
  27. package/r/job-panel.json +12 -7
  28. package/r/json-editor.json +66 -0
  29. package/r/map.json +89 -0
  30. package/r/menubar.json +52 -0
  31. package/r/mind-map.json +67 -0
  32. package/r/navigation-menu.json +52 -0
  33. package/r/order-detail.json +54 -0
  34. package/r/org-chart.json +66 -0
  35. package/r/page-builder.json +105 -0
  36. package/r/payment-methods.json +51 -0
  37. package/r/pdf-document.json +79 -0
  38. package/r/pdf-viewer.json +88 -0
  39. package/r/product-detail.json +76 -0
  40. package/r/product-grid.json +65 -0
  41. package/r/record-form.json +67 -0
  42. package/r/record-notes.json +55 -0
  43. package/r/registry.json +3411 -29
  44. package/r/search-dialog.json +51 -0
  45. package/r/settings-list.json +66 -0
  46. package/r/setup-checklist.json +51 -0
  47. package/r/share-dialog.json +52 -0
  48. package/r/sidebar.json +69 -0
  49. package/r/signature-pad.json +72 -0
  50. package/r/sketch-canvas.json +99 -0
  51. package/r/spreadsheet.json +90 -0
  52. package/r/stat-cards.json +66 -0
  53. package/r/task-list.json +63 -0
  54. package/r/task-model.json +98 -0
  55. package/r/testimonials.json +52 -0
  56. package/r/transaction-list.json +53 -0
  57. package/r/whiteboard.json +66 -0
  58. package/registry/blocks/annotate/README.md +179 -0
  59. package/registry/blocks/annotate/annotate-data.js +250 -0
  60. package/registry/blocks/annotate/annotate.jsx +646 -0
  61. package/registry/blocks/annotate/block.json +10 -0
  62. package/registry/blocks/annotate/demo.jsx +135 -0
  63. package/registry/blocks/annotate/index.js +15 -0
  64. package/registry/blocks/approval-request/README.md +116 -0
  65. package/registry/blocks/approval-request/approval-request.jsx +386 -0
  66. package/registry/blocks/approval-request/block.json +10 -0
  67. package/registry/blocks/approval-request/demo.jsx +127 -0
  68. package/registry/blocks/approval-request/index.js +4 -0
  69. package/registry/blocks/audio-player/README.md +167 -0
  70. package/registry/blocks/audio-player/audio-player.jsx +623 -0
  71. package/registry/blocks/audio-player/block.json +14 -0
  72. package/registry/blocks/audio-player/colors.js +109 -0
  73. package/registry/blocks/audio-player/demo.jsx +209 -0
  74. package/registry/blocks/audio-player/index.js +6 -0
  75. package/registry/blocks/audio-player/time.js +67 -0
  76. package/registry/blocks/audio-player/wavesurfer.js +9 -0
  77. package/registry/blocks/auth-form/README.md +126 -0
  78. package/registry/blocks/auth-form/auth-form.jsx +568 -0
  79. package/registry/blocks/auth-form/block.json +10 -0
  80. package/registry/blocks/auth-form/demo.jsx +131 -0
  81. package/registry/blocks/auth-form/index.js +3 -0
  82. package/registry/blocks/board/README.md +55 -5
  83. package/registry/blocks/board/block.json +2 -2
  84. package/registry/blocks/board/board.jsx +230 -86
  85. package/registry/blocks/board/demo.jsx +103 -24
  86. package/registry/blocks/calendar-view/README.md +180 -0
  87. package/registry/blocks/calendar-view/agenda.jsx +147 -0
  88. package/registry/blocks/calendar-view/block.json +76 -0
  89. package/registry/blocks/calendar-view/calendar-model.js +442 -0
  90. package/registry/blocks/calendar-view/calendar.jsx +627 -0
  91. package/registry/blocks/calendar-view/demo.jsx +195 -0
  92. package/registry/blocks/calendar-view/draft.jsx +49 -0
  93. package/registry/blocks/calendar-view/index.js +39 -0
  94. package/registry/blocks/calendar-view/month.jsx +346 -0
  95. package/registry/blocks/calendar-view/paint.js +69 -0
  96. package/registry/blocks/calendar-view/time-grid.jsx +527 -0
  97. package/registry/blocks/calendar-view/tray.jsx +87 -0
  98. package/registry/blocks/cart/README.md +146 -0
  99. package/registry/blocks/cart/block.json +10 -0
  100. package/registry/blocks/cart/cart.jsx +597 -0
  101. package/registry/blocks/cart/demo.jsx +98 -0
  102. package/registry/blocks/cart/index.js +4 -0
  103. package/registry/blocks/cart/money.js +28 -0
  104. package/registry/blocks/chart/README.md +316 -0
  105. package/registry/blocks/chart/block.json +10 -0
  106. package/registry/blocks/chart/cartesian.jsx +642 -0
  107. package/registry/blocks/chart/core.jsx +262 -0
  108. package/registry/blocks/chart/demo.jsx +357 -0
  109. package/registry/blocks/chart/heatmap.jsx +336 -0
  110. package/registry/blocks/chart/index.js +8 -0
  111. package/registry/blocks/chart/pie.jsx +245 -0
  112. package/registry/blocks/chart/sparkline.jsx +88 -0
  113. package/registry/blocks/chat/README.md +273 -0
  114. package/registry/blocks/chat/attachment.jsx +95 -0
  115. package/registry/blocks/chat/block.json +10 -0
  116. package/registry/blocks/chat/chat.jsx +132 -0
  117. package/registry/blocks/chat/composer.jsx +364 -0
  118. package/registry/blocks/chat/demo.jsx +578 -0
  119. package/registry/blocks/chat/header.jsx +34 -0
  120. package/registry/blocks/chat/index.js +9 -0
  121. package/registry/blocks/chat/message.jsx +450 -0
  122. package/registry/blocks/chat/scroller.jsx +247 -0
  123. package/registry/blocks/chat/text.jsx +104 -0
  124. package/registry/blocks/code-editor/README.md +210 -0
  125. package/registry/blocks/code-editor/block.json +22 -0
  126. package/registry/blocks/code-editor/code-editor.jsx +534 -0
  127. package/registry/blocks/code-editor/codemirror.js +38 -0
  128. package/registry/blocks/code-editor/demo.jsx +205 -0
  129. package/registry/blocks/code-editor/index.js +8 -0
  130. package/registry/blocks/code-editor/json.js +317 -0
  131. package/registry/blocks/code-editor/sql.js +136 -0
  132. package/registry/blocks/code-editor/text.js +101 -0
  133. package/registry/blocks/code-editor/theme.js +186 -0
  134. package/registry/blocks/comment-box/README.md +123 -0
  135. package/registry/blocks/comment-box/block.json +10 -0
  136. package/registry/blocks/comment-box/comment-body.jsx +217 -0
  137. package/registry/blocks/comment-box/comment-box.jsx +198 -0
  138. package/registry/blocks/comment-box/comment-time.jsx +77 -0
  139. package/registry/blocks/comment-box/demo.jsx +141 -0
  140. package/registry/blocks/comment-box/index.js +8 -0
  141. package/registry/blocks/contact-section/README.md +152 -0
  142. package/registry/blocks/contact-section/block.json +11 -0
  143. package/registry/blocks/contact-section/contact-section.jsx +509 -0
  144. package/registry/blocks/contact-section/demo.jsx +93 -0
  145. package/registry/blocks/contact-section/index.js +4 -0
  146. package/registry/blocks/csv-import/README.md +133 -0
  147. package/registry/blocks/csv-import/block.json +13 -0
  148. package/registry/blocks/csv-import/csv-import.jsx +479 -0
  149. package/registry/blocks/csv-import/demo.jsx +106 -0
  150. package/registry/blocks/csv-import/import.js +200 -0
  151. package/registry/blocks/csv-import/index.js +7 -0
  152. package/registry/blocks/data-table/README.md +386 -0
  153. package/registry/blocks/data-table/block.json +10 -0
  154. package/registry/blocks/data-table/data-table.jsx +1164 -0
  155. package/registry/blocks/data-table/demo.jsx +588 -0
  156. package/registry/blocks/data-table/index.js +5 -0
  157. package/registry/blocks/data-table/model.js +169 -0
  158. package/registry/blocks/diagram/README.md +108 -0
  159. package/registry/blocks/diagram/block.json +13 -0
  160. package/registry/blocks/diagram/demo.jsx +113 -0
  161. package/registry/blocks/diagram/diagram.jsx +481 -0
  162. package/registry/blocks/diagram/index.js +7 -0
  163. package/registry/blocks/diagram/mermaid.js +52 -0
  164. package/registry/blocks/diagram/palette.js +313 -0
  165. package/registry/blocks/diagram/source.js +98 -0
  166. package/registry/blocks/doc-editor/README.md +215 -0
  167. package/registry/blocks/doc-editor/block.json +15 -0
  168. package/registry/blocks/doc-editor/demo.jsx +225 -0
  169. package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
  170. package/registry/blocks/doc-editor/doc.js +309 -0
  171. package/registry/blocks/doc-editor/index.js +7 -0
  172. package/registry/blocks/doc-editor/schema.jsx +56 -0
  173. package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
  174. package/registry/blocks/doc-editor/theme.js +82 -0
  175. package/registry/blocks/doc-page/README.md +119 -0
  176. package/registry/blocks/doc-page/autosave.js +104 -0
  177. package/registry/blocks/doc-page/block.json +10 -0
  178. package/registry/blocks/doc-page/demo.jsx +137 -0
  179. package/registry/blocks/doc-page/doc-page.jsx +276 -0
  180. package/registry/blocks/doc-page/index.js +4 -0
  181. package/registry/blocks/email-render/README.md +151 -0
  182. package/registry/blocks/email-render/block.json +14 -0
  183. package/registry/blocks/email-render/demo.jsx +153 -0
  184. package/registry/blocks/email-render/doc-email.jsx +210 -0
  185. package/registry/blocks/email-render/email.jsx +221 -0
  186. package/registry/blocks/email-render/index.js +10 -0
  187. package/registry/blocks/email-render/render.js +50 -0
  188. package/registry/blocks/email-render/theme.js +215 -0
  189. package/registry/blocks/faq/README.md +101 -0
  190. package/registry/blocks/faq/block.json +11 -0
  191. package/registry/blocks/faq/demo.jsx +89 -0
  192. package/registry/blocks/faq/faq.jsx +220 -0
  193. package/registry/blocks/faq/index.js +4 -0
  194. package/registry/blocks/file-upload/README.md +138 -0
  195. package/registry/blocks/file-upload/block.json +10 -0
  196. package/registry/blocks/file-upload/demo.jsx +204 -0
  197. package/registry/blocks/file-upload/file-upload.jsx +635 -0
  198. package/registry/blocks/file-upload/index.js +4 -0
  199. package/registry/blocks/flow-canvas/README.md +420 -0
  200. package/registry/blocks/flow-canvas/block.json +13 -0
  201. package/registry/blocks/flow-canvas/board.js +819 -0
  202. package/registry/blocks/flow-canvas/chrome.jsx +649 -0
  203. package/registry/blocks/flow-canvas/context.jsx +35 -0
  204. package/registry/blocks/flow-canvas/demo.jsx +249 -0
  205. package/registry/blocks/flow-canvas/edges.jsx +107 -0
  206. package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
  207. package/registry/blocks/flow-canvas/index.js +41 -0
  208. package/registry/blocks/flow-canvas/nodes.jsx +392 -0
  209. package/registry/blocks/flow-canvas/theme.js +174 -0
  210. package/registry/blocks/footer/README.md +133 -0
  211. package/registry/blocks/footer/block.json +11 -0
  212. package/registry/blocks/footer/demo.jsx +119 -0
  213. package/registry/blocks/footer/footer.jsx +406 -0
  214. package/registry/blocks/footer/index.js +4 -0
  215. package/registry/blocks/gantt/README.md +220 -0
  216. package/registry/blocks/gantt/block.json +10 -0
  217. package/registry/blocks/gantt/demo.jsx +148 -0
  218. package/registry/blocks/gantt/gantt.jsx +923 -0
  219. package/registry/blocks/gantt/index.js +7 -0
  220. package/registry/blocks/gantt/rows.jsx +468 -0
  221. package/registry/blocks/gantt/schedule.js +278 -0
  222. package/registry/blocks/job-panel/README.md +80 -0
  223. package/registry/blocks/job-panel/block.json +3 -3
  224. package/registry/blocks/job-panel/demo.jsx +230 -3
  225. package/registry/blocks/job-panel/job-panel.jsx +169 -3
  226. package/registry/blocks/json-editor/README.md +133 -0
  227. package/registry/blocks/json-editor/block.json +10 -0
  228. package/registry/blocks/json-editor/demo.jsx +92 -0
  229. package/registry/blocks/json-editor/index.js +7 -0
  230. package/registry/blocks/json-editor/json-editor.jsx +305 -0
  231. package/registry/blocks/json-editor/json-tree.jsx +393 -0
  232. package/registry/blocks/json-editor/tree.js +225 -0
  233. package/registry/blocks/map/README.md +221 -0
  234. package/registry/blocks/map/block.json +14 -0
  235. package/registry/blocks/map/demo.jsx +201 -0
  236. package/registry/blocks/map/geo.js +198 -0
  237. package/registry/blocks/map/index.js +8 -0
  238. package/registry/blocks/map/list.jsx +128 -0
  239. package/registry/blocks/map/map-view.jsx +715 -0
  240. package/registry/blocks/map/maplibre.js +30 -0
  241. package/registry/blocks/map/marks.jsx +146 -0
  242. package/registry/blocks/map/theme.js +142 -0
  243. package/registry/blocks/menubar/README.md +109 -0
  244. package/registry/blocks/menubar/block.json +10 -0
  245. package/registry/blocks/menubar/demo.jsx +128 -0
  246. package/registry/blocks/menubar/index.js +4 -0
  247. package/registry/blocks/menubar/menubar.jsx +199 -0
  248. package/registry/blocks/mind-map/README.md +206 -0
  249. package/registry/blocks/mind-map/block.json +10 -0
  250. package/registry/blocks/mind-map/demo.jsx +103 -0
  251. package/registry/blocks/mind-map/index.js +31 -0
  252. package/registry/blocks/mind-map/mind-map.jsx +1125 -0
  253. package/registry/blocks/mind-map/topic.jsx +143 -0
  254. package/registry/blocks/mind-map/tree.js +645 -0
  255. package/registry/blocks/navigation-menu/README.md +124 -0
  256. package/registry/blocks/navigation-menu/block.json +10 -0
  257. package/registry/blocks/navigation-menu/demo.jsx +84 -0
  258. package/registry/blocks/navigation-menu/index.js +4 -0
  259. package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
  260. package/registry/blocks/order-detail/README.md +109 -0
  261. package/registry/blocks/order-detail/block.json +10 -0
  262. package/registry/blocks/order-detail/demo.jsx +88 -0
  263. package/registry/blocks/order-detail/index.js +4 -0
  264. package/registry/blocks/order-detail/order-detail.jsx +354 -0
  265. package/registry/blocks/org-chart/README.md +145 -0
  266. package/registry/blocks/org-chart/block.json +10 -0
  267. package/registry/blocks/org-chart/demo.jsx +94 -0
  268. package/registry/blocks/org-chart/index.js +7 -0
  269. package/registry/blocks/org-chart/org-chart.jsx +631 -0
  270. package/registry/blocks/org-chart/org.js +245 -0
  271. package/registry/blocks/org-chart/person.jsx +96 -0
  272. package/registry/blocks/page-builder/README.md +257 -0
  273. package/registry/blocks/page-builder/block.json +14 -0
  274. package/registry/blocks/page-builder/demo.jsx +145 -0
  275. package/registry/blocks/page-builder/grapes.js +18 -0
  276. package/registry/blocks/page-builder/index.js +11 -0
  277. package/registry/blocks/page-builder/page-builder.jsx +704 -0
  278. package/registry/blocks/page-builder/page-view.jsx +33 -0
  279. package/registry/blocks/page-builder/page.js +118 -0
  280. package/registry/blocks/page-builder/panels.jsx +588 -0
  281. package/registry/blocks/page-builder/sections.js +209 -0
  282. package/registry/blocks/page-builder/theme.js +87 -0
  283. package/registry/blocks/page-builder/thumbs.jsx +189 -0
  284. package/registry/blocks/page-builder/tokens.js +329 -0
  285. package/registry/blocks/payment-methods/README.md +104 -0
  286. package/registry/blocks/payment-methods/block.json +10 -0
  287. package/registry/blocks/payment-methods/demo.jsx +71 -0
  288. package/registry/blocks/payment-methods/index.js +4 -0
  289. package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
  290. package/registry/blocks/pdf-document/README.md +213 -0
  291. package/registry/blocks/pdf-document/block.json +13 -0
  292. package/registry/blocks/pdf-document/demo.jsx +136 -0
  293. package/registry/blocks/pdf-document/index.js +33 -0
  294. package/registry/blocks/pdf-document/money.js +83 -0
  295. package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
  296. package/registry/blocks/pdf-document/primitives.jsx +271 -0
  297. package/registry/blocks/pdf-document/quote.jsx +179 -0
  298. package/registry/blocks/pdf-document/theme.js +193 -0
  299. package/registry/blocks/pdf-viewer/README.md +191 -0
  300. package/registry/blocks/pdf-viewer/block.json +14 -0
  301. package/registry/blocks/pdf-viewer/demo.jsx +252 -0
  302. package/registry/blocks/pdf-viewer/helpers.js +270 -0
  303. package/registry/blocks/pdf-viewer/index.js +8 -0
  304. package/registry/blocks/pdf-viewer/notes.jsx +195 -0
  305. package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
  306. package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
  307. package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
  308. package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
  309. package/registry/blocks/product-detail/README.md +217 -0
  310. package/registry/blocks/product-detail/block.json +10 -0
  311. package/registry/blocks/product-detail/demo.jsx +233 -0
  312. package/registry/blocks/product-detail/index.js +7 -0
  313. package/registry/blocks/product-detail/price.jsx +115 -0
  314. package/registry/blocks/product-detail/product-detail.jsx +348 -0
  315. package/registry/blocks/product-detail/product-media.jsx +102 -0
  316. package/registry/blocks/product-detail/product-options.jsx +144 -0
  317. package/registry/blocks/product-grid/README.md +162 -0
  318. package/registry/blocks/product-grid/block.json +10 -0
  319. package/registry/blocks/product-grid/demo.jsx +255 -0
  320. package/registry/blocks/product-grid/index.js +5 -0
  321. package/registry/blocks/product-grid/product-card.jsx +232 -0
  322. package/registry/blocks/product-grid/product-grid.jsx +235 -0
  323. package/registry/blocks/record-form/README.md +196 -0
  324. package/registry/blocks/record-form/block.json +10 -0
  325. package/registry/blocks/record-form/demo.jsx +525 -0
  326. package/registry/blocks/record-form/index.js +4 -0
  327. package/registry/blocks/record-form/record-fields.jsx +457 -0
  328. package/registry/blocks/record-form/record-form.jsx +415 -0
  329. package/registry/blocks/record-form/rules.js +81 -0
  330. package/registry/blocks/record-notes/README.md +139 -0
  331. package/registry/blocks/record-notes/block.json +10 -0
  332. package/registry/blocks/record-notes/demo.jsx +179 -0
  333. package/registry/blocks/record-notes/index.js +4 -0
  334. package/registry/blocks/record-notes/record-notes.jsx +266 -0
  335. package/registry/blocks/search-dialog/README.md +108 -0
  336. package/registry/blocks/search-dialog/block.json +10 -0
  337. package/registry/blocks/search-dialog/demo.jsx +116 -0
  338. package/registry/blocks/search-dialog/index.js +3 -0
  339. package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
  340. package/registry/blocks/settings-list/README.md +171 -0
  341. package/registry/blocks/settings-list/block.json +10 -0
  342. package/registry/blocks/settings-list/demo.jsx +333 -0
  343. package/registry/blocks/settings-list/index.js +4 -0
  344. package/registry/blocks/settings-list/row-state.jsx +93 -0
  345. package/registry/blocks/settings-list/settings-list.jsx +349 -0
  346. package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
  347. package/registry/blocks/setup-checklist/README.md +142 -0
  348. package/registry/blocks/setup-checklist/block.json +10 -0
  349. package/registry/blocks/setup-checklist/demo.jsx +159 -0
  350. package/registry/blocks/setup-checklist/index.js +4 -0
  351. package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
  352. package/registry/blocks/share-dialog/README.md +113 -0
  353. package/registry/blocks/share-dialog/block.json +10 -0
  354. package/registry/blocks/share-dialog/demo.jsx +140 -0
  355. package/registry/blocks/share-dialog/index.js +3 -0
  356. package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
  357. package/registry/blocks/sidebar/README.md +190 -0
  358. package/registry/blocks/sidebar/block.json +43 -0
  359. package/registry/blocks/sidebar/demo.jsx +577 -0
  360. package/registry/blocks/sidebar/index.js +4 -0
  361. package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
  362. package/registry/blocks/sidebar/sidebar.jsx +864 -0
  363. package/registry/blocks/signature-pad/README.md +137 -0
  364. package/registry/blocks/signature-pad/block.json +13 -0
  365. package/registry/blocks/signature-pad/colors.js +115 -0
  366. package/registry/blocks/signature-pad/demo.jsx +94 -0
  367. package/registry/blocks/signature-pad/index.js +6 -0
  368. package/registry/blocks/signature-pad/pad.js +7 -0
  369. package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
  370. package/registry/blocks/signature-pad/signature.js +68 -0
  371. package/registry/blocks/sketch-canvas/README.md +280 -0
  372. package/registry/blocks/sketch-canvas/block.json +13 -0
  373. package/registry/blocks/sketch-canvas/demo.jsx +159 -0
  374. package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
  375. package/registry/blocks/sketch-canvas/index.js +9 -0
  376. package/registry/blocks/sketch-canvas/palette.js +226 -0
  377. package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
  378. package/registry/blocks/sketch-canvas/sketch.js +179 -0
  379. package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
  380. package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
  381. package/registry/blocks/sketch-canvas/stamps.js +104 -0
  382. package/registry/blocks/sketch-canvas/theme.js +131 -0
  383. package/registry/blocks/spreadsheet/README.md +307 -0
  384. package/registry/blocks/spreadsheet/block.json +13 -0
  385. package/registry/blocks/spreadsheet/cells.jsx +455 -0
  386. package/registry/blocks/spreadsheet/chrome.jsx +325 -0
  387. package/registry/blocks/spreadsheet/demo.jsx +177 -0
  388. package/registry/blocks/spreadsheet/grid.js +387 -0
  389. package/registry/blocks/spreadsheet/index.js +34 -0
  390. package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
  391. package/registry/blocks/spreadsheet/types.js +473 -0
  392. package/registry/blocks/stat-cards/README.md +173 -0
  393. package/registry/blocks/stat-cards/block.json +10 -0
  394. package/registry/blocks/stat-cards/demo.jsx +257 -0
  395. package/registry/blocks/stat-cards/index.js +4 -0
  396. package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
  397. package/registry/blocks/stat-cards/usage.jsx +243 -0
  398. package/registry/blocks/task-list/README.md +176 -0
  399. package/registry/blocks/task-list/block.json +10 -0
  400. package/registry/blocks/task-list/demo.jsx +134 -0
  401. package/registry/blocks/task-list/index.js +5 -0
  402. package/registry/blocks/task-list/task-list.jsx +907 -0
  403. package/registry/blocks/task-model/README.md +455 -0
  404. package/registry/blocks/task-model/block.json +167 -0
  405. package/registry/blocks/task-model/changes.js +89 -0
  406. package/registry/blocks/task-model/dates.js +371 -0
  407. package/registry/blocks/task-model/demo.jsx +215 -0
  408. package/registry/blocks/task-model/dnd.jsx +240 -0
  409. package/registry/blocks/task-model/index.js +97 -0
  410. package/registry/blocks/task-model/model.js +919 -0
  411. package/registry/blocks/task-model/parts.jsx +449 -0
  412. package/registry/blocks/task-model/toolbar.jsx +271 -0
  413. package/registry/blocks/testimonials/README.md +139 -0
  414. package/registry/blocks/testimonials/block.json +11 -0
  415. package/registry/blocks/testimonials/demo.jsx +137 -0
  416. package/registry/blocks/testimonials/index.js +4 -0
  417. package/registry/blocks/testimonials/testimonials.jsx +430 -0
  418. package/registry/blocks/transaction-list/README.md +126 -0
  419. package/registry/blocks/transaction-list/block.json +10 -0
  420. package/registry/blocks/transaction-list/demo.jsx +79 -0
  421. package/registry/blocks/transaction-list/index.js +4 -0
  422. package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
  423. package/registry/blocks/whiteboard/README.md +179 -0
  424. package/registry/blocks/whiteboard/block.json +10 -0
  425. package/registry/blocks/whiteboard/demo.jsx +169 -0
  426. package/registry/blocks/whiteboard/index.js +6 -0
  427. package/registry/blocks/whiteboard/templates.js +150 -0
  428. package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
  429. package/src/install.mjs +18 -0
  430. package/src/shadcn.mjs +8 -0
  431. package/templates/next/files/README.md +145 -11
  432. package/templates/next/files/app/globals.css +55 -4
  433. package/templates/next/files/check/run.mjs +3 -3
  434. package/templates/next/files/components/ui/avatar.jsx +141 -0
  435. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  436. package/templates/next/files/components/ui/button-group.jsx +70 -0
  437. package/templates/next/files/components/ui/button.jsx +132 -12
  438. package/templates/next/files/components/ui/calendar.jsx +609 -0
  439. package/templates/next/files/components/ui/carousel.jsx +281 -0
  440. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  441. package/templates/next/files/components/ui/combobox.jsx +608 -0
  442. package/templates/next/files/components/ui/command.jsx +577 -0
  443. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  444. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  445. package/templates/next/files/components/ui/distribution.jsx +117 -0
  446. package/templates/next/files/components/ui/feedback.jsx +143 -0
  447. package/templates/next/files/components/ui/field.jsx +115 -3
  448. package/templates/next/files/components/ui/file-input.jsx +234 -0
  449. package/templates/next/files/components/ui/icon.jsx +130 -8
  450. package/templates/next/files/components/ui/image.jsx +143 -0
  451. package/templates/next/files/components/ui/index.js +47 -2
  452. package/templates/next/files/components/ui/input-group.jsx +213 -0
  453. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  454. package/templates/next/files/components/ui/item.jsx +206 -0
  455. package/templates/next/files/components/ui/menu.jsx +454 -82
  456. package/templates/next/files/components/ui/notice.jsx +126 -14
  457. package/templates/next/files/components/ui/pagination.jsx +156 -0
  458. package/templates/next/files/components/ui/popover.jsx +284 -0
  459. package/templates/next/files/components/ui/radio.jsx +193 -0
  460. package/templates/next/files/components/ui/rating.jsx +131 -0
  461. package/templates/next/files/components/ui/resizable.jsx +338 -0
  462. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  463. package/templates/next/files/components/ui/separator.jsx +119 -0
  464. package/templates/next/files/components/ui/sheet.jsx +96 -11
  465. package/templates/next/files/components/ui/slider.jsx +174 -0
  466. package/templates/next/files/components/ui/stat.jsx +574 -0
  467. package/templates/next/files/components/ui/steps.jsx +338 -0
  468. package/templates/next/files/components/ui/swatch.jsx +33 -0
  469. package/templates/next/files/components/ui/table.jsx +130 -0
  470. package/templates/next/files/components/ui/toast.jsx +440 -0
  471. package/templates/next/files/components/ui/toggle.jsx +195 -0
  472. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  473. package/templates/next/template.json +264 -8
@@ -0,0 +1,574 @@
1
+ import { Children } from "react";
2
+ import { cx } from "./cx";
3
+ import { Icon } from "./icon";
4
+
5
+ // Numbers at a glance: a Stat, the strip of them, the signed change beside
6
+ // one, a status dot, a legend of dots, a meter against a limit.
7
+ // Server-safe (no hooks), so a server surface can use them directly.
8
+ // Every number is tabular (data-nums), so a column of them lines up and a
9
+ // ticking value does not shake. Colour is the signal: tones are named, as
10
+ // Badge does it, and status tones are for status only — never decoration.
11
+ // A dot can take a categorical `hue` (1..5, the chart colours) instead, for
12
+ // KINDS of things: a platform, a content type. Tone is status, hue is
13
+ // category; a tone given with a hue wins.
14
+ // Blocks use these and never draw their own.
15
+
16
+ // The text colour of a value in each tone.
17
+ const TEXT_TONES = {
18
+ neutral: "text-foreground",
19
+ muted: "text-muted-foreground",
20
+ primary: "text-primary",
21
+ success: "text-success",
22
+ warning: "text-warning",
23
+ danger: "text-destructive",
24
+ info: "text-info",
25
+ };
26
+
27
+ // The fill of a dot or a bar in each tone. neutral is a quiet grey for a
28
+ // dot; a Meter's neutral bar is bg-primary, the same as Progress, and its
29
+ // muted bar is the grey.
30
+ const FILL_TONES = {
31
+ neutral: "bg-muted-foreground",
32
+ muted: "bg-muted-foreground",
33
+ primary: "bg-primary",
34
+ success: "bg-success",
35
+ warning: "bg-warning",
36
+ danger: "bg-destructive",
37
+ info: "bg-info",
38
+ };
39
+
40
+ // The fill of a dot in each categorical hue (--color-chart-N).
41
+ const HUE_FILLS = { 1: "bg-chart-1", 2: "bg-chart-2", 3: "bg-chart-3", 4: "bg-chart-4", 5: "bg-chart-5" };
42
+
43
+ const EN = "en-US"; // one locale on the server and the client: no hydration drift
44
+ const formatNumber = (n) => (typeof n === "number" ? n.toLocaleString(EN, { maximumFractionDigits: 2 }) : String(n ?? ""));
45
+
46
+ /* ------------------------------------------------------------------------
47
+ Delta
48
+ ------------------------------------------------------------------------ */
49
+
50
+ const DELTA_SIZES = { sm: { text: "text-xs", icon: 12 }, md: { text: "text-sm", icon: 14 } };
51
+
52
+ /**
53
+ * A signed change: an arrow, the value with its sign, an optional suffix —
54
+ * "↑ +12.4%". Up is good (success) and down is bad (danger) unless
55
+ * `invert`, for "lower is better" (latency, churn, cost). Zero is neutral,
56
+ * with a flat dash and no sign.
57
+ *
58
+ * value the change, a number; its sign sets the arrow and the tone
59
+ * display what to show for the size of it instead of the number
60
+ * ("$35K"); the sign is still added. Default the number, to at
61
+ * most one decimal
62
+ * suffix after the number: "%", " pts", "ms"
63
+ * invert lower is better: down turns success, up turns danger
64
+ * label a muted line after it: "vs last week"
65
+ * size sm (text-xs) · md (text-sm)
66
+ * variant text (bare) · badge (a tinted pill, for a table cell or a tile corner)
67
+ * arrow default true; false for the bare "+$35K" of a dense row
68
+ * hideValue the arrow and its tone alone (a trend in a tight cell);
69
+ * the value is still what a screen reader hears. Always draws
70
+ * the arrow, whatever `arrow` says
71
+ */
72
+ export function Delta({ value, display, suffix = "", invert = false, label, size = "sm", variant = "text", arrow = true, hideValue = false, className }) {
73
+ const n = typeof value === "number" && Number.isFinite(value) ? value : 0;
74
+ const sign = n > 0 ? 1 : n < 0 ? -1 : 0;
75
+ const good = invert ? sign < 0 : sign > 0;
76
+ const tone = sign === 0 ? "neutral" : good ? "success" : "danger";
77
+ const s = DELTA_SIZES[size] ?? DELTA_SIZES.sm;
78
+ const amount = display ?? Math.abs(n).toLocaleString(EN, { maximumFractionDigits: 1 });
79
+ const signed = `${sign > 0 ? "+" : sign < 0 ? "−" : ""}${amount}${suffix}`;
80
+ const look =
81
+ variant === "badge"
82
+ ? {
83
+ neutral: "bg-muted text-muted-foreground",
84
+ success: "bg-success/15 text-success",
85
+ danger: "bg-destructive/15 text-destructive",
86
+ }[tone]
87
+ : { neutral: "text-muted-foreground", success: "text-success", danger: "text-destructive" }[tone];
88
+ return (
89
+ <span className={cx("inline-flex items-baseline gap-1.5", s.text, className)}>
90
+ <span
91
+ data-nums
92
+ className={cx(
93
+ "inline-flex items-center gap-0.5 whitespace-nowrap font-medium",
94
+ variant === "badge" && "rounded-sm px-1.5 py-0.5",
95
+ look,
96
+ )}
97
+ >
98
+ {arrow || hideValue ? <Icon name={sign > 0 ? "arrow-up" : sign < 0 ? "arrow-down" : "minus"} size={s.icon} className="self-center" /> : null}
99
+ {/* The sign is a real minus (U+2212) on screen; a reader hears the word. */}
100
+ {hideValue ? null : <span aria-hidden="true">{signed}</span>}
101
+ <span className="sr-only">{sign > 0 ? `up ${amount}${suffix}` : sign < 0 ? `down ${amount}${suffix}` : `no change`}</span>
102
+ </span>
103
+ {label ? <span className="text-muted-foreground">{label}</span> : null}
104
+ </span>
105
+ );
106
+ }
107
+
108
+ /* ------------------------------------------------------------------------
109
+ StatusDot and Legend
110
+ ------------------------------------------------------------------------ */
111
+
112
+ const DOT_SIZES = { sm: "size-1.5", md: "size-2" };
113
+
114
+ /**
115
+ * A small round dot in a tone: a row's state, a service's health, a
116
+ * legend key. The dot alone says nothing to a screen reader — the meaning
117
+ * is in `label` (shown), or in `label` + `hideLabel` (read, not shown), or
118
+ * in the text beside it.
119
+ *
120
+ * tone neutral · primary · success · warning · danger · info
121
+ * hue 1..5 — a categorical colour instead (a kind of thing, not
122
+ * a state); ignored when a tone is given
123
+ * size sm (6px, in a dense row) · md (8px)
124
+ * pulse a ring that breathes out, for something live right now
125
+ * (deploying, recording); still under prefers-reduced-motion
126
+ * label the words after it: "Healthy", "3 alerts"
127
+ * hideLabel keep the label for readers only
128
+ */
129
+ export function StatusDot({ tone, hue, size = "md", pulse = false, label, hideLabel = false, className }) {
130
+ const fill = tone == null && HUE_FILLS[hue] ? HUE_FILLS[hue] : FILL_TONES[tone ?? "neutral"] ?? FILL_TONES.neutral;
131
+ const dot = (
132
+ <span aria-hidden="true" className={cx("relative inline-flex shrink-0", DOT_SIZES[size] ?? DOT_SIZES.md)}>
133
+ {pulse ? <span className={cx("absolute inset-0 rounded-full opacity-60 animate-ping motion-reduce:hidden", fill)} /> : null}
134
+ <span className={cx("relative inline-flex size-full rounded-full", fill)} />
135
+ </span>
136
+ );
137
+ if (!label) return <span className={cx("inline-flex items-center", className)}>{dot}</span>;
138
+ return (
139
+ <span className={cx("inline-flex items-center gap-1.5 text-sm text-muted-foreground", className)}>
140
+ {dot}
141
+ <span className={hideLabel ? "sr-only" : "min-w-0 truncate"}>{label}</span>
142
+ </span>
143
+ );
144
+ }
145
+
146
+ /**
147
+ * A row of dot · count · label, wrapping when it runs out of room — "● 2
148
+ * overdue · ● 3 urgent". The key under a chart, the summary in a card
149
+ * header. A list, so a reader hears how many kinds there are.
150
+ *
151
+ * items [{ tone, label, count }] — count optional; an item with count 0
152
+ * is still drawn (say it, or leave it out of items). `hue` (1..5)
153
+ * in place of `tone` for a key of categories
154
+ * size sm (text-xs, 6px dots) · md (text-sm, 8px dots)
155
+ * label the list's name for readers: "Tasks by state"
156
+ */
157
+ export function Legend({ items = [], size = "md", label, className }) {
158
+ if (!items.length) return null;
159
+ return (
160
+ <ul
161
+ aria-label={label}
162
+ className={cx("flex flex-wrap items-center gap-x-3 gap-y-1", size === "sm" ? "text-xs" : "text-sm", className)}
163
+ >
164
+ {items.map((it, i) => (
165
+ <li key={it.key ?? `${it.label}-${i}`} className="inline-flex items-center gap-1.5 text-muted-foreground">
166
+ <StatusDot tone={it.tone} hue={it.hue} size={size === "sm" ? "sm" : "md"} />
167
+ {it.count != null ? (
168
+ <span data-nums className="font-medium text-foreground">
169
+ {formatNumber(it.count)}
170
+ </span>
171
+ ) : null}
172
+ <span>{it.label}</span>
173
+ </li>
174
+ ))}
175
+ </ul>
176
+ );
177
+ }
178
+
179
+ /* ------------------------------------------------------------------------
180
+ Stat and StatGroup
181
+ ------------------------------------------------------------------------ */
182
+
183
+ const STAT_SIZES = {
184
+ sm: { label: "text-xs", value: "text-lg font-semibold leading-tight", unit: "text-xs", icon: 14, delta: "sm" },
185
+ md: { label: "text-sm", value: "text-2xl font-semibold leading-tight tracking-tight", unit: "text-sm", icon: 16, delta: "sm" },
186
+ lg: { label: "text-sm", value: "font-display text-4xl font-semibold leading-none tracking-tight", unit: "text-base", icon: 18, delta: "md" },
187
+ };
188
+
189
+ /**
190
+ * One number with its name: "Hit rate 94.8%". The value is the loudest
191
+ * thing on it; everything else is muted.
192
+ *
193
+ * label what it counts: "Monthly revenue"
194
+ * value already formatted — "$1.37M", "42", "2.4/4" (a string or a
195
+ * number; a number gets thousands separators)
196
+ * unit after the value, smaller and muted: "ms", "%", "/ 10.3 TB"
197
+ * caption a muted line under it: "Unit + integration tests"
198
+ * tone colours the value, for a threshold state (a miss rate over
199
+ * budget is danger). neutral (default) · primary · success ·
200
+ * warning · danger · info
201
+ * dot a tone for a StatusDot before the label (the state of the
202
+ * thing, when the value itself stays neutral)
203
+ * icon an Icon name, muted, at the end of the label row
204
+ * delta the change beside the value: a number (a percent: 12.4 →
205
+ * "↑ +12.4%") or Delta's props ({ value, display, suffix, label })
206
+ * invert lower is better, passed to the Delta
207
+ * size sm (a dense strip) · md · lg (the one number a card is about)
208
+ * align start · end (a stat pinned to the right of a header)
209
+ */
210
+ export function Stat({ label, value, unit, caption, tone = "neutral", dot, icon, delta, invert, size = "md", align = "start", className }) {
211
+ const s = STAT_SIZES[size] ?? STAT_SIZES.md;
212
+ const d = delta == null ? null : typeof delta === "number" ? { value: delta, suffix: "%" } : delta;
213
+ return (
214
+ <div className={cx("min-w-0", align === "end" && "text-right", className)}>
215
+ {label || icon || dot ? (
216
+ <div className={cx("flex items-center gap-1.5 text-muted-foreground", s.label, align === "end" && "justify-end")}>
217
+ {dot ? <StatusDot tone={dot} size="sm" /> : null}
218
+ {label ? <span className="min-w-0 truncate">{label}</span> : null}
219
+ {icon ? <Icon name={icon} size={s.icon} className={cx("shrink-0", align !== "end" && "ml-auto")} /> : null}
220
+ </div>
221
+ ) : null}
222
+ <div className={cx("mt-1 flex flex-wrap items-baseline gap-x-2 gap-y-0.5", align === "end" && "justify-end")}>
223
+ <span className="inline-flex min-w-0 items-baseline gap-1">
224
+ <span data-nums className={cx(s.value, TEXT_TONES[tone] ?? TEXT_TONES.neutral)}>
225
+ {formatNumber(value)}
226
+ </span>
227
+ {unit ? (
228
+ <span data-nums className={cx("text-muted-foreground", s.unit)}>
229
+ {unit}
230
+ </span>
231
+ ) : null}
232
+ </span>
233
+ {d ? <Delta invert={invert} size={s.delta} {...d} /> : null}
234
+ </div>
235
+ {caption ? <p className="mt-1 text-xs text-muted-foreground">{caption}</p> : null}
236
+ </div>
237
+ );
238
+ }
239
+
240
+ // Literal class names, so Tailwind sees every one.
241
+ const COLS = { 1: "sm:grid-cols-1", 2: "sm:grid-cols-2", 3: "sm:grid-cols-3", 4: "sm:grid-cols-4" };
242
+ const SPAN_SM = { 1: "sm:col-span-1", 2: "sm:col-span-2", 3: "sm:col-span-3", 4: "sm:col-span-4" };
243
+
244
+ /**
245
+ * The strip of 2 to 4 Stats across the top of a card or a page. Two
246
+ * columns on a phone, all of them from sm up; a last cell that would
247
+ * leave a hole stretches to fill its row.
248
+ *
249
+ * variant card (default: bordered, a rule between every cell) ·
250
+ * divided (no box, a vertical rule between cells — for a strip
251
+ * already inside a Card) · bare (spacing only)
252
+ * columns from sm up; default the number of Stats (at most 4). Six
253
+ * stats in columns={3} make two rows
254
+ * label the strip's name for readers: "Cache summary"
255
+ * children the Stats
256
+ *
257
+ * Edge to edge inside a Card: variant="card" with className="rounded-none
258
+ * border-x-0" and the Card's padding taken off (-mx-4).
259
+ */
260
+ export function StatGroup({ variant = "card", columns, label, className, children }) {
261
+ const kids = Children.toArray(children).filter(Boolean);
262
+ const n = kids.length;
263
+ if (!n) return null;
264
+ const cols = Math.min(4, Math.max(1, columns ?? Math.min(n, 4)));
265
+ const phoneCols = Math.min(2, n);
266
+ const card = variant === "card";
267
+ const divided = variant === "divided";
268
+ return (
269
+ <div
270
+ role={label ? "group" : undefined}
271
+ aria-label={label}
272
+ className={cx(
273
+ "grid",
274
+ phoneCols === 1 ? "grid-cols-1" : "grid-cols-2",
275
+ COLS[cols],
276
+ card && "gap-px overflow-hidden rounded-lg border border-border bg-border",
277
+ divided && "gap-y-4",
278
+ variant === "bare" && "gap-4",
279
+ className,
280
+ )}
281
+ >
282
+ {kids.map((kid, i) => {
283
+ const last = i === n - 1;
284
+ // A last cell alone on its row spans what is left of it.
285
+ const phoneSpan = last && n % phoneCols !== 0 ? "col-span-2" : "";
286
+ const remSm = n % cols;
287
+ const smSpan = last ? SPAN_SM[remSm ? cols - remSm + 1 : 1] : phoneSpan ? "sm:col-span-1" : "";
288
+ // Divided: a rule on every cell that does not start a row.
289
+ const rulePhone = i % phoneCols !== 0;
290
+ const ruleSm = i % cols !== 0;
291
+ const rule = divided
292
+ ? cx(
293
+ "pr-4",
294
+ rulePhone && "border-l border-border pl-4",
295
+ rulePhone && !ruleSm && "sm:border-l-0 sm:pl-0",
296
+ !rulePhone && ruleSm && "sm:border-l sm:border-border sm:pl-4",
297
+ )
298
+ : "";
299
+ return (
300
+ <div key={kid.key ?? i} className={cx("min-w-0", card && "bg-card p-4", rule, phoneSpan, smSpan)}>
301
+ {kid}
302
+ </div>
303
+ );
304
+ })}
305
+ </div>
306
+ );
307
+ }
308
+
309
+ /* ------------------------------------------------------------------------
310
+ Meter
311
+ ------------------------------------------------------------------------ */
312
+
313
+ const METER_SIZES = { thin: { track: "h-1", mark: "h-3" }, md: { track: "h-2", mark: "h-4" } };
314
+
315
+ /**
316
+ * A quantity against a limit: storage used of a plan, spend of a budget,
317
+ * bandwidth of a cap. Drawn like Progress, but it is a role=meter, not a
318
+ * progressbar — Progress is how far a job has got, which only moves
319
+ * forward and ends; a Meter is how full something is, which can fall and
320
+ * can go OVER. Over the limit the bar stays full, turns danger, and a
321
+ * reader hears "over by …".
322
+ *
323
+ * value the amount used, a number in the unit of `max`
324
+ * max the limit; default 100
325
+ * label the meter's name, shown above it and read to a screen reader
326
+ * unit after the numbers: "GB", "credits"
327
+ * format (n) → string for every number shown; default thousands
328
+ * separators ("$" + n / 1000 + "K" for money)
329
+ * valueText the right side of the header; default "used / limit unit";
330
+ * null hides it (a row that shows its own numbers)
331
+ * valueTone the colour of that text: muted (default) · neutral ·
332
+ * primary · success · warning · danger · info · "bar" (the
333
+ * bar's own tone). Over the limit it is danger regardless
334
+ * target a mark on the bar at this amount (a goal, a budget line),
335
+ * named in the footer and to a reader
336
+ * targetMark default true; false keeps the target in the footer and for
337
+ * a reader but draws no tick on the bar
338
+ * direction against `target`, when no `tone` is given: higher (a goal —
339
+ * success once reached, warning below it) · lower (a budget —
340
+ * success at or under it, warning past it). Higher also keeps
341
+ * a bar over the limit out of danger: past a quota is good
342
+ * thresholds [{ at, tone }] — `at` is a percent of max; the bar takes the
343
+ * tone of the highest one reached: [{ at: 80, tone: "warning" },
344
+ * { at: 95, tone: "danger" }]
345
+ * tone the bar below every threshold: neutral (bg-primary, like
346
+ * Progress) · muted (grey, a plain share that signals
347
+ * nothing) · success · warning · danger · info
348
+ * caption a muted line under the bar, left of the target
349
+ * size thin (4px, a list row) · md (8px); a ring: sm (40px, a
350
+ * list row or a stat tile) · md (64px) · lg (96px)
351
+ * shape bar (default) · ring — a circular gauge, the percent in its
352
+ * middle, the label, value text, caption and target beside
353
+ * it. Tone, thresholds, target (a tick across the ring),
354
+ * direction, over-the-limit and what a reader hears are the
355
+ * bar's
356
+ * center a ring's middle instead of the percent: a string or a node
357
+ * ("4.2 GB", an Icon); null leaves it empty
358
+ */
359
+ export function Meter({
360
+ value,
361
+ max = 100,
362
+ label,
363
+ unit,
364
+ format = formatNumber,
365
+ valueText,
366
+ valueTone = "muted",
367
+ target,
368
+ targetMark = true,
369
+ direction,
370
+ thresholds,
371
+ tone,
372
+ caption,
373
+ size = "md",
374
+ shape = "bar",
375
+ center,
376
+ className,
377
+ ...rest
378
+ }) {
379
+ const v = typeof value === "number" && Number.isFinite(value) ? value : 0;
380
+ const limit = max > 0 ? max : 100;
381
+ const pct = (v / limit) * 100;
382
+ const over = v > limit;
383
+ const overBad = over && direction !== "higher";
384
+ const u = unit ? ` ${unit}` : "";
385
+ const hasTarget = typeof target === "number" && Number.isFinite(target);
386
+
387
+ // No tone given: the direction judges the value against the target.
388
+ const met = direction === "higher" ? v >= target : v <= target;
389
+ let barTone = tone ?? (hasTarget && (direction === "higher" || direction === "lower") ? (met ? "success" : "warning") : "neutral");
390
+ for (const t of [...(thresholds ?? [])].sort((a, b) => a.at - b.at)) if (pct >= t.at) barTone = t.tone;
391
+ if (overBad) barTone = "danger";
392
+ const fill = barTone === "neutral" ? "bg-primary" : FILL_TONES[barTone] ?? "bg-primary";
393
+ const valueClass = overBad
394
+ ? "font-medium text-destructive"
395
+ : valueTone === "bar"
396
+ ? cx("font-medium", barTone === "neutral" ? "text-primary" : TEXT_TONES[barTone] ?? "text-primary")
397
+ : valueTone === "muted"
398
+ ? "text-muted-foreground"
399
+ : cx("font-medium", TEXT_TONES[valueTone] ?? "text-muted-foreground");
400
+
401
+ const targetPct = hasTarget ? Math.min(100, Math.max(0, (target / limit) * 100)) : 0;
402
+ const shown = valueText === undefined ? `${format(v)} / ${format(limit)}${u}` : valueText;
403
+ const said = [
404
+ `${format(v)} of ${format(limit)}${u}`,
405
+ over ? `over by ${format(v - limit)}${u}` : `${Math.round(pct)}%`,
406
+ hasTarget ? `target ${format(target)}${u}` : null,
407
+ ]
408
+ .filter(Boolean)
409
+ .join(", ");
410
+ const meterProps = {
411
+ role: "meter",
412
+ "aria-label": label,
413
+ "aria-valuemin": 0,
414
+ "aria-valuemax": limit,
415
+ "aria-valuenow": Math.min(v, limit),
416
+ "aria-valuetext": said,
417
+ };
418
+
419
+ if (shape === "ring") {
420
+ return (
421
+ <MeterRing
422
+ {...{ pct, over, overBad, barTone, valueTone, valueClass, label, shown, caption, hasTarget, targetMark, targetPct, center, size, className, meterProps, rest }}
423
+ targetText={hasTarget ? `Target ${format(target)}${u}` : null}
424
+ />
425
+ );
426
+ }
427
+
428
+ const s = METER_SIZES[size] ?? METER_SIZES.md;
429
+ const footer = caption || (hasTarget && size === "md");
430
+
431
+ return (
432
+ <div className={cx("grid gap-1.5", className)}>
433
+ {label || shown ? (
434
+ <div aria-hidden="true" className="flex items-baseline justify-between gap-3 text-sm">
435
+ <span className="min-w-0 truncate font-medium text-foreground">{label}</span>
436
+ {shown ? (
437
+ <span data-nums className={cx("shrink-0 text-xs", valueClass)}>
438
+ {shown}
439
+ </span>
440
+ ) : null}
441
+ </div>
442
+ ) : null}
443
+ <div className="relative">
444
+ <div
445
+ role="meter"
446
+ aria-label={label}
447
+ aria-valuemin={0}
448
+ aria-valuemax={limit}
449
+ aria-valuenow={Math.min(v, limit)}
450
+ aria-valuetext={said}
451
+ className={cx("relative w-full overflow-hidden rounded-full bg-accent", s.track)}
452
+ {...rest}
453
+ >
454
+ <div
455
+ className={cx("h-full rounded-full transition-[width] duration-300 ease-out motion-reduce:transition-none", fill)}
456
+ style={{ width: `${Math.min(100, Math.max(0, pct))}%` }}
457
+ />
458
+ </div>
459
+ {hasTarget && targetMark ? (
460
+ <span
461
+ aria-hidden="true"
462
+ className={cx("absolute top-1/2 w-0.5 -translate-x-1/2 -translate-y-1/2 rounded-full bg-foreground", s.mark)}
463
+ style={{ left: `${targetPct}%` }}
464
+ />
465
+ ) : null}
466
+ </div>
467
+ {footer ? (
468
+ <div aria-hidden={caption ? undefined : "true"} className="flex items-baseline justify-between gap-3 text-xs text-muted-foreground">
469
+ <span className="min-w-0">{caption}</span>
470
+ {hasTarget ? (
471
+ <span data-nums className="shrink-0">
472
+ Target {format(target)}
473
+ {u}
474
+ </span>
475
+ ) : null}
476
+ </div>
477
+ ) : null}
478
+ </div>
479
+ );
480
+ }
481
+
482
+ // The ring's stroke in each tone (neutral is bg-primary's stroke, as the bar).
483
+ const STROKE_TONES = {
484
+ neutral: "stroke-primary",
485
+ muted: "stroke-muted-foreground",
486
+ primary: "stroke-primary",
487
+ success: "stroke-success",
488
+ warning: "stroke-warning",
489
+ danger: "stroke-destructive",
490
+ info: "stroke-info",
491
+ };
492
+
493
+ // px is the ring's box, w its stroke; text the middle's type.
494
+ const RING_SIZES = {
495
+ sm: { px: 40, w: 4, text: "text-2xs font-semibold", side: "text-sm", gap: "gap-2.5" },
496
+ md: { px: 64, w: 6, text: "text-sm font-semibold", side: "text-sm", gap: "gap-3" },
497
+ lg: { px: 96, w: 8, text: "text-xl font-semibold tracking-tight", side: "text-base", gap: "gap-4" },
498
+ };
499
+ RING_SIZES.thin = RING_SIZES.sm;
500
+
501
+ // Meter shape="ring": the same numbers, drawn as an arc from twelve o'clock.
502
+ function MeterRing({ pct, overBad, barTone, valueTone, valueClass, label, shown, caption, hasTarget, targetMark, targetPct, targetText, center, size, className, meterProps, rest }) {
503
+ const g = RING_SIZES[size] ?? RING_SIZES.md;
504
+ const c = g.px / 2;
505
+ const r = c - g.w / 2;
506
+ const len = 2 * Math.PI * r;
507
+ const frac = Math.min(1, Math.max(0, pct / 100));
508
+ const stroke = STROKE_TONES[barTone] ?? "stroke-primary";
509
+ const middleClass = overBad
510
+ ? "text-destructive"
511
+ : valueTone === "bar"
512
+ ? barTone === "neutral"
513
+ ? "text-primary"
514
+ : TEXT_TONES[barTone] ?? "text-primary"
515
+ : valueTone === "muted"
516
+ ? "text-foreground"
517
+ : TEXT_TONES[valueTone] ?? "text-foreground";
518
+ const middle = center === undefined ? `${Math.round(pct)}%` : center;
519
+ // The target tick: a short radial line across the ring, at its angle.
520
+ const a = (targetPct / 100) * 2 * Math.PI - Math.PI / 2;
521
+ const tick = (d) => [c + Math.cos(a) * d, c + Math.sin(a) * d];
522
+ const [x1, y1] = tick(r - g.w / 2 - 1.5);
523
+ const [x2, y2] = tick(r + g.w / 2 + 1.5);
524
+ const side = label || shown || caption || (hasTarget && size !== "sm");
525
+
526
+ return (
527
+ <div className={cx("flex min-w-0 items-center", g.gap, className)}>
528
+ <div {...meterProps} className="relative shrink-0" style={{ width: g.px, height: g.px }} {...rest}>
529
+ <svg aria-hidden="true" width={g.px} height={g.px} viewBox={`0 0 ${g.px} ${g.px}`} className="block overflow-visible">
530
+ {/* raw: an SVG gauge — the kit has no smaller part to draw an arc. */}
531
+ <circle cx={c} cy={c} r={r} fill="none" strokeWidth={g.w} className="stroke-accent" />
532
+ {frac > 0 ? (
533
+ <circle
534
+ cx={c}
535
+ cy={c}
536
+ r={r}
537
+ fill="none"
538
+ strokeWidth={g.w}
539
+ strokeLinecap="round"
540
+ strokeDasharray={`${len * frac} ${len}`}
541
+ transform={`rotate(-90 ${c} ${c})`}
542
+ className={cx("transition-[stroke-dasharray] duration-300 ease-out motion-reduce:transition-none", stroke)}
543
+ />
544
+ ) : null}
545
+ {hasTarget && targetMark ? (
546
+ <line x1={x1} y1={y1} x2={x2} y2={y2} strokeWidth={2} strokeLinecap="round" className="stroke-foreground" />
547
+ ) : null}
548
+ </svg>
549
+ {middle !== null && middle !== false ? (
550
+ <span aria-hidden="true" data-nums className={cx("absolute inset-0 flex items-center justify-center leading-none", g.text, middleClass)}>
551
+ {middle}
552
+ </span>
553
+ ) : null}
554
+ </div>
555
+ {side ? (
556
+ <div className={cx("grid min-w-0 gap-0.5", g.side)}>
557
+ {label ? <span aria-hidden="true" className="min-w-0 truncate font-medium text-foreground">{label}</span> : null}
558
+ {shown ? (
559
+ <span data-nums aria-hidden="true" className={cx("text-xs", valueClass)}>
560
+ {shown}
561
+ </span>
562
+ ) : null}
563
+ {caption || (hasTarget && size !== "sm") ? (
564
+ <span className="text-xs text-muted-foreground">
565
+ {caption}
566
+ {caption && hasTarget && size !== "sm" ? " · " : null}
567
+ {hasTarget && size !== "sm" ? <span aria-hidden="true" data-nums>{targetText}</span> : null}
568
+ </span>
569
+ ) : null}
570
+ </div>
571
+ ) : null}
572
+ </div>
573
+ );
574
+ }