makersclaw 0.1.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 (478) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -1
  3. package/THIRD-PARTY-NOTICES.md +180 -0
  4. package/package.json +15 -8
  5. package/r/annotate.json +62 -0
  6. package/r/approval-request.json +52 -0
  7. package/r/audio-player.json +74 -0
  8. package/r/auth-form.json +55 -0
  9. package/r/board.json +55 -0
  10. package/r/calendar-view.json +105 -0
  11. package/r/cart.json +62 -0
  12. package/r/chart.json +83 -0
  13. package/r/chat.json +95 -0
  14. package/r/code-editor.json +94 -0
  15. package/r/comment-box.json +64 -0
  16. package/r/contact-section.json +53 -0
  17. package/r/core.json +341 -0
  18. package/r/csv-import.json +63 -0
  19. package/r/data-table.json +69 -0
  20. package/r/diagram.json +74 -0
  21. package/r/doc-editor.json +82 -0
  22. package/r/doc-page.json +61 -0
  23. package/r/email-render.json +73 -0
  24. package/r/faq.json +50 -0
  25. package/r/file-upload.json +54 -0
  26. package/r/flow-canvas.json +93 -0
  27. package/r/footer.json +52 -0
  28. package/r/gantt.json +70 -0
  29. package/r/job-panel.json +56 -0
  30. package/r/json-editor.json +66 -0
  31. package/r/map.json +89 -0
  32. package/r/menubar.json +52 -0
  33. package/r/mind-map.json +67 -0
  34. package/r/navigation-menu.json +52 -0
  35. package/r/order-detail.json +54 -0
  36. package/r/org-chart.json +66 -0
  37. package/r/page-builder.json +105 -0
  38. package/r/payment-methods.json +51 -0
  39. package/r/pdf-document.json +79 -0
  40. package/r/pdf-viewer.json +88 -0
  41. package/r/product-detail.json +76 -0
  42. package/r/product-grid.json +65 -0
  43. package/r/record-form.json +67 -0
  44. package/r/record-notes.json +55 -0
  45. package/r/registry.json +3612 -0
  46. package/r/search-dialog.json +51 -0
  47. package/r/settings-list.json +66 -0
  48. package/r/setup-checklist.json +51 -0
  49. package/r/share-dialog.json +52 -0
  50. package/r/sidebar.json +69 -0
  51. package/r/signature-pad.json +72 -0
  52. package/r/sketch-canvas.json +99 -0
  53. package/r/spreadsheet.json +90 -0
  54. package/r/stat-cards.json +66 -0
  55. package/r/task-list.json +63 -0
  56. package/r/task-model.json +98 -0
  57. package/r/testimonials.json +52 -0
  58. package/r/transaction-list.json +53 -0
  59. package/r/whiteboard.json +66 -0
  60. package/registry/blocks/annotate/README.md +179 -0
  61. package/registry/blocks/annotate/annotate-data.js +250 -0
  62. package/registry/blocks/annotate/annotate.jsx +646 -0
  63. package/registry/blocks/annotate/block.json +10 -0
  64. package/registry/blocks/annotate/demo.jsx +135 -0
  65. package/registry/blocks/annotate/index.js +15 -0
  66. package/registry/blocks/approval-request/README.md +116 -0
  67. package/registry/blocks/approval-request/approval-request.jsx +386 -0
  68. package/registry/blocks/approval-request/block.json +10 -0
  69. package/registry/blocks/approval-request/demo.jsx +127 -0
  70. package/registry/blocks/approval-request/index.js +4 -0
  71. package/registry/blocks/audio-player/README.md +167 -0
  72. package/registry/blocks/audio-player/audio-player.jsx +623 -0
  73. package/registry/blocks/audio-player/block.json +14 -0
  74. package/registry/blocks/audio-player/colors.js +109 -0
  75. package/registry/blocks/audio-player/demo.jsx +209 -0
  76. package/registry/blocks/audio-player/index.js +6 -0
  77. package/registry/blocks/audio-player/time.js +67 -0
  78. package/registry/blocks/audio-player/wavesurfer.js +9 -0
  79. package/registry/blocks/auth-form/README.md +126 -0
  80. package/registry/blocks/auth-form/auth-form.jsx +568 -0
  81. package/registry/blocks/auth-form/block.json +10 -0
  82. package/registry/blocks/auth-form/demo.jsx +131 -0
  83. package/registry/blocks/auth-form/index.js +3 -0
  84. package/registry/blocks/board/README.md +64 -13
  85. package/registry/blocks/board/block.json +2 -2
  86. package/registry/blocks/board/board.jsx +237 -94
  87. package/registry/blocks/board/demo.jsx +103 -24
  88. package/registry/blocks/calendar-view/README.md +180 -0
  89. package/registry/blocks/calendar-view/agenda.jsx +147 -0
  90. package/registry/blocks/calendar-view/block.json +76 -0
  91. package/registry/blocks/calendar-view/calendar-model.js +442 -0
  92. package/registry/blocks/calendar-view/calendar.jsx +627 -0
  93. package/registry/blocks/calendar-view/demo.jsx +195 -0
  94. package/registry/blocks/calendar-view/draft.jsx +49 -0
  95. package/registry/blocks/calendar-view/index.js +39 -0
  96. package/registry/blocks/calendar-view/month.jsx +346 -0
  97. package/registry/blocks/calendar-view/paint.js +69 -0
  98. package/registry/blocks/calendar-view/time-grid.jsx +527 -0
  99. package/registry/blocks/calendar-view/tray.jsx +87 -0
  100. package/registry/blocks/cart/README.md +146 -0
  101. package/registry/blocks/cart/block.json +10 -0
  102. package/registry/blocks/cart/cart.jsx +597 -0
  103. package/registry/blocks/cart/demo.jsx +98 -0
  104. package/registry/blocks/cart/index.js +4 -0
  105. package/registry/blocks/cart/money.js +28 -0
  106. package/registry/blocks/chart/README.md +316 -0
  107. package/registry/blocks/chart/block.json +10 -0
  108. package/registry/blocks/chart/cartesian.jsx +642 -0
  109. package/registry/blocks/chart/core.jsx +262 -0
  110. package/registry/blocks/chart/demo.jsx +357 -0
  111. package/registry/blocks/chart/heatmap.jsx +336 -0
  112. package/registry/blocks/chart/index.js +8 -0
  113. package/registry/blocks/chart/pie.jsx +245 -0
  114. package/registry/blocks/chart/sparkline.jsx +88 -0
  115. package/registry/blocks/chat/README.md +273 -0
  116. package/registry/blocks/chat/attachment.jsx +95 -0
  117. package/registry/blocks/chat/block.json +10 -0
  118. package/registry/blocks/chat/chat.jsx +132 -0
  119. package/registry/blocks/chat/composer.jsx +364 -0
  120. package/registry/blocks/chat/demo.jsx +578 -0
  121. package/registry/blocks/chat/header.jsx +34 -0
  122. package/registry/blocks/chat/index.js +9 -0
  123. package/registry/blocks/chat/message.jsx +450 -0
  124. package/registry/blocks/chat/scroller.jsx +247 -0
  125. package/registry/blocks/chat/text.jsx +104 -0
  126. package/registry/blocks/code-editor/README.md +210 -0
  127. package/registry/blocks/code-editor/block.json +22 -0
  128. package/registry/blocks/code-editor/code-editor.jsx +534 -0
  129. package/registry/blocks/code-editor/codemirror.js +38 -0
  130. package/registry/blocks/code-editor/demo.jsx +205 -0
  131. package/registry/blocks/code-editor/index.js +8 -0
  132. package/registry/blocks/code-editor/json.js +317 -0
  133. package/registry/blocks/code-editor/sql.js +136 -0
  134. package/registry/blocks/code-editor/text.js +101 -0
  135. package/registry/blocks/code-editor/theme.js +186 -0
  136. package/registry/blocks/comment-box/README.md +123 -0
  137. package/registry/blocks/comment-box/block.json +10 -0
  138. package/registry/blocks/comment-box/comment-body.jsx +217 -0
  139. package/registry/blocks/comment-box/comment-box.jsx +198 -0
  140. package/registry/blocks/comment-box/comment-time.jsx +77 -0
  141. package/registry/blocks/comment-box/demo.jsx +141 -0
  142. package/registry/blocks/comment-box/index.js +8 -0
  143. package/registry/blocks/contact-section/README.md +152 -0
  144. package/registry/blocks/contact-section/block.json +11 -0
  145. package/registry/blocks/contact-section/contact-section.jsx +509 -0
  146. package/registry/blocks/contact-section/demo.jsx +93 -0
  147. package/registry/blocks/contact-section/index.js +4 -0
  148. package/registry/blocks/csv-import/README.md +133 -0
  149. package/registry/blocks/csv-import/block.json +13 -0
  150. package/registry/blocks/csv-import/csv-import.jsx +479 -0
  151. package/registry/blocks/csv-import/demo.jsx +106 -0
  152. package/registry/blocks/csv-import/import.js +200 -0
  153. package/registry/blocks/csv-import/index.js +7 -0
  154. package/registry/blocks/data-table/README.md +386 -0
  155. package/registry/blocks/data-table/block.json +10 -0
  156. package/registry/blocks/data-table/data-table.jsx +1164 -0
  157. package/registry/blocks/data-table/demo.jsx +588 -0
  158. package/registry/blocks/data-table/index.js +5 -0
  159. package/registry/blocks/data-table/model.js +169 -0
  160. package/registry/blocks/diagram/README.md +108 -0
  161. package/registry/blocks/diagram/block.json +13 -0
  162. package/registry/blocks/diagram/demo.jsx +113 -0
  163. package/registry/blocks/diagram/diagram.jsx +481 -0
  164. package/registry/blocks/diagram/index.js +7 -0
  165. package/registry/blocks/diagram/mermaid.js +52 -0
  166. package/registry/blocks/diagram/palette.js +313 -0
  167. package/registry/blocks/diagram/source.js +98 -0
  168. package/registry/blocks/doc-editor/README.md +215 -0
  169. package/registry/blocks/doc-editor/block.json +15 -0
  170. package/registry/blocks/doc-editor/demo.jsx +225 -0
  171. package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
  172. package/registry/blocks/doc-editor/doc.js +309 -0
  173. package/registry/blocks/doc-editor/index.js +7 -0
  174. package/registry/blocks/doc-editor/schema.jsx +56 -0
  175. package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
  176. package/registry/blocks/doc-editor/theme.js +82 -0
  177. package/registry/blocks/doc-page/README.md +119 -0
  178. package/registry/blocks/doc-page/autosave.js +104 -0
  179. package/registry/blocks/doc-page/block.json +10 -0
  180. package/registry/blocks/doc-page/demo.jsx +137 -0
  181. package/registry/blocks/doc-page/doc-page.jsx +276 -0
  182. package/registry/blocks/doc-page/index.js +4 -0
  183. package/registry/blocks/email-render/README.md +151 -0
  184. package/registry/blocks/email-render/block.json +14 -0
  185. package/registry/blocks/email-render/demo.jsx +153 -0
  186. package/registry/blocks/email-render/doc-email.jsx +210 -0
  187. package/registry/blocks/email-render/email.jsx +221 -0
  188. package/registry/blocks/email-render/index.js +10 -0
  189. package/registry/blocks/email-render/render.js +50 -0
  190. package/registry/blocks/email-render/theme.js +215 -0
  191. package/registry/blocks/faq/README.md +101 -0
  192. package/registry/blocks/faq/block.json +11 -0
  193. package/registry/blocks/faq/demo.jsx +89 -0
  194. package/registry/blocks/faq/faq.jsx +220 -0
  195. package/registry/blocks/faq/index.js +4 -0
  196. package/registry/blocks/file-upload/README.md +138 -0
  197. package/registry/blocks/file-upload/block.json +10 -0
  198. package/registry/blocks/file-upload/demo.jsx +204 -0
  199. package/registry/blocks/file-upload/file-upload.jsx +635 -0
  200. package/registry/blocks/file-upload/index.js +4 -0
  201. package/registry/blocks/flow-canvas/README.md +420 -0
  202. package/registry/blocks/flow-canvas/block.json +13 -0
  203. package/registry/blocks/flow-canvas/board.js +819 -0
  204. package/registry/blocks/flow-canvas/chrome.jsx +649 -0
  205. package/registry/blocks/flow-canvas/context.jsx +35 -0
  206. package/registry/blocks/flow-canvas/demo.jsx +249 -0
  207. package/registry/blocks/flow-canvas/edges.jsx +107 -0
  208. package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
  209. package/registry/blocks/flow-canvas/index.js +41 -0
  210. package/registry/blocks/flow-canvas/nodes.jsx +392 -0
  211. package/registry/blocks/flow-canvas/theme.js +174 -0
  212. package/registry/blocks/footer/README.md +133 -0
  213. package/registry/blocks/footer/block.json +11 -0
  214. package/registry/blocks/footer/demo.jsx +119 -0
  215. package/registry/blocks/footer/footer.jsx +406 -0
  216. package/registry/blocks/footer/index.js +4 -0
  217. package/registry/blocks/gantt/README.md +220 -0
  218. package/registry/blocks/gantt/block.json +10 -0
  219. package/registry/blocks/gantt/demo.jsx +148 -0
  220. package/registry/blocks/gantt/gantt.jsx +923 -0
  221. package/registry/blocks/gantt/index.js +7 -0
  222. package/registry/blocks/gantt/rows.jsx +468 -0
  223. package/registry/blocks/gantt/schedule.js +278 -0
  224. package/registry/blocks/job-panel/README.md +86 -2
  225. package/registry/blocks/job-panel/block.json +3 -3
  226. package/registry/blocks/job-panel/demo.jsx +230 -3
  227. package/registry/blocks/job-panel/job-panel.jsx +169 -3
  228. package/registry/blocks/json-editor/README.md +133 -0
  229. package/registry/blocks/json-editor/block.json +10 -0
  230. package/registry/blocks/json-editor/demo.jsx +92 -0
  231. package/registry/blocks/json-editor/index.js +7 -0
  232. package/registry/blocks/json-editor/json-editor.jsx +305 -0
  233. package/registry/blocks/json-editor/json-tree.jsx +393 -0
  234. package/registry/blocks/json-editor/tree.js +225 -0
  235. package/registry/blocks/map/README.md +221 -0
  236. package/registry/blocks/map/block.json +14 -0
  237. package/registry/blocks/map/demo.jsx +201 -0
  238. package/registry/blocks/map/geo.js +198 -0
  239. package/registry/blocks/map/index.js +8 -0
  240. package/registry/blocks/map/list.jsx +128 -0
  241. package/registry/blocks/map/map-view.jsx +715 -0
  242. package/registry/blocks/map/maplibre.js +30 -0
  243. package/registry/blocks/map/marks.jsx +146 -0
  244. package/registry/blocks/map/theme.js +142 -0
  245. package/registry/blocks/menubar/README.md +109 -0
  246. package/registry/blocks/menubar/block.json +10 -0
  247. package/registry/blocks/menubar/demo.jsx +128 -0
  248. package/registry/blocks/menubar/index.js +4 -0
  249. package/registry/blocks/menubar/menubar.jsx +199 -0
  250. package/registry/blocks/mind-map/README.md +206 -0
  251. package/registry/blocks/mind-map/block.json +10 -0
  252. package/registry/blocks/mind-map/demo.jsx +103 -0
  253. package/registry/blocks/mind-map/index.js +31 -0
  254. package/registry/blocks/mind-map/mind-map.jsx +1125 -0
  255. package/registry/blocks/mind-map/topic.jsx +143 -0
  256. package/registry/blocks/mind-map/tree.js +645 -0
  257. package/registry/blocks/navigation-menu/README.md +124 -0
  258. package/registry/blocks/navigation-menu/block.json +10 -0
  259. package/registry/blocks/navigation-menu/demo.jsx +84 -0
  260. package/registry/blocks/navigation-menu/index.js +4 -0
  261. package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
  262. package/registry/blocks/order-detail/README.md +109 -0
  263. package/registry/blocks/order-detail/block.json +10 -0
  264. package/registry/blocks/order-detail/demo.jsx +88 -0
  265. package/registry/blocks/order-detail/index.js +4 -0
  266. package/registry/blocks/order-detail/order-detail.jsx +354 -0
  267. package/registry/blocks/org-chart/README.md +145 -0
  268. package/registry/blocks/org-chart/block.json +10 -0
  269. package/registry/blocks/org-chart/demo.jsx +94 -0
  270. package/registry/blocks/org-chart/index.js +7 -0
  271. package/registry/blocks/org-chart/org-chart.jsx +631 -0
  272. package/registry/blocks/org-chart/org.js +245 -0
  273. package/registry/blocks/org-chart/person.jsx +96 -0
  274. package/registry/blocks/page-builder/README.md +257 -0
  275. package/registry/blocks/page-builder/block.json +14 -0
  276. package/registry/blocks/page-builder/demo.jsx +145 -0
  277. package/registry/blocks/page-builder/grapes.js +18 -0
  278. package/registry/blocks/page-builder/index.js +11 -0
  279. package/registry/blocks/page-builder/page-builder.jsx +704 -0
  280. package/registry/blocks/page-builder/page-view.jsx +33 -0
  281. package/registry/blocks/page-builder/page.js +118 -0
  282. package/registry/blocks/page-builder/panels.jsx +588 -0
  283. package/registry/blocks/page-builder/sections.js +209 -0
  284. package/registry/blocks/page-builder/theme.js +87 -0
  285. package/registry/blocks/page-builder/thumbs.jsx +189 -0
  286. package/registry/blocks/page-builder/tokens.js +329 -0
  287. package/registry/blocks/payment-methods/README.md +104 -0
  288. package/registry/blocks/payment-methods/block.json +10 -0
  289. package/registry/blocks/payment-methods/demo.jsx +71 -0
  290. package/registry/blocks/payment-methods/index.js +4 -0
  291. package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
  292. package/registry/blocks/pdf-document/README.md +213 -0
  293. package/registry/blocks/pdf-document/block.json +13 -0
  294. package/registry/blocks/pdf-document/demo.jsx +136 -0
  295. package/registry/blocks/pdf-document/index.js +33 -0
  296. package/registry/blocks/pdf-document/money.js +83 -0
  297. package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
  298. package/registry/blocks/pdf-document/primitives.jsx +271 -0
  299. package/registry/blocks/pdf-document/quote.jsx +179 -0
  300. package/registry/blocks/pdf-document/theme.js +193 -0
  301. package/registry/blocks/pdf-viewer/README.md +191 -0
  302. package/registry/blocks/pdf-viewer/block.json +14 -0
  303. package/registry/blocks/pdf-viewer/demo.jsx +252 -0
  304. package/registry/blocks/pdf-viewer/helpers.js +270 -0
  305. package/registry/blocks/pdf-viewer/index.js +8 -0
  306. package/registry/blocks/pdf-viewer/notes.jsx +195 -0
  307. package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
  308. package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
  309. package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
  310. package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
  311. package/registry/blocks/product-detail/README.md +217 -0
  312. package/registry/blocks/product-detail/block.json +10 -0
  313. package/registry/blocks/product-detail/demo.jsx +233 -0
  314. package/registry/blocks/product-detail/index.js +7 -0
  315. package/registry/blocks/product-detail/price.jsx +115 -0
  316. package/registry/blocks/product-detail/product-detail.jsx +348 -0
  317. package/registry/blocks/product-detail/product-media.jsx +102 -0
  318. package/registry/blocks/product-detail/product-options.jsx +144 -0
  319. package/registry/blocks/product-grid/README.md +162 -0
  320. package/registry/blocks/product-grid/block.json +10 -0
  321. package/registry/blocks/product-grid/demo.jsx +255 -0
  322. package/registry/blocks/product-grid/index.js +5 -0
  323. package/registry/blocks/product-grid/product-card.jsx +232 -0
  324. package/registry/blocks/product-grid/product-grid.jsx +235 -0
  325. package/registry/blocks/record-form/README.md +196 -0
  326. package/registry/blocks/record-form/block.json +10 -0
  327. package/registry/blocks/record-form/demo.jsx +525 -0
  328. package/registry/blocks/record-form/index.js +4 -0
  329. package/registry/blocks/record-form/record-fields.jsx +457 -0
  330. package/registry/blocks/record-form/record-form.jsx +415 -0
  331. package/registry/blocks/record-form/rules.js +81 -0
  332. package/registry/blocks/record-notes/README.md +139 -0
  333. package/registry/blocks/record-notes/block.json +10 -0
  334. package/registry/blocks/record-notes/demo.jsx +179 -0
  335. package/registry/blocks/record-notes/index.js +4 -0
  336. package/registry/blocks/record-notes/record-notes.jsx +266 -0
  337. package/registry/blocks/search-dialog/README.md +108 -0
  338. package/registry/blocks/search-dialog/block.json +10 -0
  339. package/registry/blocks/search-dialog/demo.jsx +116 -0
  340. package/registry/blocks/search-dialog/index.js +3 -0
  341. package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
  342. package/registry/blocks/settings-list/README.md +171 -0
  343. package/registry/blocks/settings-list/block.json +10 -0
  344. package/registry/blocks/settings-list/demo.jsx +333 -0
  345. package/registry/blocks/settings-list/index.js +4 -0
  346. package/registry/blocks/settings-list/row-state.jsx +93 -0
  347. package/registry/blocks/settings-list/settings-list.jsx +349 -0
  348. package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
  349. package/registry/blocks/setup-checklist/README.md +142 -0
  350. package/registry/blocks/setup-checklist/block.json +10 -0
  351. package/registry/blocks/setup-checklist/demo.jsx +159 -0
  352. package/registry/blocks/setup-checklist/index.js +4 -0
  353. package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
  354. package/registry/blocks/share-dialog/README.md +113 -0
  355. package/registry/blocks/share-dialog/block.json +10 -0
  356. package/registry/blocks/share-dialog/demo.jsx +140 -0
  357. package/registry/blocks/share-dialog/index.js +3 -0
  358. package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
  359. package/registry/blocks/sidebar/README.md +190 -0
  360. package/registry/blocks/sidebar/block.json +43 -0
  361. package/registry/blocks/sidebar/demo.jsx +577 -0
  362. package/registry/blocks/sidebar/index.js +4 -0
  363. package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
  364. package/registry/blocks/sidebar/sidebar.jsx +864 -0
  365. package/registry/blocks/signature-pad/README.md +137 -0
  366. package/registry/blocks/signature-pad/block.json +13 -0
  367. package/registry/blocks/signature-pad/colors.js +115 -0
  368. package/registry/blocks/signature-pad/demo.jsx +94 -0
  369. package/registry/blocks/signature-pad/index.js +6 -0
  370. package/registry/blocks/signature-pad/pad.js +7 -0
  371. package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
  372. package/registry/blocks/signature-pad/signature.js +68 -0
  373. package/registry/blocks/sketch-canvas/README.md +280 -0
  374. package/registry/blocks/sketch-canvas/block.json +13 -0
  375. package/registry/blocks/sketch-canvas/demo.jsx +159 -0
  376. package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
  377. package/registry/blocks/sketch-canvas/index.js +9 -0
  378. package/registry/blocks/sketch-canvas/palette.js +226 -0
  379. package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
  380. package/registry/blocks/sketch-canvas/sketch.js +179 -0
  381. package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
  382. package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
  383. package/registry/blocks/sketch-canvas/stamps.js +104 -0
  384. package/registry/blocks/sketch-canvas/theme.js +131 -0
  385. package/registry/blocks/spreadsheet/README.md +307 -0
  386. package/registry/blocks/spreadsheet/block.json +13 -0
  387. package/registry/blocks/spreadsheet/cells.jsx +455 -0
  388. package/registry/blocks/spreadsheet/chrome.jsx +325 -0
  389. package/registry/blocks/spreadsheet/demo.jsx +177 -0
  390. package/registry/blocks/spreadsheet/grid.js +387 -0
  391. package/registry/blocks/spreadsheet/index.js +34 -0
  392. package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
  393. package/registry/blocks/spreadsheet/types.js +473 -0
  394. package/registry/blocks/stat-cards/README.md +173 -0
  395. package/registry/blocks/stat-cards/block.json +10 -0
  396. package/registry/blocks/stat-cards/demo.jsx +257 -0
  397. package/registry/blocks/stat-cards/index.js +4 -0
  398. package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
  399. package/registry/blocks/stat-cards/usage.jsx +243 -0
  400. package/registry/blocks/task-list/README.md +176 -0
  401. package/registry/blocks/task-list/block.json +10 -0
  402. package/registry/blocks/task-list/demo.jsx +134 -0
  403. package/registry/blocks/task-list/index.js +5 -0
  404. package/registry/blocks/task-list/task-list.jsx +907 -0
  405. package/registry/blocks/task-model/README.md +455 -0
  406. package/registry/blocks/task-model/block.json +167 -0
  407. package/registry/blocks/task-model/changes.js +89 -0
  408. package/registry/blocks/task-model/dates.js +371 -0
  409. package/registry/blocks/task-model/demo.jsx +215 -0
  410. package/registry/blocks/task-model/dnd.jsx +240 -0
  411. package/registry/blocks/task-model/index.js +97 -0
  412. package/registry/blocks/task-model/model.js +919 -0
  413. package/registry/blocks/task-model/parts.jsx +449 -0
  414. package/registry/blocks/task-model/toolbar.jsx +271 -0
  415. package/registry/blocks/testimonials/README.md +139 -0
  416. package/registry/blocks/testimonials/block.json +11 -0
  417. package/registry/blocks/testimonials/demo.jsx +137 -0
  418. package/registry/blocks/testimonials/index.js +4 -0
  419. package/registry/blocks/testimonials/testimonials.jsx +430 -0
  420. package/registry/blocks/transaction-list/README.md +126 -0
  421. package/registry/blocks/transaction-list/block.json +10 -0
  422. package/registry/blocks/transaction-list/demo.jsx +79 -0
  423. package/registry/blocks/transaction-list/index.js +4 -0
  424. package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
  425. package/registry/blocks/whiteboard/README.md +179 -0
  426. package/registry/blocks/whiteboard/block.json +10 -0
  427. package/registry/blocks/whiteboard/demo.jsx +169 -0
  428. package/registry/blocks/whiteboard/index.js +6 -0
  429. package/registry/blocks/whiteboard/templates.js +150 -0
  430. package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
  431. package/src/install.mjs +18 -0
  432. package/src/shadcn.mjs +171 -0
  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/parts/fixture.jsx +1 -1
  437. package/templates/next/files/components/parts/sample.js +15 -0
  438. package/templates/next/files/components/ui/avatar.jsx +141 -0
  439. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  440. package/templates/next/files/components/ui/button-group.jsx +70 -0
  441. package/templates/next/files/components/ui/button.jsx +132 -12
  442. package/templates/next/files/components/ui/calendar.jsx +609 -0
  443. package/templates/next/files/components/ui/carousel.jsx +281 -0
  444. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  445. package/templates/next/files/components/ui/combobox.jsx +608 -0
  446. package/templates/next/files/components/ui/command.jsx +577 -0
  447. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  448. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  449. package/templates/next/files/components/ui/distribution.jsx +117 -0
  450. package/templates/next/files/components/ui/feedback.jsx +143 -0
  451. package/templates/next/files/components/ui/field.jsx +115 -3
  452. package/templates/next/files/components/ui/file-input.jsx +234 -0
  453. package/templates/next/files/components/ui/icon.jsx +130 -8
  454. package/templates/next/files/components/ui/image.jsx +143 -0
  455. package/templates/next/files/components/ui/index.js +47 -2
  456. package/templates/next/files/components/ui/input-group.jsx +213 -0
  457. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  458. package/templates/next/files/components/ui/item.jsx +206 -0
  459. package/templates/next/files/components/ui/menu.jsx +454 -82
  460. package/templates/next/files/components/ui/notice.jsx +126 -14
  461. package/templates/next/files/components/ui/pagination.jsx +156 -0
  462. package/templates/next/files/components/ui/popover.jsx +284 -0
  463. package/templates/next/files/components/ui/radio.jsx +193 -0
  464. package/templates/next/files/components/ui/rating.jsx +131 -0
  465. package/templates/next/files/components/ui/resizable.jsx +338 -0
  466. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  467. package/templates/next/files/components/ui/separator.jsx +119 -0
  468. package/templates/next/files/components/ui/sheet.jsx +96 -11
  469. package/templates/next/files/components/ui/slider.jsx +174 -0
  470. package/templates/next/files/components/ui/stat.jsx +574 -0
  471. package/templates/next/files/components/ui/steps.jsx +338 -0
  472. package/templates/next/files/components/ui/swatch.jsx +33 -0
  473. package/templates/next/files/components/ui/table.jsx +130 -0
  474. package/templates/next/files/components/ui/toast.jsx +440 -0
  475. package/templates/next/files/components/ui/toggle.jsx +195 -0
  476. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  477. package/templates/next/files/lib/sample.js +4 -12
  478. package/templates/next/template.json +264 -8
@@ -0,0 +1,383 @@
1
+ "use client";
2
+
3
+ import { useEffect, useId, useState } from "react";
4
+ import { Badge, Button, DatePicker, Empty, Icon, IconButton, Notice, Skeleton, cx, todayString } from "../../ui";
5
+
6
+ // Money records as a plain list: one row per charge, payment or invoice,
7
+ // optionally grouped by month, with a date-range filter, an export and a
8
+ // per-row download. A list, not a table: no columns, no sorting — rows
9
+ // come in in the order they should show.
10
+
11
+ // Server and browser may differ in locale, time zone and even the day:
12
+ // the first render uses fixed ones (en-US, UTC) so it matches the server's
13
+ // HTML, then the reader's own take over.
14
+ function useHydrated() {
15
+ const [hydrated, setHydrated] = useState(false);
16
+ useEffect(() => setHydrated(true), []);
17
+ return hydrated;
18
+ }
19
+
20
+ const formats = new Map();
21
+ function money(amount, currency = "USD", locale) {
22
+ const key = `${locale ?? ""}|${currency}`;
23
+ let f = formats.get(key);
24
+ if (!f) {
25
+ try {
26
+ f = new Intl.NumberFormat(locale, { style: "currency", currency });
27
+ } catch {
28
+ f = new Intl.NumberFormat(locale, { style: "currency", currency: "USD" });
29
+ }
30
+ formats.set(key, f);
31
+ }
32
+ return f.format(Math.abs(Number(amount) || 0));
33
+ }
34
+
35
+ const DAY = /^\d{4}-\d{2}-\d{2}$/;
36
+ const dayOf = (value) => (typeof value === "string" ? value.slice(0, 10) : "");
37
+
38
+ // "Sep 21, 2026", or "Sep 21, 2026, 12:30 PM" when the row has a time.
39
+ function when(value, locale, timeZone) {
40
+ if (!value) return "";
41
+ if (typeof value === "string" && DAY.test(value)) {
42
+ const [y, m, d] = value.split("-").map(Number);
43
+ return new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeZone: "UTC" }).format(Date.UTC(y, m - 1, d));
44
+ }
45
+ const d = new Date(value);
46
+ if (Number.isNaN(d.getTime())) return String(value);
47
+ return new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short", timeZone }).format(d);
48
+ }
49
+
50
+ function monthLabel(key, locale) {
51
+ const [y, m] = key.split("-").map(Number);
52
+ if (!y || !m) return "Undated";
53
+ return new Intl.DateTimeFormat(locale, { month: "long", year: "numeric", timeZone: "UTC" }).format(Date.UTC(y, m - 1, 1));
54
+ }
55
+
56
+ const daysBetween = (from, to) => {
57
+ const a = Date.parse(`${from}T00:00:00Z`);
58
+ const b = Date.parse(`${to}T00:00:00Z`);
59
+ return Math.round((b - a) / 86400000);
60
+ };
61
+
62
+ // An invoice's badge: paid, void, or how long until (or since) it is due.
63
+ function invoiceBadge(row, today) {
64
+ const status = String(row.status ?? "").toLowerCase();
65
+ if (status === "paid") return { tone: "success", text: "Paid" };
66
+ if (status === "void" || status === "cancelled") return { tone: "neutral", text: status === "void" ? "Void" : "Cancelled" };
67
+ if (status === "draft") return { tone: "neutral", text: "Draft" };
68
+ const due = dayOf(row.dueDate);
69
+ if (!DAY.test(due)) return status === "overdue" ? { tone: "danger", text: "Overdue" } : { tone: "info", text: "Open" };
70
+ const left = daysBetween(today, due);
71
+ if (left > 0) return { tone: "info", text: `Due in ${left} ${left === 1 ? "day" : "days"}` };
72
+ if (left === 0) return { tone: "warning", text: "Due today" };
73
+ return { tone: "danger", text: `${-left} ${left === -1 ? "day" : "days"} overdue` };
74
+ }
75
+
76
+ // A history row's direction and state.
77
+ function flowOf(row) {
78
+ const status = String(row.status ?? "").toLowerCase();
79
+ const incoming = row.direction ? row.direction === "in" : Number(row.amount) >= 0;
80
+ if (status === "pending") return { key: "pending", icon: "clock", word: "Pending", incoming };
81
+ if (status === "failed" || status === "declined") return { key: "failed", icon: "x", word: "Failed", incoming };
82
+ if (status === "refunded") return { key: "refunded", icon: "refresh", word: "Refunded", incoming };
83
+ return { key: incoming ? "in" : "out", icon: incoming ? "arrow-down" : "arrow-up", word: incoming ? "Received" : "Paid", incoming };
84
+ }
85
+
86
+ const MARK = {
87
+ in: "text-success",
88
+ out: "text-foreground",
89
+ pending: "text-muted-foreground",
90
+ failed: "text-destructive",
91
+ refunded: "text-muted-foreground",
92
+ };
93
+
94
+ async function attempt(fn) {
95
+ try {
96
+ const res = await fn();
97
+ return res && res.ok === false ? res.error || "That did not work." : null;
98
+ } catch (e) {
99
+ return e?.message || "That did not work.";
100
+ }
101
+ }
102
+
103
+ function RowAction({ row, onDownload, downloadHref, label, onError }) {
104
+ const [busy, setBusy] = useState(false);
105
+ const href = downloadHref?.(row);
106
+ if (!href && !onDownload) return null;
107
+ async function run() {
108
+ setBusy(true);
109
+ onError(null);
110
+ onError(await attempt(() => onDownload(row)));
111
+ setBusy(false);
112
+ }
113
+ return href ? (
114
+ <Button iconOnly variant="quiet" href={href} aria-label={label} title={label} className="shrink-0">
115
+ <Icon name="download" size={18} />
116
+ </Button>
117
+ ) : (
118
+ <IconButton icon="download" label={label} onClick={run} loading={busy} />
119
+ );
120
+ }
121
+
122
+ function RowError({ error }) {
123
+ return error ? (
124
+ <p role="alert" className="basis-full text-xs text-destructive">
125
+ {error}
126
+ </p>
127
+ ) : null;
128
+ }
129
+
130
+ function HistoryRow({ row, currency, locale, timeZone, onOpen, onDownload, downloadHref }) {
131
+ const [error, setError] = useState(null);
132
+ const flow = flowOf(row);
133
+ const amount = money(row.amount, row.currency ?? currency, locale);
134
+ const sign = flow.key === "in" ? "+" : flow.key === "out" ? "−" : "";
135
+ const title = onOpen ? (
136
+ <Button variant="link" size="inherit" onClick={() => onOpen(row)} className="text-left font-medium">
137
+ {row.name}
138
+ </Button>
139
+ ) : (
140
+ <span className="font-medium">{row.name}</span>
141
+ );
142
+ return (
143
+ <li className="flex flex-wrap items-center gap-3 rounded-lg border border-border p-3 sm:gap-4 sm:p-4">
144
+ <span className={cx("grid size-10 shrink-0 place-items-center rounded-md border border-border bg-card", MARK[flow.key])}>
145
+ <Icon name={flow.icon} size={18} />
146
+ <span className="sr-only">{flow.word}</span>
147
+ </span>
148
+ <div className="grid min-w-0 flex-1 gap-0.5">
149
+ <p className="truncate">{title}</p>
150
+ <p className="truncate text-sm text-muted-foreground">
151
+ {row.description ? `${row.description} · ` : ""}
152
+ {when(row.date, locale, timeZone)}
153
+ </p>
154
+ </div>
155
+ <div className="grid shrink-0 justify-items-end gap-0.5 text-right">
156
+ <p
157
+ className={cx(
158
+ "text-sm font-semibold tabular-nums",
159
+ MARK[flow.key],
160
+ flow.key === "failed" && "line-through",
161
+ )}
162
+ >
163
+ {sign}
164
+ {amount}
165
+ </p>
166
+ {flow.key === "pending" || flow.key === "failed" || flow.key === "refunded" ? (
167
+ <p className="text-xs text-muted-foreground">{flow.word}</p>
168
+ ) : null}
169
+ </div>
170
+ <RowAction row={row} onDownload={onDownload} downloadHref={downloadHref} label={`Download ${row.name}`} onError={setError} />
171
+ <RowError error={error} />
172
+ </li>
173
+ );
174
+ }
175
+
176
+ function InvoiceRow({ row, currency, locale, timeZone, today, onOpen, onDownload, downloadHref }) {
177
+ const [error, setError] = useState(null);
178
+ const badge = invoiceBadge(row, today);
179
+ const name = row.number ?? row.name;
180
+ return (
181
+ <li className="flex flex-wrap items-center gap-x-4 gap-y-2 py-4">
182
+ <div className="grid min-w-0 basis-full gap-0.5 sm:flex-1 sm:basis-auto">
183
+ {onOpen ? (
184
+ <Button variant="link" size="inherit" onClick={() => onOpen(row)} className="justify-self-start text-left font-semibold">
185
+ {name}
186
+ </Button>
187
+ ) : (
188
+ <p className="truncate font-semibold">{name}</p>
189
+ )}
190
+ <p className="truncate text-sm text-muted-foreground">
191
+ {row.number && row.name ? `${row.name} · ` : ""}
192
+ {when(row.date, locale, timeZone)}
193
+ </p>
194
+ </div>
195
+ <Badge tone={badge.tone} variant="soft">
196
+ {badge.text}
197
+ </Badge>
198
+ <p className="ml-auto text-sm font-semibold tabular-nums">{money(row.amount, row.currency ?? currency, locale)}</p>
199
+ <RowAction row={row} onDownload={onDownload} downloadHref={downloadHref} label={`Download ${name}`} onError={setError} />
200
+ <RowError error={error} />
201
+ </li>
202
+ );
203
+ }
204
+
205
+ function Loading({ variant }) {
206
+ return (
207
+ <ul aria-busy="true" aria-label="Loading" className={cx("grid", variant === "history" ? "gap-2" : "divide-y divide-border")}>
208
+ {[0, 1, 2].map((i) => (
209
+ <li key={i} className={cx("flex items-center gap-3", variant === "history" ? "rounded-lg border border-border p-4" : "py-4")}>
210
+ {variant === "history" ? <Skeleton shape="rect" className="size-10" /> : null}
211
+ <div className="grid flex-1 gap-2">
212
+ <Skeleton className="w-1/3" />
213
+ <Skeleton className="w-1/4" />
214
+ </div>
215
+ <Skeleton className="w-16" />
216
+ </li>
217
+ ))}
218
+ </ul>
219
+ );
220
+ }
221
+
222
+ export function TransactionList({
223
+ rows,
224
+ variant = "history",
225
+ currency = "USD",
226
+ locale: localeProp,
227
+ groupBy,
228
+ title,
229
+ description,
230
+ loading = false,
231
+ error,
232
+ dateFilter = false,
233
+ range: rangeProp,
234
+ onRangeChange,
235
+ onExport,
236
+ exportLabel = "Export",
237
+ onOpen,
238
+ onDownload,
239
+ downloadHref,
240
+ emptyTitle,
241
+ emptyBody,
242
+ today,
243
+ className,
244
+ }) {
245
+ const hydrated = useHydrated();
246
+ const locale = localeProp ?? (hydrated ? undefined : "en-US");
247
+ const timeZone = hydrated ? undefined : "UTC";
248
+ const invoices = variant === "invoices";
249
+ const headingId = useId();
250
+ const [ownRange, setOwnRange] = useState(null);
251
+ const [exporting, setExporting] = useState(false);
252
+ const [exportError, setExportError] = useState(null);
253
+ const range = rangeProp !== undefined ? rangeProp : ownRange;
254
+ const setRange = (next) => {
255
+ if (rangeProp === undefined) setOwnRange(next);
256
+ onRangeChange?.(next);
257
+ };
258
+ const now = today ?? (hydrated ? todayString() : new Date().toISOString().slice(0, 10));
259
+ const group = (groupBy ?? (invoices ? "none" : "month")) === "month";
260
+ const heading = title ?? (invoices ? "Invoices" : "Transactions");
261
+
262
+ const all = (rows ?? []).filter(Boolean);
263
+ const shown = range?.from
264
+ ? all.filter((r) => {
265
+ const d = dayOf(r.date);
266
+ return d >= range.from && d <= (range.to ?? range.from);
267
+ })
268
+ : all;
269
+
270
+ const groups = [];
271
+ if (group) {
272
+ const at = new Map();
273
+ for (const r of shown) {
274
+ const key = dayOf(r.date).slice(0, 7) || "none";
275
+ if (!at.has(key)) {
276
+ at.set(key, groups.length);
277
+ groups.push({ key, rows: [] });
278
+ }
279
+ groups[at.get(key)].rows.push(r);
280
+ }
281
+ } else groups.push({ key: "all", rows: shown });
282
+
283
+ async function runExport() {
284
+ setExporting(true);
285
+ setExportError(null);
286
+ setExportError(await attempt(() => onExport(shown, range)));
287
+ setExporting(false);
288
+ }
289
+
290
+ const rowProps = { currency, locale, timeZone, today: now, onOpen, onDownload, downloadHref };
291
+ const Row = invoices ? InvoiceRow : HistoryRow;
292
+ const listClass = invoices ? "divide-y divide-border" : "grid gap-2";
293
+
294
+ let body;
295
+ if (loading) body = <Loading variant={variant} />;
296
+ else if (!all.length)
297
+ body = (
298
+ <Empty
299
+ icon={invoices ? "receipt" : "dollar"}
300
+ title={emptyTitle ?? (invoices ? "No invoices yet" : "No transactions yet")}
301
+ body={emptyBody ?? (invoices ? "Invoices appear here once they are issued." : "Payments in and out appear here.")}
302
+ />
303
+ );
304
+ else if (!shown.length)
305
+ body = (
306
+ <Empty
307
+ icon="calendar"
308
+ title="Nothing in these dates"
309
+ body="Pick a wider range, or clear it to see everything."
310
+ action={
311
+ <Button variant="secondary" onClick={() => setRange(null)}>
312
+ Clear dates
313
+ </Button>
314
+ }
315
+ />
316
+ );
317
+ else
318
+ body = (
319
+ <div className="grid gap-5">
320
+ {groups.map((g) =>
321
+ group ? (
322
+ <section key={g.key} aria-label={g.key === "none" ? "Undated" : monthLabel(g.key, locale)} className="grid gap-2">
323
+ <h3 className="px-1 text-sm font-semibold text-muted-foreground">
324
+ {g.key === "none" ? "Undated" : monthLabel(g.key, locale)}
325
+ </h3>
326
+ <ul className={listClass}>
327
+ {g.rows.map((r) => (
328
+ <Row key={r.id} row={r} {...rowProps} />
329
+ ))}
330
+ </ul>
331
+ </section>
332
+ ) : (
333
+ <ul key={g.key} aria-labelledby={headingId} className={listClass}>
334
+ {g.rows.map((r) => (
335
+ <Row key={r.id} row={r} {...rowProps} />
336
+ ))}
337
+ </ul>
338
+ ),
339
+ )}
340
+ </div>
341
+ );
342
+
343
+ return (
344
+ <section aria-labelledby={headingId} className={cx("grid gap-4 rounded-lg border border-border bg-card p-4 text-card-foreground sm:p-6", className)}>
345
+ <header className="flex flex-wrap items-start justify-between gap-3">
346
+ <div className="min-w-0">
347
+ <h2 id={headingId} className="font-semibold">
348
+ {heading}
349
+ </h2>
350
+ {description ? <p className="mt-0.5 text-sm text-muted-foreground">{description}</p> : null}
351
+ </div>
352
+ {dateFilter || onExport ? (
353
+ <div className="flex w-full flex-wrap items-center gap-2 sm:w-auto">
354
+ {dateFilter ? (
355
+ <DatePicker
356
+ mode="range"
357
+ value={range}
358
+ onChange={setRange}
359
+ placeholder="All dates"
360
+ presets
361
+ size="sm"
362
+ label="Show dates"
363
+ className="min-w-0 flex-1 sm:w-56 sm:flex-none"
364
+ />
365
+ ) : null}
366
+ {onExport ? (
367
+ <Button size="sm" icon="download" onClick={runExport} loading={exporting} disabled={loading || !shown.length}>
368
+ {exportLabel}
369
+ </Button>
370
+ ) : null}
371
+ </div>
372
+ ) : null}
373
+ </header>
374
+ {error ? <Notice tone="danger">{error}</Notice> : null}
375
+ {exportError ? (
376
+ <Notice tone="danger" onDismiss={() => setExportError(null)}>
377
+ {exportError}
378
+ </Notice>
379
+ ) : null}
380
+ {body}
381
+ </section>
382
+ );
383
+ }
@@ -0,0 +1,179 @@
1
+ # Whiteboard
2
+
3
+ A full-page board to think on, friendly like Miro. A top bar holds the
4
+ board's title (click it to rename), the save state, a Board / Text view
5
+ switch, Export PNG and, when you give it `onShare`, a Share button. Under
6
+ it is the canvas from `sketch-canvas`: the tool rail (a bottom bar on a
7
+ phone), the toolbar that floats over a selection, zoom, undo and redo.
8
+
9
+ Give it `onCreateTask` and a selected note or text becomes a task from
10
+ the top bar; the note keeps a small **Task** badge from then on.
11
+
12
+ An empty board offers three starting points: **Blank**, **Grid** (six
13
+ titled areas, three by two) and **2×2 matrix** (impact against effort,
14
+ four tinted quadrants with axes). The **Text view** lists every word on
15
+ the board, grouped by frame — the reading of the board for a screen
16
+ reader, and what you hand an agent.
17
+
18
+ ```jsx
19
+ import { Whiteboard } from "../components/blocks/whiteboard"; // a Makersclaw app ("./blocks/whiteboard" from components/)
20
+ import { Whiteboard } from "@/components/makersclaw/blocks/whiteboard"; // a shadcn project
21
+ ```
22
+
23
+ It is a client component: render it from a `"use client"` component.
24
+ `makersclaw add whiteboard` adds `sketch-canvas` with it (and its npm
25
+ package, `@excalidraw/excalidraw`: run `npm install` after). The helpers
26
+ for reading a board — `sketchToText`, `sketchItems`, `isSketchEmpty` —
27
+ come from `sketch-canvas`.
28
+
29
+ ## The data
30
+
31
+ A board is two things you store: its **title** (a string) and its
32
+ **sketch** (plain JSON, a `jsonb` column) — the sketch format is
33
+ `sketch-canvas`'s (its README, "The data"). Colours in a sketch are theme
34
+ tokens, so a board repaints when the workspace theme changes.
35
+
36
+ One table does it: `boards(id, title text, sketch jsonb, sketch_text text,
37
+ updated_at)`. Keep `sketch_text` (`sketchToText(sketch)`) for search and
38
+ for agents.
39
+
40
+ ## Props
41
+
42
+ - `title` — the board's name, controlled. Change it when `onRename`
43
+ answers ok.
44
+ - `defaultTitle` — the name, uncontrolled (default "Untitled board").
45
+ - `onRename(title)` — `async`, returns `{ ok: true }` or
46
+ `{ ok: false, error? }`. Called when the reader renames the board (Enter
47
+ or leaving the field; Esc puts the old name back). While it runs the
48
+ new name shows; a failure keeps it and shows the error with Retry.
49
+ Without it the title still edits, in memory.
50
+ - `value` — the sketch, controlled (see sketch-canvas: pass back exactly
51
+ what `onChange` gave you).
52
+ - `defaultValue` — the sketch, uncontrolled. With neither, the board
53
+ starts empty and shows the templates.
54
+ - `onChange(sketch)` — the whole sketch after an edit settles (debounced).
55
+ - `onSave(sketch)` — `async`, `{ ok }`. Called with every settled edit and
56
+ on Cmd/Ctrl+S. The top bar shows "Saving…", "Saved", or the error with a
57
+ Retry. A throw counts as a failure.
58
+ - `changeDelay` — ms of quiet before `onChange` / `onSave` (default 600).
59
+ - `templates` — the starting points an empty board offers (default
60
+ `WHITEBOARD_TEMPLATES`: blank, grid, matrix). Each is
61
+ `{ id, label, description?, create(), preview?, icon? }`: `create()`
62
+ returns a sketch (or an element array) to lay on the board, or `null`
63
+ for "start blank". `preview` is a small node drawn in the tile (else an
64
+ `icon`, else a frame glyph; the three built-ins draw their own). `[]`
65
+ shows sketch-canvas's plain hint instead.
66
+ - `onShare()` — shows a Share button (primary) that calls it: open your
67
+ `share-dialog`. Without it there is no Share button. `shareLabel`
68
+ renames it (default "Share").
69
+ - `onExport(blob, { title, fileName })` — `async`, `{ ok }`: take the PNG
70
+ yourself (attach it, upload it). Without it, Export downloads
71
+ `<title>.png`. Either way a failure shows on the button.
72
+ - `onCreateTask({ title, sourceIds })` — turns notes into tasks. With it,
73
+ selecting a note (a shape with words in it) or a text shows **Create
74
+ task** in the top bar: a small form with the words as the title, ready
75
+ to edit (Enter creates). Several selected notes make one task each.
76
+ `async`, return `{ ok: true, id? }` or `{ ok: false, error? }` (a throw
77
+ counts as failed). `sourceIds` are the board elements it came from (the
78
+ note and its words). While it runs the note shows "Creating…"; on
79
+ success the note keeps a **Task** badge (stored in the sketch, as
80
+ `customData.task: { id, title }` on those elements) and is not offered
81
+ again; a failure says so and leaves the note as it was. `taskLabel`
82
+ renames the button (default "Create task").
83
+ - `onOpenTask({ id, title, sourceIds })` — makes each Task badge (and the
84
+ success toast) a link: open the task. Without it the badges only mark.
85
+ - `onBack()` — shows a back arrow at the left of the top bar; `backLabel`
86
+ is its name (default "Back").
87
+ - `meta` — a short node beside the title on wide screens ("Edited by Priya
88
+ Raman", "View only").
89
+ - `readOnly` — `false` (default). `true`: the title is plain text, the
90
+ canvas pans and zooms but does not edit, no templates.
91
+ - `defaultView` — `"board"` (default) or `"text"`: which view opens.
92
+ - `canvasRef` — a ref (`useSketchCanvas()` from sketch-canvas) that
93
+ receives the canvas handle: `exportImage()`, `getScene()`,
94
+ `insertElements()`… (sketch-canvas README, "The handle").
95
+ - `className` — layout: width, margin, height. The default height is
96
+ `h-[40rem]`; a height class of yours (`h-dvh` for a full page, `h-full`,
97
+ `flex-1`) replaces it. Never colour.
98
+
99
+ ### Templates
100
+
101
+ `WHITEBOARD_TEMPLATES` is the default list. `gridSketch(opts)` and
102
+ `matrixSketch(opts)` build the two drawn ones, so your own templates can
103
+ reuse them:
104
+
105
+ - `gridSketch({ columns = 3, rows = 2, width = 360, height = 260, gap = 48, names })`
106
+ — titled frames; `names` overrides "Area 1", "Area 2"…
107
+ - `matrixSketch({ x = "Effort", y = "Impact", quadrants = ["Quick wins", "Big bets", "Fill-ins", "Not now"], size = 360 })`
108
+ — four locked, tinted quadrants (notes land on them without moving
109
+ them), two axes, the quadrant names as editable text.
110
+
111
+ ## Example
112
+
113
+ A board page that saves itself:
114
+
115
+ ```jsx
116
+ "use client";
117
+ import { useState } from "react";
118
+ import { Whiteboard } from "./blocks/whiteboard";
119
+ import { sketchToText } from "./blocks/sketch-canvas";
120
+ import { updateRow } from "../lib/actions";
121
+
122
+ export default function BoardPage({ board, onShare }) {
123
+ const [title, setTitle] = useState(board.title);
124
+ return (
125
+ <Whiteboard
126
+ title={title}
127
+ onRename={async (next) => {
128
+ const res = await updateRow({ source: "public.boards", id: board.id, patch: { title: next } });
129
+ if (res.ok) setTitle(next);
130
+ return res;
131
+ }}
132
+ defaultValue={board.sketch} // jsonb, may be null
133
+ onSave={(sketch) => updateRow({ source: "public.boards", id: board.id, patch: { sketch, sketch_text: sketchToText(sketch) } })}
134
+ onShare={onShare}
135
+ className="h-dvh rounded-none border-0"
136
+ />
137
+ );
138
+ }
139
+ ```
140
+
141
+ Notes that become tasks (a `tasks` table of your own):
142
+
143
+ ```jsx
144
+ <Whiteboard
145
+ defaultValue={board.sketch}
146
+ onSave={save}
147
+ onCreateTask={({ title, sourceIds }) => insertRow({ source: "public.tasks", values: { title, board_id: board.id, source_ids: sourceIds } })}
148
+ onOpenTask={(task) => router.push(`/tasks/${task.id}`)}
149
+ />
150
+ ```
151
+
152
+ `insertRow` answers `{ ok, id }`; the id is what the badge keeps.
153
+
154
+ A retro template of your own, beside the built-in ones:
155
+
156
+ ```jsx
157
+ import { WHITEBOARD_TEMPLATES, gridSketch } from "./blocks/whiteboard";
158
+
159
+ const templates = [
160
+ ...WHITEBOARD_TEMPLATES,
161
+ { id: "retro", label: "Retro", description: "Went well, to improve, actions", icon: "history",
162
+ create: () => gridSketch({ columns: 3, rows: 1, height: 520, names: ["Went well", "To improve", "Actions"] }) },
163
+ ];
164
+
165
+ <Whiteboard templates={templates} onSave={save} />
166
+ ```
167
+
168
+ ## What it will not do
169
+
170
+ - Collaborate live: no cursors of others, saves are last-write-wins (as
171
+ sketch-canvas).
172
+ - Share by itself: `onShare` is yours — open `share-dialog`, copy a link.
173
+ - Keep a list of boards: one board per component; the list is your page.
174
+ - Turn on snap-to-grid from a template: the canvas menu has it.
175
+ - Show a minimap (sketch-canvas has none).
176
+
177
+ A board it cannot be is your own component in `components/` — not an edit
178
+ to this block. Its files are fixed: `npm run check` refuses a change, and
179
+ `makersclaw add whiteboard` restores them.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "whiteboard",
3
+ "title": "Whiteboard",
4
+ "description": "A full-page freeform whiteboard on sketch-canvas: a top bar with the board's title (click to rename), the save state (Saving…, Saved, or the error with Retry), a Board / Text view switch, Export PNG and an optional Share button; under it the Miro-style canvas (tool rail, floating toolbar, zoom, undo). An empty board offers starter templates — blank, a grid of titled areas, a 2×2 matrix — and the Text view lists every word on the board for a screen reader or an agent. With onCreateTask, a selected note or text becomes a task from the top bar (\"Create task\", editable title; several notes make one task each), and a small badge marks it on the board from then on. The sketch is plain JSON; saves are async callbacks answering { ok }.",
5
+ "useWhen": "A screen is one board to think on: a team whiteboard, a planning or prioritisation board, a place to sketch an idea and keep it with a record. Not for marking up a screenshot (annotate), sketching a UI to build (sketch-to-app), a structured board of cards and connectors (flow-canvas), or a kanban (board).",
6
+ "tags": ["whiteboard", "board", "sketch", "draw", "drawing", "canvas", "excalidraw", "miro", "brainstorm", "matrix", "2x2", "grid", "template", "export", "png", "share", "task", "create task", "action items"],
7
+ "exports": ["Whiteboard", "WHITEBOARD_TEMPLATES", "gridSketch", "matrixSketch"],
8
+ "files": ["index.js", "whiteboard.jsx", "templates.js"],
9
+ "requires": ["sketch-canvas"]
10
+ }