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,131 @@
1
+ "use client";
2
+
3
+ // AuthForm, every variant — the gallery's and the smoke test's surface.
4
+ // Not installed into apps: `makersclaw add auth-form` lays index.js and
5
+ // auth-form.jsx only. Nothing signs anyone in: the callbacks wait a
6
+ // moment and answer. Turn on "Fail the next submit" to see the error, or
7
+ // type an email with "taken" in it.
8
+ import { useState } from "react";
9
+ import { Field, Icon, Select, Switch } from "../components/ui";
10
+ import { AuthForm } from "../components/blocks/auth-form";
11
+
12
+ const wait = (ms) => new Promise((r) => setTimeout(r, ms));
13
+
14
+ const Logo = () => (
15
+ <span className="grid size-10 place-items-center rounded-md bg-primary text-primary-foreground">
16
+ <Icon name="layers" size={20} />
17
+ </span>
18
+ );
19
+
20
+ const ROLES = [
21
+ { value: "founder", label: "Founder" },
22
+ { value: "ops", label: "Operations" },
23
+ { value: "sales", label: "Sales" },
24
+ { value: "engineering", label: "Engineering" },
25
+ ];
26
+
27
+ const TIPS = [
28
+ "Use a password manager, and a different password for every account.",
29
+ "Never share it, not even with someone from our team.",
30
+ "Turn on two-step sign-in in Security.",
31
+ ];
32
+
33
+ // Each source file is one variant: its props, and the label in the switcher.
34
+ const VARIANTS = [
35
+ { key: "basic", label: "Sign in — email and password", props: { mode: "sign-in" } },
36
+ { key: "google", label: "Sign in — then Google", props: { mode: "sign-in", providers: ["google"] } },
37
+ { key: "email-only", label: "Sign in — email only, Google", props: { mode: "sign-in", password: false, providers: ["google"], title: "Log in or create an account", description: null } },
38
+ { key: "providers-first", label: "Sign in — providers first", props: { mode: "sign-in", providers: ["github", "google"], providersFirst: true, title: "Sign in to Ledgerly" } },
39
+ { key: "magic", label: "Magic link, SSO and terms", props: { mode: "magic-link", providers: ["sso"], title: "Welcome back" } },
40
+ { key: "page", label: "Full page — remember for 30 days", props: { mode: "sign-in", layout: "page", providers: ["google", "apple", "microsoft"], providersFirst: true, remember: "Remember me for 30 days", title: "Welcome back", description: "Sign in to your dashboard, reports and settings." } },
41
+ { key: "card", label: "Card — reset link and remember me", props: { mode: "sign-in", remember: true, title: "Sign in to Ledgerly" } },
42
+ { key: "sign-up", label: "Sign up — confirm, news, terms", props: { mode: "sign-up", newsletter: true, acceptTerms: true, title: "Create a Ledgerly account" } },
43
+ {
44
+ key: "sign-up-fields",
45
+ label: "Sign up — more fields and rules",
46
+ props: {
47
+ mode: "sign-up",
48
+ providers: ["github"],
49
+ rules: [
50
+ { label: "At least 10 characters", test: (v) => v.length >= 10 },
51
+ { label: "A number", test: (v) => /\d/.test(v) },
52
+ ],
53
+ fields: [
54
+ { name: "firstName", label: "First name", autoComplete: "given-name", required: true, half: true },
55
+ { name: "lastName", label: "Last name", autoComplete: "family-name", required: true, half: true },
56
+ { name: "username", label: "Username", autoComplete: "username", hint: "Shown on your comments. You can change it later." },
57
+ { name: "role", label: "Your role", type: "select", options: ROLES },
58
+ ],
59
+ },
60
+ },
61
+ { key: "reset", label: "Reset — email a link", props: { mode: "reset" } },
62
+ { key: "change", label: "Change password — rules beside", props: { mode: "change-password", tips: TIPS } },
63
+ ];
64
+
65
+ export default function AuthFormDemo() {
66
+ const [key, setKey] = useState("basic");
67
+ const [fail, setFail] = useState(false);
68
+ const [log, setLog] = useState(null);
69
+ const variant = VARIANTS.find((v) => v.key === key) ?? VARIANTS[0];
70
+
71
+ // The links switch variants in place, as an app's routes would.
72
+ const go = (to) => () => setKey(to);
73
+ const links = {
74
+ "sign-up": go("sign-up"),
75
+ "sign-in": go("basic"),
76
+ reset: go("reset"),
77
+ "magic-link": go("magic"),
78
+ terms: "#terms",
79
+ privacy: "#privacy",
80
+ };
81
+
82
+ async function onSubmit(values, mode) {
83
+ await wait(700);
84
+ const shown = { ...values };
85
+ for (const k of ["password", "currentPassword", "newPassword"]) if (k in shown) shown[k] = "••••••";
86
+ if (fail) {
87
+ setFail(false);
88
+ return { ok: false, error: mode === "change-password" ? "Your current password is not right." : "We could not reach the server. Check your connection and try again." };
89
+ }
90
+ if (values.email?.includes("taken")) return { ok: false, error: `An account already uses ${values.email}. Sign in instead.` };
91
+ setLog(`${mode}: ${JSON.stringify(shown)}`);
92
+ return { ok: true };
93
+ }
94
+
95
+ async function onProvider(id) {
96
+ await wait(600);
97
+ if (fail) {
98
+ setFail(false);
99
+ return { ok: false, error: `The ${id} window closed before you finished. Try again.` };
100
+ }
101
+ setLog(`provider: ${id}`);
102
+ return { ok: true };
103
+ }
104
+
105
+ return (
106
+ <div className="grid gap-6">
107
+ <div className="flex flex-wrap items-end gap-x-6 gap-y-2">
108
+ <Field id="auth-variant" label="Variant" className="w-full sm:w-80">
109
+ <Select id="auth-variant" value={key} onChange={(e) => setKey(e.target.value)} options={VARIANTS.map((v) => ({ value: v.key, label: v.label }))} />
110
+ </Field>
111
+ <Switch id="auth-fail" label="Fail the next submit" checked={fail} onChange={(e) => setFail(e.target.checked)} />
112
+ </div>
113
+
114
+ <div className="grid justify-items-center rounded-lg bg-muted px-4 py-8">
115
+ <AuthForm
116
+ key={key}
117
+ {...variant.props}
118
+ logo={key === "change" ? undefined : <Logo />}
119
+ links={links}
120
+ onSubmit={onSubmit}
121
+ onProvider={onProvider}
122
+ onCancel={key === "change" ? () => setLog("change-password: cancelled") : undefined}
123
+ />
124
+ </div>
125
+
126
+ <p className="min-h-5 break-all text-xs text-muted-foreground" aria-live="polite">
127
+ {log ? `Sent — ${log}` : "Submit a form to see what the callback receives."}
128
+ </p>
129
+ </div>
130
+ );
131
+ }
@@ -0,0 +1,3 @@
1
+ // The AuthForm block — `makersclaw add auth-form`. Fixed: compose it
2
+ // through its props (README.md beside this file).
3
+ export { AuthForm, PASSWORD_RULES } from "./auth-form";
@@ -27,7 +27,8 @@ record goes missing; it can be dragged out of it, not into it.
27
27
  example cards move on screen without saving (they are not rows).
28
28
  - `groupBy` — the column that holds the stage, e.g. `"stage"`.
29
29
  - `columns` — the stages in order: `["lead", "call", "won"]` (labels are
30
- made from the keys) or `[{ key: "lead", label: "New lead" }, …]`.
30
+ made from the keys) or `[{ key: "lead", label: "New lead", icon? }, …]`.
31
+ `icon` is a kit `Icon` name, drawn before the stage's label.
31
32
  - `onMove(row, to, from)` — save the move; return `{ ok: true }` or
32
33
  `{ ok: false, error }` (a throw counts as failed). In a Makersclaw app it
33
34
  is one line over `moveRow` (lib/actions.js — the activity row included):
@@ -38,10 +39,13 @@ record goes missing; it can be dragged out of it, not into it.
38
39
  also names the card in its menu, in announcements and in errors.
39
40
  - `onOpen(row)` — the title becomes a button: open your `Sheet` to edit
40
41
  the record. The block draws that button; you never style one.
41
- - `renderDetails(row, { column })` — what the card says under its title:
42
- the part of the board that is yours. Kit parts and tokens only.
42
+ - `renderDetails(row, { column, layout })` — what the card says under its
43
+ title: the part of the board that is yours. Kit parts and tokens only.
44
+ In `layout="stacked"` it sits at the row's end instead, so keep it short
45
+ there (a badge, an avatar); `layout` tells you which.
43
46
  - `metaOf(row)` — a plain muted line under the title, when that is all
44
- the card needs (ignored when `renderDetails` is set).
47
+ the card needs (ignored on cards when `renderDetails` is set; a stacked
48
+ row shows both).
45
49
  - `actionsOf(row)` — more menu items for a card, kit `Menu` shape:
46
50
  `[{ label, onSelect, icon?, tone?: "danger" }]`. The "Move to" items
47
51
  follow them.
@@ -52,6 +56,21 @@ record goes missing; it can be dragged out of it, not into it.
52
56
  - `addLabel` · `createPlaceholder` · `emptyLabel` · `otherLabel` — words.
53
57
  - `limits` — a work-in-progress limit per stage: `{ doing: 3 }` shows
54
58
  `4/3` in the header, in the warning tone, when it is exceeded.
59
+ - `aggregate(rows, column)` — a figure beside each stage's count, from the
60
+ records in it: ``(list) => `${list.reduce((s, r) => s + r.points, 0)}pt` ``
61
+ → "13pt". A string or a node; `column` is null for "No stage".
62
+ - `accentOf(row)` — the record's category as a colour on one edge of its
63
+ card: `1` … `5` (the chart tokens, `chart-1` … `chart-5`), or `null` for
64
+ none. A category, never a status: show what it means in words too (a
65
+ legend, or the type on the card).
66
+ - `accentEdge` — `"top"` (default) or `"start"` (the left edge, in a
67
+ right-to-left page the right). Stacked rows always use the start edge.
68
+ - `layout` — `"columns"` (default: side by side, dragged) or `"stacked"`:
69
+ the stages one under another as folding sections (icon, label, count,
70
+ chevron), each record a compact row. Rows move through their menu
71
+ ("Move to …"); nothing drags, so on a phone the page just scrolls.
72
+ - `defaultOpen` — stacked: the stage keys open at first, e.g.
73
+ `["todo"]`. Default: every stage open.
55
74
  - `label` — what the board is called to a screen reader.
56
75
  - `className` — layout around it (width, margin). Never colour.
57
76
 
@@ -118,13 +137,44 @@ export default function Pipeline({ deals, error }) {
118
137
  }
119
138
  ```
120
139
 
140
+ A sprint (icons, points per stage, a top edge by type) and a stacked list:
141
+
142
+ ```jsx
143
+ const TYPE_HUE = { feature: 1, bug: 4, task: 2 };
144
+
145
+ <Board
146
+ rows={stories}
147
+ groupBy="status"
148
+ columns={[{ key: "todo", label: "To do", icon: "inbox" }, { key: "doing", label: "In progress", icon: "zap" }, { key: "done", label: "Done", icon: "circle-check" }]}
149
+ onMove={(s, to) => moveRow({ source: "public.stories", id: s.id, stateColumn: "status", to })}
150
+ aggregate={(list) => `${list.reduce((n, s) => n + (s.points ?? 0), 0)}pt`}
151
+ accentOf={(s) => TYPE_HUE[s.type] ?? null}
152
+ renderDetails={(s) => <Badge>{s.points}pt</Badge>}
153
+ label="Stories by status"
154
+ />
155
+
156
+ <Board
157
+ layout="stacked"
158
+ rows={chores}
159
+ groupBy="state"
160
+ columns={[{ key: "todo", label: "To do", icon: "inbox" }, { key: "done", label: "Done", icon: "circle-check" }]}
161
+ defaultOpen={["todo"]}
162
+ onMove={(c, to) => moveRow({ source: "public.chores", id: c.id, stateColumn: "state", to })}
163
+ metaOf={(c) => c.room}
164
+ renderDetails={(c) => <Badge tone={c.every === "daily" ? "warning" : "info"}>{c.every}</Badge>}
165
+ label="Chores by state"
166
+ />
167
+ ```
168
+
121
169
  ## What it will not do
122
170
 
123
171
  - Order cards inside a column: they keep the order of `rows` — sort in
124
172
  the surface's `loadRows`.
125
173
  - Create a stage: `columns` is the surface's; a new stage is a new entry.
126
174
  - Colour a column: stages are not status. Put a `Badge` on the card when a
127
- stage means something the founder must see.
175
+ stage means something the founder must see. (`accentOf` colours a card
176
+ by its category, not its stage.)
177
+ - Drag in `layout="stacked"`: rows move from their menu.
128
178
 
129
179
  A board it cannot be is your own component in `components/`, built from
130
180
  the kit — not an edit to this block. Its files are fixed: `npm run check`
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "board",
3
3
  "title": "Board",
4
- "description": "Records as cards in columns, one per stage; drag a card to another column (mouse, touch, or the card's menu from the keyboard) and the stage is saved.",
4
+ "description": "Records as cards in columns, one per stage; drag a card to another column (mouse, touch, or the card's menu from the keyboard) and the stage is saved. Optional column icons, a per-column total (\"13pt\"), a category colour on each card's edge, and a stacked layout of folding sections with compact rows.",
5
5
  "useWhen": "A process where each record sits in one stage and moves forward: a pipeline, a hiring funnel, a sprint, a content calendar by status, outreach by reply state. Not for records with no stages (a table) or items placed on a timeline.",
6
- "tags": ["board", "kanban", "pipeline", "stages", "columns", "cards", "drag", "drop", "status", "workflow", "funnel"],
6
+ "tags": ["board", "kanban", "pipeline", "stages", "columns", "cards", "drag", "drop", "status", "workflow", "funnel", "sprint", "accent", "stacked", "collapsible"],
7
7
  "exports": ["Board"],
8
8
  "files": ["index.js", "board.jsx"],
9
9
  "requires": []
@@ -3,7 +3,7 @@
3
3
  import { useEffect, useId, useMemo, useRef, useState } from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import { isSample } from "../../parts";
6
- import { Button, Icon, Input, Menu, Notice, cx } from "../../ui";
6
+ import { Button, Collapsible, Icon, Input, Menu, Notice, cx } from "../../ui";
7
7
 
8
8
  // Board — records as cards in columns, one column per stage, moved by
9
9
  // dragging or from the card's menu. The block owns the behaviour a board
@@ -21,9 +21,38 @@ import { Button, Icon, Input, Menu, Notice, cx } from "../../ui";
21
21
  // titleOf={(d) => d.name} renderDetails={(d) => <DealFacts deal={d} />}
22
22
  // onOpen={setEditing} />
23
23
  //
24
+ // Opt-in: an icon per column (`columns[].icon`), a figure beside each
25
+ // count (`aggregate(rows)` → "13pt"), a category's colour on each card's
26
+ // edge (`accentOf(row)` → 1…5, `accentEdge` top | start), and
27
+ // `layout="stacked"` — the stages as folding sections of compact rows.
28
+ //
24
29
  // README.md beside this file lists every prop.
25
30
 
26
31
  const OTHER = "__other";
32
+
33
+ // A card's accent: a category's colour on one edge, from the chart tokens
34
+ // (chart-1…5), written out whole so Tailwind finds every class.
35
+ const ACCENTS = {
36
+ top: {
37
+ 1: "border-t-[3px] border-t-chart-1",
38
+ 2: "border-t-[3px] border-t-chart-2",
39
+ 3: "border-t-[3px] border-t-chart-3",
40
+ 4: "border-t-[3px] border-t-chart-4",
41
+ 5: "border-t-[3px] border-t-chart-5",
42
+ },
43
+ start: {
44
+ 1: "border-s-[3px] border-s-chart-1",
45
+ 2: "border-s-[3px] border-s-chart-2",
46
+ 3: "border-s-[3px] border-s-chart-3",
47
+ 4: "border-s-[3px] border-s-chart-4",
48
+ 5: "border-s-[3px] border-s-chart-5",
49
+ },
50
+ };
51
+
52
+ function accentHue(value) {
53
+ const n = typeof value === "string" ? Number(value.replace(/^chart-/, "")) : value;
54
+ return Number.isInteger(n) && n >= 1 && n <= 5 ? n : null;
55
+ }
27
56
  const DRAG_START_PX = { mouse: 5, pen: 6, touch: 8 };
28
57
 
29
58
  function humanize(key) {
@@ -54,6 +83,11 @@ export function Board({
54
83
  addLabel = "Add",
55
84
  createPlaceholder = "Title, then Enter",
56
85
  limits,
86
+ aggregate,
87
+ accentOf,
88
+ accentEdge = "top",
89
+ layout = "columns",
90
+ defaultOpen,
57
91
  label = "Board",
58
92
  emptyLabel = "Nothing here yet",
59
93
  otherLabel = "No stage",
@@ -107,6 +141,12 @@ export function Board({
107
141
  return out;
108
142
  }, [list, cols, overrides]); // eslint-disable-line react-hooks/exhaustive-deps
109
143
 
144
+ const stacked = layout === "stacked";
145
+ const accent = (row, edge = accentEdge) => {
146
+ if (!accentOf) return null;
147
+ const hue = accentHue(accentOf(row));
148
+ return hue ? (ACCENTS[edge] ?? ACCENTS.top)[hue] : null;
149
+ };
110
150
  const shown = byColumn.get(OTHER).length ? [...cols, { key: OTHER, label: otherLabel, other: true }] : cols;
111
151
  const labelOf = (key) => shown.find((c) => c.key === key)?.label ?? humanize(key);
112
152
 
@@ -244,34 +284,115 @@ export function Board({
244
284
  }
245
285
  }
246
286
 
287
+ // The "Add" at a stage's foot, and the inline field it opens.
288
+ function adder(col, headingId, pad = "px-2 pb-2") {
289
+ if (!onCreate || col.other) return null;
290
+ if (adding !== col.key) {
291
+ return (
292
+ <div className={pad}>
293
+ <Button
294
+ variant="quiet"
295
+ size="sm"
296
+ icon="plus"
297
+ align="start"
298
+ className="w-full"
299
+ onClick={() => {
300
+ setAdding(col.key);
301
+ setDraft("");
302
+ }}
303
+ >
304
+ {addLabel}
305
+ </Button>
306
+ </div>
307
+ );
308
+ }
309
+ return (
310
+ <form onSubmit={(e) => create(e, col.key)} className={pad}>
311
+ <label htmlFor={`${headingId}-new`} className="sr-only">
312
+ New in {col.label}
313
+ </label>
314
+ <Input
315
+ id={`${headingId}-new`}
316
+ autoFocus
317
+ value={draft}
318
+ disabled={busy}
319
+ placeholder={createPlaceholder}
320
+ onChange={(e) => setDraft(e.target.value)}
321
+ onKeyDown={(e) => {
322
+ // Enter adds here, not through the form's implicit submit: a
323
+ // synthetic Enter (an agent testing the app) has no keypress to
324
+ // submit with. Never while an input method is composing a word.
325
+ if (e.key === "Enter" && !e.nativeEvent.isComposing) create(e, col.key);
326
+ else if (e.key === "Escape") {
327
+ setAdding(null);
328
+ setDraft("");
329
+ }
330
+ }}
331
+ onBlur={() => {
332
+ if (!draft.trim()) setAdding(null);
333
+ }}
334
+ />
335
+ </form>
336
+ );
337
+ }
338
+
339
+ function header(col, cards) {
340
+ const limit = limits?.[col.key];
341
+ const over = typeof limit === "number" && cards.length > limit;
342
+ return {
343
+ icon: col.icon ? <Icon name={col.icon} size={16} className="shrink-0 text-muted-foreground" /> : null,
344
+ total: aggregate ? (
345
+ <span data-nums className="shrink-0 text-xs text-muted-foreground">
346
+ {aggregate(cards, col.other ? null : col.key)}
347
+ </span>
348
+ ) : null,
349
+ count: (
350
+ <span
351
+ data-nums
352
+ className={cx("shrink-0 font-mono text-xs", over ? "font-semibold text-warning" : "text-muted-foreground")}
353
+ title={typeof limit === "number" ? `${cards.length} of a limit of ${limit}` : undefined}
354
+ >
355
+ {typeof limit === "number" ? `${cards.length}/${limit}` : cards.length}
356
+ </span>
357
+ ),
358
+ };
359
+ }
360
+
361
+ function moveItems(row) {
362
+ return movable
363
+ ? shown
364
+ .filter((c) => !c.other && c.key !== columnOf(row))
365
+ .map((c) => ({ label: `Move to ${c.label}`, icon: "arrow-right", onSelect: () => move(row, c.key) }))
366
+ : [];
367
+ }
368
+
369
+ function titleButton(row, title, extra) {
370
+ return onOpen ? (
371
+ <button
372
+ type="button"
373
+ onClick={() => onOpen(row)}
374
+ className={cx("block w-full rounded-sm text-left text-sm font-medium outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring", extra)}
375
+ >
376
+ {title}
377
+ </button>
378
+ ) : (
379
+ <p className={cx("text-sm font-medium", extra)}>{title}</p>
380
+ );
381
+ }
382
+
247
383
  function card(row, { ghost = false } = {}) {
248
384
  const title = titleOf(row);
249
385
  const body = (
250
386
  <>
251
- {onOpen ? (
252
- <button
253
- type="button"
254
- onClick={() => onOpen(row)}
255
- className="block w-full rounded-sm text-left text-sm font-medium outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring"
256
- >
257
- {title}
258
- </button>
259
- ) : (
260
- <p className="text-sm font-medium">{title}</p>
261
- )}
387
+ {titleButton(row, title)}
262
388
  {renderDetails ? (
263
- <div className="mt-2">{renderDetails(row, { column: columnOf(row) })}</div>
389
+ <div className="mt-2">{renderDetails(row, { column: columnOf(row), layout: "columns" })}</div>
264
390
  ) : metaOf ? (
265
391
  <div className="mt-1 text-xs text-muted-foreground">{metaOf(row)}</div>
266
392
  ) : null}
267
393
  </>
268
394
  );
269
- const moveTo = movable
270
- ? shown
271
- .filter((c) => !c.other && c.key !== columnOf(row))
272
- .map((c) => ({ label: `Move to ${c.label}`, icon: "arrow-right", onSelect: () => move(row, c.key) }))
273
- : [];
274
- const items = [...(actionsOf?.(row) ?? []), ...moveTo];
395
+ const items = [...(actionsOf?.(row) ?? []), ...moveItems(row)];
275
396
  return (
276
397
  <div className="flex items-start gap-1">
277
398
  {movable && !ghost ? (
@@ -285,18 +406,89 @@ export function Board({
285
406
  </span>
286
407
  ) : null}
287
408
  <div className="min-w-0 flex-1">{body}</div>
288
- {!ghost ? <Menu items={items} label={`Actions for ${title}`} className="-mr-1 -mt-1 shrink-0" /> : null}
409
+ {!ghost ? <Menu items={items} label={`Actions for ${title}`} size="md" className="-mr-2 -mt-2 -mb-2 shrink-0" /> : null}
410
+ </div>
411
+ );
412
+ }
413
+
414
+ const notice = error ? (
415
+ <Notice tone="danger" onDismiss={() => setError(null)}>
416
+ {error}
417
+ </Notice>
418
+ ) : null;
419
+ const live = (
420
+ <p aria-live="polite" className="sr-only">
421
+ {announce}
422
+ </p>
423
+ );
424
+
425
+ // Stacked: the stages one under another, each a section that folds, the
426
+ // records as compact rows. Nothing drags here — a row moves through its
427
+ // menu ("Move to …"), the same path the keyboard takes on the columns —
428
+ // so a phone scrolls the page, never a board sideways.
429
+ if (stacked) {
430
+ const opens = defaultOpen == null ? null : new Set((Array.isArray(defaultOpen) ? defaultOpen : [defaultOpen]).map(String));
431
+ return (
432
+ <div className={cx("grid gap-3", className)}>
433
+ {notice}
434
+ <div role="region" aria-label={label} className="overflow-hidden rounded-lg border border-border bg-card text-card-foreground">
435
+ {shown.map((col) => {
436
+ const rowsHere = byColumn.get(col.key) ?? [];
437
+ const head = header(col, rowsHere);
438
+ const headingId = `${uid}-${col.key}`;
439
+ return (
440
+ <Collapsible
441
+ key={col.key}
442
+ variant="flush"
443
+ defaultOpen={opens ? opens.has(col.key) : true}
444
+ title={
445
+ <span className="flex min-w-0 items-center gap-2">
446
+ {head.icon}
447
+ <span id={headingId} className="truncate font-semibold">
448
+ {col.label}
449
+ </span>
450
+ </span>
451
+ }
452
+ meta={
453
+ <span className="flex items-center gap-2">
454
+ {head.total}
455
+ {head.count}
456
+ </span>
457
+ }
458
+ >
459
+ <ul aria-labelledby={headingId} className={cx("-mx-4 divide-y divide-border border-t border-border", !onCreate || col.other ? "-mb-4" : "mb-2")}>
460
+ {rowsHere.map((row) => {
461
+ const id = keyOf(row);
462
+ const title = titleOf(row);
463
+ const items = [...(actionsOf?.(row) ?? []), ...moveItems(row)];
464
+ return (
465
+ <li key={id} data-board-card={id} className={cx("flex min-h-11 items-center gap-3 px-4 py-1.5", accent(row, "start"))}>
466
+ <div className="min-w-0 flex-1">
467
+ {titleButton(row, title, "truncate")}
468
+ {metaOf ? <div className="truncate text-xs text-muted-foreground">{metaOf(row)}</div> : null}
469
+ </div>
470
+ {renderDetails ? (
471
+ <div className="flex shrink-0 items-center gap-2">{renderDetails(row, { column: columnOf(row), layout: "stacked" })}</div>
472
+ ) : null}
473
+ <Menu items={items} label={`Actions for ${title}`} size="md" className="-mr-2 shrink-0" />
474
+ </li>
475
+ );
476
+ })}
477
+ {rowsHere.length === 0 ? <li className="px-4 py-3 text-xs text-muted-foreground">{emptyLabel}</li> : null}
478
+ </ul>
479
+ {adder(col, headingId, "-mx-2")}
480
+ </Collapsible>
481
+ );
482
+ })}
483
+ </div>
484
+ {live}
289
485
  </div>
290
486
  );
291
487
  }
292
488
 
293
489
  return (
294
490
  <div className={cx("grid gap-3", className)}>
295
- {error ? (
296
- <Notice tone="danger" onDismiss={() => setError(null)}>
297
- {error}
298
- </Notice>
299
- ) : null}
491
+ {notice}
300
492
  <div
301
493
  ref={boardRef}
302
494
  role="region"
@@ -306,8 +498,7 @@ export function Board({
306
498
  >
307
499
  {shown.map((col) => {
308
500
  const cards = byColumn.get(col.key) ?? [];
309
- const limit = limits?.[col.key];
310
- const over = typeof limit === "number" && cards.length > limit;
501
+ const head = header(col, cards);
311
502
  const target = drag && drag.over === col.key && !col.other && columnOf(drag.row) !== col.key;
312
503
  const headingId = `${uid}-${col.key}`;
313
504
  return (
@@ -320,17 +511,13 @@ export function Board({
320
511
  target && "bg-accent ring-2 ring-ring",
321
512
  )}
322
513
  >
323
- <header className="flex min-h-11 items-center justify-between gap-2 px-3">
324
- <h3 id={headingId} className="truncate text-sm font-semibold">
514
+ <header className="flex min-h-11 items-center gap-2 px-3">
515
+ {head.icon}
516
+ <h3 id={headingId} className="min-w-0 flex-1 truncate text-sm font-semibold">
325
517
  {col.label}
326
518
  </h3>
327
- <span
328
- data-nums
329
- className={cx("shrink-0 font-mono text-xs", over ? "font-semibold text-warning" : "text-muted-foreground")}
330
- title={typeof limit === "number" ? `${cards.length} of a limit of ${limit}` : undefined}
331
- >
332
- {typeof limit === "number" ? `${cards.length}/${limit}` : cards.length}
333
- </span>
519
+ {head.total}
520
+ {head.count}
334
521
  </header>
335
522
  <ul className="flex min-h-16 flex-1 flex-col gap-2 overflow-y-auto px-2 pb-2">
336
523
  {cards.map((row) => {
@@ -352,6 +539,7 @@ export function Board({
352
539
  }}
353
540
  className={cx(
354
541
  "rounded-md border border-border bg-card p-3 text-card-foreground shadow-sm",
542
+ accent(row),
355
543
  movable && "sm:cursor-grab",
356
544
  lifted && "opacity-40",
357
545
  )}
@@ -364,64 +552,20 @@ export function Board({
364
552
  <li className="rounded-md border border-dashed border-border p-3 text-xs text-muted-foreground">{emptyLabel}</li>
365
553
  ) : null}
366
554
  </ul>
367
- {onCreate && !col.other ? (
368
- adding === col.key ? (
369
- <form onSubmit={(e) => create(e, col.key)} className="px-2 pb-2">
370
- <label htmlFor={`${headingId}-new`} className="sr-only">
371
- New in {col.label}
372
- </label>
373
- <Input
374
- id={`${headingId}-new`}
375
- autoFocus
376
- value={draft}
377
- disabled={busy}
378
- placeholder={createPlaceholder}
379
- onChange={(e) => setDraft(e.target.value)}
380
- onKeyDown={(e) => {
381
- // Enter adds here, not through the form's implicit
382
- // submit: a synthetic Enter (an agent testing the
383
- // app) has no keypress to submit with. Never while
384
- // an input method is composing a word.
385
- if (e.key === "Enter" && !e.nativeEvent.isComposing) create(e, col.key);
386
- else if (e.key === "Escape") {
387
- setAdding(null);
388
- setDraft("");
389
- }
390
- }}
391
- onBlur={() => {
392
- if (!draft.trim()) setAdding(null);
393
- }}
394
- />
395
- </form>
396
- ) : (
397
- <div className="px-2 pb-2">
398
- <Button
399
- variant="quiet"
400
- size="sm"
401
- icon="plus"
402
- className="w-full justify-start"
403
- onClick={() => {
404
- setAdding(col.key);
405
- setDraft("");
406
- }}
407
- >
408
- {addLabel}
409
- </Button>
410
- </div>
411
- )
412
- ) : null}
555
+ {adder(col, headingId)}
413
556
  </section>
414
557
  );
415
558
  })}
416
559
  </div>
417
- <p aria-live="polite" className="sr-only">
418
- {announce}
419
- </p>
560
+ {live}
420
561
  {drag && portal
421
562
  ? createPortal(
422
563
  <div
423
564
  aria-hidden="true"
424
- className="pointer-events-none fixed z-50 rotate-2 rounded-md border border-border bg-card p-3 text-card-foreground shadow-lg"
565
+ className={cx(
566
+ "pointer-events-none fixed z-50 rotate-2 rounded-md border border-border bg-card p-3 text-card-foreground shadow-lg",
567
+ accent(drag.row),
568
+ )}
425
569
  style={{ left: drag.x - drag.offsetX, top: drag.y - drag.offsetY, width: drag.width }}
426
570
  >
427
571
  {card(drag.row, { ghost: true })}