makersclaw 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) 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/install.mjs +18 -0
  430. package/src/shadcn.mjs +8 -0
  431. package/templates/next/files/README.md +145 -11
  432. package/templates/next/files/app/globals.css +55 -4
  433. package/templates/next/files/check/run.mjs +3 -3
  434. package/templates/next/files/components/ui/avatar.jsx +141 -0
  435. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  436. package/templates/next/files/components/ui/button-group.jsx +70 -0
  437. package/templates/next/files/components/ui/button.jsx +132 -12
  438. package/templates/next/files/components/ui/calendar.jsx +609 -0
  439. package/templates/next/files/components/ui/carousel.jsx +281 -0
  440. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  441. package/templates/next/files/components/ui/combobox.jsx +608 -0
  442. package/templates/next/files/components/ui/command.jsx +577 -0
  443. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  444. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  445. package/templates/next/files/components/ui/distribution.jsx +117 -0
  446. package/templates/next/files/components/ui/feedback.jsx +143 -0
  447. package/templates/next/files/components/ui/field.jsx +115 -3
  448. package/templates/next/files/components/ui/file-input.jsx +234 -0
  449. package/templates/next/files/components/ui/icon.jsx +130 -8
  450. package/templates/next/files/components/ui/image.jsx +143 -0
  451. package/templates/next/files/components/ui/index.js +47 -2
  452. package/templates/next/files/components/ui/input-group.jsx +213 -0
  453. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  454. package/templates/next/files/components/ui/item.jsx +206 -0
  455. package/templates/next/files/components/ui/menu.jsx +454 -82
  456. package/templates/next/files/components/ui/notice.jsx +126 -14
  457. package/templates/next/files/components/ui/pagination.jsx +156 -0
  458. package/templates/next/files/components/ui/popover.jsx +284 -0
  459. package/templates/next/files/components/ui/radio.jsx +193 -0
  460. package/templates/next/files/components/ui/rating.jsx +131 -0
  461. package/templates/next/files/components/ui/resizable.jsx +338 -0
  462. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  463. package/templates/next/files/components/ui/separator.jsx +119 -0
  464. package/templates/next/files/components/ui/sheet.jsx +96 -11
  465. package/templates/next/files/components/ui/slider.jsx +174 -0
  466. package/templates/next/files/components/ui/stat.jsx +574 -0
  467. package/templates/next/files/components/ui/steps.jsx +338 -0
  468. package/templates/next/files/components/ui/swatch.jsx +33 -0
  469. package/templates/next/files/components/ui/table.jsx +130 -0
  470. package/templates/next/files/components/ui/toast.jsx +440 -0
  471. package/templates/next/files/components/ui/toggle.jsx +195 -0
  472. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  473. package/templates/next/template.json +264 -8
@@ -0,0 +1,597 @@
1
+ "use client";
2
+
3
+ import { useEffect, useId, useState } from "react";
4
+ import {
5
+ Button,
6
+ Card,
7
+ Checkbox,
8
+ Empty,
9
+ Field,
10
+ Icon,
11
+ IconButton,
12
+ Image,
13
+ Input,
14
+ Notice,
15
+ Select,
16
+ Separator,
17
+ Skeleton,
18
+ cx,
19
+ } from "../../ui";
20
+ import { asAmount, countOf, lineTotal, money, subtotalOf } from "./money";
21
+
22
+ // The cart and its checkout step. Line items come in as props; every
23
+ // change goes out through a callback that returns { ok } and the row says
24
+ // when it failed. The checkout step collects contact and delivery details
25
+ // only — never a card: payment is Paddle's, and the step ends at `onPay`.
26
+
27
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
28
+ const ADDRESS_KEYS = ["address", "city", "postal", "country"];
29
+
30
+ async function attempt(fn) {
31
+ try {
32
+ const res = await fn();
33
+ return res && res.ok === false ? res.error || "That did not save." : null;
34
+ } catch (e) {
35
+ return e?.message || "That did not save.";
36
+ }
37
+ }
38
+
39
+ function quantityOptions(item) {
40
+ const max = Math.max(Number(item.maxQuantity) || 10, Number(item.quantity) || 1);
41
+ return Array.from({ length: max }, (_, i) => ({ value: String(i + 1), label: String(i + 1) }));
42
+ }
43
+
44
+ // Server and browser may differ in locale, time zone and even the day:
45
+ // the first render uses fixed ones (en-US, UTC) so it matches the server's
46
+ // HTML, then the reader's own take over.
47
+ function useHydrated() {
48
+ const [hydrated, setHydrated] = useState(false);
49
+ useEffect(() => setHydrated(true), []);
50
+ return hydrated;
51
+ }
52
+
53
+ /* ---------- one line item ---------- */
54
+
55
+ function LineItem({ item, currency: currencyProp, locale, editable, onQuantityChange, onRemove }) {
56
+ const currency = item.currency ?? currencyProp;
57
+ const compareAt = Number(item.compareAt) > Number(item.price) ? Number(item.compareAt) : null;
58
+ const [busy, setBusy] = useState(null);
59
+ const [error, setError] = useState(null);
60
+ const qtyId = useId();
61
+
62
+ async function change(next) {
63
+ if (!onQuantityChange) return;
64
+ setBusy("qty");
65
+ setError(null);
66
+ setError(await attempt(() => onQuantityChange(item, next)));
67
+ setBusy(null);
68
+ }
69
+ async function remove() {
70
+ setBusy("remove");
71
+ setError(null);
72
+ const failed = await attempt(() => onRemove(item));
73
+ if (failed) setError(failed);
74
+ setBusy(null);
75
+ }
76
+
77
+ return (
78
+ <li className="p-4">
79
+ <div className="flex gap-3 sm:gap-4">
80
+ <Image src={item.image} alt="" ratio="square" fit="cover" className="size-20 shrink-0 sm:size-24" />
81
+ <div className="flex min-w-0 flex-1 flex-col gap-2">
82
+ <div className="flex items-start justify-between gap-2">
83
+ <div className="min-w-0">
84
+ {item.href ? (
85
+ <Button variant="link" href={item.href} className="font-medium leading-snug">
86
+ {item.name}
87
+ </Button>
88
+ ) : (
89
+ <p className="font-medium leading-snug">{item.name}</p>
90
+ )}
91
+ {item.variant ? <p className="mt-0.5 text-sm text-muted-foreground">{item.variant}</p> : null}
92
+ </div>
93
+ {editable && onRemove ? (
94
+ <IconButton
95
+ icon="x"
96
+ label={`Remove ${item.name}`}
97
+ size="sm"
98
+ onClick={remove}
99
+ disabled={Boolean(busy)}
100
+ className="-mr-2 -mt-1"
101
+ />
102
+ ) : null}
103
+ </div>
104
+ <div className="mt-auto flex flex-wrap items-center justify-between gap-2">
105
+ {editable && onQuantityChange ? (
106
+ <div className="flex items-center gap-2">
107
+ <label htmlFor={qtyId} className="text-sm text-muted-foreground">
108
+ Qty
109
+ </label>
110
+ <Select
111
+ id={qtyId}
112
+ value={String(item.quantity)}
113
+ onChange={(e) => change(Number(e.target.value))}
114
+ options={quantityOptions(item)}
115
+ disabled={Boolean(busy)}
116
+ className="w-20"
117
+ />
118
+ </div>
119
+ ) : (
120
+ <p className="text-sm text-muted-foreground">Qty {item.quantity}</p>
121
+ )}
122
+ <div className="text-right">
123
+ <p className="font-semibold tabular-nums">
124
+ {compareAt ? (
125
+ <>
126
+ <s className="mr-1.5 text-sm font-normal text-muted-foreground">
127
+ <span className="sr-only">Was </span>
128
+ {money(compareAt * (Number(item.quantity) || 0), currency, locale)}
129
+ </s>
130
+ <span className="sr-only">now </span>
131
+ </>
132
+ ) : null}
133
+ {money(lineTotal(item), currency, locale)}
134
+ </p>
135
+ {Number(item.quantity) > 1 ? (
136
+ <p className="text-xs text-muted-foreground tabular-nums">{money(item.price, currency, locale)} each</p>
137
+ ) : null}
138
+ </div>
139
+ </div>
140
+ {error ? (
141
+ <p role="alert" className="text-xs text-destructive">
142
+ {error}
143
+ </p>
144
+ ) : null}
145
+ </div>
146
+ </div>
147
+ </li>
148
+ );
149
+ }
150
+
151
+ /* ---------- the totals ---------- */
152
+
153
+ function SummaryRow({ label, value, strong, tone }) {
154
+ return (
155
+ <div
156
+ className={cx(
157
+ "flex items-baseline justify-between gap-3",
158
+ strong ? "mt-1.5 border-t border-border pt-3 text-base" : "text-sm",
159
+ )}
160
+ >
161
+ <dt className={strong ? "font-semibold" : "text-muted-foreground"}>{label}</dt>
162
+ <dd
163
+ className={cx(
164
+ "text-right tabular-nums",
165
+ strong ? "text-xl font-semibold" : "font-medium",
166
+ tone === "success" && "text-success",
167
+ )}
168
+ >
169
+ {value}
170
+ </dd>
171
+ </div>
172
+ );
173
+ }
174
+
175
+ function charge(v, currency, locale, freeLabel) {
176
+ if (typeof v === "string") return { value: <span className="font-normal text-muted-foreground">{v}</span> };
177
+ if (v === 0) return { value: freeLabel, tone: "success" };
178
+ return { value: money(v, currency, locale) };
179
+ }
180
+
181
+ function Totals({ items, currency, locale, shipping, tax, discount, onRemoveCode }) {
182
+ const subtotal = subtotalOf(items);
183
+ const off = discount ? Math.abs(asAmount(discount.amount)) : 0;
184
+ const total = Math.max(0, subtotal - off + asAmount(shipping) + asAmount(tax));
185
+ const ship = shipping !== undefined ? charge(shipping, currency, locale, "Free") : null;
186
+ const taxRow = tax !== undefined ? charge(tax, currency, locale, money(0, currency, locale)) : null;
187
+ return (
188
+ <dl className="grid gap-2.5">
189
+ <SummaryRow label="Subtotal" value={money(subtotal, currency, locale)} />
190
+ {discount ? (
191
+ <div className="flex items-center justify-between gap-3 text-sm">
192
+ <dt className="flex min-w-0 items-center gap-1 text-muted-foreground">
193
+ <Icon name="tag" size={14} className="shrink-0" />
194
+ <span className="truncate">{discount.label || `Code ${discount.code}`}</span>
195
+ {onRemoveCode ? (
196
+ <IconButton icon="x" size="sm" label={`Remove code ${discount.code ?? ""}`.trim()} onClick={onRemoveCode} className="-my-2" />
197
+ ) : null}
198
+ </dt>
199
+ <dd className="font-medium tabular-nums text-success">−{money(off, currency, locale)}</dd>
200
+ </div>
201
+ ) : null}
202
+ {ship ? <SummaryRow label="Shipping" {...ship} /> : null}
203
+ {taxRow ? <SummaryRow label="Tax" {...taxRow} /> : null}
204
+ <SummaryRow label="Total" value={money(total, currency, locale)} strong />
205
+ </dl>
206
+ );
207
+ }
208
+
209
+ function PromoCode({ onApplyCode }) {
210
+ const [code, setCode] = useState("");
211
+ const [busy, setBusy] = useState(false);
212
+ const [error, setError] = useState(null);
213
+ const id = useId();
214
+ async function apply(e) {
215
+ e.preventDefault();
216
+ const value = code.trim();
217
+ if (!value) return;
218
+ setBusy(true);
219
+ setError(null);
220
+ const failed = await attempt(() => onApplyCode(value));
221
+ setBusy(false);
222
+ if (failed) setError(failed);
223
+ else setCode("");
224
+ }
225
+ return (
226
+ <form onSubmit={apply} className="grid gap-1.5">
227
+ <label htmlFor={id} className="text-sm font-medium">
228
+ Discount code
229
+ </label>
230
+ <div className="flex gap-2">
231
+ <Input
232
+ id={id}
233
+ value={code}
234
+ onChange={(e) => setCode(e.target.value)}
235
+ placeholder="Enter code"
236
+ autoCapitalize="characters"
237
+ invalid={Boolean(error)}
238
+ aria-describedby={error ? `${id}-error` : undefined}
239
+ className="min-w-0 flex-1"
240
+ />
241
+ <Button type="submit" loading={busy} disabled={!code.trim()}>
242
+ Apply
243
+ </Button>
244
+ </div>
245
+ {error ? (
246
+ <p id={`${id}-error`} role="alert" className="text-xs text-destructive">
247
+ {error}
248
+ </p>
249
+ ) : null}
250
+ </form>
251
+ );
252
+ }
253
+
254
+ /* ---------- states ---------- */
255
+
256
+ function Loading({ step }) {
257
+ return (
258
+ <div aria-busy="true" aria-label="Loading the cart" className="grid gap-6 lg:grid-cols-3">
259
+ <Card padding="none" className="lg:col-span-2">
260
+ {[0, 1].map((i) => (
261
+ <div key={i} className="flex gap-4 border-b border-border p-4 last:border-b-0">
262
+ <Skeleton shape="rect" className="size-20 sm:size-24" />
263
+ <div className="grid flex-1 content-start gap-2">
264
+ <Skeleton className="w-1/2" />
265
+ <Skeleton className="w-1/4" />
266
+ </div>
267
+ </div>
268
+ ))}
269
+ </Card>
270
+ <Card title={step === "checkout" ? "Order summary" : "Summary"}>
271
+ <div className="grid gap-3">
272
+ <Skeleton className="w-full" />
273
+ <Skeleton className="w-full" />
274
+ <Skeleton className="w-2/3" />
275
+ </div>
276
+ </Card>
277
+ </div>
278
+ );
279
+ }
280
+
281
+ /* ---------- the checkout step ---------- */
282
+
283
+ function CheckoutForm({ total, requireAddress, terms, defaultDetails, payLabel, payNote, onPay, onBack, backLabel }) {
284
+ const base = useId();
285
+ const [details, setDetails] = useState(() => ({
286
+ email: "",
287
+ name: "",
288
+ address: "",
289
+ city: "",
290
+ postal: "",
291
+ country: "",
292
+ ...defaultDetails,
293
+ }));
294
+ const [agreed, setAgreed] = useState(false);
295
+ const [errors, setErrors] = useState({});
296
+ const [busy, setBusy] = useState(false);
297
+ const [failure, setFailure] = useState(null);
298
+ const set = (key) => (e) => setDetails((d) => ({ ...d, [key]: e.target.value }));
299
+ const id = (k) => `${base}-${k}`;
300
+
301
+ function validate() {
302
+ const next = {};
303
+ if (!EMAIL.test(details.email.trim())) next.email = "Enter an email address like name@company.com.";
304
+ if (requireAddress) {
305
+ if (!details.name.trim()) next.name = "Enter the name to deliver to.";
306
+ for (const k of ADDRESS_KEYS) if (!String(details[k] ?? "").trim()) next[k] = "Required.";
307
+ }
308
+ if (terms && !agreed) next.terms = "Tick this to continue.";
309
+ return next;
310
+ }
311
+
312
+ async function submit(e) {
313
+ e.preventDefault();
314
+ const found = validate();
315
+ setErrors(found);
316
+ setFailure(null);
317
+ if (Object.keys(found).length) {
318
+ const first = Object.keys(found)[0];
319
+ document.getElementById(id(first))?.focus();
320
+ return;
321
+ }
322
+ const out = { email: details.email.trim() };
323
+ if (requireAddress) for (const k of ["name", ...ADDRESS_KEYS]) out[k] = String(details[k]).trim();
324
+ setBusy(true);
325
+ const failed = await attempt(() => onPay(out));
326
+ setBusy(false);
327
+ if (failed) setFailure(failed);
328
+ }
329
+
330
+ const err = (k) => errors[k];
331
+ const inputProps = (k, extra) => ({
332
+ id: id(k),
333
+ value: details[k] ?? "",
334
+ onChange: set(k),
335
+ invalid: Boolean(err(k)),
336
+ "aria-describedby": err(k) ? `${id(k)}-error` : undefined,
337
+ disabled: busy,
338
+ ...extra,
339
+ });
340
+
341
+ return (
342
+ <form onSubmit={submit} noValidate className="grid gap-6">
343
+ <section className="grid gap-4">
344
+ <SectionHead icon="mail" title="Contact" description="Where the receipt and order updates go." />
345
+ <Field id={id("email")} label="Email" error={err("email")} required>
346
+ <Input {...inputProps("email", { type: "email", autoComplete: "email", placeholder: "you@company.com" })} />
347
+ </Field>
348
+ </section>
349
+
350
+ {requireAddress ? (
351
+ <>
352
+ <Separator />
353
+ <section className="grid gap-4">
354
+ <SectionHead icon="truck" title="Delivery" description="Where the order should arrive." />
355
+ <Field id={id("name")} label="Full name" error={err("name")} required>
356
+ <Input {...inputProps("name", { autoComplete: "name" })} />
357
+ </Field>
358
+ <Field id={id("address")} label="Street address" error={err("address")} required>
359
+ <Input {...inputProps("address", { autoComplete: "street-address" })} />
360
+ </Field>
361
+ <div className="grid gap-4 sm:grid-cols-3">
362
+ <Field id={id("city")} label="City" error={err("city")} required>
363
+ <Input {...inputProps("city", { autoComplete: "address-level2" })} />
364
+ </Field>
365
+ <Field id={id("postal")} label="Postal code" error={err("postal")} required>
366
+ <Input {...inputProps("postal", { autoComplete: "postal-code" })} />
367
+ </Field>
368
+ <Field id={id("country")} label="Country" error={err("country")} required>
369
+ <Input {...inputProps("country", { autoComplete: "country-name" })} />
370
+ </Field>
371
+ </div>
372
+ </section>
373
+ </>
374
+ ) : null}
375
+
376
+ <Separator />
377
+
378
+ <section className="grid gap-3">
379
+ {terms ? (
380
+ <div className="grid gap-1">
381
+ <Checkbox
382
+ id={id("terms")}
383
+ checked={agreed}
384
+ onChange={(e) => setAgreed(e.target.checked)}
385
+ label={terms}
386
+ disabled={busy}
387
+ aria-invalid={err("terms") ? true : undefined}
388
+ aria-describedby={err("terms") ? `${id("terms")}-error` : undefined}
389
+ />
390
+ {err("terms") ? (
391
+ <p id={`${id("terms")}-error`} role="alert" className="text-xs text-destructive">
392
+ {err("terms")}
393
+ </p>
394
+ ) : null}
395
+ </div>
396
+ ) : null}
397
+ {failure ? <Notice tone="danger" title="The order did not go through">{failure}</Notice> : null}
398
+ <Button type="submit" variant="primary" icon="lock" loading={busy} className="w-full">
399
+ {payLabel ?? `Continue to payment · ${total}`}
400
+ </Button>
401
+ {payNote ? <p className="text-center text-xs text-muted-foreground">{payNote}</p> : null}
402
+ {onBack ? (
403
+ <Button variant="quiet" icon="arrow-left" onClick={onBack} disabled={busy} className="justify-self-center">
404
+ {backLabel}
405
+ </Button>
406
+ ) : null}
407
+ </section>
408
+ </form>
409
+ );
410
+ }
411
+
412
+ function SectionHead({ icon, title, description }) {
413
+ return (
414
+ <div className="flex items-center gap-3">
415
+ <span className="grid size-9 shrink-0 place-items-center rounded-full bg-primary/10 text-primary">
416
+ <Icon name={icon} size={16} />
417
+ </span>
418
+ <div className="min-w-0">
419
+ <h3 className="font-semibold leading-tight">{title}</h3>
420
+ {description ? <p className="text-sm text-muted-foreground">{description}</p> : null}
421
+ </div>
422
+ </div>
423
+ );
424
+ }
425
+
426
+ /* ---------- the block ---------- */
427
+
428
+ export function Cart({
429
+ items,
430
+ step = "cart",
431
+ currency = "USD",
432
+ locale: localeProp,
433
+ shipping,
434
+ tax,
435
+ discount,
436
+ note,
437
+ loading = false,
438
+ error,
439
+ title,
440
+ onQuantityChange,
441
+ onRemove,
442
+ onApplyCode,
443
+ onRemoveCode,
444
+ onCheckout,
445
+ checkoutLabel = "Checkout",
446
+ onContinueShopping,
447
+ continueHref,
448
+ continueLabel = "Continue shopping",
449
+ emptyTitle = "Your cart is empty",
450
+ emptyBody = "Anything you add shows up here.",
451
+ requireAddress = true,
452
+ terms,
453
+ defaultDetails,
454
+ onPay,
455
+ payLabel,
456
+ payNote = "You pay on the next screen. We never see your card.",
457
+ onBack,
458
+ backLabel = "Back to cart",
459
+ className,
460
+ }) {
461
+ const hydrated = useHydrated();
462
+ const locale = localeProp ?? (hydrated ? undefined : "en-US");
463
+ const [checkingOut, setCheckingOut] = useState(false);
464
+ const [checkoutError, setCheckoutError] = useState(null);
465
+ const checkout = step === "checkout";
466
+ const list = (items ?? []).filter(Boolean);
467
+ const count = countOf(list);
468
+ const heading = title ?? (checkout ? "Checkout" : "Cart");
469
+
470
+ const subtotal = subtotalOf(list);
471
+ const off = discount ? Math.abs(asAmount(discount.amount)) : 0;
472
+ const total = money(Math.max(0, subtotal - off + asAmount(shipping) + asAmount(tax)), currency, locale);
473
+
474
+ async function goToCheckout() {
475
+ if (!onCheckout) return;
476
+ setCheckingOut(true);
477
+ setCheckoutError(null);
478
+ const failed = await attempt(() => onCheckout());
479
+ setCheckingOut(false);
480
+ if (failed) setCheckoutError(failed);
481
+ }
482
+
483
+ const header = (
484
+ <div className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1">
485
+ <h2 className="text-xl font-semibold">{heading}</h2>
486
+ {!loading && list.length ? (
487
+ <p className="text-sm text-muted-foreground">
488
+ {count} {count === 1 ? "item" : "items"}
489
+ </p>
490
+ ) : null}
491
+ </div>
492
+ );
493
+
494
+ let body;
495
+ if (loading) body = <Loading step={step} />;
496
+ else if (!list.length) {
497
+ const action =
498
+ continueHref || onContinueShopping ? (
499
+ <Button variant="primary" href={continueHref} onClick={onContinueShopping}>
500
+ {continueLabel}
501
+ </Button>
502
+ ) : null;
503
+ body = <Empty icon="shopping-cart" title={emptyTitle} body={emptyBody} action={action} className="py-16" />;
504
+ } else if (checkout) {
505
+ body = (
506
+ <div className="grid items-start gap-6 lg:grid-cols-5 lg:gap-10">
507
+ <div className="order-2 lg:order-1 lg:col-span-3">
508
+ <CheckoutForm
509
+ total={total}
510
+ requireAddress={requireAddress}
511
+ terms={terms}
512
+ defaultDetails={defaultDetails}
513
+ payLabel={payLabel}
514
+ payNote={payNote}
515
+ onPay={onPay ?? (async () => ({ ok: true }))}
516
+ onBack={onBack}
517
+ backLabel={backLabel}
518
+ />
519
+ </div>
520
+ <Card title="Order summary" padding="none" className="order-1 lg:sticky lg:top-4 lg:order-2 lg:col-span-2">
521
+ <ul className="divide-y divide-border border-y border-border">
522
+ {list.map((item) => (
523
+ <LineItem key={item.key ?? item.id} item={item} currency={currency} locale={locale} editable={false} />
524
+ ))}
525
+ </ul>
526
+ <div className="p-4">
527
+ <Totals items={list} currency={currency} locale={locale} shipping={shipping} tax={tax} discount={discount} />
528
+ {note ? <SummaryNote note={note} className="mt-4" /> : null}
529
+ </div>
530
+ </Card>
531
+ </div>
532
+ );
533
+ } else {
534
+ body = (
535
+ <div className="grid items-start gap-6 lg:grid-cols-3">
536
+ <Card padding="none" className="lg:col-span-2">
537
+ <ul aria-label="Items in the cart" className="divide-y divide-border">
538
+ {list.map((item) => (
539
+ <LineItem
540
+ key={item.key ?? item.id}
541
+ item={item}
542
+ currency={currency}
543
+ locale={locale}
544
+ editable
545
+ onQuantityChange={onQuantityChange}
546
+ onRemove={onRemove}
547
+ />
548
+ ))}
549
+ </ul>
550
+ </Card>
551
+ <Card title="Summary" className="lg:sticky lg:top-4">
552
+ <div className="grid gap-4">
553
+ <Totals
554
+ items={list}
555
+ currency={currency}
556
+ locale={locale}
557
+ shipping={shipping}
558
+ tax={tax}
559
+ discount={discount}
560
+ onRemoveCode={onRemoveCode}
561
+ />
562
+ {onApplyCode && !discount ? <PromoCode onApplyCode={onApplyCode} /> : null}
563
+ {checkoutError ? <Notice tone="danger">{checkoutError}</Notice> : null}
564
+ {onCheckout ? (
565
+ <Button variant="primary" icon="lock" onClick={goToCheckout} loading={checkingOut} className="w-full">
566
+ {checkoutLabel}
567
+ </Button>
568
+ ) : null}
569
+ {continueHref || onContinueShopping ? (
570
+ <Button variant="quiet" href={continueHref} onClick={onContinueShopping} className="w-full">
571
+ {continueLabel}
572
+ </Button>
573
+ ) : null}
574
+ {note ? <SummaryNote note={note} /> : null}
575
+ </div>
576
+ </Card>
577
+ </div>
578
+ );
579
+ }
580
+
581
+ return (
582
+ <div className={cx("grid gap-4", className)}>
583
+ {header}
584
+ {error ? <Notice tone="danger">{error}</Notice> : null}
585
+ {body}
586
+ </div>
587
+ );
588
+ }
589
+
590
+ function SummaryNote({ note, className }) {
591
+ return (
592
+ <div className={cx("flex items-start gap-2 rounded-md bg-muted p-3 text-sm", className)}>
593
+ <Icon name="truck" size={16} className="mt-0.5 shrink-0 text-muted-foreground" />
594
+ <div className="min-w-0 text-muted-foreground">{note}</div>
595
+ </div>
596
+ );
597
+ }
@@ -0,0 +1,98 @@
1
+ "use client";
2
+
3
+ // The Cart with items in memory — the gallery's and the smoke test's
4
+ // surface. Not installed into apps: `makersclaw add cart` lays index.js,
5
+ // cart.jsx and money.js only.
6
+ import { useState } from "react";
7
+ import { Switch, ToggleGroup } from "../components/ui";
8
+ import { Cart } from "../components/blocks/cart";
9
+
10
+ const photo = (id) => `https://images.unsplash.com/${id}?w=320&h=320&fit=crop&auto=format&q=70`;
11
+
12
+ const START = [
13
+ { id: "li_1", name: "Field jacket", image: photo("photo-1591047139829-d91aecb6caea"), price: 184, quantity: 1, variant: "Olive · M" },
14
+ { id: "li_2", name: "Canvas weekender", image: photo("photo-1553062407-98eeb64c6a62"), price: 129, quantity: 1, variant: "Sand" },
15
+ { id: "li_3", name: "Merino crew socks", image: photo("photo-1586350977771-b3b0abd50c82"), price: 18, quantity: 3, variant: "Charcoal · 3 pack" },
16
+ ];
17
+
18
+ const CODES = { WELCOME10: 0.1, SPRING: 0.15 };
19
+
20
+ const VIEWS = [
21
+ { value: "cart", label: "Cart" },
22
+ { value: "checkout", label: "Checkout" },
23
+ { value: "empty", label: "Empty" },
24
+ { value: "loading", label: "Loading" },
25
+ ];
26
+
27
+ const wait = (ms) => new Promise((r) => setTimeout(r, ms));
28
+
29
+ export default function CartDemo() {
30
+ const [view, setView] = useState("cart");
31
+ const [items, setItems] = useState(START);
32
+ const [discount, setDiscount] = useState(null);
33
+ const [failing, setFailing] = useState(false);
34
+ const [paid, setPaid] = useState(null);
35
+
36
+ const subtotal = items.reduce((s, i) => s + i.price * i.quantity, 0);
37
+ const fail = async () => {
38
+ await wait(400);
39
+ return failing ? { ok: false, error: "The shop did not answer. Try again." } : null;
40
+ };
41
+
42
+ return (
43
+ <div className="grid gap-6">
44
+ <div className="flex flex-wrap items-center justify-between gap-3">
45
+ <ToggleGroup items={VIEWS} value={view} onChange={setView} size="sm" aria-label="Which state to show" />
46
+ <Switch id="cart-fail" checked={failing} onChange={(e) => setFailing(e.target.checked)} label="Make saves fail" />
47
+ </div>
48
+
49
+ {paid ? (
50
+ <p role="status" className="text-sm text-muted-foreground">
51
+ onPay was called for {paid.email}. The app would open Paddle's checkout now.
52
+ </p>
53
+ ) : null}
54
+
55
+ <Cart
56
+ items={view === "empty" ? [] : items}
57
+ loading={view === "loading"}
58
+ step={view === "checkout" ? "checkout" : "cart"}
59
+ shipping={subtotal >= 150 ? 0 : 12}
60
+ tax="Calculated at payment"
61
+ discount={discount ? { code: discount.code, amount: Math.round(subtotal * discount.rate * 100) / 100 } : null}
62
+ note={subtotal >= 150 ? "Free delivery applied. Arrives in 3–5 working days." : "Free delivery on orders over $150."}
63
+ onQuantityChange={async (item, quantity) => {
64
+ const failed = await fail();
65
+ if (failed) return failed;
66
+ setItems((all) => all.map((i) => (i.id === item.id ? { ...i, quantity } : i)));
67
+ return { ok: true };
68
+ }}
69
+ onRemove={async (item) => {
70
+ const failed = await fail();
71
+ if (failed) return failed;
72
+ setItems((all) => all.filter((i) => i.id !== item.id));
73
+ return { ok: true };
74
+ }}
75
+ onApplyCode={async (code) => {
76
+ await wait(400);
77
+ const rate = CODES[code.toUpperCase()];
78
+ if (!rate) return { ok: false, error: `"${code}" is not a code we know. Try WELCOME10.` };
79
+ setDiscount({ code: code.toUpperCase(), rate });
80
+ return { ok: true };
81
+ }}
82
+ onRemoveCode={() => setDiscount(null)}
83
+ onCheckout={() => setView("checkout")}
84
+ onContinueShopping={() => setItems(START)}
85
+ continueLabel={view === "empty" ? "Browse the shop" : "Continue shopping"}
86
+ terms="I agree to the terms of sale and the returns policy"
87
+ defaultDetails={{ email: "maya@northwind.co" }}
88
+ onPay={async (details) => {
89
+ const failed = await fail();
90
+ if (failed) return failed;
91
+ setPaid(details);
92
+ return { ok: true };
93
+ }}
94
+ onBack={() => setView("cart")}
95
+ />
96
+ </div>
97
+ );
98
+ }