makersclaw 0.7.0 → 0.8.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 (419) hide show
  1. package/README.md +17 -4
  2. package/package.json +1 -1
  3. package/r/activity-log.json +52 -0
  4. package/r/agent-changes.json +51 -0
  5. package/r/agent-chat.json +53 -0
  6. package/r/agent-column.json +85 -0
  7. package/r/agent-dock.json +57 -0
  8. package/r/agent-kit.json +49 -0
  9. package/r/agent-marks.json +49 -0
  10. package/r/agent-pane.json +93 -0
  11. package/r/ai-action.json +56 -0
  12. package/r/annotate.json +4 -4
  13. package/r/approval-request.json +2 -2
  14. package/r/approval.json +54 -0
  15. package/r/ask-bar.json +50 -0
  16. package/r/audio-player.json +2 -2
  17. package/r/auth-form.json +2 -2
  18. package/r/automation-editor.json +66 -0
  19. package/r/automation-list.json +57 -0
  20. package/r/automation-model.json +118 -0
  21. package/r/automations-screen.json +71 -0
  22. package/r/board.json +2 -2
  23. package/r/calendar-view.json +3 -3
  24. package/r/cart.json +2 -2
  25. package/r/chart.json +5 -5
  26. package/r/chat-pane.json +84 -0
  27. package/r/chat.json +3 -3
  28. package/r/code-editor.json +2 -2
  29. package/r/comment-box.json +3 -3
  30. package/r/connect-card.json +51 -0
  31. package/r/contact-section.json +2 -2
  32. package/r/core.json +18 -6
  33. package/r/cost.json +51 -0
  34. package/r/csv-import.json +3 -3
  35. package/r/data-picker.json +60 -0
  36. package/r/data-table.json +2 -2
  37. package/r/diagram.json +2 -2
  38. package/r/doc-editor.json +2 -2
  39. package/r/doc-page.json +3 -3
  40. package/r/email-render.json +2 -2
  41. package/r/faq.json +2 -2
  42. package/r/file-upload.json +2 -2
  43. package/r/first-run.json +63 -0
  44. package/r/fix-note.json +57 -0
  45. package/r/flow-canvas.json +3 -3
  46. package/r/flow-editor.json +79 -0
  47. package/r/footer.json +3 -3
  48. package/r/gantt.json +3 -3
  49. package/r/job-panel.json +2 -2
  50. package/r/json-editor.json +3 -3
  51. package/r/library-shelf.json +56 -0
  52. package/r/map.json +2 -2
  53. package/r/margin-notes.json +67 -0
  54. package/r/menubar.json +2 -2
  55. package/r/mind-map.json +4 -4
  56. package/r/navigation-menu.json +2 -2
  57. package/r/needs-you.json +55 -0
  58. package/r/order-detail.json +2 -2
  59. package/r/org-chart.json +4 -4
  60. package/r/pace-bar.json +69 -0
  61. package/r/page-builder.json +3 -3
  62. package/r/payment-methods.json +2 -2
  63. package/r/pdf-document.json +2 -2
  64. package/r/pdf-viewer.json +3 -3
  65. package/r/product-detail.json +2 -2
  66. package/r/product-grid.json +3 -3
  67. package/r/record-form.json +2 -2
  68. package/r/record-grid.json +52 -0
  69. package/r/record-notes.json +4 -4
  70. package/r/registry.json +4089 -1510
  71. package/r/run-history.json +52 -0
  72. package/r/run-view.json +80 -0
  73. package/r/schedule-card.json +54 -0
  74. package/r/schedule-engine.json +79 -0
  75. package/r/schedule-gantt.json +83 -0
  76. package/r/schedule-ruler.json +64 -0
  77. package/r/search-dialog.json +2 -2
  78. package/r/settings-list.json +2 -2
  79. package/r/setup-checklist.json +2 -2
  80. package/r/share-dialog.json +2 -2
  81. package/r/sidebar.json +3 -3
  82. package/r/signature-pad.json +2 -2
  83. package/r/sketch-canvas.json +3 -3
  84. package/r/source-receipt.json +52 -0
  85. package/r/spreadsheet.json +3 -3
  86. package/r/stat-cards.json +3 -3
  87. package/r/step-picker.json +53 -0
  88. package/r/step-settings.json +72 -0
  89. package/r/suggestion.json +58 -0
  90. package/r/sum-bar.json +64 -0
  91. package/r/task-list.json +3 -3
  92. package/r/task-model.json +2 -2
  93. package/r/testimonials.json +2 -2
  94. package/r/tier-map.json +67 -0
  95. package/r/time-grid.json +73 -0
  96. package/r/time-strip.json +64 -0
  97. package/r/top-bar.json +66 -0
  98. package/r/transaction-list.json +2 -2
  99. package/r/trigger-picker.json +61 -0
  100. package/r/whiteboard.json +4 -4
  101. package/r/workflow-view.json +55 -0
  102. package/registry/blocks/activity-log/README.md +112 -0
  103. package/registry/blocks/activity-log/activity-log.jsx +351 -0
  104. package/registry/blocks/activity-log/block.json +33 -0
  105. package/registry/blocks/activity-log/demo.jsx +48 -0
  106. package/registry/blocks/activity-log/index.js +4 -0
  107. package/registry/blocks/agent-changes/README.md +94 -0
  108. package/registry/blocks/agent-changes/agent-changes.jsx +118 -0
  109. package/registry/blocks/agent-changes/block.json +28 -0
  110. package/registry/blocks/agent-changes/demo.jsx +39 -0
  111. package/registry/blocks/agent-changes/index.js +3 -0
  112. package/registry/blocks/agent-chat/README.md +145 -0
  113. package/registry/blocks/agent-chat/agent-chat.jsx +415 -0
  114. package/registry/blocks/agent-chat/block.json +30 -0
  115. package/registry/blocks/agent-chat/demo.jsx +165 -0
  116. package/registry/blocks/agent-chat/index.js +3 -0
  117. package/registry/blocks/agent-column/README.md +197 -0
  118. package/registry/blocks/agent-column/agent-column.jsx +492 -0
  119. package/registry/blocks/agent-column/block.json +67 -0
  120. package/registry/blocks/agent-column/column-picker.jsx +163 -0
  121. package/registry/blocks/agent-column/demo.jsx +50 -0
  122. package/registry/blocks/agent-column/index.js +7 -0
  123. package/registry/blocks/agent-column/model.js +164 -0
  124. package/registry/blocks/agent-column/receipt.jsx +483 -0
  125. package/registry/blocks/agent-column/spreadsheet-type.jsx +24 -0
  126. package/registry/blocks/agent-dock/README.md +210 -0
  127. package/registry/blocks/agent-dock/agent-dock.jsx +356 -0
  128. package/registry/blocks/agent-dock/block.json +47 -0
  129. package/registry/blocks/agent-dock/demo.jsx +153 -0
  130. package/registry/blocks/agent-dock/dock-model.js +118 -0
  131. package/registry/blocks/agent-dock/index.js +5 -0
  132. package/registry/blocks/agent-kit/README.md +73 -0
  133. package/registry/blocks/agent-kit/agent-kit.jsx +86 -0
  134. package/registry/blocks/agent-kit/block.json +10 -0
  135. package/registry/blocks/agent-kit/demo.jsx +35 -0
  136. package/registry/blocks/agent-kit/index.js +3 -0
  137. package/registry/blocks/agent-marks/README.md +80 -0
  138. package/registry/blocks/agent-marks/agent-marks.jsx +133 -0
  139. package/registry/blocks/agent-marks/block.json +27 -0
  140. package/registry/blocks/agent-marks/demo.jsx +49 -0
  141. package/registry/blocks/agent-marks/index.js +3 -0
  142. package/registry/blocks/agent-pane/README.md +225 -0
  143. package/registry/blocks/agent-pane/agent-pane.jsx +244 -0
  144. package/registry/blocks/agent-pane/block.json +41 -0
  145. package/registry/blocks/agent-pane/composer.jsx +6 -0
  146. package/registry/blocks/agent-pane/demo.jsx +233 -0
  147. package/registry/blocks/agent-pane/dock-context.js +10 -0
  148. package/registry/blocks/agent-pane/index.js +4 -0
  149. package/registry/blocks/agent-pane/prose.jsx +84 -0
  150. package/registry/blocks/agent-pane/questions.jsx +134 -0
  151. package/registry/blocks/agent-pane/transcript.jsx +268 -0
  152. package/registry/blocks/agent-pane/work.jsx +368 -0
  153. package/registry/blocks/ai-action/README.md +94 -0
  154. package/registry/blocks/ai-action/ai-action.jsx +188 -0
  155. package/registry/blocks/ai-action/block.json +34 -0
  156. package/registry/blocks/ai-action/demo.jsx +93 -0
  157. package/registry/blocks/ai-action/index.js +3 -0
  158. package/registry/blocks/annotate/README.md +14 -11
  159. package/registry/blocks/approval/README.md +145 -0
  160. package/registry/blocks/approval/approval.jsx +163 -0
  161. package/registry/blocks/approval/block.json +31 -0
  162. package/registry/blocks/approval/demo.jsx +121 -0
  163. package/registry/blocks/approval/index.js +3 -0
  164. package/registry/blocks/ask-bar/README.md +105 -0
  165. package/registry/blocks/ask-bar/ask-bar.jsx +166 -0
  166. package/registry/blocks/ask-bar/block.json +26 -0
  167. package/registry/blocks/ask-bar/demo.jsx +78 -0
  168. package/registry/blocks/ask-bar/index.js +3 -0
  169. package/registry/blocks/automation-editor/README.md +291 -0
  170. package/registry/blocks/automation-editor/automation-editor.jsx +656 -0
  171. package/registry/blocks/automation-editor/block.json +39 -0
  172. package/registry/blocks/automation-editor/demo.jsx +284 -0
  173. package/registry/blocks/automation-editor/index.js +4 -0
  174. package/registry/blocks/automation-editor/run-inputs.jsx +82 -0
  175. package/registry/blocks/automation-list/README.md +129 -0
  176. package/registry/blocks/automation-list/automation-list.jsx +476 -0
  177. package/registry/blocks/automation-list/block.json +35 -0
  178. package/registry/blocks/automation-list/demo.jsx +67 -0
  179. package/registry/blocks/automation-list/index.js +3 -0
  180. package/registry/blocks/automation-model/README.md +109 -0
  181. package/registry/blocks/automation-model/block.json +135 -0
  182. package/registry/blocks/automation-model/catalog.js +256 -0
  183. package/registry/blocks/automation-model/check.js +161 -0
  184. package/registry/blocks/automation-model/demo.jsx +42 -0
  185. package/registry/blocks/automation-model/edit.js +262 -0
  186. package/registry/blocks/automation-model/fixes.js +287 -0
  187. package/registry/blocks/automation-model/glyph.jsx +13 -0
  188. package/registry/blocks/automation-model/graph.js +410 -0
  189. package/registry/blocks/automation-model/index.js +33 -0
  190. package/registry/blocks/automation-model/overlay.js +175 -0
  191. package/registry/blocks/automation-model/parts.jsx +94 -0
  192. package/registry/blocks/automation-model/schedule.js +53 -0
  193. package/registry/blocks/automation-model/templates.js +128 -0
  194. package/registry/blocks/automation-model/values.js +29 -0
  195. package/registry/blocks/automation-model/words.js +439 -0
  196. package/registry/blocks/automations-screen/README.md +207 -0
  197. package/registry/blocks/automations-screen/automations-screen.jsx +452 -0
  198. package/registry/blocks/automations-screen/block.json +47 -0
  199. package/registry/blocks/automations-screen/demo.jsx +364 -0
  200. package/registry/blocks/automations-screen/index.js +4 -0
  201. package/registry/blocks/automations-screen/screen-model.js +129 -0
  202. package/registry/blocks/chart/cartesian.jsx +1 -1
  203. package/registry/blocks/chart/core.jsx +33 -23
  204. package/registry/blocks/chart/pie.jsx +1 -1
  205. package/registry/blocks/chat/README.md +4 -1
  206. package/registry/blocks/chat/demo.jsx +2 -2
  207. package/registry/blocks/chat-pane/README.md +143 -0
  208. package/registry/blocks/chat-pane/block.json +48 -0
  209. package/registry/blocks/chat-pane/chat-attach.js +166 -0
  210. package/registry/blocks/chat-pane/chat-composer.jsx +195 -0
  211. package/registry/blocks/chat-pane/chat-context.js +17 -0
  212. package/registry/blocks/chat-pane/chat-model.js +43 -0
  213. package/registry/blocks/chat-pane/chat-pane.jsx +398 -0
  214. package/registry/blocks/chat-pane/chats-list.jsx +52 -0
  215. package/registry/blocks/chat-pane/demo.jsx +103 -0
  216. package/registry/blocks/chat-pane/index.js +9 -0
  217. package/registry/blocks/connect-card/README.md +99 -0
  218. package/registry/blocks/connect-card/block.json +10 -0
  219. package/registry/blocks/connect-card/connect-card.jsx +103 -0
  220. package/registry/blocks/connect-card/demo.jsx +49 -0
  221. package/registry/blocks/connect-card/index.js +3 -0
  222. package/registry/blocks/cost/README.md +115 -0
  223. package/registry/blocks/cost/block.json +10 -0
  224. package/registry/blocks/cost/cost.jsx +176 -0
  225. package/registry/blocks/cost/demo.jsx +66 -0
  226. package/registry/blocks/cost/index.js +3 -0
  227. package/registry/blocks/data-picker/README.md +81 -0
  228. package/registry/blocks/data-picker/block.json +38 -0
  229. package/registry/blocks/data-picker/data-picker.jsx +210 -0
  230. package/registry/blocks/data-picker/demo.jsx +34 -0
  231. package/registry/blocks/data-picker/fields.js +89 -0
  232. package/registry/blocks/data-picker/index.js +4 -0
  233. package/registry/blocks/data-table/demo.jsx +1 -1
  234. package/registry/blocks/first-run/README.md +118 -0
  235. package/registry/blocks/first-run/block.json +11 -0
  236. package/registry/blocks/first-run/demo.jsx +88 -0
  237. package/registry/blocks/first-run/first-run-model.js +51 -0
  238. package/registry/blocks/first-run/first-run.jsx +156 -0
  239. package/registry/blocks/first-run/index.js +5 -0
  240. package/registry/blocks/first-run/probe-rules.js +26 -0
  241. package/registry/blocks/fix-note/README.md +79 -0
  242. package/registry/blocks/fix-note/block.json +35 -0
  243. package/registry/blocks/fix-note/demo.jsx +30 -0
  244. package/registry/blocks/fix-note/fix-note.jsx +235 -0
  245. package/registry/blocks/fix-note/index.js +3 -0
  246. package/registry/blocks/flow-canvas/README.md +15 -8
  247. package/registry/blocks/flow-editor/README.md +108 -0
  248. package/registry/blocks/flow-editor/block.json +44 -0
  249. package/registry/blocks/flow-editor/demo.jsx +115 -0
  250. package/registry/blocks/flow-editor/flow-canvas.jsx +568 -0
  251. package/registry/blocks/flow-editor/flow-editor.jsx +154 -0
  252. package/registry/blocks/flow-editor/index.js +6 -0
  253. package/registry/blocks/flow-editor/minimap.jsx +78 -0
  254. package/registry/blocks/flow-editor/outline.jsx +134 -0
  255. package/registry/blocks/footer/README.md +3 -2
  256. package/registry/blocks/library-shelf/README.md +117 -0
  257. package/registry/blocks/library-shelf/block.json +28 -0
  258. package/registry/blocks/library-shelf/demo.jsx +68 -0
  259. package/registry/blocks/library-shelf/index.js +3 -0
  260. package/registry/blocks/library-shelf/library-shelf.jsx +211 -0
  261. package/registry/blocks/library-shelf/probe-rules.js +15 -0
  262. package/registry/blocks/margin-notes/README.md +222 -0
  263. package/registry/blocks/margin-notes/block.json +10 -0
  264. package/registry/blocks/margin-notes/demo.jsx +144 -0
  265. package/registry/blocks/margin-notes/index.js +20 -0
  266. package/registry/blocks/margin-notes/margin-model.js +224 -0
  267. package/registry/blocks/margin-notes/margin-notes.jsx +465 -0
  268. package/registry/blocks/mind-map/README.md +4 -2
  269. package/registry/blocks/needs-you/README.md +177 -0
  270. package/registry/blocks/needs-you/block.json +34 -0
  271. package/registry/blocks/needs-you/demo.jsx +143 -0
  272. package/registry/blocks/needs-you/index.js +3 -0
  273. package/registry/blocks/needs-you/needs-you.jsx +441 -0
  274. package/registry/blocks/org-chart/README.md +4 -2
  275. package/registry/blocks/pace-bar/README.md +230 -0
  276. package/registry/blocks/pace-bar/block.json +10 -0
  277. package/registry/blocks/pace-bar/demo.jsx +255 -0
  278. package/registry/blocks/pace-bar/index.js +22 -0
  279. package/registry/blocks/pace-bar/pace-bar.jsx +461 -0
  280. package/registry/blocks/pace-bar/pace-model.js +288 -0
  281. package/registry/blocks/page-builder/README.md +1 -1
  282. package/registry/blocks/page-builder/demo.jsx +3 -3
  283. package/registry/blocks/pdf-viewer/README.md +4 -1
  284. package/registry/blocks/record-grid/README.md +100 -0
  285. package/registry/blocks/record-grid/block.json +28 -0
  286. package/registry/blocks/record-grid/demo.jsx +43 -0
  287. package/registry/blocks/record-grid/index.js +3 -0
  288. package/registry/blocks/record-grid/record-grid.jsx +251 -0
  289. package/registry/blocks/run-history/README.md +138 -0
  290. package/registry/blocks/run-history/block.json +10 -0
  291. package/registry/blocks/run-history/demo.jsx +74 -0
  292. package/registry/blocks/run-history/index.js +3 -0
  293. package/registry/blocks/run-history/run-history.jsx +218 -0
  294. package/registry/blocks/run-view/README.md +174 -0
  295. package/registry/blocks/run-view/block.json +50 -0
  296. package/registry/blocks/run-view/demo.jsx +286 -0
  297. package/registry/blocks/run-view/index.js +5 -0
  298. package/registry/blocks/run-view/run-controls.jsx +266 -0
  299. package/registry/blocks/run-view/run-view.jsx +236 -0
  300. package/registry/blocks/run-view/runs-list.jsx +99 -0
  301. package/registry/blocks/schedule-card/README.md +121 -0
  302. package/registry/blocks/schedule-card/block.json +10 -0
  303. package/registry/blocks/schedule-card/demo.jsx +82 -0
  304. package/registry/blocks/schedule-card/index.js +3 -0
  305. package/registry/blocks/schedule-card/schedule-card.jsx +136 -0
  306. package/registry/blocks/schedule-engine/README.md +137 -0
  307. package/registry/blocks/schedule-engine/block.json +10 -0
  308. package/registry/blocks/schedule-engine/demo.jsx +82 -0
  309. package/registry/blocks/schedule-engine/engine.js +769 -0
  310. package/registry/blocks/schedule-engine/index.js +9 -0
  311. package/registry/blocks/schedule-engine/ops.js +71 -0
  312. package/registry/blocks/schedule-engine/place.js +294 -0
  313. package/registry/blocks/schedule-engine/tree.js +79 -0
  314. package/registry/blocks/schedule-engine/waits.js +80 -0
  315. package/registry/blocks/schedule-gantt/README.md +159 -0
  316. package/registry/blocks/schedule-gantt/block.json +10 -0
  317. package/registry/blocks/schedule-gantt/demo.jsx +223 -0
  318. package/registry/blocks/schedule-gantt/gantt-model.js +219 -0
  319. package/registry/blocks/schedule-gantt/geometry.js +176 -0
  320. package/registry/blocks/schedule-gantt/index.js +26 -0
  321. package/registry/blocks/schedule-gantt/schedule-gantt.jsx +882 -0
  322. package/registry/blocks/schedule-gantt/sheet.jsx +372 -0
  323. package/registry/blocks/schedule-gantt/track.jsx +190 -0
  324. package/registry/blocks/schedule-ruler/README.md +148 -0
  325. package/registry/blocks/schedule-ruler/block.json +10 -0
  326. package/registry/blocks/schedule-ruler/demo.jsx +181 -0
  327. package/registry/blocks/schedule-ruler/index.js +21 -0
  328. package/registry/blocks/schedule-ruler/ruler-model.js +239 -0
  329. package/registry/blocks/schedule-ruler/schedule-ruler.jsx +548 -0
  330. package/registry/blocks/sidebar/README.md +23 -13
  331. package/registry/blocks/sketch-canvas/README.md +15 -9
  332. package/registry/blocks/source-receipt/README.md +97 -0
  333. package/registry/blocks/source-receipt/block.json +30 -0
  334. package/registry/blocks/source-receipt/demo.jsx +71 -0
  335. package/registry/blocks/source-receipt/index.js +3 -0
  336. package/registry/blocks/source-receipt/source-receipt.jsx +107 -0
  337. package/registry/blocks/spreadsheet/spreadsheet.jsx +15 -1
  338. package/registry/blocks/step-picker/README.md +78 -0
  339. package/registry/blocks/step-picker/block.json +31 -0
  340. package/registry/blocks/step-picker/demo.jsx +23 -0
  341. package/registry/blocks/step-picker/index.js +3 -0
  342. package/registry/blocks/step-picker/step-picker.jsx +144 -0
  343. package/registry/blocks/step-settings/README.md +100 -0
  344. package/registry/blocks/step-settings/block.json +44 -0
  345. package/registry/blocks/step-settings/demo.jsx +93 -0
  346. package/registry/blocks/step-settings/fields.jsx +58 -0
  347. package/registry/blocks/step-settings/flow-settings.jsx +115 -0
  348. package/registry/blocks/step-settings/index.js +5 -0
  349. package/registry/blocks/step-settings/step-settings.jsx +290 -0
  350. package/registry/blocks/suggestion/README.md +171 -0
  351. package/registry/blocks/suggestion/block.json +40 -0
  352. package/registry/blocks/suggestion/demo.jsx +91 -0
  353. package/registry/blocks/suggestion/index.js +3 -0
  354. package/registry/blocks/suggestion/suggestion.jsx +436 -0
  355. package/registry/blocks/sum-bar/README.md +122 -0
  356. package/registry/blocks/sum-bar/block.json +10 -0
  357. package/registry/blocks/sum-bar/demo.jsx +110 -0
  358. package/registry/blocks/sum-bar/index.js +5 -0
  359. package/registry/blocks/sum-bar/sum-bar.jsx +209 -0
  360. package/registry/blocks/sum-bar/sum-model.js +126 -0
  361. package/registry/blocks/tier-map/README.md +217 -0
  362. package/registry/blocks/tier-map/block.json +10 -0
  363. package/registry/blocks/tier-map/demo.jsx +222 -0
  364. package/registry/blocks/tier-map/index.js +24 -0
  365. package/registry/blocks/tier-map/tier-map.jsx +574 -0
  366. package/registry/blocks/tier-map/tier-model.js +318 -0
  367. package/registry/blocks/time-grid/README.md +305 -0
  368. package/registry/blocks/time-grid/block.json +10 -0
  369. package/registry/blocks/time-grid/demo.jsx +279 -0
  370. package/registry/blocks/time-grid/grid-model.js +322 -0
  371. package/registry/blocks/time-grid/index.js +25 -0
  372. package/registry/blocks/time-grid/time-grid.jsx +1325 -0
  373. package/registry/blocks/time-strip/README.md +141 -0
  374. package/registry/blocks/time-strip/block.json +10 -0
  375. package/registry/blocks/time-strip/demo.jsx +129 -0
  376. package/registry/blocks/time-strip/index.js +19 -0
  377. package/registry/blocks/time-strip/strip-model.js +178 -0
  378. package/registry/blocks/time-strip/time-strip.jsx +260 -0
  379. package/registry/blocks/top-bar/README.md +149 -0
  380. package/registry/blocks/top-bar/block.json +35 -0
  381. package/registry/blocks/top-bar/demo.jsx +78 -0
  382. package/registry/blocks/top-bar/index.js +5 -0
  383. package/registry/blocks/top-bar/probe-rules.js +74 -0
  384. package/registry/blocks/top-bar/top-bar-model.js +152 -0
  385. package/registry/blocks/top-bar/top-bar.jsx +244 -0
  386. package/registry/blocks/trigger-picker/README.md +98 -0
  387. package/registry/blocks/trigger-picker/block.json +38 -0
  388. package/registry/blocks/trigger-picker/demo.jsx +59 -0
  389. package/registry/blocks/trigger-picker/index.js +3 -0
  390. package/registry/blocks/trigger-picker/trigger-picker.jsx +374 -0
  391. package/registry/blocks/whiteboard/README.md +20 -14
  392. package/registry/blocks/workflow-view/README.md +123 -0
  393. package/registry/blocks/workflow-view/block.json +10 -0
  394. package/registry/blocks/workflow-view/demo.jsx +90 -0
  395. package/registry/blocks/workflow-view/index.js +3 -0
  396. package/registry/blocks/workflow-view/workflow-view.jsx +203 -0
  397. package/src/cli.mjs +2 -2
  398. package/src/install.mjs +100 -22
  399. package/src/registry.mjs +37 -3
  400. package/templates/next/browser/lib/data.js +6 -1
  401. package/templates/next/files/README.md +909 -26
  402. package/templates/next/files/app/shell.jsx +54 -37
  403. package/templates/next/files/check/automation-format.ts +2103 -0
  404. package/templates/next/files/check/automation-package.ts +142 -0
  405. package/templates/next/files/check/run.mjs +1043 -12
  406. package/templates/next/files/components/ui/field.jsx +17 -4
  407. package/templates/next/files/components/ui/icon.jsx +13 -0
  408. package/templates/next/files/components/ui/index.js +3 -1
  409. package/templates/next/files/components/ui/layout.jsx +382 -0
  410. package/templates/next/files/components/ui/notice.jsx +70 -0
  411. package/templates/next/files/components/ui/page.jsx +124 -0
  412. package/templates/next/files/components/ui/stat.jsx +22 -7
  413. package/templates/next/files/components/ui/toast.jsx +6 -3
  414. package/templates/next/files/lib/automations.js +660 -0
  415. package/templates/next/files/lib/claw.js +244 -5
  416. package/templates/next/files/lib/door.js +92 -0
  417. package/templates/next/files/lib/hooks.js +1694 -6
  418. package/templates/next/files/lib/platform.js +611 -14
  419. package/templates/next/template.json +22 -3
package/r/sidebar.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "title": "Sidebar",
6
6
  "description": "An app's navigation down the left edge: app name or workspace switcher, groups of items with icons, counts and nested items, the signed-in person with their menu; collapses to icons (remembered) and becomes a Sheet behind a trigger on a phone. Optional: inset or floating look, a ⌘K search over every item, folding groups with colour dots, a second column (a mail list, or a parent's children to drill into), a \"New\" button and a \"…\" menu per item (a chat history).",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.7.0/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -31,7 +31,7 @@
31
31
  "path": "registry/blocks/sidebar/README.md",
32
32
  "type": "registry:file",
33
33
  "target": "@components/makersclaw/blocks/sidebar/README.md",
34
- "content": "# Sidebar\n\nAn app's navigation down the left edge: the app's name (or a workspace\nswitcher), groups of items with icons, counts and nested items, a slot of\nyour own, and the signed-in person at the foot with their menu. On a wide\nwindow it collapses to icons — every label stays, as a tooltip — and\nremembers that. On a phone it is not a column at all: it is a Sheet that\n`SidebarTrigger` opens (from the leading edge; a bottom sheet under\n640px), and it closes when an item is chosen.\n\n```jsx\nimport { Sidebar, SidebarLayout, SidebarTrigger } from \"../components/blocks/sidebar\"; // a Makersclaw app (\"./blocks/sidebar\" from components/)\nimport { Sidebar, SidebarLayout, SidebarTrigger } from \"@/components/makersclaw/blocks/sidebar\"; // a shadcn project\n```\n\nIt is a client component. In a Makersclaw app it belongs in\n`app/shell.jsx`, around the surfaces — the shell's nav is what it replaces.\n\n## The data\n\n`groups` is a list of `{ label?, items }`. An item:\n\n- `label` — what it says (required).\n- `href` — where it goes; rendered as a link (base path applied). Or\n- `onSelect(item)` — what choosing it does. Both may be given.\n- `icon` — a kit icon name. Needed for the icon rail (a missing one shows\n `file`).\n- `active` — true on the current page: `aria-current=\"page\"` and the\n highlighted look. The parent of an active item is open to begin with.\n- `badge` — a count or a word, shown on the right; a dot in the rail.\n- `items` — nested items (same shape, one level): the item becomes a\n collapsible row. In the rail its icon widens the sidebar with it open.\n With `drilldown` it opens them instead (see Sidebar).\n- `hue` — 1..5: a colour dot in place of the icon (a favourite, a label).\n- `description` — a muted second line (shown on children in drill-in).\n- `actions` — kit `Menu` items: a \"…\" at the row's end, shown on hover\n or focus (always on a touch screen). Each `onSelect(item)` may be async\n and return `{ ok, error? }`; `{ ok: false }` or a throw shows an error\n toast. Not drawn in the icon rail.\n- `keywords` — extra words the ⌘K search matches, never shown.\n- `disabled` · `key` (default `href`, then `label`).\n\nA group is `{ label?, items, collapsible?, defaultOpen?, key? }`.\n`collapsible: true` makes its heading fold it; `defaultOpen` (default\ntrue) is where it starts. The icon rail shows every group unfolded.\n\n## Props\n\n### SidebarLayout\n\n- `sidebar` — the `<Sidebar>` element.\n- `children` — the page beside it. Put `<SidebarTrigger />` in its header.\n- `storageKey` — remember collapsed/expanded in this browser under this\n key. Optional; without it every visit starts at `defaultCollapsed`.\n- `defaultCollapsed` — default `false`.\n- `collapsed` + `onCollapsedChange(next)` — control it yourself instead.\n- `shortcut` — Cmd/Ctrl + this key toggles it; default `\"b\"`, `null` for none.\n- `variant` — `\"inset\"` draws the page as a card on the frame's ground.\n Default: the Sidebar's own `variant`, so you rarely pass it here.\n- `className` — the frame's height and edges (`min-h-dvh` in a shell).\n Never colour.\n\n### Sidebar\n\n- `groups` — see The data. `items` is the one-group shorthand.\n- `title` — the app's or workspace's name, at the top and on the sheet.\n- `subtitle` — a muted line under it (a plan, a team).\n- `logo` — a node beside the title; default a square `Avatar` of `title`.\n- `switcher` — kit `Menu` items (`[{ label, onSelect, icon? }]`): the title\n becomes a menu for changing workspace. `switcherLabel` names it\n (default \"Switch workspace\"); a reader hears \"<title>, <switcherLabel>\",\n so a voice user who says the title still hits it.\n- `user` — `{ name, email?, src? }`, shown at the foot with an `Avatar`.\n- `userMenu` — kit `Menu` items (`[{ label, onSelect, icon?, tone?: \"danger\",\n disabled? }]`, and groups and separators): the person becomes a menu\n button opening these upward (beside the rail when it is icons), flipping\n where there is no room. A choice also closes the phone sheet.\n- `children` — your own content under the groups (a target, a promo, a\n help link). Hidden in the icon rail.\n- `label` — the nav landmark's name, default \"Main\".\n- `className` — layout only. Never colour.\n\nShapes and extras (all optional; leave them out and it is the column\nabove):\n\n- `variant` — `\"sidebar\"` (default: a bordered column) · `\"inset\"` (no\n border; the page beside it becomes a rounded card) · `\"floating\"` (a\n rounded card held off the window's edge). A phone is a sheet either way.\n- `headerActions` — a node at the top right: a notifications `Menu`, a\n button. Hidden in the icon rail; first row of the phone sheet.\n- `switcherPlacement` — `\"header\"` (default) · `\"footer\"`: the switcher\n moves to the foot, over the person, and the top keeps only `logo`.\n- `search` — `true` or `{ placeholder?, hotkey?, label?, empty?,\n groupLabel? }`: a search row under the top that opens the kit\n `CommandDialog` over every item (children listed under their parent's\n name). `hotkey` defaults to `\"k\"` (⌘K / Ctrl+K), `null` for none. A\n palette choice runs the item's `onSelect`; an item with only `href`\n is followed as a page load (the app's base path applied). Give items\n `onSelect` with `router.push` for a client-side jump.\n- `primaryAction` — `{ label, icon?, onSelect?, href? }`: one button above\n the groups (\"New chat\"). `onSelect` may return `{ ok: false, error }`,\n shown as a toast.\n- `footerActions` — kit `Menu` items behind a \"+\" beside the person (New\n deal, Invite). `footerActionsLabel` names it, default \"Create\". Same\n `{ ok }` rule as `actions`.\n- `drilldown` — `\"inline\"` (default: a parent folds open) · `\"panel\"`\n (its children open in a second column with a close button; Esc closes\n it; the icon rail stays narrow beside it) · `\"replace\"` (its children\n replace the list, under a Back row). The parent holding the active\n item starts open. On a phone both are the replace form.\n- `panel` — a second column beside the nav from 768px, 320px wide: your\n own node, or `{ title?, actions?, search?, items, loading?, error?,\n onRetry?, empty?, onSelect?, query?, onQueryChange?, filter? }`.\n - `items`: `[{ key?, title, subtitle?, description?, meta?, icon?,\n media?, active?, href?, onSelect?, disabled? }]` — a mail is sender\n (title), date (meta), subject (subtitle), teaser (description).\n - `search`: `true` or `{ placeholder }`: a field that filters the items\n here; `filter: false` when you filter them yourself from\n `onQueryChange(query)`.\n - `loading` draws skeleton rows, `error` (text) a notice with Try\n again (`onRetry`), and no items the `empty` line.\n - On a phone it is the sheet's second screen: choosing a nav item (or\n the panel's own row at the top) shows it, with a Back row.\n\n### SidebarTrigger\n\nThe header button: opens the sheet on a phone, collapses to icons from\n768px. `className` for placement.\n\n### useSidebar()\n\n`{ collapsed, setCollapsed, toggle, mobileOpen, setMobileOpen }` inside a\n`SidebarLayout`, for a control of your own; `null` outside one.\n\n## Example\n\n```jsx\n// app/shell.jsx — the app's shell, the surfaces as the sidebar's items\n\"use client\";\nimport { usePathname } from \"next/navigation\";\nimport { Sidebar, SidebarLayout, SidebarTrigger } from \"../components/blocks/sidebar\";\n\nconst ICONS = { inbox: \"inbox\", deals: \"dollar\", contacts: \"users\", reports: \"chart\" };\n\nexport default function Shell({ name, surfaces, children }) {\n const pathname = usePathname() ?? \"\";\n const activeKey = decodeURIComponent(/^\\/s\\/([^/?#]+)/.exec(pathname)?.[1] ?? \"\");\n const items = surfaces.map((s) => ({\n key: s.key,\n label: s.label,\n href: `/s/${encodeURIComponent(s.key)}`,\n icon: ICONS[s.key] ?? \"file\",\n active: s.key === activeKey,\n badge: s.built ? undefined : \"planned\",\n }));\n return (\n <SidebarLayout\n storageKey={`${name}.sidebar`}\n className=\"min-h-dvh\"\n sidebar={<Sidebar title={name} items={items} label={`${name} surfaces`} />}\n >\n <header className=\"flex min-h-14 items-center gap-2 border-b border-border px-2 md:hidden\">\n <SidebarTrigger />\n <span className=\"font-semibold\">{name}</span>\n </header>\n <main className=\"min-w-0 flex-1 p-4 sm:p-6\">{children}</main>\n </SidebarLayout>\n );\n}\n```\n\n## What it will not do\n\n- Know the route: say which item is `active` (from `usePathname()`).\n- Nest deeper than one level: a second level is a page of its own.\n- Cover the page on a wide window or dock on the right: floating is a\n card beside the page, not over it; it is on the left from 768px and a\n sheet below that.\n- Hold the panel's data: the list, its loading and its errors are yours.\n- Take a colour: it wears the workspace theme.\n\nA sidebar it cannot be is your own component in `components/`, built from\nthe kit — not an edit to this block. Its files are fixed: `npm run check`\nrefuses a change, and `makersclaw add sidebar` restores them.\n\n## Credits\n\nThe inset, floating, search, folding-group, panel, drill-in and item-menu\nshapes follow blocks.so (https://blocks.so, MIT) — a rewrite on the\nMakersclaw kit, none of its code.\n"
34
+ "content": "# Sidebar\n\nAn app's navigation down the left edge: the app's name (or a workspace\nswitcher), groups of items with icons, counts and nested items, a slot of\nyour own, and the signed-in person at the foot with their menu. On a wide\nwindow it collapses to icons — every label stays, as a tooltip — and\nremembers that. On a phone it is not a column at all: it is a Sheet that\n`SidebarTrigger` opens (from the leading edge; a bottom sheet under\n640px), and it closes when an item is chosen.\n\n```jsx\nimport { Sidebar, SidebarLayout, SidebarTrigger } from \"../components/blocks/sidebar\"; // a Makersclaw app (\"./blocks/sidebar\" from components/)\nimport { Sidebar, SidebarLayout, SidebarTrigger } from \"@/components/makersclaw/blocks/sidebar\"; // a shadcn project\n```\n\nIt is a client component. In a Makersclaw app it belongs in\n`app/shell.jsx`, around the surfaces — the shell's nav is what it replaces.\n\n## The data\n\n`groups` is a list of `{ label?, items }`. An item:\n\n- `label` — what it says (required).\n- `href` — where it goes; rendered as a link (base path applied). Or\n- `onSelect(item)` — what choosing it does. Both may be given.\n- `icon` — a kit icon name. Needed for the icon rail (a missing one shows\n `file`).\n- `active` — true on the current page: `aria-current=\"page\"` and the\n highlighted look. The parent of an active item is open to begin with.\n- `badge` — a count or a word, shown on the right; a dot in the rail.\n- `items` — nested items (same shape, one level): the item becomes a\n collapsible row. In the rail its icon widens the sidebar with it open.\n With `drilldown` it opens them instead (see Sidebar).\n- `hue` — 1..5: a colour dot in place of the icon (a favourite, a label).\n- `description` — a muted second line (shown on children in drill-in).\n- `actions` — kit `Menu` items: a \"…\" at the row's end, shown on hover\n or focus (always on a touch screen). Each `onSelect(item)` may be async\n and return `{ ok, error? }`; `{ ok: false }` or a throw shows an error\n toast. Not drawn in the icon rail.\n- `keywords` — extra words the ⌘K search matches, never shown.\n- `disabled` · `key` (default `href`, then `label`).\n\nA group is `{ label?, items, collapsible?, defaultOpen?, key? }`.\n`collapsible: true` makes its heading fold it; `defaultOpen` (default\ntrue) is where it starts. The icon rail shows every group unfolded.\n\n## Props\n\n### SidebarLayout\n\n- `sidebar` — the `<Sidebar>` element.\n- `children` — the page beside it. Put `<SidebarTrigger />` in its header.\n- `storageKey` — remember collapsed/expanded in this browser under this\n key. Optional; without it every visit starts at `defaultCollapsed`.\n- `defaultCollapsed` — default `false`.\n- `collapsed` + `onCollapsedChange(next)` — control it yourself instead.\n- `shortcut` — Cmd/Ctrl + this key toggles it; default `\"b\"`, `null` for none.\n- `variant` — `\"inset\"` draws the page as a card on the frame's ground.\n Default: the Sidebar's own `variant`, so you rarely pass it here.\n- `className` — the frame's edges, and its height from its parent: in a\n shell it sits in the kit's `AppLayout contentMode=\"fill\"` with\n `min-h-0 flex-1` (the Example). The kit's `AppLayout` owns the\n window's height; `min-h-dvh` or `h-dvh` here is refused by `npm run\n check`. Never colour.\n\n### Sidebar\n\n- `groups` — see The data. `items` is the one-group shorthand.\n- `title` — the app's or workspace's name, at the top and on the sheet.\n- `subtitle` — a muted line under it (a plan, a team).\n- `logo` — a node beside the title; default a square `Avatar` of `title`.\n- `switcher` — kit `Menu` items (`[{ label, onSelect, icon? }]`): the title\n becomes a menu for changing workspace. `switcherLabel` names it\n (default \"Switch workspace\"); a reader hears \"<title>, <switcherLabel>\",\n so a voice user who says the title still hits it.\n- `user` — `{ name, email?, src? }`, shown at the foot with an `Avatar`.\n- `userMenu` — kit `Menu` items (`[{ label, onSelect, icon?, tone?: \"danger\",\n disabled? }]`, and groups and separators): the person becomes a menu\n button opening these upward (beside the rail when it is icons), flipping\n where there is no room. A choice also closes the phone sheet.\n- `children` — your own content under the groups (a target, a promo, a\n help link). Hidden in the icon rail.\n- `label` — the nav landmark's name, default \"Main\".\n- `className` — layout only. Never colour.\n\nShapes and extras (all optional; leave them out and it is the column\nabove):\n\n- `variant` — `\"sidebar\"` (default: a bordered column) · `\"inset\"` (no\n border; the page beside it becomes a rounded card) · `\"floating\"` (a\n rounded card held off the window's edge). A phone is a sheet either way.\n- `headerActions` — a node at the top right: a notifications `Menu`, a\n button. Hidden in the icon rail; first row of the phone sheet.\n- `switcherPlacement` — `\"header\"` (default) · `\"footer\"`: the switcher\n moves to the foot, over the person, and the top keeps only `logo`.\n- `search` — `true` or `{ placeholder?, hotkey?, label?, empty?,\n groupLabel? }`: a search row under the top that opens the kit\n `CommandDialog` over every item (children listed under their parent's\n name). `hotkey` defaults to `\"k\"` (⌘K / Ctrl+K), `null` for none. A\n palette choice runs the item's `onSelect`; an item with only `href`\n is followed as a page load (the app's base path applied). Give items\n `onSelect` with `router.push` for a client-side jump.\n- `primaryAction` — `{ label, icon?, onSelect?, href? }`: one button above\n the groups (\"New chat\"). `onSelect` may return `{ ok: false, error }`,\n shown as a toast.\n- `footerActions` — kit `Menu` items behind a \"+\" beside the person (New\n deal, Invite). `footerActionsLabel` names it, default \"Create\". Same\n `{ ok }` rule as `actions`.\n- `drilldown` — `\"inline\"` (default: a parent folds open) · `\"panel\"`\n (its children open in a second column with a close button; Esc closes\n it; the icon rail stays narrow beside it) · `\"replace\"` (its children\n replace the list, under a Back row). The parent holding the active\n item starts open. On a phone both are the replace form.\n- `panel` — a second column beside the nav from 768px, 320px wide: your\n own node, or `{ title?, actions?, search?, items, loading?, error?,\n onRetry?, empty?, onSelect?, query?, onQueryChange?, filter? }`.\n - `items`: `[{ key?, title, subtitle?, description?, meta?, icon?,\n media?, active?, href?, onSelect?, disabled? }]` — a mail is sender\n (title), date (meta), subject (subtitle), teaser (description).\n - `search`: `true` or `{ placeholder }`: a field that filters the items\n here; `filter: false` when you filter them yourself from\n `onQueryChange(query)`.\n - `loading` draws skeleton rows, `error` (text) a notice with Try\n again (`onRetry`), and no items the `empty` line.\n - On a phone it is the sheet's second screen: choosing a nav item (or\n the panel's own row at the top) shows it, with a Back row.\n\n### SidebarTrigger\n\nThe header button: opens the sheet on a phone, collapses to icons from\n768px. `className` for placement.\n\n### useSidebar()\n\n`{ collapsed, setCollapsed, toggle, mobileOpen, setMobileOpen }` inside a\n`SidebarLayout`, for a control of your own; `null` outside one.\n\n## Example\n\n```jsx\n// app/shell.jsx — the app's shell, the surfaces as the sidebar's items\n\"use client\";\nimport { usePathname } from \"next/navigation\";\nimport { AppLayout } from \"../components/ui\";\nimport { Sidebar, SidebarLayout, SidebarTrigger } from \"../components/blocks/sidebar\";\n\nconst ICONS = { inbox: \"inbox\", deals: \"dollar\", contacts: \"users\", reports: \"chart\" };\n\nexport default function Shell({ name, surfaces, children }) {\n const pathname = usePathname() ?? \"\";\n const activeKey = decodeURIComponent(/^\\/s\\/([^/?#]+)/.exec(pathname)?.[1] ?? \"\");\n const items = surfaces.map((s) => ({\n key: s.key,\n label: s.label,\n href: `/s/${encodeURIComponent(s.key)}`,\n icon: ICONS[s.key] ?? \"file\",\n active: s.key === activeKey,\n badge: s.built ? undefined : \"planned\",\n }));\n // The outer AppLayout owns the window; the inner one (it fills its\n // slot) is the content that scrolls, back to its top on a new route.\n return (\n <AppLayout contentMode=\"fill\">\n <SidebarLayout\n storageKey={`${name}.sidebar`}\n className=\"min-h-0 flex-1\"\n sidebar={<Sidebar title={name} items={items} label={`${name} surfaces`} />}\n >\n <header className=\"flex min-h-14 items-center gap-2 border-b border-border px-2 md:hidden\">\n <SidebarTrigger />\n <span className=\"font-semibold\">{name}</span>\n </header>\n <AppLayout contentClassName=\"p-4 sm:p-6\" scrollKey={pathname}>\n {children}\n </AppLayout>\n </SidebarLayout>\n </AppLayout>\n );\n}\n```\n\n## What it will not do\n\n- Know the route: say which item is `active` (from `usePathname()`).\n- Nest deeper than one level: a second level is a page of its own.\n- Cover the page on a wide window or dock on the right: floating is a\n card beside the page, not over it; it is on the left from 768px and a\n sheet below that.\n- Hold the panel's data: the list, its loading and its errors are yours.\n- Take a colour: it wears the workspace theme.\n\nA sidebar it cannot be is your own component in `components/`, built from\nthe kit — not an edit to this block. Its files are fixed: `npm run check`\nrefuses a change, and `makersclaw add sidebar` restores them.\n\n## Credits\n\nThe inset, floating, search, folding-group, panel, drill-in and item-menu\nshapes follow blocks.so (https://blocks.so, MIT) — a rewrite on the\nMakersclaw kit, none of its code.\n"
35
35
  }
36
36
  ],
37
37
  "categories": [
@@ -62,7 +62,7 @@
62
62
  "docs": "Installed to components/makersclaw/blocks/sidebar. Import: import { Sidebar, SidebarLayout, SidebarTrigger, useSidebar } from \"@/components/makersclaw/blocks/sidebar\". Props and an example: components/makersclaw/blocks/sidebar/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
63
63
  "meta": {
64
64
  "makersclaw": {
65
- "version": "0.7.0",
65
+ "version": "0.8.1",
66
66
  "useWhen": "An app with more than a handful of places to go (inbox, deals, contacts, reports, settings, projects) that wants a real app shell: compose it in app/shell.jsx around the surfaces. Not for in-page tabs (Tabs) or a short strip of links."
67
67
  }
68
68
  }
@@ -5,7 +5,7 @@
5
5
  "title": "SignaturePad",
6
6
  "description": "A signature field (signature_pad) in the workspace theme: a full-name field, then draw on a paper box (smooth pen strokes, undo the last stroke, clear with Undo) or type the name set as a signature. Sign returns a record: a cropped transparent PNG in dark ink, the typed name, the mode and the time; the signed view shows it with Sign again. Works as a form field too, through a handle (toPNG, getSignature).",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.7.0/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json"
9
9
  ],
10
10
  "dependencies": [
11
11
  "signature_pad@5.1.4"
@@ -65,7 +65,7 @@
65
65
  "docs": "Installed to components/makersclaw/blocks/signature-pad. Import: import { SignaturePad, useSignaturePad, signatureRecord, formatSignedAt } from \"@/components/makersclaw/blocks/signature-pad\". Props and an example: components/makersclaw/blocks/signature-pad/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
66
66
  "meta": {
67
67
  "makersclaw": {
68
- "version": "0.7.0",
68
+ "version": "0.8.1",
69
69
  "useWhen": "A screen needs someone to sign: accepting a proposal or a quote, a delivery or work-done sign-off, a waiver, a consent form, an approval on a record. The proposal-accept block is built on it. It records an acceptance with a picture of the signature — it is not a certified legal e-signature (no identity check, no audit trail beyond what you store)."
70
70
  }
71
71
  }
@@ -5,7 +5,7 @@
5
5
  "title": "SketchCanvas",
6
6
  "description": "A freeform drawing canvas (Excalidraw) in the workspace theme: a Miro-style tool rail (select, pan, draw, shapes, arrows, text, image, eraser, frames), a floating toolbar over the selection with colours from the theme's tokens, zoom and undo controls, a friendly empty state, and stamp tools that place ready-made drawings (UI wireframe pieces built in). Optional locked background image for annotating a screenshot. The sketch is plain JSON; helpers read its words for an agent, and the handle exports a PNG.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.7.0/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json"
9
9
  ],
10
10
  "dependencies": [
11
11
  "@excalidraw/excalidraw@0.18.1"
@@ -69,7 +69,7 @@
69
69
  "path": "registry/blocks/sketch-canvas/README.md",
70
70
  "type": "registry:file",
71
71
  "target": "@components/makersclaw/blocks/sketch-canvas/README.md",
72
- "content": "# SketchCanvas\n\nA freeform drawing canvas in the workspace theme, friendly like Miro. A\ntool rail on the left (a bar along the bottom on a phone): select, pan,\ndraw, rectangle, ellipse, diamond, arrow, line, text, image, eraser, frame\n— each with its one-key shortcut. Select something and a small toolbar\nfloats above it: colour and fill from the theme's palette, stroke, text\nsize, bring to front / send to back, duplicate, delete. Undo and redo sit\nbottom left, zoom and fit-to-screen bottom right, a menu top right\n(download PNG, snap to grid, shortcuts, clear). An empty canvas says how\nto start. Stamp tools place ready-made drawings with one click — the six\nUI wireframe pieces come built in.\n\nIt is [Excalidraw](https://github.com/excalidraw/excalidraw) (MIT)\nunderneath: its canvas, selection, text editing, history and shortcuts;\nour rail, toolbars, palette and empty state, in the kit. Excalidraw's own\ntool bar, properties panel, main menu, library, share / collaboration\nbuttons, welcome screen and sidebars are hidden. The blocks built on this\none — `whiteboard`, `annotate`, `sketch-to-app` — import it, never\n`@excalidraw/excalidraw`.\n\n```jsx\nimport { SketchCanvas, sketchToText } from \"../components/blocks/sketch-canvas\"; // a Makersclaw app (\"./blocks/sketch-canvas\" from components/)\nimport { SketchCanvas, sketchToText } from \"@/components/makersclaw/blocks/sketch-canvas\"; // a shadcn project\n```\n\n`SketchCanvas` is a client component: render it from a `\"use client\"`\ncomponent. The helpers (`sketchToText`, `sketchItems`, `emptySketch`,\n`isSketchEmpty`, `toSketch`) are plain functions and work on the server.\n\n`makersclaw add sketch-canvas` adds `@excalidraw/excalidraw` (pinned,\nexact) to package.json: run `npm install` after. It loads with the page\n(no `import()`); the canvas mounts after the first render, and until then\n— on the server — the frame shows \"Loading the canvas…\", with the\nsketch's words for a screen reader.\n\n## The data\n\nA sketch is plain JSON. Store it as it comes out of `onChange` / `onSave`\n(a `jsonb` column).\n\n```js\n{\n type: \"sketch\",\n version: 1,\n elements: [ /* Excalidraw elements, non-deleted, in paint order (first = back) */ ],\n files: { \"<fileId>\": { id, mimeType: \"image/png\", dataURL: \"data:image/png;base64,…\", created } },\n appState: { gridModeEnabled: false },\n}\n```\n\n- `elements` are Excalidraw's own element objects: `type` is `rectangle`,\n `ellipse`, `diamond`, `arrow`, `line`, `freedraw`, `text`, `image` or\n `frame`; each has `id`, `x`, `y`, `width`, `height`, `strokeColor`,\n `backgroundColor`, `strokeWidth`, `roughness`, `groupIds`, `frameId`…\n A `text` has `text`, `fontSize`, and `containerId` when it is the label\n of a shape; a shape lists its label and arrows in `boundElements`.\n- **Colours are tokens.** Every colour picked in the canvas is a theme\n token, and the element keeps it in `customData.tokens`:\n `{ strokeColor: \"primary\", backgroundColor: \"chart-2:soft\" }`. The\n concrete colour beside it (`strokeColor`) is what the token resolved to\n when it was saved; on load, and whenever the theme or light/dark\n changes, the canvas resolves every token again and repaints. A colour\n with no token (pasted from elsewhere) stays as it is.\n Tokens: `foreground`, `muted-foreground`, `primary`, `destructive`,\n `warning`, `success`, `info`, `chart-2` … `chart-5` (ink), and for\n fills also `none`, `muted` and `<slot>:soft` (the slot mixed into the\n page background — a sticky-note tint). `STROKES` and `FILLS` list them\n with labels.\n- **Stamps** mark what they place: every element of one stamp shares a\n group and carries `customData: { stamp: \"button\", stampId }`.\n- `files` holds the images the elements show (only those). Images are\n data URLs inside the JSON — keep them small, or store the file\n elsewhere and keep the sketch light.\n- The `background` image is never in the value; it comes from the prop.\n- Written by hand (a starter template, a seed), an element may leave out\n what Excalidraw can default (`version`, `seed`, `strokeWidth`,\n `roughness`…) and give its colours only as tokens:\n `{ id: \"a\", type: \"rectangle\", x: 0, y: 0, width: 160, height: 72, customData: { tokens: { strokeColor: \"foreground\", backgroundColor: \"chart-2:soft\" } } }`.\n A text needs `text`, `fontSize` and a rough `width`/`height` (it is\n re-measured). Or skip hand-written elements: insert skeletons through\n the handle (below).\n- `sketchToText(sketch)` reads the words out for an agent; see Helpers.\n\n## Props\n\n- `value` — the sketch, controlled. A new `value` that differs from what\n the canvas last sent replaces the drawing (loading another record) and\n clears undo. Pass back exactly what `onChange` gave you and nothing\n resets. Also takes a bare element array or Excalidraw's own export\n (`{ elements, files, appState }`).\n- `defaultValue` — the starting sketch, uncontrolled. With neither, it\n starts empty.\n- `onChange(sketch)` — the whole sketch, after an edit settles\n (debounced by `changeDelay`). Not called for pan, zoom or selection.\n- `onSave(sketch)` — `async`, returns `{ ok: true }` or\n `{ ok: false, error? }`. Called with the same sketch, right after\n `onChange`, and on Cmd/Ctrl+S. The canvas shows \"Saving…\", \"Saved\",\n or the error with a Retry. A throw counts as a failure.\n- `changeDelay` — ms of quiet before `onChange` / `onSave` (default 600).\n- `readOnly` — `false` (default). `true` shows the sketch to look at: pan\n and zoom, no rail, no toolbar, no edits.\n- `background` — `{ src, width?, height? }`: an image laid at the back,\n locked (it cannot be selected, moved, erased or deleted), top-left at\n (0, 0). For marking up a screenshot (annotate). `src` is a data URL, or\n a same-origin URL (a cross-origin one draws, but spoils `exportImage`).\n Without `width`/`height` the image's own size is used. When it first\n lands on an empty sketch, the view fits it.\n- `tools` — ids of the built-in tools to offer, in rail order:\n `[\"select\", \"hand\", \"draw\", \"rectangle\", \"ellipse\", \"diamond\", \"arrow\",\n \"line\", \"text\", \"image\", \"eraser\", \"frame\"]` (all, the default). A tool\n left out is also unreachable by its shortcut. `SKETCH_TOOLS` lists them\n with labels, icons and keys.\n- `stamps` — stamp tools after the built-ins:\n `[{ id, label, icon, create() }]`. `create()` returns element\n skeletons (below) laid out from (0, 0); a click on the canvas places\n them centred on the pointer (Enter: the middle of the view; Esc\n cancels), grouped, selected. `WIREFRAME_STAMPS` are button, input, card,\n nav bar, table and image placeholder.\n- `grid` — `true` (default): a dotted background that pans and zooms with\n the drawing. `false`: plain.\n- `empty` — what an empty, editable canvas shows in its middle. Omit for\n the built-in hint (\"Start sketching…\"); `false` for nothing; or a node\n (starter templates: give its buttons `pointer-events-auto`, the layer\n lets clicks through to the canvas). Shown while nothing is drawn and the\n select or pan tool is active.\n- `actions` — nodes in the top-right corner, before the menu (a Share\n button, a title chip).\n- `canvasRef` — a ref (`useSketchCanvas()`) that receives the handle.\n- `onReady(handle)` — once, when the canvas has mounted.\n- `label` — the accessible name of the canvas region (default \"Sketch\").\n- `className` — layout: width, margin, height. The default height is\n `h-[32rem]`; a height class of yours (`h-dvh`, `h-full`, `min-h-…`,\n `flex-1`) replaces it. Never colour.\n\n### The handle\n\n`canvasRef.current` (and `onReady`'s argument):\n\n- `getScene({ withBackground? })` — the sketch now (what `onChange`\n sends), without waiting for the debounce.\n- `setScene(sketch)` — replace the drawing (undoable).\n- `insertElements(skeletons, opts?)` → the new element ids. Skeletons are\n Excalidraw's `convertToExcalidrawElements` input:\n `{ type: \"rectangle\" | \"ellipse\" | \"diamond\", x, y, width, height, label?: { text, fontSize?, textAlign? } }`,\n `{ type: \"text\", x, y, text, fontSize? }`,\n `{ type: \"arrow\" | \"line\", x, y, points: [[0, 0], [dx, dy]], start?: { id }, end?: { id } }`,\n `{ type: \"frame\", children: [ids], name }`, `{ type: \"image\", fileId, x, y, width, height }`.\n Colours may be token names (`strokeColor: \"primary\"`,\n `backgroundColor: \"warning:soft\"`); a shape with no stroke gets\n `foreground`; text is the system font. Options:\n - `at` — `{ x, y }` in canvas coordinates; the skeletons' box is\n centred there (or its top-left, with `anchor: \"top-left\"`). Default:\n the middle of the view. `false`: keep the skeletons' own x/y.\n - `group` — group them (move as one). `stamp: \"<kind>\"` groups too and\n marks them for `sketchToText`.\n - `customData` — merged into every new element's customData (annotate:\n `{ note: 3 }`).\n - `files` — `[{ id, dataURL, mimeType, created }]` to add first, for\n image skeletons.\n - `select` — `true` (default): select what was inserted.\n- `exportImage(opts?)` → `Promise<Blob>`, a PNG made by Excalidraw's own\n export, in the theme's colours now, on the theme's background. Options:\n `scale` (default 2), `padding` (px, default 16), `transparent: true`\n (no background), `withBackground: false` (leave the background image\n out), `onlySelected: true`.\n- `zoomToFit({ animate? })` — fit everything in view (Shift+1).\n- `setTool(id)` — a built-in tool id or a stamp id.\n- `undo()`, `redo()`, `clear()`, `focus()`.\n- `save()` — send `onChange` / `onSave` now.\n- `palette()` — token → the concrete colour it resolves to now.\n- `repaint()` — re-read the theme and repaint (the canvas already does\n this when `data-theme` changes or a theme stylesheet loads).\n- `api` — Excalidraw's own imperative API, for anything else. Reaching for\n it ties you to Excalidraw 0.18; prefer the methods above.\n\n### Helpers\n\nPlain functions; they take a sketch (or an element array) and never throw\non a partial one:\n\n- `emptySketch()` — `{ type: \"sketch\", version: 1, elements: [], files: {}, appState: {} }`.\n- `isSketchEmpty(sketch)` — nothing drawn (deleted elements and the\n background image do not count).\n- `toSketch(value)` — any accepted input → a sketch.\n- `sketchToText(sketch, { stamps = true })` — the words, for an agent or a\n reader: one line per text or stamp in reading order (top to bottom,\n then left to right), grouped under `# <frame name>` per frame (then\n `# Outside frames`); a shape's label reads as its text; a stamp reads\n `[button] Sign up`, an image `[image]`. `stamps: false` drops the\n brackets. An empty sketch gives `\"\"`.\n- `sketchItems(sketch)` — the same, structured: `[{ kind: \"frame\" | \"stamp\" | \"text\" | \"image\", id, text?, name?, stamp?, container?, frame, x, y, width, height }]`.\n- `STROKES`, `FILLS` — `[{ token, label }]`, the palette the toolbar offers.\n- `SKETCH_TOOLS`, `WIREFRAME_STAMPS` — as above.\n\n## Theming, colours and fonts\n\n- **Chrome.** Excalidraw's own CSS variables (its menus, dialogs, context\n menu, hints) point at the workspace tokens (`theme.js`). Light or dark\n follows the nearest `data-theme` (else `color-scheme`, else the OS).\n- **Canvas colours.** Excalidraw needs concrete colours; they are read at\n run time from the tokens' CSS variables and never written in source.\n Excalidraw's dark mode (which inverts the whole canvas with a filter) is\n switched off: the tokens are already the dark scheme's.\n- **Fonts.** Every text is drawn in the device's own sans-serif\n (Excalidraw's \"Helvetica\" family — Helvetica, Arial…), so no font is ever\n fetched: Excalidraw's hand-drawn fonts would otherwise load from a\n third-party CDN. Text pasted from another Excalidraw is moved into it.\n The strokes keep their hand-drawn look (Sketchy / Clean in the toolbar).\n- **Stylesheet.** The block imports `@excalidraw/excalidraw/index.css`\n from the package; the app's bundler ships it like any CSS.\n\n## Example\n\nA whiteboard that saves itself:\n\n```jsx\n// surfaces/sketch.jsx — client: one board, saved as it is drawn\n\"use client\";\nimport { useSearchParams } from \"next/navigation\";\nimport { useRow } from \"../lib/data\";\nimport { updateRow } from \"../lib/actions\";\nimport { SketchCanvas } from \"../components/blocks/sketch-canvas\";\n\nexport default function Board() {\n const id = useSearchParams().get(\"row\");\n const { row: board, loading } = useRow({ source: \"boards\", id });\n if (loading || !board) return null;\n return (\n <SketchCanvas\n key={board.id}\n label={board.title}\n defaultValue={board.sketch} // jsonb, may be null; read once per board\n onSave={(sketch) => updateRow({ source: \"boards\", id: board.id, patch: { sketch } })}\n className=\"h-dvh rounded-none border-0\"\n />\n );\n}\n```\n\nIn a server-mode app the same calls are `loadRows` in a server surface and the Server Actions of `lib/actions`.\n\nMarking up a screenshot, with numbered notes:\n\n```jsx\nconst canvas = useSketchCanvas();\nconst addNote = (n) =>\n canvas.current?.insertElements(\n [{ type: \"ellipse\", x: 0, y: 0, width: 32, height: 32, strokeColor: \"destructive\", backgroundColor: \"destructive:soft\", label: { text: String(n) } }],\n { group: true, customData: { note: n } },\n );\n\n<SketchCanvas canvasRef={canvas} background={{ src: screenshotDataUrl }} tools={[\"select\", \"hand\", \"draw\", \"rectangle\", \"arrow\", \"text\", \"eraser\"]} onChange={setSketch} />\nconst image = await canvas.current.exportImage(); // the screenshot with the marks, as a PNG\n```\n\nA wireframe for an agent:\n\n```jsx\nimport { SketchCanvas, WIREFRAME_STAMPS, sketchToText, useSketchCanvas } from \"./blocks/sketch-canvas\";\n\nconst canvas = useSketchCanvas();\n<SketchCanvas canvasRef={canvas} stamps={WIREFRAME_STAMPS} tools={[\"select\", \"hand\", \"draw\", \"rectangle\", \"arrow\", \"text\", \"eraser\", \"frame\"]} onChange={setSketch} />\n\nconst build = async () => onBuild({ image: await canvas.current.exportImage(), sketch, text: sketchToText(sketch), prompt });\n// sketchToText → \"# Login\\nWelcome back\\n[input] Email\\n[button] Sign in\"\n```\n\n## What it will not do\n\n- Collaborate live (several cursors): Excalidraw's collaboration is a\n server of its own, not wired here. Saves are last-write-wins.\n- Offer Excalidraw's library, share links, \"text to diagram\" / AI, or its\n hand-drawn fonts. Its command palette (Cmd+/) and help dialog (?) still\n open, themed; the palette may name actions that do nothing here.\n- Show a minimap.\n- Keep images out of the JSON: an image lives as a data URL in `files`.\n- Render on the server: the server shows the frame and the sketch's\n words; the drawing appears when the page runs.\n- Pick an arbitrary colour: only the theme's tokens.\n\nA canvas it cannot be is your own component in `components/` — not an edit\nto this block. Its files are fixed: `npm run check` refuses a change, and\n`makersclaw add sketch-canvas` restores them.\n\n## Credits\n\nExcalidraw (https://github.com/excalidraw/excalidraw), MIT — installed from\nnpm as a dependency, not copied here. See THIRD-PARTY-NOTICES.md.\n"
72
+ "content": "# SketchCanvas\n\nA freeform drawing canvas in the workspace theme, friendly like Miro. A\ntool rail on the left (a bar along the bottom on a phone): select, pan,\ndraw, rectangle, ellipse, diamond, arrow, line, text, image, eraser, frame\n— each with its one-key shortcut. Select something and a small toolbar\nfloats above it: colour and fill from the theme's palette, stroke, text\nsize, bring to front / send to back, duplicate, delete. Undo and redo sit\nbottom left, zoom and fit-to-screen bottom right, a menu top right\n(download PNG, snap to grid, shortcuts, clear). An empty canvas says how\nto start. Stamp tools place ready-made drawings with one click — the six\nUI wireframe pieces come built in.\n\nIt is [Excalidraw](https://github.com/excalidraw/excalidraw) (MIT)\nunderneath: its canvas, selection, text editing, history and shortcuts;\nour rail, toolbars, palette and empty state, in the kit. Excalidraw's own\ntool bar, properties panel, main menu, library, share / collaboration\nbuttons, welcome screen and sidebars are hidden. The blocks built on this\none — `whiteboard`, `annotate`, `sketch-to-app` — import it, never\n`@excalidraw/excalidraw`.\n\n```jsx\nimport { SketchCanvas, sketchToText } from \"../components/blocks/sketch-canvas\"; // a Makersclaw app (\"./blocks/sketch-canvas\" from components/)\nimport { SketchCanvas, sketchToText } from \"@/components/makersclaw/blocks/sketch-canvas\"; // a shadcn project\n```\n\n`SketchCanvas` is a client component: render it from a `\"use client\"`\ncomponent. The helpers (`sketchToText`, `sketchItems`, `emptySketch`,\n`isSketchEmpty`, `toSketch`) are plain functions and work on the server.\n\n`makersclaw add sketch-canvas` adds `@excalidraw/excalidraw` (pinned,\nexact) to package.json: run `npm install` after. It loads with the page\n(no `import()`); the canvas mounts after the first render, and until then\n— on the server — the frame shows \"Loading the canvas…\", with the\nsketch's words for a screen reader.\n\n## The data\n\nA sketch is plain JSON. Store it as it comes out of `onChange` / `onSave`\n(a `jsonb` column).\n\n```js\n{\n type: \"sketch\",\n version: 1,\n elements: [ /* Excalidraw elements, non-deleted, in paint order (first = back) */ ],\n files: { \"<fileId>\": { id, mimeType: \"image/png\", dataURL: \"data:image/png;base64,…\", created } },\n appState: { gridModeEnabled: false },\n}\n```\n\n- `elements` are Excalidraw's own element objects: `type` is `rectangle`,\n `ellipse`, `diamond`, `arrow`, `line`, `freedraw`, `text`, `image` or\n `frame`; each has `id`, `x`, `y`, `width`, `height`, `strokeColor`,\n `backgroundColor`, `strokeWidth`, `roughness`, `groupIds`, `frameId`…\n A `text` has `text`, `fontSize`, and `containerId` when it is the label\n of a shape; a shape lists its label and arrows in `boundElements`.\n- **Colours are tokens.** Every colour picked in the canvas is a theme\n token, and the element keeps it in `customData.tokens`:\n `{ strokeColor: \"primary\", backgroundColor: \"chart-2:soft\" }`. The\n concrete colour beside it (`strokeColor`) is what the token resolved to\n when it was saved; on load, and whenever the theme or light/dark\n changes, the canvas resolves every token again and repaints. A colour\n with no token (pasted from elsewhere) stays as it is.\n Tokens: `foreground`, `muted-foreground`, `primary`, `destructive`,\n `warning`, `success`, `info`, `chart-2` … `chart-5` (ink), and for\n fills also `none`, `muted` and `<slot>:soft` (the slot mixed into the\n page background — a sticky-note tint). `STROKES` and `FILLS` list them\n with labels.\n- **Stamps** mark what they place: every element of one stamp shares a\n group and carries `customData: { stamp: \"button\", stampId }`.\n- `files` holds the images the elements show (only those). Images are\n data URLs inside the JSON — keep them small, or store the file\n elsewhere and keep the sketch light.\n- The `background` image is never in the value; it comes from the prop.\n- Written by hand (a starter template, a seed), an element may leave out\n what Excalidraw can default (`version`, `seed`, `strokeWidth`,\n `roughness`…) and give its colours only as tokens:\n `{ id: \"a\", type: \"rectangle\", x: 0, y: 0, width: 160, height: 72, customData: { tokens: { strokeColor: \"foreground\", backgroundColor: \"chart-2:soft\" } } }`.\n A text needs `text`, `fontSize` and a rough `width`/`height` (it is\n re-measured). Or skip hand-written elements: insert skeletons through\n the handle (below).\n- `sketchToText(sketch)` reads the words out for an agent; see Helpers.\n\n## Props\n\n- `value` — the sketch, controlled. A new `value` that differs from what\n the canvas last sent replaces the drawing (loading another record) and\n clears undo. Pass back exactly what `onChange` gave you and nothing\n resets. Also takes a bare element array or Excalidraw's own export\n (`{ elements, files, appState }`).\n- `defaultValue` — the starting sketch, uncontrolled. With neither, it\n starts empty.\n- `onChange(sketch)` — the whole sketch, after an edit settles\n (debounced by `changeDelay`). Not called for pan, zoom or selection.\n- `onSave(sketch)` — `async`, returns `{ ok: true }` or\n `{ ok: false, error? }`. Called with the same sketch, right after\n `onChange`, and on Cmd/Ctrl+S. The canvas shows \"Saving…\", \"Saved\",\n or the error with a Retry. A throw counts as a failure.\n- `changeDelay` — ms of quiet before `onChange` / `onSave` (default 600).\n- `readOnly` — `false` (default). `true` shows the sketch to look at: pan\n and zoom, no rail, no toolbar, no edits.\n- `background` — `{ src, width?, height? }`: an image laid at the back,\n locked (it cannot be selected, moved, erased or deleted), top-left at\n (0, 0). For marking up a screenshot (annotate). `src` is a data URL, or\n a same-origin URL (a cross-origin one draws, but spoils `exportImage`).\n Without `width`/`height` the image's own size is used. When it first\n lands on an empty sketch, the view fits it.\n- `tools` — ids of the built-in tools to offer, in rail order:\n `[\"select\", \"hand\", \"draw\", \"rectangle\", \"ellipse\", \"diamond\", \"arrow\",\n \"line\", \"text\", \"image\", \"eraser\", \"frame\"]` (all, the default). A tool\n left out is also unreachable by its shortcut. `SKETCH_TOOLS` lists them\n with labels, icons and keys.\n- `stamps` — stamp tools after the built-ins:\n `[{ id, label, icon, create() }]`. `create()` returns element\n skeletons (below) laid out from (0, 0); a click on the canvas places\n them centred on the pointer (Enter: the middle of the view; Esc\n cancels), grouped, selected. `WIREFRAME_STAMPS` are button, input, card,\n nav bar, table and image placeholder.\n- `grid` — `true` (default): a dotted background that pans and zooms with\n the drawing. `false`: plain.\n- `empty` — what an empty, editable canvas shows in its middle. Omit for\n the built-in hint (\"Start sketching…\"); `false` for nothing; or a node\n (starter templates: give its buttons `pointer-events-auto`, the layer\n lets clicks through to the canvas). Shown while nothing is drawn and the\n select or pan tool is active.\n- `actions` — nodes in the top-right corner, before the menu (a Share\n button, a title chip).\n- `canvasRef` — a ref (`useSketchCanvas()`) that receives the handle.\n- `onReady(handle)` — once, when the canvas has mounted.\n- `label` — the accessible name of the canvas region (default \"Sketch\").\n- `className` — layout: width, margin, height. The default height is\n `h-[32rem]`; a height class of yours (`h-full`, `min-h-…`, `min-h-0\n flex-1`) replaces it. A canvas that is the whole surface sits in an\n `AppLayout contentMode=\"fill\"` from the kit with `min-h-0 flex-1` (the\n Example): never `h-dvh` or a `vh` height, which `npm run check`\n refuses. Never colour.\n\n### The handle\n\n`canvasRef.current` (and `onReady`'s argument):\n\n- `getScene({ withBackground? })` — the sketch now (what `onChange`\n sends), without waiting for the debounce.\n- `setScene(sketch)` — replace the drawing (undoable).\n- `insertElements(skeletons, opts?)` → the new element ids. Skeletons are\n Excalidraw's `convertToExcalidrawElements` input:\n `{ type: \"rectangle\" | \"ellipse\" | \"diamond\", x, y, width, height, label?: { text, fontSize?, textAlign? } }`,\n `{ type: \"text\", x, y, text, fontSize? }`,\n `{ type: \"arrow\" | \"line\", x, y, points: [[0, 0], [dx, dy]], start?: { id }, end?: { id } }`,\n `{ type: \"frame\", children: [ids], name }`, `{ type: \"image\", fileId, x, y, width, height }`.\n Colours may be token names (`strokeColor: \"primary\"`,\n `backgroundColor: \"warning:soft\"`); a shape with no stroke gets\n `foreground`; text is the system font. Options:\n - `at` — `{ x, y }` in canvas coordinates; the skeletons' box is\n centred there (or its top-left, with `anchor: \"top-left\"`). Default:\n the middle of the view. `false`: keep the skeletons' own x/y.\n - `group` — group them (move as one). `stamp: \"<kind>\"` groups too and\n marks them for `sketchToText`.\n - `customData` — merged into every new element's customData (annotate:\n `{ note: 3 }`).\n - `files` — `[{ id, dataURL, mimeType, created }]` to add first, for\n image skeletons.\n - `select` — `true` (default): select what was inserted.\n- `exportImage(opts?)` → `Promise<Blob>`, a PNG made by Excalidraw's own\n export, in the theme's colours now, on the theme's background. Options:\n `scale` (default 2), `padding` (px, default 16), `transparent: true`\n (no background), `withBackground: false` (leave the background image\n out), `onlySelected: true`.\n- `zoomToFit({ animate? })` — fit everything in view (Shift+1).\n- `setTool(id)` — a built-in tool id or a stamp id.\n- `undo()`, `redo()`, `clear()`, `focus()`.\n- `save()` — send `onChange` / `onSave` now.\n- `palette()` — token → the concrete colour it resolves to now.\n- `repaint()` — re-read the theme and repaint (the canvas already does\n this when `data-theme` changes or a theme stylesheet loads).\n- `api` — Excalidraw's own imperative API, for anything else. Reaching for\n it ties you to Excalidraw 0.18; prefer the methods above.\n\n### Helpers\n\nPlain functions; they take a sketch (or an element array) and never throw\non a partial one:\n\n- `emptySketch()` — `{ type: \"sketch\", version: 1, elements: [], files: {}, appState: {} }`.\n- `isSketchEmpty(sketch)` — nothing drawn (deleted elements and the\n background image do not count).\n- `toSketch(value)` — any accepted input → a sketch.\n- `sketchToText(sketch, { stamps = true })` — the words, for an agent or a\n reader: one line per text or stamp in reading order (top to bottom,\n then left to right), grouped under `# <frame name>` per frame (then\n `# Outside frames`); a shape's label reads as its text; a stamp reads\n `[button] Sign up`, an image `[image]`. `stamps: false` drops the\n brackets. An empty sketch gives `\"\"`.\n- `sketchItems(sketch)` — the same, structured: `[{ kind: \"frame\" | \"stamp\" | \"text\" | \"image\", id, text?, name?, stamp?, container?, frame, x, y, width, height }]`.\n- `STROKES`, `FILLS` — `[{ token, label }]`, the palette the toolbar offers.\n- `SKETCH_TOOLS`, `WIREFRAME_STAMPS` — as above.\n\n## Theming, colours and fonts\n\n- **Chrome.** Excalidraw's own CSS variables (its menus, dialogs, context\n menu, hints) point at the workspace tokens (`theme.js`). Light or dark\n follows the nearest `data-theme` (else `color-scheme`, else the OS).\n- **Canvas colours.** Excalidraw needs concrete colours; they are read at\n run time from the tokens' CSS variables and never written in source.\n Excalidraw's dark mode (which inverts the whole canvas with a filter) is\n switched off: the tokens are already the dark scheme's.\n- **Fonts.** Every text is drawn in the device's own sans-serif\n (Excalidraw's \"Helvetica\" family — Helvetica, Arial…), so no font is ever\n fetched: Excalidraw's hand-drawn fonts would otherwise load from a\n third-party CDN. Text pasted from another Excalidraw is moved into it.\n The strokes keep their hand-drawn look (Sketchy / Clean in the toolbar).\n- **Stylesheet.** The block imports `@excalidraw/excalidraw/index.css`\n from the package; the app's bundler ships it like any CSS.\n\n## Example\n\nA whiteboard that saves itself:\n\n```jsx\n// surfaces/sketch.jsx — client: one board, saved as it is drawn\n\"use client\";\nimport { useSearchParams } from \"next/navigation\";\nimport { useRow } from \"../lib/data\";\nimport { updateRow } from \"../lib/actions\";\nimport { AppLayout } from \"../components/ui\";\nimport { SketchCanvas } from \"../components/blocks/sketch-canvas\";\n\nexport default function Board() {\n const id = useSearchParams().get(\"row\");\n const { row: board, loading } = useRow({ source: \"boards\", id });\n if (loading || !board) return null;\n return (\n <AppLayout contentMode=\"fill\">\n <SketchCanvas\n key={board.id}\n label={board.title}\n defaultValue={board.sketch} // jsonb, may be null; read once per board\n onSave={(sketch) => updateRow({ source: \"boards\", id: board.id, patch: { sketch } })}\n className=\"min-h-0 flex-1 rounded-none border-0\"\n />\n </AppLayout>\n );\n}\n```\n\nIn a server-mode app the same calls are `loadRows` in a server surface and the Server Actions of `lib/actions`.\n\nMarking up a screenshot, with numbered notes:\n\n```jsx\nconst canvas = useSketchCanvas();\nconst addNote = (n) =>\n canvas.current?.insertElements(\n [{ type: \"ellipse\", x: 0, y: 0, width: 32, height: 32, strokeColor: \"destructive\", backgroundColor: \"destructive:soft\", label: { text: String(n) } }],\n { group: true, customData: { note: n } },\n );\n\n<SketchCanvas canvasRef={canvas} background={{ src: screenshotDataUrl }} tools={[\"select\", \"hand\", \"draw\", \"rectangle\", \"arrow\", \"text\", \"eraser\"]} onChange={setSketch} />\nconst image = await canvas.current.exportImage(); // the screenshot with the marks, as a PNG\n```\n\nA wireframe for an agent:\n\n```jsx\nimport { SketchCanvas, WIREFRAME_STAMPS, sketchToText, useSketchCanvas } from \"./blocks/sketch-canvas\";\n\nconst canvas = useSketchCanvas();\n<SketchCanvas canvasRef={canvas} stamps={WIREFRAME_STAMPS} tools={[\"select\", \"hand\", \"draw\", \"rectangle\", \"arrow\", \"text\", \"eraser\", \"frame\"]} onChange={setSketch} />\n\nconst build = async () => onBuild({ image: await canvas.current.exportImage(), sketch, text: sketchToText(sketch), prompt });\n// sketchToText → \"# Login\\nWelcome back\\n[input] Email\\n[button] Sign in\"\n```\n\n## What it will not do\n\n- Collaborate live (several cursors): Excalidraw's collaboration is a\n server of its own, not wired here. Saves are last-write-wins.\n- Offer Excalidraw's library, share links, \"text to diagram\" / AI, or its\n hand-drawn fonts. Its command palette (Cmd+/) and help dialog (?) still\n open, themed; the palette may name actions that do nothing here.\n- Show a minimap.\n- Keep images out of the JSON: an image lives as a data URL in `files`.\n- Render on the server: the server shows the frame and the sketch's\n words; the drawing appears when the page runs.\n- Pick an arbitrary colour: only the theme's tokens.\n\nA canvas it cannot be is your own component in `components/` — not an edit\nto this block. Its files are fixed: `npm run check` refuses a change, and\n`makersclaw add sketch-canvas` restores them.\n\n## Credits\n\nExcalidraw (https://github.com/excalidraw/excalidraw), MIT — installed from\nnpm as a dependency, not copied here. See THIRD-PARTY-NOTICES.md.\n"
73
73
  }
74
74
  ],
75
75
  "categories": [
@@ -92,7 +92,7 @@
92
92
  "docs": "Installed to components/makersclaw/blocks/sketch-canvas. Import: import { SketchCanvas, useSketchCanvas, SKETCH_TOOLS, WIREFRAME_STAMPS, STROKES, FILLS, emptySketch, isSketchEmpty, sketchToText, sketchItems, toSketch } from \"@/components/makersclaw/blocks/sketch-canvas\". Props and an example: components/makersclaw/blocks/sketch-canvas/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
93
93
  "meta": {
94
94
  "makersclaw": {
95
- "version": "0.7.0",
95
+ "version": "0.8.1",
96
96
  "useWhen": "A screen needs freehand drawing: a whiteboard, marking up a screenshot, sketching a UI wireframe, a diagram drawn by hand. The whiteboard, annotate and sketch-to-app blocks are built on it. Not for structured boards of cards and connectors (flow-canvas), charts (chart) or a kanban (board)."
97
97
  }
98
98
  }
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "source-receipt",
4
+ "type": "registry:block",
5
+ "title": "SourceReceipt",
6
+ "description": "Where one value came from, as a clipping: the page or the mail and its title, the address, the date it was read, a trust word (\"their own site\", \"a 2023 directory\") and the trust mark's shape, the words on it with the deciding ones underlined wherever they appear (case-insensitive, never HTML), and Open the source. A thin wrapper over agent-column's clipping (Data Enrichment's receipt) for a value that stands on its own, so every app draws a source the same way.",
7
+ "registryDependencies": [
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json",
9
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/agent-column.json"
10
+ ],
11
+ "dependencies": [],
12
+ "files": [
13
+ {
14
+ "path": "registry/blocks/source-receipt/index.js",
15
+ "type": "registry:component",
16
+ "target": "@components/makersclaw/blocks/source-receipt/index.js",
17
+ "content": "// The SourceReceipt block — `makersclaw add source-receipt`. Fixed:\n// compose it through its props (README.md beside this file).\nexport { SourceReceipt, markExcerpt } from \"./source-receipt\";\n"
18
+ },
19
+ {
20
+ "path": "registry/blocks/source-receipt/source-receipt.jsx",
21
+ "type": "registry:component",
22
+ "target": "@components/makersclaw/blocks/source-receipt/source-receipt.jsx",
23
+ "content": "\"use client\";\n\nimport { Button, Icon, cx } from \"../../ui\";\nimport { Clipping } from \"../agent-column\";\n\n// SourceReceipt — where one value came from, as a clipping (the app kit,\n// D15): the page or the mail, its date, a trust word (\"their own site\",\n// \"a 2023 directory\"), the words on it with the deciding ones underlined,\n// and Open the source. For a value that is not in an agent column: a\n// CRM's found title, a note's proof margin, a newsletter's source line.\n//\n// It is NOT a second receipt. The clipping is agent-column's (Data\n// Enrichment's \"the receipt\"); this wraps it for one source standing on\n// its own, so both draw the same thing. No door: the source is app data\n// the agent wrote. Props in, callbacks out.\n\n/** Wrap every occurrence of each mark in [[…]] (the clipping's mark for\n * deciding words), case-insensitive, longest first so no mark lands\n * inside another. With no marks, the excerpt's own [[…]] (the agent's)\n * stand; with marks, they replace them. Plain strings only: never HTML. */\nexport function markExcerpt(excerpt, marks) {\n const list = [...new Set((marks ?? []).map((m) => String(m ?? \"\").trim()).filter((m) => m && !/[[\\]]/.test(m)))].sort((a, b) => b.length - a.length);\n if (!list.length) return String(excerpt ?? \"\");\n const text = String(excerpt ?? \"\").replace(/\\[\\[|\\]\\]/g, \"\");\n if (!text) return text;\n const re = new RegExp(list.map((m) => m.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")).join(\"|\"), \"gi\");\n return text.replace(re, (hit) => `[[${hit}]]`);\n}\n\n/** \"acme.com\", from a URL; null when it is not one. */\nfunction siteOf(url) {\n try {\n return new URL(/^https?:/i.test(url) ? url : `https://${url}`).hostname.replace(/^www\\./i, \"\");\n } catch {\n return null;\n }\n}\n\n/**\n * title the page's or the mail's title (\"Careers · Klarwerk\")\n * site where: a site (\"klarwerk.de\") or a mailbox (\"Sofia Reyes\n * <sofia@crumb.co>\"); from `url` when left out\n * url the source's address; the clipping links it\n * kind \"site\" (default) or \"mail\": the icon before the trust word\n * date when it was read or sent, in words (\"read 22 Sep\")\n * trust a word for how far to trust it (\"their own site\")\n * sure sure · likely · guess: the trust mark's shape, beside the title\n * excerpt the words on it\n * marks the deciding words, underlined wherever they appear\n * onOpen() opens the source; without it, with a url, the source opens\n * in a new tab\n * openLabel default \"Open the source\"\n * action a node at the head's end (a \"Pick\" for one of two)\n * picked drawn as the one chosen\n */\nexport function SourceReceipt({\n title,\n site,\n url,\n kind = \"site\",\n date,\n trust,\n sure,\n excerpt,\n marks = [],\n onOpen,\n openLabel = \"Open the source\",\n action,\n picked = false,\n className,\n}) {\n const where = site ?? (url ? siteOf(url) : null);\n // The clipping draws a url as its linked address; a mailbox or a site\n // without one rides in its date line instead.\n const read = [url ? null : where, date].filter(Boolean).join(\" · \") || undefined;\n const href = url ? (/^https?:/i.test(url) ? url : `https://${url}`) : null;\n return (\n <Clipping\n source={{ url: url || undefined, title: title || where || undefined, evidence: excerpt ? markExcerpt(excerpt, marks) : undefined, read }}\n trust={sure}\n title={title || where || \"A source\"}\n action={action}\n picked={picked}\n className={cx(\"min-w-0 text-sm\", className)}\n >\n {trust || onOpen || href ? (\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-xs\">\n {trust ? (\n <span className=\"inline-flex min-w-0 items-center gap-1 text-muted-foreground\">\n <Icon name={kind === \"mail\" ? \"mail\" : \"globe\"} size={12} className=\"shrink-0\" />\n <span className=\"min-w-0 break-words\">{trust}</span>\n </span>\n ) : null}\n {onOpen ? (\n <Button variant=\"link\" size=\"inherit\" onClick={onOpen} className=\"ml-auto\">\n {openLabel} <Icon name=\"external\" size={12} />\n </Button>\n ) : href ? (\n <Button variant=\"link\" size=\"inherit\" href={href} target=\"_blank\" rel=\"noreferrer\" className=\"ml-auto\">\n {openLabel} <Icon name=\"external\" size={12} />\n </Button>\n ) : null}\n </div>\n ) : null}\n </Clipping>\n );\n}\n"
24
+ },
25
+ {
26
+ "path": "registry/blocks/source-receipt/README.md",
27
+ "type": "registry:file",
28
+ "target": "@components/makersclaw/blocks/source-receipt/README.md",
29
+ "content": "# SourceReceipt\n\nWhere one value came from, drawn as a clipping:\n\n- the page's or the mail's title, with the trust mark's shape beside it;\n- its address (linked) or the mailbox, and the date it was read;\n- the words on it, with the **deciding words underlined** wherever they\n appear;\n- a trust word (\"their own site\", \"a 2023 directory\");\n- **Open the source**.\n\nA member reads the claim and its proof in one look, and decides how far\nto trust it.\n\nIt is not a second receipt. The clipping is `agent-column`'s (Data\nEnrichment's \"the receipt\"); this block wraps it for one source standing\non its own: a CRM's found title, a note's proof margin, a newsletter's\nsource line. Inside a column of answers, use `agent-column`'s `Receipt`.\n\n```jsx\nimport { SourceReceipt } from \"../components/blocks/source-receipt\"; // a Makersclaw app (\"./blocks/source-receipt\" from components/)\nimport { SourceReceipt } from \"@/components/makersclaw/blocks/source-receipt\"; // a shadcn project\n```\n\nA client component. It requires `agent-column` (and through it\n`agent-marks`), laid with it.\n\n## Which hook feeds it\n\nNone. The source is app data the agent wrote beside the value: its\naddress, its title, the words it read, the words that decided. Keep\nthem in the record (a `source` column, a `sources` table) and pass them\nin.\n\n## Props\n\n- `title` — the page's or the mail's title (\"Careers · Klarwerk\").\n- `url` — the source's address. The clipping shows it short\n (\"klarwerk.de/careers\") and links it.\n- `site` — where, when there is no `url`: a mailbox (\"Sofia Reyes\n <sofia@crumb.co>\") or a site's name. From `url` when left out.\n- `kind` — `site` (default) or `mail`: the icon before the trust word.\n- `date` — when it was read or sent, in words (\"read 22 Sep\").\n- `trust` — a word for how far to trust it (\"their own site\", \"her\n signature\", \"a 2023 directory\").\n- `sure` — `sure` · `likely` · `guess`: the trust mark's shape beside\n the title (filled, half, dashed).\n- `excerpt` — the words on it.\n- `marks` — the deciding words, `string[]`. Every occurrence of each is\n underlined, whatever its case. Without `marks`, an excerpt's own\n `[[…]]` (the agent's marking) are underlined instead.\n- `onOpen()` — opens the source your way. Without it, a `url` opens in a\n new tab.\n- `openLabel` — default \"Open the source\".\n- `action` — a node at the head's end: a \"Pick 70\" when two sources\n disagree.\n- `picked` — drawn as the one chosen.\n- `className` — layout around it. Never colour.\n\n`markExcerpt(excerpt, marks)` is exported: the excerpt with `[[…]]`\naround every deciding word, as the clipping reads it.\n\n## Who may do what\n\nAnyone who can see the value can see its source. The receipt has no\nwrites; a Pick is your own `action`, and your own action's rules hold.\n\n## Never\n\n- Never build the excerpt from HTML or inject it: it is drawn as text,\n and the underlines are elements, never markup in a string.\n- Never show a value as found with no receipt to open.\n- Never colour the trust alone: the mark's shape and the word say it.\n\n## Example\n\nThe source of a contact's job title, under the field.\n\n```jsx\nimport { SourceReceipt } from \"./blocks/source-receipt\";\n\nexport function TitleSource({ person }) {\n const s = person.title_source;\n if (!s) return null;\n return (\n <SourceReceipt\n title={s.title}\n url={s.url}\n date={`read ${s.read_on}`}\n trust={s.trust}\n sure={s.sure}\n excerpt={s.words}\n marks={[person.job_title]}\n />\n );\n}\n```\n"
30
+ }
31
+ ],
32
+ "categories": [
33
+ "source",
34
+ "citation",
35
+ "receipt",
36
+ "provenance",
37
+ "evidence",
38
+ "quote",
39
+ "clipping",
40
+ "trust",
41
+ "proof",
42
+ "reference",
43
+ "found"
44
+ ],
45
+ "docs": "Installed to components/makersclaw/blocks/source-receipt. Import: import { SourceReceipt, markExcerpt } from \"@/components/makersclaw/blocks/source-receipt\". Props and an example: components/makersclaw/blocks/source-receipt/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
46
+ "meta": {
47
+ "makersclaw": {
48
+ "version": "0.8.1",
49
+ "useWhen": "A value the agent found should show its proof beside it: a contact's title from an email signature, a company's size from its site, a figure in a note or a newsletter with its source in the margin, two sources side by side for a person to pick. For a whole column of answers across records use agent-column; for a value proposed but not kept yet, put the receipt under a suggestion."
50
+ }
51
+ }
52
+ }