makersclaw 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) 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/cli.mjs +19 -6
  430. package/src/install.mjs +18 -0
  431. package/src/registry.mjs +38 -4
  432. package/src/shadcn.mjs +14 -1
  433. package/templates/next/files/README.md +145 -11
  434. package/templates/next/files/app/globals.css +55 -4
  435. package/templates/next/files/check/run.mjs +3 -3
  436. package/templates/next/files/components/ui/avatar.jsx +141 -0
  437. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  438. package/templates/next/files/components/ui/button-group.jsx +70 -0
  439. package/templates/next/files/components/ui/button.jsx +132 -12
  440. package/templates/next/files/components/ui/calendar.jsx +609 -0
  441. package/templates/next/files/components/ui/carousel.jsx +281 -0
  442. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  443. package/templates/next/files/components/ui/combobox.jsx +608 -0
  444. package/templates/next/files/components/ui/command.jsx +577 -0
  445. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  446. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  447. package/templates/next/files/components/ui/distribution.jsx +117 -0
  448. package/templates/next/files/components/ui/feedback.jsx +143 -0
  449. package/templates/next/files/components/ui/field.jsx +115 -3
  450. package/templates/next/files/components/ui/file-input.jsx +234 -0
  451. package/templates/next/files/components/ui/icon.jsx +130 -8
  452. package/templates/next/files/components/ui/image.jsx +143 -0
  453. package/templates/next/files/components/ui/index.js +47 -2
  454. package/templates/next/files/components/ui/input-group.jsx +213 -0
  455. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  456. package/templates/next/files/components/ui/item.jsx +206 -0
  457. package/templates/next/files/components/ui/menu.jsx +454 -82
  458. package/templates/next/files/components/ui/notice.jsx +126 -14
  459. package/templates/next/files/components/ui/pagination.jsx +156 -0
  460. package/templates/next/files/components/ui/popover.jsx +284 -0
  461. package/templates/next/files/components/ui/radio.jsx +193 -0
  462. package/templates/next/files/components/ui/rating.jsx +131 -0
  463. package/templates/next/files/components/ui/resizable.jsx +338 -0
  464. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  465. package/templates/next/files/components/ui/separator.jsx +119 -0
  466. package/templates/next/files/components/ui/sheet.jsx +96 -11
  467. package/templates/next/files/components/ui/slider.jsx +174 -0
  468. package/templates/next/files/components/ui/stat.jsx +574 -0
  469. package/templates/next/files/components/ui/steps.jsx +338 -0
  470. package/templates/next/files/components/ui/swatch.jsx +33 -0
  471. package/templates/next/files/components/ui/table.jsx +130 -0
  472. package/templates/next/files/components/ui/toast.jsx +440 -0
  473. package/templates/next/files/components/ui/toggle.jsx +195 -0
  474. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  475. package/templates/next/template.json +264 -8
@@ -0,0 +1,89 @@
1
+ "use client";
2
+
3
+ // The Faq in every variant — the gallery's and the smoke test's surface.
4
+ // Not installed into apps: `makersclaw add faq` lays index.js and
5
+ // faq.jsx only. Pick a variant and a state; the call to action only
6
+ // counts its presses here.
7
+ import { useState } from "react";
8
+ import { Field, Select, ToggleGroup } from "../components/ui";
9
+ import { Faq } from "../components/blocks/faq";
10
+
11
+ const QUESTIONS = [
12
+ {
13
+ id: "trial",
14
+ icon: "clock",
15
+ question: "How long is the free trial?",
16
+ answer: "Fourteen days, with every feature on. We ask for a card only when you choose a plan, and nothing is charged before day fifteen.",
17
+ },
18
+ {
19
+ id: "switch",
20
+ icon: "repeat",
21
+ question: "Can I move my data from another tool?",
22
+ answer: "Yes. Import a CSV from any spreadsheet, or connect your old CRM and we copy contacts, deals and notes across in one pass.",
23
+ },
24
+ {
25
+ id: "seats",
26
+ icon: "users",
27
+ question: "Do I pay per person?",
28
+ answer: "Plans include five seats. Each extra seat is $8 a month, billed only for the days it was in use.",
29
+ },
30
+ {
31
+ id: "cancel",
32
+ icon: "log-out",
33
+ question: "What happens if I cancel?",
34
+ answer: "Your workspace stays readable for 90 days, and you can export everything as CSV at any time. After that it is deleted for good.",
35
+ },
36
+ {
37
+ id: "security",
38
+ icon: "shield-check",
39
+ question: "Where is my data stored?",
40
+ answer: "In the EU (Frankfurt) by default, or the US on request. Everything is encrypted at rest and in transit, and backed up daily.",
41
+ },
42
+ {
43
+ id: "support",
44
+ icon: "life-buoy",
45
+ question: "How do I reach a person?",
46
+ answer: "Write to the chat in the corner or email support. A person replies within an hour on weekdays, 9 to 6 CET.",
47
+ },
48
+ ];
49
+
50
+ const CTA = { title: "Still have a question?", body: "Tell us what you are trying to do and we will reply within the hour.", label: "Send us a note", icon: "mail" };
51
+
52
+ const VARIANTS = [
53
+ { id: "list-01", label: "Accordion · one open at a time", props: { layout: "accordion", description: "The things people ask before they sign up.", defaultOpen: "trial" } },
54
+ { id: "grid-01", label: "Grid · two columns with icons", props: { layout: "grid", columns: 2, description: "Short answers to the usual questions." } },
55
+ { id: "cards-icons-01", label: "Grid · icon cards and a request", props: { layout: "grid", description: "Short answers to the usual questions.", cta: CTA } },
56
+ { id: "grid-cta-01", label: "Grid · plain cards and a CTA", props: { layout: "grid", description: "Short answers to the usual questions.", cta: CTA, plainIcons: true } },
57
+ { id: "left-title-01", label: "Grid · title on the left", props: { layout: "grid", titlePosition: "start", look: "plain", description: "Short answers to the usual questions.", plainIcons: true } },
58
+ { id: "simple-01", label: "List · every answer shown", props: { layout: "list", description: "The things people ask before they sign up.", plainIcons: true } },
59
+ { id: "multi", label: "Accordion · several open, title on the left", props: { layout: "accordion", type: "multiple", titlePosition: "start", kicker: "Support", cta: CTA, plainIcons: true } },
60
+ ];
61
+
62
+ const STATES = [
63
+ { value: "filled", label: "Filled" },
64
+ { value: "loading", label: "Loading" },
65
+ { value: "empty", label: "Empty" },
66
+ ];
67
+
68
+ export default function FaqDemo() {
69
+ const [variant, setVariant] = useState("list-01");
70
+ const [state, setState] = useState("filled");
71
+ const [asks, setAsks] = useState(0);
72
+ const v = VARIANTS.find((x) => x.id === variant) ?? VARIANTS[0];
73
+ const { plainIcons, ...props } = v.props;
74
+ const items = state === "empty" ? [] : plainIcons ? QUESTIONS.map(({ icon, ...q }) => q) : QUESTIONS;
75
+ const cta = props.cta ? { ...props.cta, onClick: () => setAsks((n) => n + 1) } : undefined;
76
+
77
+ return (
78
+ <div className="grid gap-2">
79
+ <div className="flex flex-wrap items-end gap-3 px-4 pt-4 sm:px-6">
80
+ <Field id="faq-variant" label="Variant" className="w-full sm:w-80">
81
+ <Select id="faq-variant" value={variant} onChange={(e) => setVariant(e.target.value)} options={VARIANTS.map((x) => ({ value: x.id, label: x.label }))} />
82
+ </Field>
83
+ <ToggleGroup aria-label="State" items={STATES} value={state} onChange={setState} />
84
+ {asks ? <p className="pb-3 text-sm text-muted-foreground">Note asked for {asks}×</p> : null}
85
+ </div>
86
+ <Faq key={`${variant}-${state}`} {...props} cta={cta} items={items} loading={state === "loading"} />
87
+ </div>
88
+ );
89
+ }
@@ -0,0 +1,220 @@
1
+ "use client";
2
+
3
+ import { Accordion, Button, Empty, Icon, Kicker, Skeleton, cx } from "../../ui";
4
+
5
+ // Faq — a marketing section of questions and answers. Three layouts over
6
+ // the same rows: an accordion (one open at a time, or several), a grid
7
+ // of cards (optionally with an icon each), and a plain list with every
8
+ // answer shown. The title sits above or beside them, and an optional
9
+ // "need more help?" call to action closes the section.
10
+ //
11
+ // <Faq title="Questions, answered" items={faqs}
12
+ // cta={{ title: "Still stuck?", label: "Email support", href: "/contact" }} />
13
+ //
14
+ // README.md beside this file lists every prop.
15
+
16
+ const COLUMNS = {
17
+ 1: "grid-cols-1",
18
+ 2: "grid-cols-1 sm:grid-cols-2",
19
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
20
+ };
21
+
22
+ const keyOf = (item, i) => String(item.id ?? i);
23
+
24
+ function Header({ kicker, title, description, center }) {
25
+ if (!kicker && !title && !description) return null;
26
+ return (
27
+ <div className={cx("grid content-start gap-3", center ? "mx-auto max-w-2xl justify-items-center text-center" : "max-w-xl")}>
28
+ {kicker ? <Kicker>{kicker}</Kicker> : null}
29
+ {title ? <h2 className="text-balance text-3xl font-semibold tracking-tight sm:text-4xl">{title}</h2> : null}
30
+ {description ? <p className="text-pretty text-base text-muted-foreground sm:text-lg">{description}</p> : null}
31
+ </div>
32
+ );
33
+ }
34
+
35
+ function Answer({ children }) {
36
+ return <div className="text-pretty text-base leading-relaxed text-muted-foreground [&_a]:text-primary [&_a]:underline [&_p+p]:mt-3">{children}</div>;
37
+ }
38
+
39
+ function IconBadge({ name }) {
40
+ if (!name) return null;
41
+ return (
42
+ <span className="grid size-12 shrink-0 place-items-center rounded-lg bg-primary text-primary-foreground">
43
+ <Icon name={name} size={22} />
44
+ </span>
45
+ );
46
+ }
47
+
48
+ function Cta({ cta, center }) {
49
+ if (!cta) return null;
50
+ return (
51
+ <div className={cx("grid gap-3", center ? "justify-items-center text-center" : "justify-items-start")}>
52
+ {cta.title ? <h3 className="text-2xl font-semibold tracking-tight">{cta.title}</h3> : null}
53
+ {cta.body ? <p className="max-w-xl text-pretty text-base text-muted-foreground sm:text-lg">{cta.body}</p> : null}
54
+ {cta.label ? (
55
+ <Button variant="primary" href={cta.href} onClick={cta.onClick} icon={cta.icon} className="mt-2">
56
+ {cta.label}
57
+ </Button>
58
+ ) : null}
59
+ </div>
60
+ );
61
+ }
62
+
63
+ function Loading({ layout, columns }) {
64
+ if (layout === "grid")
65
+ return (
66
+ <div aria-busy="true" aria-label="Loading questions" className={cx("grid gap-6", COLUMNS[columns] ?? COLUMNS[3])}>
67
+ {[0, 1, 2].map((i) => (
68
+ <div key={i} className="grid gap-3 rounded-lg border border-border bg-card p-6">
69
+ <Skeleton className="w-3/4" />
70
+ <Skeleton className="w-full" />
71
+ <Skeleton className="w-5/6" />
72
+ </div>
73
+ ))}
74
+ </div>
75
+ );
76
+ return (
77
+ <div aria-busy="true" aria-label="Loading questions" className="grid gap-5">
78
+ {[0, 1, 2, 3].map((i) => (
79
+ <div key={i} className="grid gap-3 border-b border-border pb-5">
80
+ <Skeleton className={i % 2 ? "w-1/2" : "w-2/3"} />
81
+ </div>
82
+ ))}
83
+ </div>
84
+ );
85
+ }
86
+
87
+ function Grid({ items, columns, look }) {
88
+ return (
89
+ <div className={cx("grid gap-6", COLUMNS[columns] ?? COLUMNS[3])}>
90
+ {items.map((item, i) => (
91
+ <article
92
+ key={keyOf(item, i)}
93
+ id={item.anchor}
94
+ className={cx("grid min-w-0 content-start", look === "plain" ? "" : "rounded-lg border border-border bg-card text-card-foreground")}
95
+ >
96
+ <div className={cx("grid gap-5 border-b border-border pb-4", look === "plain" ? "" : "px-6 pt-6")}>
97
+ <IconBadge name={item.icon} />
98
+ <h3 className="text-pretty text-lg font-semibold leading-snug">{item.question}</h3>
99
+ </div>
100
+ <div className={cx("pt-4", look === "plain" ? "" : "px-6 pb-6")}>
101
+ <Answer>{item.answer}</Answer>
102
+ </div>
103
+ </article>
104
+ ))}
105
+ </div>
106
+ );
107
+ }
108
+
109
+ function List({ items }) {
110
+ return (
111
+ <dl className="grid gap-2">
112
+ {items.map((item, i) => (
113
+ <div key={keyOf(item, i)} id={item.anchor} className="grid min-w-0">
114
+ <dt className="flex items-center gap-3 border-b border-border py-5 text-lg font-semibold">
115
+ {item.icon ? <Icon name={item.icon} className="shrink-0 text-muted-foreground" /> : null}
116
+ <span className="min-w-0 text-pretty">{item.question}</span>
117
+ </dt>
118
+ <dd className="py-5">
119
+ <Answer>{item.answer}</Answer>
120
+ </dd>
121
+ </div>
122
+ ))}
123
+ </dl>
124
+ );
125
+ }
126
+
127
+ function Folding({ items, type, defaultOpen, value, onOpenChange, label }) {
128
+ const multiple = type === "multiple";
129
+ return (
130
+ <Accordion
131
+ aria-label={label}
132
+ type={multiple ? "multiple" : "single"}
133
+ defaultValue={defaultOpen ?? (multiple ? [] : null)}
134
+ value={value}
135
+ onChange={onOpenChange}
136
+ items={items.map((item, i) => ({
137
+ key: keyOf(item, i),
138
+ title: (
139
+ <span className="flex items-center gap-3 py-2 text-base font-semibold sm:text-lg">
140
+ {item.icon ? <Icon name={item.icon} className="shrink-0 text-muted-foreground" /> : null}
141
+ <span className="min-w-0 text-pretty">{item.question}</span>
142
+ </span>
143
+ ),
144
+ content: <Answer>{item.answer}</Answer>,
145
+ }))}
146
+ />
147
+ );
148
+ }
149
+
150
+ export function Faq({
151
+ items,
152
+ layout = "accordion",
153
+ kicker,
154
+ title = "Frequently asked questions",
155
+ description,
156
+ titlePosition = "top",
157
+ columns,
158
+ look = "card",
159
+ type = "single",
160
+ defaultOpen,
161
+ open,
162
+ onOpenChange,
163
+ cta,
164
+ loading = false,
165
+ empty,
166
+ label,
167
+ className,
168
+ }) {
169
+ const list = (items ?? []).filter((it) => it && it.question);
170
+ const side = titlePosition === "start";
171
+ const cols = columns ?? (side ? 2 : 3);
172
+ const narrow = !side && layout !== "grid";
173
+
174
+ let body;
175
+ if (loading) body = <Loading layout={layout} columns={cols} />;
176
+ else if (list.length === 0)
177
+ body = (
178
+ <Empty
179
+ icon="message-circle"
180
+ title={empty?.title ?? "No questions yet"}
181
+ body={empty?.body ?? "Answers to what people ask most will show here."}
182
+ />
183
+ );
184
+ else if (layout === "grid") body = <Grid items={list} columns={cols} look={look} />;
185
+ else if (layout === "list") body = <List items={list} />;
186
+ else
187
+ body = (
188
+ <Folding
189
+ items={list}
190
+ type={type}
191
+ defaultOpen={defaultOpen}
192
+ value={open}
193
+ onOpenChange={onOpenChange}
194
+ label={typeof title === "string" ? title : "Questions"}
195
+ />
196
+ );
197
+
198
+ const header = <Header kicker={kicker} title={title} description={description} center={!side} />;
199
+ return (
200
+ <section aria-label={label ?? (typeof title === "string" ? title : "Frequently asked questions")} className={cx("px-4 py-16 sm:px-6 sm:py-20", className)}>
201
+ <div className={cx("mx-auto grid w-full gap-12 sm:gap-16", narrow ? "max-w-3xl" : "max-w-6xl")}>
202
+ {side ? (
203
+ <div className="grid gap-10 lg:grid-cols-[minmax(0,2fr)_minmax(0,3fr)] lg:gap-12">
204
+ <div className="grid content-start gap-8">
205
+ {header}
206
+ <Cta cta={cta} />
207
+ </div>
208
+ <div className="min-w-0">{body}</div>
209
+ </div>
210
+ ) : (
211
+ <>
212
+ {header}
213
+ <div className="min-w-0">{body}</div>
214
+ <Cta cta={cta} center />
215
+ </>
216
+ )}
217
+ </div>
218
+ </section>
219
+ );
220
+ }
@@ -0,0 +1,4 @@
1
+ // The Faq block — `makersclaw add faq`. Fixed: compose it through its
2
+ // props (README.md beside this file); a section it cannot be is your own
3
+ // component in components/.
4
+ export { Faq } from "./faq";
@@ -0,0 +1,138 @@
1
+ # FileUpload
2
+
3
+ Files chosen or dropped, each one uploaded through your `onUpload` as
4
+ soon as it lands. Every file shows its bar while it runs (with Cancel),
5
+ the reason and a Retry when it fails, and a Remove once it is up. Files
6
+ the picker refuses (wrong type, too big, too many) are named in a notice.
7
+ The upload itself is yours: the block never fetches.
8
+
9
+ ```jsx
10
+ import { FileUpload } from "../components/blocks/file-upload"; // a Makersclaw app ("./blocks/file-upload" from components/)
11
+ import { FileUpload } from "@/components/makersclaw/blocks/file-upload"; // a shadcn project
12
+ ```
13
+
14
+ A client component. The picker is the kit's `FileDrop` (or `FileInput`
15
+ with `picker="button"`), so the browser's own file dialog opens and the
16
+ keyboard works: Tab to the zone, Enter or Space.
17
+
18
+ ## The data
19
+
20
+ What the block tells you about a file (in `onChange` and `onRemove`):
21
+ `{ id, name, size, type, url?, ...whatever your onUpload returned }`.
22
+ Never the `File` and never the block's own state.
23
+
24
+ ## Props
25
+
26
+ - `onUpload(file, { onProgress, signal })` — upload one `File`. Call
27
+ `onProgress(percent)` (0–100) as it goes; without it the bar sweeps.
28
+ Watch `signal` (an AbortSignal): it aborts when the person cancels or
29
+ replaces the file, and pass it to `fetch`. Return `{ ok: true, url?,
30
+ ...anything }` or `{ ok: false, error }`; a throw counts as failed and
31
+ its message is shown. Without `onUpload` the block is a picker only:
32
+ files count as added at once.
33
+ - `variant` — how the files show, default `"list"`:
34
+ - `list` — the drop zone, then a card per file (name, size, state).
35
+ - `single` — one file at a time in a filled panel; a new pick replaces
36
+ it (and aborts its upload). An import, a contract.
37
+ - `sections` — a one-row drop zone, then the files grouped under
38
+ "Ready", "Uploading" (failed ones stay here with Retry) and
39
+ "Finished".
40
+ - `preview` — cards with the picture itself for images. `columns={2}`
41
+ lays them two across from 640px.
42
+ - `avatar` — one picture of a person or a company: the current one (or
43
+ the initials), Upload picture, Remove. Takes `value` (the current
44
+ URL) and `name`; `onChange(url | null)`.
45
+ - `onRemove(file)` — delete an uploaded file from storage; return
46
+ `{ ok }` like `onUpload`. The row shows a spinner, and on failure stays
47
+ with the reason. Without it Remove only drops the row. Removing a file
48
+ that is still queued, uploading or failed never calls it.
49
+ - `onChange(files)` — the uploaded files, every time that list changes.
50
+ Save their ids or URLs with the record here.
51
+ - `defaultFiles` — what shows at first: files already uploaded
52
+ (`[{ id, name, size, type, url? }]`). An entry that is `{ id?, file }`
53
+ (a `File` you got from a paste or a drop elsewhere on the page) starts
54
+ uploading on mount.
55
+ - `accept` — as the input's: `"image/*"`, `".csv,.xlsx"`. The picker
56
+ greys out the rest; a drop of the rest is refused and named.
57
+ - `multiple` — default `true` (`false` for `single` and `avatar`).
58
+ - `maxSize` — bytes, per file. Bigger files are refused and named.
59
+ - `maxFiles` — how many in all; the zone says so when it is full.
60
+ - `autoUpload` — default `true`. `false` holds new files as "Ready to
61
+ upload" with Clear and an "Upload N files" button, for a form that
62
+ sends its attachments on submit.
63
+ - `picker` — `"drop"` (default: the drop zone) · `"button"` (a
64
+ `FileInput` button and the hint beside it, for a tight form row).
65
+ - `label` — the zone's line (default "Drop files here or browse"); in
66
+ `avatar`, the name beside the picture ("Profile picture").
67
+ - `hint` — the muted line: default built from `accept` and `maxSize`
68
+ ("Images · up to 4 MB").
69
+ - `buttonLabel` — `picker="button"`'s text, default "Add files".
70
+ - `uploadLabel` — the queue's submit text, or `avatar`'s button text.
71
+ - `columns` — `1` (default) or `2`, for `list` and `preview`.
72
+ - `disabled` — no picking, no retry, no remove.
73
+ - `aria-label` — the drop zone's name when `label` is not enough.
74
+ - `className` — layout around it. Never colour.
75
+
76
+ `formatSize(bytes)` ("3.1 MB") and `fileIcon(type, name)` (the kit icon
77
+ for a file) are exported too, for your own file rows.
78
+
79
+ ## Example
80
+
81
+ ```jsx
82
+ // components/DealFiles.jsx — client
83
+ "use client";
84
+ import { FileUpload } from "./blocks/file-upload";
85
+
86
+ // Your storage route answers a PUT with { id, url }. XMLHttpRequest, not
87
+ // fetch, because only it reports upload progress.
88
+ function put(file, { onProgress, signal }) {
89
+ return new Promise((resolve) => {
90
+ const xhr = new XMLHttpRequest();
91
+ xhr.open("PUT", `/api/files?name=${encodeURIComponent(file.name)}`);
92
+ xhr.upload.onprogress = (e) => e.lengthComputable && onProgress((e.loaded / e.total) * 100);
93
+ xhr.onload = () =>
94
+ xhr.status < 300 ? resolve({ ok: true, ...JSON.parse(xhr.responseText) }) : resolve({ ok: false, error: `Upload failed (${xhr.status}).` });
95
+ xhr.onerror = () => resolve({ ok: false, error: "The connection dropped. Try again." });
96
+ signal.addEventListener("abort", () => xhr.abort());
97
+ xhr.send(file);
98
+ });
99
+ }
100
+
101
+ export default function DealFiles({ deal, onSaveFiles }) {
102
+ return (
103
+ <FileUpload
104
+ defaultFiles={deal.files}
105
+ onUpload={put}
106
+ onRemove={(f) => fetch(`/api/files/${f.id}`, { method: "DELETE" }).then((r) => ({ ok: r.ok }))}
107
+ onChange={(files) => onSaveFiles(files.map((f) => ({ id: f.id, name: f.name, size: f.size, url: f.url })))}
108
+ maxSize={50 * 1024 * 1024}
109
+ />
110
+ );
111
+ }
112
+ ```
113
+
114
+ One spreadsheet to import, and a profile picture:
115
+
116
+ ```jsx
117
+ <FileUpload variant="single" accept=".csv,.xlsx" maxSize={10 * 1024 * 1024} onUpload={put} onChange={([f]) => setImport(f ?? null)} />
118
+
119
+ <FileUpload variant="avatar" name={me.name} value={me.avatarUrl} onUpload={put} onChange={(url) => saveProfile({ avatar_url: url })} />
120
+ ```
121
+
122
+ ## What it will not do
123
+
124
+ - Store anything: `onUpload` is yours (a storage bucket, a signed URL).
125
+ - Crop or resize a picture, or read a spreadsheet's rows: do that in
126
+ `onUpload` or after `onChange`.
127
+ - Reorder files, or keep a list you control from outside: `defaultFiles`
128
+ is where it starts; remount it (a `key`) to start again.
129
+ - Show a chat message's attachments: that is the chat block's composer.
130
+
131
+ A file picker it cannot be is your own component in `components/`,
132
+ built on the kit's `FileInput` or `FileDrop` — not an edit to this
133
+ block. Its files are fixed: `npm run check` refuses a change, and
134
+ `makersclaw add file-upload` restores them.
135
+
136
+ ## Credits
137
+
138
+ Ported from blocks.so (https://blocks.so, file-upload 01, 03–06, MIT) and Creative Tim UI (https://github.com/creativetimofficial/ui, modals-05 and account-avatar-upload-01, MIT), rewritten on the Makersclaw kit.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "file-upload",
3
+ "title": "FileUpload",
4
+ "description": "Files chosen or dropped, each uploaded through your async onUpload(file, { onProgress, signal }) with a progress bar, cancel while it runs, a retry when it fails and a remove once done. Variants: a list of file cards, one file at a time, Uploading/Finished sections, image thumbnails (one or two columns), and a profile picture.",
5
+ "useWhen": "A form or page takes files the app stores: attachments on a record, a CSV to import, product photos, a logo, a profile picture. Not for showing files already stored with no way to add (a table or list), and not for a chat message's attachments (the chat block's composer has those).",
6
+ "tags": ["file", "upload", "dropzone", "drag", "drop", "attachment", "progress", "image", "photo", "avatar", "profile picture", "csv", "import", "retry"],
7
+ "exports": ["FileUpload", "formatSize", "fileIcon"],
8
+ "files": ["index.js", "file-upload.jsx"],
9
+ "requires": []
10
+ }
@@ -0,0 +1,204 @@
1
+ "use client";
2
+
3
+ // FileUpload with a pretend uploader in memory — the gallery's and the
4
+ // smoke test's surface. Not installed into apps: `makersclaw add
5
+ // file-upload` lays index.js and file-upload.jsx only.
6
+ import { useEffect, useRef, useState } from "react";
7
+ import { Button, Card, Field, Input, Notice, Select, Switch } from "../components/ui";
8
+ import { FileUpload } from "../components/blocks/file-upload";
9
+
10
+ const MB = 1024 * 1024;
11
+
12
+ const VARIANTS = [
13
+ { value: "list", label: "List — file cards" },
14
+ { value: "single", label: "Single — one file" },
15
+ { value: "sections", label: "Sections — uploading / finished" },
16
+ { value: "preview", label: "Preview — thumbnails" },
17
+ { value: "grid", label: "Preview — two columns" },
18
+ { value: "queue", label: "Button picker — upload on submit" },
19
+ { value: "avatar", label: "Avatar — profile picture" },
20
+ ];
21
+
22
+ // A grey placeholder picture, so the thumbnails have something to show: a
23
+ // real PNG (a landscape, or a round portrait), not SVG markup, which an
24
+ // app's check refuses in its code.
25
+ const LANDSCAPE_PNG = "iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4CAAAAABQyaazAAABnElEQVR42u3Y223EMAxE0em/j1uJ+0gteSKbYB3bkofryYL8H/EIkABKegkvNbCBDWxgAxvYwAY2sIENbGADs4DLrRKBy++KAy7LmFBX+/aEuty3I9T1vm2hAnybwgYe8W0JG9jABjawgQ38P8AeFp5/HsyfqPPfJPmvuvx3cf7PQn8e/SjCgUA0EB4h1DlfvVAnfeVCnfVVCw1AEoHwKKEMvlKhHL5KoSy+QqE8vjqhTL4yoQ9ICBAeK5TPNyncicnomxLuxeT0TQixAsEt3E/J6xsUcgGQqfUsQPAKMQPBKzyYkd93TIgZCF7h4YgqfLvCgYRKfDvCkUQVkPHVTgDBKcQOBKdwMKAy33rD4R2pzrfWcXxHKvTdd8QPBKNw5lAUAxlbaxwINuHkqVWx77snFUCwCacvvsp9H03nL77qfW9NqQByUT0NEDKEivMdA0KKUHm+A0DIESrQlw9kGwhJQkX6toCQJVSm708gpAkV6ssHsgYkHAiBQsX67oAQKVSu71OoYF8+kBuQcCDEChXt+wISXO9AwoFk1ytk7oEIFbJZugAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4CAAAAABQyaazAAAA5ElEQVR42u3awRGDMBBD0e2/HtXjWnJnEsLYoNWYrwI87wgr1QhPAQQIECBAgAABAgQIECBAgAAB9gN1TBRQ35MC1O8kAHWebqD+pxOoa2kDSs8Ly+FbEZaDt0Isk29aWC7frHBXoOQSls83Jyyjb0q4JVAyCncESk7hhkDJKtwPKHmFAN1AySwECBAgQIAAAQIECJBPfoD8uHM8ygJywOSI3g+M70nymybKxHVgfF+c37iP+M3CyF995O9mRvzy6AJx9fkXrN9OiHc8/ZIF5oMBCBAgQIAAAQIECBAgQIAAAQbnA5oGvOFZY0eXAAAAAElFTkSuQmCC";
26
+ const PORTRAIT_PNG = "";
27
+ function picture(name, shape) {
28
+ const bytes = Uint8Array.from(atob(shape === "circle" ? PORTRAIT_PNG : LANDSCAPE_PNG), (c) => c.charCodeAt(0));
29
+ return new File([bytes], name, { type: "image/png" });
30
+ }
31
+
32
+ function blob(name, bytes, type) {
33
+ return new File([new Uint8Array(bytes)], name, { type });
34
+ }
35
+
36
+ // Files "handed over" on mount so every state shows without a drop: one
37
+ // of them fails once, so Retry has something to do.
38
+ const HANDED = {
39
+ list: () => [
40
+ blob("q3-pipeline.csv", 184_000, "text/csv"),
41
+ blob("vendor-contracts.zip", 6.2 * MB, "application/zip"),
42
+ blob("kickoff-notes.docx", 42_000, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
43
+ ],
44
+ single: () => [blob("customers-import.csv", 3.1 * MB, "text/csv")],
45
+ sections: () => [picture("storefront-hero.png"), picture("team-offsite.png", "circle"), picture("vendor-contracts.png")],
46
+ preview: () => [picture("storefront-hero.png"), picture("vendor-contracts.png", "circle")],
47
+ grid: () => [picture("shelf-oak-front.png"), picture("shelf-oak-side.png", "circle"), picture("vendor-contracts.png")],
48
+ queue: () => [],
49
+ };
50
+
51
+ const DONE = {
52
+ list: [{ id: "d1", name: "brand-guidelines.pdf", size: 2.4 * MB, type: "application/pdf" }],
53
+ single: [],
54
+ sections: [{ id: "d2", name: "logo-v3-final.png", size: 88_000, type: "image/png" }],
55
+ preview: [],
56
+ grid: [],
57
+ queue: [],
58
+ };
59
+
60
+ export default function FileUploadDemo() {
61
+ const [variant, setVariant] = useState("list");
62
+ const [seed, setSeed] = useState(0);
63
+ const [failNext, setFailNext] = useState(false);
64
+ const [saved, setSaved] = useState(null);
65
+ const failOnce = useRef(new Set());
66
+ const failRef = useRef(failNext);
67
+ failRef.current = failNext;
68
+
69
+ // Hand the samples over once the page is in the browser (File is not
70
+ // on the server).
71
+ function rerun() {
72
+ failOnce.current = new Set(["vendor-contracts.zip", "vendor-contracts.png"]);
73
+ setSeed((s) => s + 1);
74
+ }
75
+ useEffect(rerun, [variant]);
76
+
77
+ function upload(file, { onProgress, signal }) {
78
+ const slow = file.size > MB ? 7 : 16;
79
+ return new Promise((resolve) => {
80
+ let p = 0;
81
+ const t = setInterval(() => {
82
+ if (signal.aborted) {
83
+ clearInterval(t);
84
+ resolve({ ok: false, error: "Cancelled." });
85
+ return;
86
+ }
87
+ p += slow + Math.random() * 8;
88
+ // Decided here, not at the start, so an upload that was aborted
89
+ // (a cancel, React's dev double mount) does not use the failure up.
90
+ if (p > 58 && (failOnce.current.has(file.name) || failRef.current)) {
91
+ clearInterval(t);
92
+ if (!failOnce.current.delete(file.name)) {
93
+ failRef.current = false;
94
+ setFailNext(false);
95
+ }
96
+ resolve({ ok: false, error: "The connection dropped at 60%. Try again." });
97
+ } else if (p >= 100) {
98
+ clearInterval(t);
99
+ onProgress(100);
100
+ resolve({ ok: true, id: `f_${Math.random().toString(36).slice(2, 8)}` });
101
+ } else onProgress(p);
102
+ }, 260);
103
+ });
104
+ }
105
+
106
+ async function remove(file) {
107
+ await new Promise((r) => setTimeout(r, 500));
108
+ return { ok: true, file };
109
+ }
110
+
111
+ const handed = seed > 0 ? (HANDED[variant]?.() ?? []).map((file, i) => ({ id: `s${seed}-${i}`, file })) : [];
112
+ const defaults = [...(DONE[variant] ?? []), ...handed];
113
+ const common = {
114
+ onUpload: upload,
115
+ onRemove: remove,
116
+ onChange: (files) => setSaved(files.length),
117
+ defaultFiles: defaults,
118
+ };
119
+
120
+ let body;
121
+ if (variant === "list") {
122
+ body = (
123
+ <Card title="Share files with Northwind" description="Everything here goes to the client's folder." titleSize="lg">
124
+ <div className="grid gap-4">
125
+ <Field id="fu-folder" label="Folder name">
126
+ <Input id="fu-folder" defaultValue="Q3 planning" />
127
+ </Field>
128
+ <FileUpload {...common} maxSize={50 * MB} hint="Any file type · up to 50 MB each" />
129
+ </div>
130
+ </Card>
131
+ );
132
+ } else if (variant === "single") {
133
+ body = (
134
+ <Card title="Import customers" description="One spreadsheet, a row per customer." titleSize="lg">
135
+ <FileUpload {...common} variant="single" accept=".csv,.xlsx,.xls" maxSize={10 * MB} />
136
+ </Card>
137
+ );
138
+ } else if (variant === "sections") {
139
+ body = (
140
+ <div className="mx-auto w-full max-w-sm">
141
+ <FileUpload {...common} variant="sections" accept="image/png,image/jpeg,image/gif,image/svg+xml" maxSize={10 * MB} label="Drop images here or browse" />
142
+ </div>
143
+ );
144
+ } else if (variant === "preview" || variant === "grid") {
145
+ body = (
146
+ <Card
147
+ title={variant === "grid" ? "Product photos" : "Cover images"}
148
+ description={variant === "grid" ? "The first photo is the one buyers see." : "Shown on the project's page and in search."}
149
+ titleSize="lg"
150
+ >
151
+ <FileUpload {...common} variant="preview" columns={variant === "grid" ? 2 : 1} accept="image/*" maxSize={4 * MB} maxFiles={6} />
152
+ </Card>
153
+ );
154
+ } else if (variant === "queue") {
155
+ body = (
156
+ <Card title="Expense report" description="Attach the receipts, then send them in one go." titleSize="lg">
157
+ <div className="grid gap-4">
158
+ <Field id="fu-trip" label="Trip">
159
+ <Input id="fu-trip" defaultValue="Lisbon customer visits" />
160
+ </Field>
161
+ <FileUpload {...common} picker="button" buttonLabel="Attach receipts" autoUpload={false} accept="image/*,.pdf" maxSize={8 * MB} />
162
+ </div>
163
+ </Card>
164
+ );
165
+ } else {
166
+ body = (
167
+ <Card title="Your profile" titleSize="lg">
168
+ <div className="grid gap-4">
169
+ <FileUpload
170
+ variant="avatar"
171
+ name="Maya Okafor"
172
+ onUpload={upload}
173
+ onRemove={() => remove(null)}
174
+ maxSize={2 * MB}
175
+ hint="Square PNG or JPG, at least 400 × 400, up to 2 MB"
176
+ />
177
+ <Notice title="A good picture">A clear, recent photo of your face, on a plain background, helps teammates find you.</Notice>
178
+ </div>
179
+ </Card>
180
+ );
181
+ }
182
+
183
+ return (
184
+ <div className="grid gap-4">
185
+ <div className="flex flex-wrap items-end gap-x-4 gap-y-2">
186
+ <Field id="fu-variant" label="Variant" className="w-full sm:w-72">
187
+ <Select id="fu-variant" value={variant} onChange={(e) => setVariant(e.target.value)} options={VARIANTS} />
188
+ </Field>
189
+ <Switch id="fu-fail" checked={failNext} onChange={(e) => setFailNext(e.target.checked)} label="Fail the next upload" />
190
+ <Button variant="quiet" size="sm" icon="refresh" onClick={rerun}>
191
+ Run the samples again
192
+ </Button>
193
+ </div>
194
+ <div key={`${variant}-${seed}`} className="mx-auto w-full max-w-xl">
195
+ {body}
196
+ </div>
197
+ {saved !== null && variant !== "avatar" ? (
198
+ <p className="text-center text-xs text-muted-foreground" aria-live="polite">
199
+ onChange: {saved} {saved === 1 ? "file" : "files"} uploaded
200
+ </p>
201
+ ) : null}
202
+ </div>
203
+ );
204
+ }