makersclaw 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) hide show
  1. package/THIRD-PARTY-NOTICES.md +180 -0
  2. package/package.json +3 -2
  3. package/r/annotate.json +62 -0
  4. package/r/approval-request.json +52 -0
  5. package/r/audio-player.json +74 -0
  6. package/r/auth-form.json +55 -0
  7. package/r/board.json +10 -6
  8. package/r/calendar-view.json +105 -0
  9. package/r/cart.json +62 -0
  10. package/r/chart.json +83 -0
  11. package/r/chat.json +95 -0
  12. package/r/code-editor.json +94 -0
  13. package/r/comment-box.json +64 -0
  14. package/r/contact-section.json +53 -0
  15. package/r/core.json +205 -8
  16. package/r/csv-import.json +63 -0
  17. package/r/data-table.json +69 -0
  18. package/r/diagram.json +74 -0
  19. package/r/doc-editor.json +82 -0
  20. package/r/doc-page.json +61 -0
  21. package/r/email-render.json +73 -0
  22. package/r/faq.json +50 -0
  23. package/r/file-upload.json +54 -0
  24. package/r/flow-canvas.json +93 -0
  25. package/r/footer.json +52 -0
  26. package/r/gantt.json +70 -0
  27. package/r/job-panel.json +12 -7
  28. package/r/json-editor.json +66 -0
  29. package/r/map.json +89 -0
  30. package/r/menubar.json +52 -0
  31. package/r/mind-map.json +67 -0
  32. package/r/navigation-menu.json +52 -0
  33. package/r/order-detail.json +54 -0
  34. package/r/org-chart.json +66 -0
  35. package/r/page-builder.json +105 -0
  36. package/r/payment-methods.json +51 -0
  37. package/r/pdf-document.json +79 -0
  38. package/r/pdf-viewer.json +88 -0
  39. package/r/product-detail.json +76 -0
  40. package/r/product-grid.json +65 -0
  41. package/r/record-form.json +67 -0
  42. package/r/record-notes.json +55 -0
  43. package/r/registry.json +3411 -29
  44. package/r/search-dialog.json +51 -0
  45. package/r/settings-list.json +66 -0
  46. package/r/setup-checklist.json +51 -0
  47. package/r/share-dialog.json +52 -0
  48. package/r/sidebar.json +69 -0
  49. package/r/signature-pad.json +72 -0
  50. package/r/sketch-canvas.json +99 -0
  51. package/r/spreadsheet.json +90 -0
  52. package/r/stat-cards.json +66 -0
  53. package/r/task-list.json +63 -0
  54. package/r/task-model.json +98 -0
  55. package/r/testimonials.json +52 -0
  56. package/r/transaction-list.json +53 -0
  57. package/r/whiteboard.json +66 -0
  58. package/registry/blocks/annotate/README.md +179 -0
  59. package/registry/blocks/annotate/annotate-data.js +250 -0
  60. package/registry/blocks/annotate/annotate.jsx +646 -0
  61. package/registry/blocks/annotate/block.json +10 -0
  62. package/registry/blocks/annotate/demo.jsx +135 -0
  63. package/registry/blocks/annotate/index.js +15 -0
  64. package/registry/blocks/approval-request/README.md +116 -0
  65. package/registry/blocks/approval-request/approval-request.jsx +386 -0
  66. package/registry/blocks/approval-request/block.json +10 -0
  67. package/registry/blocks/approval-request/demo.jsx +127 -0
  68. package/registry/blocks/approval-request/index.js +4 -0
  69. package/registry/blocks/audio-player/README.md +167 -0
  70. package/registry/blocks/audio-player/audio-player.jsx +623 -0
  71. package/registry/blocks/audio-player/block.json +14 -0
  72. package/registry/blocks/audio-player/colors.js +109 -0
  73. package/registry/blocks/audio-player/demo.jsx +209 -0
  74. package/registry/blocks/audio-player/index.js +6 -0
  75. package/registry/blocks/audio-player/time.js +67 -0
  76. package/registry/blocks/audio-player/wavesurfer.js +9 -0
  77. package/registry/blocks/auth-form/README.md +126 -0
  78. package/registry/blocks/auth-form/auth-form.jsx +568 -0
  79. package/registry/blocks/auth-form/block.json +10 -0
  80. package/registry/blocks/auth-form/demo.jsx +131 -0
  81. package/registry/blocks/auth-form/index.js +3 -0
  82. package/registry/blocks/board/README.md +55 -5
  83. package/registry/blocks/board/block.json +2 -2
  84. package/registry/blocks/board/board.jsx +230 -86
  85. package/registry/blocks/board/demo.jsx +103 -24
  86. package/registry/blocks/calendar-view/README.md +180 -0
  87. package/registry/blocks/calendar-view/agenda.jsx +147 -0
  88. package/registry/blocks/calendar-view/block.json +76 -0
  89. package/registry/blocks/calendar-view/calendar-model.js +442 -0
  90. package/registry/blocks/calendar-view/calendar.jsx +627 -0
  91. package/registry/blocks/calendar-view/demo.jsx +195 -0
  92. package/registry/blocks/calendar-view/draft.jsx +49 -0
  93. package/registry/blocks/calendar-view/index.js +39 -0
  94. package/registry/blocks/calendar-view/month.jsx +346 -0
  95. package/registry/blocks/calendar-view/paint.js +69 -0
  96. package/registry/blocks/calendar-view/time-grid.jsx +527 -0
  97. package/registry/blocks/calendar-view/tray.jsx +87 -0
  98. package/registry/blocks/cart/README.md +146 -0
  99. package/registry/blocks/cart/block.json +10 -0
  100. package/registry/blocks/cart/cart.jsx +597 -0
  101. package/registry/blocks/cart/demo.jsx +98 -0
  102. package/registry/blocks/cart/index.js +4 -0
  103. package/registry/blocks/cart/money.js +28 -0
  104. package/registry/blocks/chart/README.md +316 -0
  105. package/registry/blocks/chart/block.json +10 -0
  106. package/registry/blocks/chart/cartesian.jsx +642 -0
  107. package/registry/blocks/chart/core.jsx +262 -0
  108. package/registry/blocks/chart/demo.jsx +357 -0
  109. package/registry/blocks/chart/heatmap.jsx +336 -0
  110. package/registry/blocks/chart/index.js +8 -0
  111. package/registry/blocks/chart/pie.jsx +245 -0
  112. package/registry/blocks/chart/sparkline.jsx +88 -0
  113. package/registry/blocks/chat/README.md +273 -0
  114. package/registry/blocks/chat/attachment.jsx +95 -0
  115. package/registry/blocks/chat/block.json +10 -0
  116. package/registry/blocks/chat/chat.jsx +132 -0
  117. package/registry/blocks/chat/composer.jsx +364 -0
  118. package/registry/blocks/chat/demo.jsx +578 -0
  119. package/registry/blocks/chat/header.jsx +34 -0
  120. package/registry/blocks/chat/index.js +9 -0
  121. package/registry/blocks/chat/message.jsx +450 -0
  122. package/registry/blocks/chat/scroller.jsx +247 -0
  123. package/registry/blocks/chat/text.jsx +104 -0
  124. package/registry/blocks/code-editor/README.md +210 -0
  125. package/registry/blocks/code-editor/block.json +22 -0
  126. package/registry/blocks/code-editor/code-editor.jsx +534 -0
  127. package/registry/blocks/code-editor/codemirror.js +38 -0
  128. package/registry/blocks/code-editor/demo.jsx +205 -0
  129. package/registry/blocks/code-editor/index.js +8 -0
  130. package/registry/blocks/code-editor/json.js +317 -0
  131. package/registry/blocks/code-editor/sql.js +136 -0
  132. package/registry/blocks/code-editor/text.js +101 -0
  133. package/registry/blocks/code-editor/theme.js +186 -0
  134. package/registry/blocks/comment-box/README.md +123 -0
  135. package/registry/blocks/comment-box/block.json +10 -0
  136. package/registry/blocks/comment-box/comment-body.jsx +217 -0
  137. package/registry/blocks/comment-box/comment-box.jsx +198 -0
  138. package/registry/blocks/comment-box/comment-time.jsx +77 -0
  139. package/registry/blocks/comment-box/demo.jsx +141 -0
  140. package/registry/blocks/comment-box/index.js +8 -0
  141. package/registry/blocks/contact-section/README.md +152 -0
  142. package/registry/blocks/contact-section/block.json +11 -0
  143. package/registry/blocks/contact-section/contact-section.jsx +509 -0
  144. package/registry/blocks/contact-section/demo.jsx +93 -0
  145. package/registry/blocks/contact-section/index.js +4 -0
  146. package/registry/blocks/csv-import/README.md +133 -0
  147. package/registry/blocks/csv-import/block.json +13 -0
  148. package/registry/blocks/csv-import/csv-import.jsx +479 -0
  149. package/registry/blocks/csv-import/demo.jsx +106 -0
  150. package/registry/blocks/csv-import/import.js +200 -0
  151. package/registry/blocks/csv-import/index.js +7 -0
  152. package/registry/blocks/data-table/README.md +386 -0
  153. package/registry/blocks/data-table/block.json +10 -0
  154. package/registry/blocks/data-table/data-table.jsx +1164 -0
  155. package/registry/blocks/data-table/demo.jsx +588 -0
  156. package/registry/blocks/data-table/index.js +5 -0
  157. package/registry/blocks/data-table/model.js +169 -0
  158. package/registry/blocks/diagram/README.md +108 -0
  159. package/registry/blocks/diagram/block.json +13 -0
  160. package/registry/blocks/diagram/demo.jsx +113 -0
  161. package/registry/blocks/diagram/diagram.jsx +481 -0
  162. package/registry/blocks/diagram/index.js +7 -0
  163. package/registry/blocks/diagram/mermaid.js +52 -0
  164. package/registry/blocks/diagram/palette.js +313 -0
  165. package/registry/blocks/diagram/source.js +98 -0
  166. package/registry/blocks/doc-editor/README.md +215 -0
  167. package/registry/blocks/doc-editor/block.json +15 -0
  168. package/registry/blocks/doc-editor/demo.jsx +225 -0
  169. package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
  170. package/registry/blocks/doc-editor/doc.js +309 -0
  171. package/registry/blocks/doc-editor/index.js +7 -0
  172. package/registry/blocks/doc-editor/schema.jsx +56 -0
  173. package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
  174. package/registry/blocks/doc-editor/theme.js +82 -0
  175. package/registry/blocks/doc-page/README.md +119 -0
  176. package/registry/blocks/doc-page/autosave.js +104 -0
  177. package/registry/blocks/doc-page/block.json +10 -0
  178. package/registry/blocks/doc-page/demo.jsx +137 -0
  179. package/registry/blocks/doc-page/doc-page.jsx +276 -0
  180. package/registry/blocks/doc-page/index.js +4 -0
  181. package/registry/blocks/email-render/README.md +151 -0
  182. package/registry/blocks/email-render/block.json +14 -0
  183. package/registry/blocks/email-render/demo.jsx +153 -0
  184. package/registry/blocks/email-render/doc-email.jsx +210 -0
  185. package/registry/blocks/email-render/email.jsx +221 -0
  186. package/registry/blocks/email-render/index.js +10 -0
  187. package/registry/blocks/email-render/render.js +50 -0
  188. package/registry/blocks/email-render/theme.js +215 -0
  189. package/registry/blocks/faq/README.md +101 -0
  190. package/registry/blocks/faq/block.json +11 -0
  191. package/registry/blocks/faq/demo.jsx +89 -0
  192. package/registry/blocks/faq/faq.jsx +220 -0
  193. package/registry/blocks/faq/index.js +4 -0
  194. package/registry/blocks/file-upload/README.md +138 -0
  195. package/registry/blocks/file-upload/block.json +10 -0
  196. package/registry/blocks/file-upload/demo.jsx +204 -0
  197. package/registry/blocks/file-upload/file-upload.jsx +635 -0
  198. package/registry/blocks/file-upload/index.js +4 -0
  199. package/registry/blocks/flow-canvas/README.md +420 -0
  200. package/registry/blocks/flow-canvas/block.json +13 -0
  201. package/registry/blocks/flow-canvas/board.js +819 -0
  202. package/registry/blocks/flow-canvas/chrome.jsx +649 -0
  203. package/registry/blocks/flow-canvas/context.jsx +35 -0
  204. package/registry/blocks/flow-canvas/demo.jsx +249 -0
  205. package/registry/blocks/flow-canvas/edges.jsx +107 -0
  206. package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
  207. package/registry/blocks/flow-canvas/index.js +41 -0
  208. package/registry/blocks/flow-canvas/nodes.jsx +392 -0
  209. package/registry/blocks/flow-canvas/theme.js +174 -0
  210. package/registry/blocks/footer/README.md +133 -0
  211. package/registry/blocks/footer/block.json +11 -0
  212. package/registry/blocks/footer/demo.jsx +119 -0
  213. package/registry/blocks/footer/footer.jsx +406 -0
  214. package/registry/blocks/footer/index.js +4 -0
  215. package/registry/blocks/gantt/README.md +220 -0
  216. package/registry/blocks/gantt/block.json +10 -0
  217. package/registry/blocks/gantt/demo.jsx +148 -0
  218. package/registry/blocks/gantt/gantt.jsx +923 -0
  219. package/registry/blocks/gantt/index.js +7 -0
  220. package/registry/blocks/gantt/rows.jsx +468 -0
  221. package/registry/blocks/gantt/schedule.js +278 -0
  222. package/registry/blocks/job-panel/README.md +80 -0
  223. package/registry/blocks/job-panel/block.json +3 -3
  224. package/registry/blocks/job-panel/demo.jsx +230 -3
  225. package/registry/blocks/job-panel/job-panel.jsx +169 -3
  226. package/registry/blocks/json-editor/README.md +133 -0
  227. package/registry/blocks/json-editor/block.json +10 -0
  228. package/registry/blocks/json-editor/demo.jsx +92 -0
  229. package/registry/blocks/json-editor/index.js +7 -0
  230. package/registry/blocks/json-editor/json-editor.jsx +305 -0
  231. package/registry/blocks/json-editor/json-tree.jsx +393 -0
  232. package/registry/blocks/json-editor/tree.js +225 -0
  233. package/registry/blocks/map/README.md +221 -0
  234. package/registry/blocks/map/block.json +14 -0
  235. package/registry/blocks/map/demo.jsx +201 -0
  236. package/registry/blocks/map/geo.js +198 -0
  237. package/registry/blocks/map/index.js +8 -0
  238. package/registry/blocks/map/list.jsx +128 -0
  239. package/registry/blocks/map/map-view.jsx +715 -0
  240. package/registry/blocks/map/maplibre.js +30 -0
  241. package/registry/blocks/map/marks.jsx +146 -0
  242. package/registry/blocks/map/theme.js +142 -0
  243. package/registry/blocks/menubar/README.md +109 -0
  244. package/registry/blocks/menubar/block.json +10 -0
  245. package/registry/blocks/menubar/demo.jsx +128 -0
  246. package/registry/blocks/menubar/index.js +4 -0
  247. package/registry/blocks/menubar/menubar.jsx +199 -0
  248. package/registry/blocks/mind-map/README.md +206 -0
  249. package/registry/blocks/mind-map/block.json +10 -0
  250. package/registry/blocks/mind-map/demo.jsx +103 -0
  251. package/registry/blocks/mind-map/index.js +31 -0
  252. package/registry/blocks/mind-map/mind-map.jsx +1125 -0
  253. package/registry/blocks/mind-map/topic.jsx +143 -0
  254. package/registry/blocks/mind-map/tree.js +645 -0
  255. package/registry/blocks/navigation-menu/README.md +124 -0
  256. package/registry/blocks/navigation-menu/block.json +10 -0
  257. package/registry/blocks/navigation-menu/demo.jsx +84 -0
  258. package/registry/blocks/navigation-menu/index.js +4 -0
  259. package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
  260. package/registry/blocks/order-detail/README.md +109 -0
  261. package/registry/blocks/order-detail/block.json +10 -0
  262. package/registry/blocks/order-detail/demo.jsx +88 -0
  263. package/registry/blocks/order-detail/index.js +4 -0
  264. package/registry/blocks/order-detail/order-detail.jsx +354 -0
  265. package/registry/blocks/org-chart/README.md +145 -0
  266. package/registry/blocks/org-chart/block.json +10 -0
  267. package/registry/blocks/org-chart/demo.jsx +94 -0
  268. package/registry/blocks/org-chart/index.js +7 -0
  269. package/registry/blocks/org-chart/org-chart.jsx +631 -0
  270. package/registry/blocks/org-chart/org.js +245 -0
  271. package/registry/blocks/org-chart/person.jsx +96 -0
  272. package/registry/blocks/page-builder/README.md +257 -0
  273. package/registry/blocks/page-builder/block.json +14 -0
  274. package/registry/blocks/page-builder/demo.jsx +145 -0
  275. package/registry/blocks/page-builder/grapes.js +18 -0
  276. package/registry/blocks/page-builder/index.js +11 -0
  277. package/registry/blocks/page-builder/page-builder.jsx +704 -0
  278. package/registry/blocks/page-builder/page-view.jsx +33 -0
  279. package/registry/blocks/page-builder/page.js +118 -0
  280. package/registry/blocks/page-builder/panels.jsx +588 -0
  281. package/registry/blocks/page-builder/sections.js +209 -0
  282. package/registry/blocks/page-builder/theme.js +87 -0
  283. package/registry/blocks/page-builder/thumbs.jsx +189 -0
  284. package/registry/blocks/page-builder/tokens.js +329 -0
  285. package/registry/blocks/payment-methods/README.md +104 -0
  286. package/registry/blocks/payment-methods/block.json +10 -0
  287. package/registry/blocks/payment-methods/demo.jsx +71 -0
  288. package/registry/blocks/payment-methods/index.js +4 -0
  289. package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
  290. package/registry/blocks/pdf-document/README.md +213 -0
  291. package/registry/blocks/pdf-document/block.json +13 -0
  292. package/registry/blocks/pdf-document/demo.jsx +136 -0
  293. package/registry/blocks/pdf-document/index.js +33 -0
  294. package/registry/blocks/pdf-document/money.js +83 -0
  295. package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
  296. package/registry/blocks/pdf-document/primitives.jsx +271 -0
  297. package/registry/blocks/pdf-document/quote.jsx +179 -0
  298. package/registry/blocks/pdf-document/theme.js +193 -0
  299. package/registry/blocks/pdf-viewer/README.md +191 -0
  300. package/registry/blocks/pdf-viewer/block.json +14 -0
  301. package/registry/blocks/pdf-viewer/demo.jsx +252 -0
  302. package/registry/blocks/pdf-viewer/helpers.js +270 -0
  303. package/registry/blocks/pdf-viewer/index.js +8 -0
  304. package/registry/blocks/pdf-viewer/notes.jsx +195 -0
  305. package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
  306. package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
  307. package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
  308. package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
  309. package/registry/blocks/product-detail/README.md +217 -0
  310. package/registry/blocks/product-detail/block.json +10 -0
  311. package/registry/blocks/product-detail/demo.jsx +233 -0
  312. package/registry/blocks/product-detail/index.js +7 -0
  313. package/registry/blocks/product-detail/price.jsx +115 -0
  314. package/registry/blocks/product-detail/product-detail.jsx +348 -0
  315. package/registry/blocks/product-detail/product-media.jsx +102 -0
  316. package/registry/blocks/product-detail/product-options.jsx +144 -0
  317. package/registry/blocks/product-grid/README.md +162 -0
  318. package/registry/blocks/product-grid/block.json +10 -0
  319. package/registry/blocks/product-grid/demo.jsx +255 -0
  320. package/registry/blocks/product-grid/index.js +5 -0
  321. package/registry/blocks/product-grid/product-card.jsx +232 -0
  322. package/registry/blocks/product-grid/product-grid.jsx +235 -0
  323. package/registry/blocks/record-form/README.md +196 -0
  324. package/registry/blocks/record-form/block.json +10 -0
  325. package/registry/blocks/record-form/demo.jsx +525 -0
  326. package/registry/blocks/record-form/index.js +4 -0
  327. package/registry/blocks/record-form/record-fields.jsx +457 -0
  328. package/registry/blocks/record-form/record-form.jsx +415 -0
  329. package/registry/blocks/record-form/rules.js +81 -0
  330. package/registry/blocks/record-notes/README.md +139 -0
  331. package/registry/blocks/record-notes/block.json +10 -0
  332. package/registry/blocks/record-notes/demo.jsx +179 -0
  333. package/registry/blocks/record-notes/index.js +4 -0
  334. package/registry/blocks/record-notes/record-notes.jsx +266 -0
  335. package/registry/blocks/search-dialog/README.md +108 -0
  336. package/registry/blocks/search-dialog/block.json +10 -0
  337. package/registry/blocks/search-dialog/demo.jsx +116 -0
  338. package/registry/blocks/search-dialog/index.js +3 -0
  339. package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
  340. package/registry/blocks/settings-list/README.md +171 -0
  341. package/registry/blocks/settings-list/block.json +10 -0
  342. package/registry/blocks/settings-list/demo.jsx +333 -0
  343. package/registry/blocks/settings-list/index.js +4 -0
  344. package/registry/blocks/settings-list/row-state.jsx +93 -0
  345. package/registry/blocks/settings-list/settings-list.jsx +349 -0
  346. package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
  347. package/registry/blocks/setup-checklist/README.md +142 -0
  348. package/registry/blocks/setup-checklist/block.json +10 -0
  349. package/registry/blocks/setup-checklist/demo.jsx +159 -0
  350. package/registry/blocks/setup-checklist/index.js +4 -0
  351. package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
  352. package/registry/blocks/share-dialog/README.md +113 -0
  353. package/registry/blocks/share-dialog/block.json +10 -0
  354. package/registry/blocks/share-dialog/demo.jsx +140 -0
  355. package/registry/blocks/share-dialog/index.js +3 -0
  356. package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
  357. package/registry/blocks/sidebar/README.md +190 -0
  358. package/registry/blocks/sidebar/block.json +43 -0
  359. package/registry/blocks/sidebar/demo.jsx +577 -0
  360. package/registry/blocks/sidebar/index.js +4 -0
  361. package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
  362. package/registry/blocks/sidebar/sidebar.jsx +864 -0
  363. package/registry/blocks/signature-pad/README.md +137 -0
  364. package/registry/blocks/signature-pad/block.json +13 -0
  365. package/registry/blocks/signature-pad/colors.js +115 -0
  366. package/registry/blocks/signature-pad/demo.jsx +94 -0
  367. package/registry/blocks/signature-pad/index.js +6 -0
  368. package/registry/blocks/signature-pad/pad.js +7 -0
  369. package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
  370. package/registry/blocks/signature-pad/signature.js +68 -0
  371. package/registry/blocks/sketch-canvas/README.md +280 -0
  372. package/registry/blocks/sketch-canvas/block.json +13 -0
  373. package/registry/blocks/sketch-canvas/demo.jsx +159 -0
  374. package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
  375. package/registry/blocks/sketch-canvas/index.js +9 -0
  376. package/registry/blocks/sketch-canvas/palette.js +226 -0
  377. package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
  378. package/registry/blocks/sketch-canvas/sketch.js +179 -0
  379. package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
  380. package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
  381. package/registry/blocks/sketch-canvas/stamps.js +104 -0
  382. package/registry/blocks/sketch-canvas/theme.js +131 -0
  383. package/registry/blocks/spreadsheet/README.md +307 -0
  384. package/registry/blocks/spreadsheet/block.json +13 -0
  385. package/registry/blocks/spreadsheet/cells.jsx +455 -0
  386. package/registry/blocks/spreadsheet/chrome.jsx +325 -0
  387. package/registry/blocks/spreadsheet/demo.jsx +177 -0
  388. package/registry/blocks/spreadsheet/grid.js +387 -0
  389. package/registry/blocks/spreadsheet/index.js +34 -0
  390. package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
  391. package/registry/blocks/spreadsheet/types.js +473 -0
  392. package/registry/blocks/stat-cards/README.md +173 -0
  393. package/registry/blocks/stat-cards/block.json +10 -0
  394. package/registry/blocks/stat-cards/demo.jsx +257 -0
  395. package/registry/blocks/stat-cards/index.js +4 -0
  396. package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
  397. package/registry/blocks/stat-cards/usage.jsx +243 -0
  398. package/registry/blocks/task-list/README.md +176 -0
  399. package/registry/blocks/task-list/block.json +10 -0
  400. package/registry/blocks/task-list/demo.jsx +134 -0
  401. package/registry/blocks/task-list/index.js +5 -0
  402. package/registry/blocks/task-list/task-list.jsx +907 -0
  403. package/registry/blocks/task-model/README.md +455 -0
  404. package/registry/blocks/task-model/block.json +167 -0
  405. package/registry/blocks/task-model/changes.js +89 -0
  406. package/registry/blocks/task-model/dates.js +371 -0
  407. package/registry/blocks/task-model/demo.jsx +215 -0
  408. package/registry/blocks/task-model/dnd.jsx +240 -0
  409. package/registry/blocks/task-model/index.js +97 -0
  410. package/registry/blocks/task-model/model.js +919 -0
  411. package/registry/blocks/task-model/parts.jsx +449 -0
  412. package/registry/blocks/task-model/toolbar.jsx +271 -0
  413. package/registry/blocks/testimonials/README.md +139 -0
  414. package/registry/blocks/testimonials/block.json +11 -0
  415. package/registry/blocks/testimonials/demo.jsx +137 -0
  416. package/registry/blocks/testimonials/index.js +4 -0
  417. package/registry/blocks/testimonials/testimonials.jsx +430 -0
  418. package/registry/blocks/transaction-list/README.md +126 -0
  419. package/registry/blocks/transaction-list/block.json +10 -0
  420. package/registry/blocks/transaction-list/demo.jsx +79 -0
  421. package/registry/blocks/transaction-list/index.js +4 -0
  422. package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
  423. package/registry/blocks/whiteboard/README.md +179 -0
  424. package/registry/blocks/whiteboard/block.json +10 -0
  425. package/registry/blocks/whiteboard/demo.jsx +169 -0
  426. package/registry/blocks/whiteboard/index.js +6 -0
  427. package/registry/blocks/whiteboard/templates.js +150 -0
  428. package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
  429. package/src/cli.mjs +19 -6
  430. package/src/install.mjs +18 -0
  431. package/src/registry.mjs +38 -4
  432. package/src/shadcn.mjs +14 -1
  433. package/templates/next/files/README.md +145 -11
  434. package/templates/next/files/app/globals.css +55 -4
  435. package/templates/next/files/check/run.mjs +3 -3
  436. package/templates/next/files/components/ui/avatar.jsx +141 -0
  437. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  438. package/templates/next/files/components/ui/button-group.jsx +70 -0
  439. package/templates/next/files/components/ui/button.jsx +132 -12
  440. package/templates/next/files/components/ui/calendar.jsx +609 -0
  441. package/templates/next/files/components/ui/carousel.jsx +281 -0
  442. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  443. package/templates/next/files/components/ui/combobox.jsx +608 -0
  444. package/templates/next/files/components/ui/command.jsx +577 -0
  445. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  446. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  447. package/templates/next/files/components/ui/distribution.jsx +117 -0
  448. package/templates/next/files/components/ui/feedback.jsx +143 -0
  449. package/templates/next/files/components/ui/field.jsx +115 -3
  450. package/templates/next/files/components/ui/file-input.jsx +234 -0
  451. package/templates/next/files/components/ui/icon.jsx +130 -8
  452. package/templates/next/files/components/ui/image.jsx +143 -0
  453. package/templates/next/files/components/ui/index.js +47 -2
  454. package/templates/next/files/components/ui/input-group.jsx +213 -0
  455. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  456. package/templates/next/files/components/ui/item.jsx +206 -0
  457. package/templates/next/files/components/ui/menu.jsx +454 -82
  458. package/templates/next/files/components/ui/notice.jsx +126 -14
  459. package/templates/next/files/components/ui/pagination.jsx +156 -0
  460. package/templates/next/files/components/ui/popover.jsx +284 -0
  461. package/templates/next/files/components/ui/radio.jsx +193 -0
  462. package/templates/next/files/components/ui/rating.jsx +131 -0
  463. package/templates/next/files/components/ui/resizable.jsx +338 -0
  464. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  465. package/templates/next/files/components/ui/separator.jsx +119 -0
  466. package/templates/next/files/components/ui/sheet.jsx +96 -11
  467. package/templates/next/files/components/ui/slider.jsx +174 -0
  468. package/templates/next/files/components/ui/stat.jsx +574 -0
  469. package/templates/next/files/components/ui/steps.jsx +338 -0
  470. package/templates/next/files/components/ui/swatch.jsx +33 -0
  471. package/templates/next/files/components/ui/table.jsx +130 -0
  472. package/templates/next/files/components/ui/toast.jsx +440 -0
  473. package/templates/next/files/components/ui/toggle.jsx +195 -0
  474. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  475. package/templates/next/template.json +264 -8
@@ -0,0 +1,415 @@
1
+ "use client";
2
+
3
+ import { useEffect, useId, useMemo, useRef, useState } from "react";
4
+ import { Button, Card, Confirm, Empty, Notice, Separator, Sheet, Skeleton, cx } from "../../ui";
5
+ import { RecordField, WIDE } from "./record-fields";
6
+ import { checkAll, checkField } from "./rules";
7
+
8
+ // RecordForm — edit (or create) one record from a list of fields: the
9
+ // fields are data, grouped into titled sections, drawn with the kit's
10
+ // parts. It holds the draft, checks it as the founder types, and saves it
11
+ // through `onSave`, which answers { ok } — or { ok: false, error, errors }
12
+ // with a message per field, shown under that field. In a card, on a page,
13
+ // or in a dialog (a centred Sheet).
14
+
15
+ const SAVED_FOR = 3000;
16
+
17
+ function sameValues(a, b) {
18
+ try {
19
+ return JSON.stringify(a) === JSON.stringify(b);
20
+ } catch {
21
+ return a === b;
22
+ }
23
+ }
24
+
25
+ /** The fields' starting values: the record's, else each field's default. */
26
+ function startFrom(fields, values) {
27
+ const out = { ...(values ?? {}) };
28
+ for (const f of fields) {
29
+ if (out[f.name] !== undefined) continue;
30
+ if (f.defaultValue !== undefined) out[f.name] = f.defaultValue;
31
+ else if (f.type === "checkboxes" || f.type === "images" || f.type === "tags" || (f.type === "combobox" && f.multiple)) out[f.name] = [];
32
+ else if (f.type === "checkbox" || f.type === "switch") out[f.name] = false;
33
+ }
34
+ return out;
35
+ }
36
+
37
+ /** What goes out: numbers as numbers, text trimmed, hidden fields dropped. */
38
+ function outOf(fields, draft) {
39
+ const out = { ...draft };
40
+ for (const f of fields) {
41
+ const v = out[f.name];
42
+ if (f.type === "number" && typeof v === "string") out[f.name] = v.trim() === "" ? null : Number(v);
43
+ else if (typeof v === "string" && f.trim !== false && f.type !== "password") out[f.name] = v.trim();
44
+ }
45
+ return out;
46
+ }
47
+
48
+ export function RecordForm({
49
+ sections: sectionsProp,
50
+ fields: fieldsProp,
51
+ values,
52
+ onSave,
53
+ onCancel,
54
+ onDelete,
55
+ onChange,
56
+ title,
57
+ description,
58
+ container = "card",
59
+ layout = "stacked",
60
+ columns = 2,
61
+ open = true,
62
+ onClose,
63
+ submitLabel = "Save changes",
64
+ cancelLabel = "Cancel",
65
+ savedLabel = "Saved",
66
+ deleteLabel = "Delete",
67
+ confirmDelete,
68
+ requireChanges = true,
69
+ loading = false,
70
+ error: loadError,
71
+ onRetry,
72
+ emptyLabel = "There is nothing to fill in here yet.",
73
+ className,
74
+ }) {
75
+ const formId = useId();
76
+ const sections = useMemo(
77
+ () => (sectionsProp?.length ? sectionsProp : fieldsProp?.length ? [{ fields: fieldsProp }] : []),
78
+ [sectionsProp, fieldsProp],
79
+ );
80
+ const allFields = useMemo(() => sections.flatMap((s) => s.fields ?? []), [sections]);
81
+
82
+ const [baseline, setBaseline] = useState(() => startFrom(allFields, values));
83
+ const [draft, setDraft] = useState(baseline);
84
+ const [touched, setTouched] = useState({});
85
+ const [errors, setErrors] = useState({});
86
+ const [formError, setFormError] = useState(null);
87
+ const [saving, setSaving] = useState(false);
88
+ const [savedAt, setSavedAt] = useState(null);
89
+ const [asking, setAsking] = useState(false);
90
+ const [deleting, setDeleting] = useState(false);
91
+ const seen = useRef(values);
92
+ const alive = useRef(true);
93
+ useEffect(() => {
94
+ alive.current = true;
95
+ return () => {
96
+ alive.current = false;
97
+ };
98
+ }, []);
99
+
100
+ // A new record (a different `values`) starts the form over.
101
+ useEffect(() => {
102
+ if (sameValues(seen.current, values)) return;
103
+ seen.current = values;
104
+ const fresh = startFrom(allFields, values);
105
+ setBaseline(fresh);
106
+ setDraft(fresh);
107
+ setTouched({});
108
+ setErrors({});
109
+ setFormError(null);
110
+ }, [values, allFields]);
111
+
112
+ // A dialog opens on the record as it stands, not on last time's edits.
113
+ const wasOpen = useRef(open);
114
+ useEffect(() => {
115
+ if (open && !wasOpen.current) {
116
+ setDraft(baseline);
117
+ setTouched({});
118
+ setErrors({});
119
+ setFormError(null);
120
+ setSavedAt(null);
121
+ }
122
+ wasOpen.current = open;
123
+ }, [open, baseline]);
124
+
125
+ useEffect(() => {
126
+ if (!savedAt) return;
127
+ const t = setTimeout(() => setSavedAt(null), SAVED_FOR);
128
+ return () => clearTimeout(t);
129
+ }, [savedAt]);
130
+
131
+ const visible = (f) => (typeof f.when === "function" ? f.when(draft) : true);
132
+ const shownFields = allFields.filter(visible);
133
+ const dirty = !sameValues(draft, baseline);
134
+ const idOf = (name) => `${formId}-${name}`;
135
+
136
+ function set(name, value) {
137
+ const next = { ...draft, [name]: value };
138
+ setDraft(next);
139
+ setSavedAt(null);
140
+ onChange?.(next);
141
+ // A field already marked wrong is checked again as it is fixed, and so
142
+ // is a field that must match this one (a confirm).
143
+ setErrors((e) => {
144
+ const out = { ...e };
145
+ for (const f of allFields) {
146
+ const mine = f.name === name && (out[name] !== undefined || touched[name]);
147
+ const pointer = f.matches === name && out[f.name] !== undefined;
148
+ if (!mine && !pointer) continue;
149
+ const m = checkField(f, next);
150
+ if (m) out[f.name] = m;
151
+ else delete out[f.name];
152
+ }
153
+ return out;
154
+ });
155
+ }
156
+
157
+ function blur(name) {
158
+ setTouched((t) => (t[name] ? t : { ...t, [name]: true }));
159
+ const f = allFields.find((x) => x.name === name);
160
+ if (!f) return;
161
+ const m = checkField(f, draft);
162
+ setErrors((e) => {
163
+ if (m) return { ...e, [name]: m };
164
+ if (e[name] === undefined) return e;
165
+ const { [name]: _drop, ...rest } = e;
166
+ return rest;
167
+ });
168
+ }
169
+
170
+ function focusField(name) {
171
+ if (typeof document === "undefined") return;
172
+ const el = document.getElementById(idOf(name));
173
+ if (!el) return;
174
+ const target = el.matches("input,select,textarea,button") ? el : el.querySelector("input:not([type=hidden]),select,textarea,button");
175
+ target?.focus();
176
+ }
177
+
178
+ function reset() {
179
+ setDraft(baseline);
180
+ setTouched({});
181
+ setErrors({});
182
+ setFormError(null);
183
+ }
184
+
185
+ async function submit(e) {
186
+ e?.preventDefault?.();
187
+ if (saving || !onSave) return;
188
+ const found = checkAll(shownFields, draft);
189
+ setErrors(found);
190
+ const bad = shownFields.find((f) => found[f.name]);
191
+ if (bad) {
192
+ const n = Object.keys(found).length;
193
+ setFormError(n === 1 ? "One field needs attention." : `${n} fields need attention.`);
194
+ focusField(bad.name);
195
+ return;
196
+ }
197
+ setFormError(null);
198
+ setSaving(true);
199
+ // A field hidden by its `when` is not sent.
200
+ const kept = { ...draft };
201
+ for (const f of allFields) if (!shownFields.includes(f)) delete kept[f.name];
202
+ const out = outOf(shownFields, kept);
203
+ const changed = Object.keys(out).filter((k) => !sameValues(out[k], baseline[k]));
204
+ let res;
205
+ try {
206
+ res = await onSave(out, { changed });
207
+ } catch (err) {
208
+ res = { ok: false, error: err?.message };
209
+ }
210
+ if (!alive.current) return;
211
+ setSaving(false);
212
+ if (res?.ok) {
213
+ setBaseline(draft);
214
+ setTouched({});
215
+ setSavedAt(Date.now());
216
+ if (container === "dialog") onClose?.();
217
+ return;
218
+ }
219
+ const fieldErrors = res?.errors && typeof res.errors === "object" ? res.errors : {};
220
+ setErrors(fieldErrors);
221
+ const named = shownFields.find((f) => fieldErrors[f.name]);
222
+ setFormError(res?.error || (named ? "Some fields were not accepted. Fix them and save again." : "The changes were not saved. Try again."));
223
+ if (named) focusField(named.name);
224
+ }
225
+
226
+ async function remove() {
227
+ setDeleting(true);
228
+ let res;
229
+ try {
230
+ res = await onDelete();
231
+ } catch (err) {
232
+ res = { ok: false, error: err?.message };
233
+ }
234
+ if (!alive.current) return;
235
+ setDeleting(false);
236
+ setAsking(false);
237
+ if (!res?.ok) setFormError(res?.error || "It was not deleted. Try again.");
238
+ else if (container === "dialog") onClose?.();
239
+ }
240
+
241
+ function cancel() {
242
+ reset();
243
+ if (container === "dialog") onClose?.();
244
+ onCancel?.();
245
+ }
246
+
247
+ const split = layout === "split" && container !== "dialog";
248
+ const grid = columns >= 2 && container !== "dialog" ? "grid gap-4 sm:grid-cols-2" : "grid gap-4";
249
+ const busy = saving || deleting;
250
+
251
+ let body;
252
+ if (loadError) {
253
+ body = (
254
+ <Notice tone="danger" title="This could not be loaded" action={onRetry ? <Button size="sm" onClick={onRetry}>Try again</Button> : null}>
255
+ {loadError}
256
+ </Notice>
257
+ );
258
+ } else if (loading) {
259
+ body = (
260
+ <div aria-busy="true" aria-label="Loading" className={grid}>
261
+ {[0, 1, 2, 3].map((i) => (
262
+ <div key={i} className="grid gap-2">
263
+ <Skeleton className="w-24" />
264
+ <Skeleton shape="rect" className="h-11 w-full" />
265
+ </div>
266
+ ))}
267
+ </div>
268
+ );
269
+ } else if (allFields.length === 0) {
270
+ body = <Empty icon="file" title={emptyLabel} />;
271
+ } else {
272
+ body = (
273
+ <div className={cx("grid", split ? "gap-8" : "gap-6")}>
274
+ {sections.map((section, si) => {
275
+ const fields = (section.fields ?? []).filter(visible);
276
+ if (fields.length === 0) return null;
277
+ const head =
278
+ section.title || section.description ? (
279
+ <div className="min-w-0">
280
+ {section.title ? <h3 className="text-sm font-semibold text-foreground">{section.title}</h3> : null}
281
+ {section.description ? <p className="mt-1 text-sm text-muted-foreground">{section.description}</p> : null}
282
+ </div>
283
+ ) : null;
284
+ const cols = section.columns ?? columns;
285
+ const sectionGrid = cols >= 2 && container !== "dialog" ? "grid gap-4 sm:grid-cols-2" : "grid gap-4";
286
+ return (
287
+ <div key={section.key ?? section.title ?? si} className="grid gap-6">
288
+ {si > 0 && split ? <Separator /> : null}
289
+ <section className={split ? "grid gap-4 md:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] md:gap-8" : "grid gap-4"}>
290
+ {head}
291
+ <div className={sectionGrid}>
292
+ {fields.map((f) => {
293
+ const wide = f.width === "full" || (f.width !== "half" && WIDE.has(f.type ?? "text"));
294
+ return (
295
+ <div key={f.name} className={cx("min-w-0", wide && "sm:col-span-2")}>
296
+ <RecordField
297
+ field={f}
298
+ id={idOf(f.name)}
299
+ value={draft[f.name]}
300
+ values={draft}
301
+ error={errors[f.name]}
302
+ disabled={busy}
303
+ onChange={(v) => set(f.name, v)}
304
+ onBlur={() => blur(f.name)}
305
+ />
306
+ </div>
307
+ );
308
+ })}
309
+ </div>
310
+ </section>
311
+ </div>
312
+ );
313
+ })}
314
+ </div>
315
+ );
316
+ }
317
+
318
+ const ready = !loading && !loadError && allFields.length > 0;
319
+ const status = (
320
+ <p aria-live="polite" className="min-w-0 flex-1 text-sm text-muted-foreground">
321
+ {saving ? "Saving…" : savedAt ? savedLabel : dirty ? "Unsaved changes" : ""}
322
+ </p>
323
+ );
324
+ const buttons = ready ? (
325
+ <>
326
+ {onDelete && container !== "dialog" ? (
327
+ <Button variant="danger" onClick={() => setAsking(true)} disabled={busy} className="max-sm:order-last max-sm:w-full">
328
+ {deleteLabel}
329
+ </Button>
330
+ ) : null}
331
+ {container !== "dialog" ? status : null}
332
+ {onCancel || container === "dialog" || dirty ? (
333
+ <Button variant="quiet" onClick={cancel} disabled={busy}>
334
+ {onCancel || container === "dialog" ? cancelLabel : "Discard"}
335
+ </Button>
336
+ ) : null}
337
+ <Button type="submit" form={formId} variant="primary" loading={saving} disabled={deleting || (requireChanges && !dirty)}>
338
+ {submitLabel}
339
+ </Button>
340
+ </>
341
+ ) : null;
342
+
343
+ const notice = formError ? (
344
+ <Notice tone="danger" onDismiss={() => setFormError(null)}>
345
+ {formError}
346
+ </Notice>
347
+ ) : null;
348
+
349
+ const form = (
350
+ <form id={formId} noValidate onSubmit={submit} className="grid gap-6" aria-busy={saving || undefined}>
351
+ {notice}
352
+ {body}
353
+ </form>
354
+ );
355
+
356
+ const deleteDialog = onDelete ? (
357
+ <Confirm
358
+ open={asking}
359
+ onClose={() => setAsking(false)}
360
+ onConfirm={remove}
361
+ busy={deleting}
362
+ tone="danger"
363
+ title={confirmDelete?.title ?? `${deleteLabel}?`}
364
+ body={confirmDelete?.body ?? "This cannot be undone."}
365
+ confirmLabel={confirmDelete?.confirmLabel ?? deleteLabel}
366
+ consequences={confirmDelete?.consequences}
367
+ requireText={confirmDelete?.requireText}
368
+ acknowledge={confirmDelete?.acknowledge}
369
+ />
370
+ ) : null;
371
+
372
+ if (container === "dialog") {
373
+ return (
374
+ <Sheet
375
+ open={open}
376
+ onClose={onClose}
377
+ side="center"
378
+ title={title}
379
+ description={description}
380
+ className={className}
381
+ footer={buttons}
382
+ >
383
+ {form}
384
+ </Sheet>
385
+ );
386
+ }
387
+
388
+ const footer = buttons ? <div className="flex flex-wrap items-center justify-end gap-2 border-t border-border pt-4">{buttons}</div> : null;
389
+
390
+ if (container === "page") {
391
+ return (
392
+ <div className={cx("grid gap-6", className)}>
393
+ {title || description ? (
394
+ <header className="min-w-0">
395
+ {title ? <h2 className="text-xl font-semibold leading-tight">{title}</h2> : null}
396
+ {description ? <p className="mt-1 max-w-prose text-sm text-muted-foreground">{description}</p> : null}
397
+ </header>
398
+ ) : null}
399
+ {form}
400
+ {footer}
401
+ {deleteDialog}
402
+ </div>
403
+ );
404
+ }
405
+
406
+ return (
407
+ <Card title={title} description={description} className={className}>
408
+ <div className="grid gap-6">
409
+ {form}
410
+ {footer}
411
+ </div>
412
+ {deleteDialog}
413
+ </Card>
414
+ );
415
+ }
@@ -0,0 +1,81 @@
1
+ // What a field's value must be, as data: required, the type's own shape
2
+ // (an email, a web address, a number in range), a length, a pattern, a
3
+ // match with another field, and the field's own `validate`. One message
4
+ // per field, the first rule it breaks. Plain functions: no React.
5
+
6
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
7
+
8
+ /** Is there nothing in it? "", null, [], an unticked box, a 0 rating. */
9
+ export function isBlank(value, type) {
10
+ if (value === undefined || value === null) return true;
11
+ if (typeof value === "string") return value.trim() === "";
12
+ if (Array.isArray(value)) return value.length === 0;
13
+ if (type === "checkbox" || type === "switch") return value !== true;
14
+ if (type === "rating") return !value;
15
+ return false;
16
+ }
17
+
18
+ /** The first thing wrong with `field`'s value in `values`, or null. */
19
+ export function checkField(field, values) {
20
+ const type = field.type ?? "text";
21
+ const value = values[field.name];
22
+ const label = field.label ?? field.name;
23
+ if (isBlank(value, type)) {
24
+ // An empty confirm is wrong only once there is something to confirm.
25
+ if (field.matches && !isBlank(values[field.matches])) return field.matchMessage ?? "These do not match.";
26
+ if (!field.required) return null;
27
+ if (type === "checkbox" || type === "switch") return field.requiredMessage ?? "This must be ticked to go on.";
28
+ if (["select", "combobox", "radio", "choice-cards", "date", "rating"].includes(type)) return field.requiredMessage ?? `Choose ${lower(label)}.`;
29
+ if (type === "photo" || type === "images") return field.requiredMessage ?? `Add ${lower(label)}.`;
30
+ return field.requiredMessage ?? `${label} is required.`;
31
+ }
32
+ if (typeof value === "string") {
33
+ const text = value.trim();
34
+ if (type === "email" && !EMAIL.test(text)) return "Enter an email like name@company.com.";
35
+ if (type === "url" && !isUrl(text)) return "Enter a full address, starting with https://.";
36
+ if (type === "number") {
37
+ const n = Number(text);
38
+ if (!Number.isFinite(n)) return "Enter a number.";
39
+ if (field.min !== undefined && n < Number(field.min)) return `Enter ${field.min} or more.`;
40
+ if (field.max !== undefined && n > Number(field.max)) return `Enter ${field.max} or less.`;
41
+ }
42
+ if (field.minLength && text.length < field.minLength) return `Use at least ${field.minLength} characters.`;
43
+ if (field.maxLength && text.length > field.maxLength) return `Use ${field.maxLength} characters at most.`;
44
+ if (field.pattern && !new RegExp(`^(?:${field.pattern})$`).test(text)) return field.patternMessage ?? "This is not in the expected form.";
45
+ }
46
+ if (Array.isArray(value) && field.maxItems && value.length > field.maxItems) return `Choose ${field.maxItems} at most.`;
47
+ if (field.matches && value !== values[field.matches]) return field.matchMessage ?? "These do not match.";
48
+ if (typeof field.validate === "function") {
49
+ try {
50
+ const said = field.validate(value, values);
51
+ if (typeof said === "string" && said) return said;
52
+ } catch (e) {
53
+ return e?.message ?? "This value was refused.";
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+
59
+ /** Every visible field's message, as { name: message }. */
60
+ export function checkAll(fields, values) {
61
+ const errors = {};
62
+ for (const f of fields) {
63
+ const m = checkField(f, values);
64
+ if (m) errors[f.name] = m;
65
+ }
66
+ return errors;
67
+ }
68
+
69
+ function isUrl(text) {
70
+ try {
71
+ const u = new URL(text);
72
+ return u.protocol === "http:" || u.protocol === "https:";
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+
78
+ function lower(label) {
79
+ const s = String(label);
80
+ return s.length > 1 && s[1] === s[1].toLowerCase() ? s[0].toLowerCase() + s.slice(1) : s;
81
+ }
@@ -0,0 +1,139 @@
1
+ # RecordNotes
2
+
3
+ The notes kept on one record — a deal, a contact, a company — to sit
4
+ beside its `record-form`. A composer at the top adds a note (rich text,
5
+ `@` to mention a teammate, Cmd/Ctrl+Enter or Add note). The notes follow,
6
+ newest first, grouped under "Today", "Yesterday", "Mon 21 Sep", each with
7
+ its author, "2 h ago" and the body as written. Your own notes have a ⋯
8
+ menu: Edit opens the same composer in place, Delete asks first.
9
+
10
+ Every save goes out through an async callback that answers `{ ok }`. The
11
+ block keeps no copy of the notes: when a callback succeeds, the page puts
12
+ the change into `notes`. When one fails, the words stay and the block
13
+ says why — under the composer, or on the note.
14
+
15
+ ```jsx
16
+ import { RecordNotes } from "../components/blocks/record-notes"; // a Makersclaw app ("./blocks/record-notes" from components/)
17
+ import { RecordNotes } from "@/components/makersclaw/blocks/record-notes"; // a shadcn project
18
+ ```
19
+
20
+ It is a client component: render it from a `"use client"` component, and
21
+ load the notes in the server surface (README §4). `makersclaw add
22
+ record-notes` adds `comment-box` and `doc-editor` with it (and the editor's
23
+ npm packages: run `npm install` after).
24
+
25
+ ## The data
26
+
27
+ A note in `notes`:
28
+
29
+ ```js
30
+ {
31
+ id: "n-204",
32
+ author: { id: "u-lena", name: "Lena Fischer", src: "https://…/lena.jpg" },
33
+ body: [ /* the doc onAdd gave you (BlockNote JSON) */ ], // or a plain string
34
+ createdAt: "2026-09-23T09:12:00Z", // ISO string, Date or ms
35
+ updatedAt: null, // set → "(edited)"
36
+ }
37
+ ```
38
+
39
+ One table, a row per note: `record_id`, `author_id`, `body jsonb`,
40
+ `body_text` (`docToText(doc)` from `doc-editor`, for search), `created_at`,
41
+ `updated_at`. A note is the author's: by default only notes whose
42
+ `author.id` is `me.id` (or that carry `mine: true`) get Edit and Delete.
43
+
44
+ ## Props
45
+
46
+ - `notes` — required: the record's notes, any order (the block sorts by
47
+ `createdAt`).
48
+ - `me` — `{ id, name, src? }`, who is writing: their avatar is beside the
49
+ composer, and their notes are editable.
50
+ - `onAdd(doc)` — `async`, returns `{ ok: true }` or `{ ok: false, error? }`.
51
+ Add the note to `notes` before answering ok. Without it there is no
52
+ composer (a read-only log).
53
+ - `onEdit(note, doc)` — `async`, `{ ok }`. Replace the note's body (and set
54
+ `updatedAt`). Without it there is no Edit.
55
+ - `onDelete(note)` — `async`, `{ ok }`, after the reader confirms. Drop the
56
+ note from `notes`. Without it there is no Delete.
57
+ - `canEdit(note)` — who may edit and delete which note, when "the author"
58
+ is not the rule (an admin may delete any note). Default: the author.
59
+ - `mentions` — `async (query) => [{ id, label, description? }]`: turns on
60
+ `@` in the composer.
61
+ - `title` — `"Notes"`; the card's heading and the list's name.
62
+ - `description` — a line under the title.
63
+ - `placeholder` — `"Add a note…"`.
64
+ - `addLabel` — the composer's button, `"Add note"`.
65
+ - `emptyText` — shown when there are no notes.
66
+ - `order` — `"newest"` (default: composer on top, newest first) ·
67
+ `"oldest"` (a log read top to bottom, composer at the end).
68
+ - `frame` — `"card"` (default: a Card with the title and a count) ·
69
+ `"none"` (just the composer and notes, for a tab or a sheet that has its
70
+ own heading).
71
+ - `className` — layout around it.
72
+
73
+ ## Example
74
+
75
+ ```jsx
76
+ // components/DealNotes.jsx — client
77
+ "use client";
78
+ import { useState } from "react";
79
+ import { deleteRow, insertRow, updateRow } from "../lib/actions";
80
+ import { RecordNotes } from "./blocks/record-notes";
81
+ import { docToText } from "./blocks/doc-editor";
82
+
83
+ export default function DealNotes({ deal, me, team, initial }) {
84
+ const [notes, setNotes] = useState(initial);
85
+ const findPeople = async (q) =>
86
+ team.filter((p) => p.name.toLowerCase().includes(q.toLowerCase())).map((p) => ({ id: p.id, label: p.name }));
87
+
88
+ async function add(doc) {
89
+ const res = await insertRow({
90
+ source: "public.deal_notes",
91
+ values: { deal_id: deal.id, author_id: me.id, body: doc, body_text: docToText(doc) },
92
+ });
93
+ if (!res.ok) return res;
94
+ setNotes((n) => [{ id: res.id, author: me, body: doc, createdAt: new Date() }, ...n]);
95
+ return { ok: true };
96
+ }
97
+
98
+ async function edit(note, doc) {
99
+ const updatedAt = new Date();
100
+ const res = await updateRow({ source: "public.deal_notes", id: note.id, patch: { body: doc, body_text: docToText(doc), updated_at: updatedAt } });
101
+ if (res.ok) setNotes((n) => n.map((x) => (x.id === note.id ? { ...x, body: doc, updatedAt } : x)));
102
+ return res;
103
+ }
104
+
105
+ async function remove(note) {
106
+ const res = await deleteRow({ source: "public.deal_notes", id: note.id });
107
+ if (res.ok) setNotes((n) => n.filter((x) => x.id !== note.id));
108
+ return res;
109
+ }
110
+
111
+ return <RecordNotes notes={notes} me={me} onAdd={add} onEdit={edit} onDelete={remove} mentions={findPeople} />;
112
+ }
113
+ ```
114
+
115
+ Beside the form, on a record page:
116
+
117
+ ```jsx
118
+ <div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_24rem]">
119
+ <RecordForm … />
120
+ <DealNotes … />
121
+ </div>
122
+ ```
123
+
124
+ ## What it will not do
125
+
126
+ - Pin, tag, react to or reply under a note: a note is a dated entry, not
127
+ a thread (`comment-box` for a discussion).
128
+ - Log activity by itself (emails sent, stage changes): pass those in as
129
+ notes if you want them in the list, with no `onEdit`/`onDelete` rights.
130
+ - Page or search the notes: it draws what it is given, sorted. Load the
131
+ latest few dozen and a "Show older" of your own.
132
+ - Collaborate live: two people editing one note is last-write-wins.
133
+ - Notify anyone mentioned: read `docMentions(doc)` in `onAdd` and send it
134
+ yourself.
135
+
136
+ A notes panel it cannot be is your own component in `components/`,
137
+ built from `comment-box`'s `CommentComposer`, `CommentBody` and
138
+ `CommentTime` — not an edit to this block. Its files are fixed: `npm run
139
+ check` refuses a change, and `makersclaw add record-notes` restores them.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "record-notes",
3
+ "title": "RecordNotes",
4
+ "description": "Dated rich-text notes on one record (a deal, a contact, a company), to sit beside record-form: a composer with @mentions and Cmd/Ctrl+Enter adds a note; the notes follow newest first (or oldest), grouped by day, each with author avatar, name and relative time; your own notes edit in place and delete after a confirm. Every save is an async callback answering { ok }; a failure keeps the words and says why where it happened.",
5
+ "useWhen": "A record page keeps a running log of notes: call notes on a deal, context on a contact, a history on a customer or a candidate. Not a discussion thread without edit and delete (comment-box), not one long document per record (doc-editor or doc-page), not an automatic activity feed.",
6
+ "tags": ["notes", "record", "deal", "contact", "crm", "log", "history", "comment", "mention", "rich text", "blocknote", "edit", "delete"],
7
+ "exports": ["RecordNotes"],
8
+ "files": ["index.js", "record-notes.jsx"],
9
+ "requires": ["comment-box", "doc-editor"]
10
+ }