makersclaw 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (478) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -1
  3. package/THIRD-PARTY-NOTICES.md +180 -0
  4. package/package.json +15 -8
  5. package/r/annotate.json +62 -0
  6. package/r/approval-request.json +52 -0
  7. package/r/audio-player.json +74 -0
  8. package/r/auth-form.json +55 -0
  9. package/r/board.json +55 -0
  10. package/r/calendar-view.json +105 -0
  11. package/r/cart.json +62 -0
  12. package/r/chart.json +83 -0
  13. package/r/chat.json +95 -0
  14. package/r/code-editor.json +94 -0
  15. package/r/comment-box.json +64 -0
  16. package/r/contact-section.json +53 -0
  17. package/r/core.json +341 -0
  18. package/r/csv-import.json +63 -0
  19. package/r/data-table.json +69 -0
  20. package/r/diagram.json +74 -0
  21. package/r/doc-editor.json +82 -0
  22. package/r/doc-page.json +61 -0
  23. package/r/email-render.json +73 -0
  24. package/r/faq.json +50 -0
  25. package/r/file-upload.json +54 -0
  26. package/r/flow-canvas.json +93 -0
  27. package/r/footer.json +52 -0
  28. package/r/gantt.json +70 -0
  29. package/r/job-panel.json +56 -0
  30. package/r/json-editor.json +66 -0
  31. package/r/map.json +89 -0
  32. package/r/menubar.json +52 -0
  33. package/r/mind-map.json +67 -0
  34. package/r/navigation-menu.json +52 -0
  35. package/r/order-detail.json +54 -0
  36. package/r/org-chart.json +66 -0
  37. package/r/page-builder.json +105 -0
  38. package/r/payment-methods.json +51 -0
  39. package/r/pdf-document.json +79 -0
  40. package/r/pdf-viewer.json +88 -0
  41. package/r/product-detail.json +76 -0
  42. package/r/product-grid.json +65 -0
  43. package/r/record-form.json +67 -0
  44. package/r/record-notes.json +55 -0
  45. package/r/registry.json +3612 -0
  46. package/r/search-dialog.json +51 -0
  47. package/r/settings-list.json +66 -0
  48. package/r/setup-checklist.json +51 -0
  49. package/r/share-dialog.json +52 -0
  50. package/r/sidebar.json +69 -0
  51. package/r/signature-pad.json +72 -0
  52. package/r/sketch-canvas.json +99 -0
  53. package/r/spreadsheet.json +90 -0
  54. package/r/stat-cards.json +66 -0
  55. package/r/task-list.json +63 -0
  56. package/r/task-model.json +98 -0
  57. package/r/testimonials.json +52 -0
  58. package/r/transaction-list.json +53 -0
  59. package/r/whiteboard.json +66 -0
  60. package/registry/blocks/annotate/README.md +179 -0
  61. package/registry/blocks/annotate/annotate-data.js +250 -0
  62. package/registry/blocks/annotate/annotate.jsx +646 -0
  63. package/registry/blocks/annotate/block.json +10 -0
  64. package/registry/blocks/annotate/demo.jsx +135 -0
  65. package/registry/blocks/annotate/index.js +15 -0
  66. package/registry/blocks/approval-request/README.md +116 -0
  67. package/registry/blocks/approval-request/approval-request.jsx +386 -0
  68. package/registry/blocks/approval-request/block.json +10 -0
  69. package/registry/blocks/approval-request/demo.jsx +127 -0
  70. package/registry/blocks/approval-request/index.js +4 -0
  71. package/registry/blocks/audio-player/README.md +167 -0
  72. package/registry/blocks/audio-player/audio-player.jsx +623 -0
  73. package/registry/blocks/audio-player/block.json +14 -0
  74. package/registry/blocks/audio-player/colors.js +109 -0
  75. package/registry/blocks/audio-player/demo.jsx +209 -0
  76. package/registry/blocks/audio-player/index.js +6 -0
  77. package/registry/blocks/audio-player/time.js +67 -0
  78. package/registry/blocks/audio-player/wavesurfer.js +9 -0
  79. package/registry/blocks/auth-form/README.md +126 -0
  80. package/registry/blocks/auth-form/auth-form.jsx +568 -0
  81. package/registry/blocks/auth-form/block.json +10 -0
  82. package/registry/blocks/auth-form/demo.jsx +131 -0
  83. package/registry/blocks/auth-form/index.js +3 -0
  84. package/registry/blocks/board/README.md +64 -13
  85. package/registry/blocks/board/block.json +2 -2
  86. package/registry/blocks/board/board.jsx +237 -94
  87. package/registry/blocks/board/demo.jsx +103 -24
  88. package/registry/blocks/calendar-view/README.md +180 -0
  89. package/registry/blocks/calendar-view/agenda.jsx +147 -0
  90. package/registry/blocks/calendar-view/block.json +76 -0
  91. package/registry/blocks/calendar-view/calendar-model.js +442 -0
  92. package/registry/blocks/calendar-view/calendar.jsx +627 -0
  93. package/registry/blocks/calendar-view/demo.jsx +195 -0
  94. package/registry/blocks/calendar-view/draft.jsx +49 -0
  95. package/registry/blocks/calendar-view/index.js +39 -0
  96. package/registry/blocks/calendar-view/month.jsx +346 -0
  97. package/registry/blocks/calendar-view/paint.js +69 -0
  98. package/registry/blocks/calendar-view/time-grid.jsx +527 -0
  99. package/registry/blocks/calendar-view/tray.jsx +87 -0
  100. package/registry/blocks/cart/README.md +146 -0
  101. package/registry/blocks/cart/block.json +10 -0
  102. package/registry/blocks/cart/cart.jsx +597 -0
  103. package/registry/blocks/cart/demo.jsx +98 -0
  104. package/registry/blocks/cart/index.js +4 -0
  105. package/registry/blocks/cart/money.js +28 -0
  106. package/registry/blocks/chart/README.md +316 -0
  107. package/registry/blocks/chart/block.json +10 -0
  108. package/registry/blocks/chart/cartesian.jsx +642 -0
  109. package/registry/blocks/chart/core.jsx +262 -0
  110. package/registry/blocks/chart/demo.jsx +357 -0
  111. package/registry/blocks/chart/heatmap.jsx +336 -0
  112. package/registry/blocks/chart/index.js +8 -0
  113. package/registry/blocks/chart/pie.jsx +245 -0
  114. package/registry/blocks/chart/sparkline.jsx +88 -0
  115. package/registry/blocks/chat/README.md +273 -0
  116. package/registry/blocks/chat/attachment.jsx +95 -0
  117. package/registry/blocks/chat/block.json +10 -0
  118. package/registry/blocks/chat/chat.jsx +132 -0
  119. package/registry/blocks/chat/composer.jsx +364 -0
  120. package/registry/blocks/chat/demo.jsx +578 -0
  121. package/registry/blocks/chat/header.jsx +34 -0
  122. package/registry/blocks/chat/index.js +9 -0
  123. package/registry/blocks/chat/message.jsx +450 -0
  124. package/registry/blocks/chat/scroller.jsx +247 -0
  125. package/registry/blocks/chat/text.jsx +104 -0
  126. package/registry/blocks/code-editor/README.md +210 -0
  127. package/registry/blocks/code-editor/block.json +22 -0
  128. package/registry/blocks/code-editor/code-editor.jsx +534 -0
  129. package/registry/blocks/code-editor/codemirror.js +38 -0
  130. package/registry/blocks/code-editor/demo.jsx +205 -0
  131. package/registry/blocks/code-editor/index.js +8 -0
  132. package/registry/blocks/code-editor/json.js +317 -0
  133. package/registry/blocks/code-editor/sql.js +136 -0
  134. package/registry/blocks/code-editor/text.js +101 -0
  135. package/registry/blocks/code-editor/theme.js +186 -0
  136. package/registry/blocks/comment-box/README.md +123 -0
  137. package/registry/blocks/comment-box/block.json +10 -0
  138. package/registry/blocks/comment-box/comment-body.jsx +217 -0
  139. package/registry/blocks/comment-box/comment-box.jsx +198 -0
  140. package/registry/blocks/comment-box/comment-time.jsx +77 -0
  141. package/registry/blocks/comment-box/demo.jsx +141 -0
  142. package/registry/blocks/comment-box/index.js +8 -0
  143. package/registry/blocks/contact-section/README.md +152 -0
  144. package/registry/blocks/contact-section/block.json +11 -0
  145. package/registry/blocks/contact-section/contact-section.jsx +509 -0
  146. package/registry/blocks/contact-section/demo.jsx +93 -0
  147. package/registry/blocks/contact-section/index.js +4 -0
  148. package/registry/blocks/csv-import/README.md +133 -0
  149. package/registry/blocks/csv-import/block.json +13 -0
  150. package/registry/blocks/csv-import/csv-import.jsx +479 -0
  151. package/registry/blocks/csv-import/demo.jsx +106 -0
  152. package/registry/blocks/csv-import/import.js +200 -0
  153. package/registry/blocks/csv-import/index.js +7 -0
  154. package/registry/blocks/data-table/README.md +386 -0
  155. package/registry/blocks/data-table/block.json +10 -0
  156. package/registry/blocks/data-table/data-table.jsx +1164 -0
  157. package/registry/blocks/data-table/demo.jsx +588 -0
  158. package/registry/blocks/data-table/index.js +5 -0
  159. package/registry/blocks/data-table/model.js +169 -0
  160. package/registry/blocks/diagram/README.md +108 -0
  161. package/registry/blocks/diagram/block.json +13 -0
  162. package/registry/blocks/diagram/demo.jsx +113 -0
  163. package/registry/blocks/diagram/diagram.jsx +481 -0
  164. package/registry/blocks/diagram/index.js +7 -0
  165. package/registry/blocks/diagram/mermaid.js +52 -0
  166. package/registry/blocks/diagram/palette.js +313 -0
  167. package/registry/blocks/diagram/source.js +98 -0
  168. package/registry/blocks/doc-editor/README.md +215 -0
  169. package/registry/blocks/doc-editor/block.json +15 -0
  170. package/registry/blocks/doc-editor/demo.jsx +225 -0
  171. package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
  172. package/registry/blocks/doc-editor/doc.js +309 -0
  173. package/registry/blocks/doc-editor/index.js +7 -0
  174. package/registry/blocks/doc-editor/schema.jsx +56 -0
  175. package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
  176. package/registry/blocks/doc-editor/theme.js +82 -0
  177. package/registry/blocks/doc-page/README.md +119 -0
  178. package/registry/blocks/doc-page/autosave.js +104 -0
  179. package/registry/blocks/doc-page/block.json +10 -0
  180. package/registry/blocks/doc-page/demo.jsx +137 -0
  181. package/registry/blocks/doc-page/doc-page.jsx +276 -0
  182. package/registry/blocks/doc-page/index.js +4 -0
  183. package/registry/blocks/email-render/README.md +151 -0
  184. package/registry/blocks/email-render/block.json +14 -0
  185. package/registry/blocks/email-render/demo.jsx +153 -0
  186. package/registry/blocks/email-render/doc-email.jsx +210 -0
  187. package/registry/blocks/email-render/email.jsx +221 -0
  188. package/registry/blocks/email-render/index.js +10 -0
  189. package/registry/blocks/email-render/render.js +50 -0
  190. package/registry/blocks/email-render/theme.js +215 -0
  191. package/registry/blocks/faq/README.md +101 -0
  192. package/registry/blocks/faq/block.json +11 -0
  193. package/registry/blocks/faq/demo.jsx +89 -0
  194. package/registry/blocks/faq/faq.jsx +220 -0
  195. package/registry/blocks/faq/index.js +4 -0
  196. package/registry/blocks/file-upload/README.md +138 -0
  197. package/registry/blocks/file-upload/block.json +10 -0
  198. package/registry/blocks/file-upload/demo.jsx +204 -0
  199. package/registry/blocks/file-upload/file-upload.jsx +635 -0
  200. package/registry/blocks/file-upload/index.js +4 -0
  201. package/registry/blocks/flow-canvas/README.md +420 -0
  202. package/registry/blocks/flow-canvas/block.json +13 -0
  203. package/registry/blocks/flow-canvas/board.js +819 -0
  204. package/registry/blocks/flow-canvas/chrome.jsx +649 -0
  205. package/registry/blocks/flow-canvas/context.jsx +35 -0
  206. package/registry/blocks/flow-canvas/demo.jsx +249 -0
  207. package/registry/blocks/flow-canvas/edges.jsx +107 -0
  208. package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
  209. package/registry/blocks/flow-canvas/index.js +41 -0
  210. package/registry/blocks/flow-canvas/nodes.jsx +392 -0
  211. package/registry/blocks/flow-canvas/theme.js +174 -0
  212. package/registry/blocks/footer/README.md +133 -0
  213. package/registry/blocks/footer/block.json +11 -0
  214. package/registry/blocks/footer/demo.jsx +119 -0
  215. package/registry/blocks/footer/footer.jsx +406 -0
  216. package/registry/blocks/footer/index.js +4 -0
  217. package/registry/blocks/gantt/README.md +220 -0
  218. package/registry/blocks/gantt/block.json +10 -0
  219. package/registry/blocks/gantt/demo.jsx +148 -0
  220. package/registry/blocks/gantt/gantt.jsx +923 -0
  221. package/registry/blocks/gantt/index.js +7 -0
  222. package/registry/blocks/gantt/rows.jsx +468 -0
  223. package/registry/blocks/gantt/schedule.js +278 -0
  224. package/registry/blocks/job-panel/README.md +86 -2
  225. package/registry/blocks/job-panel/block.json +3 -3
  226. package/registry/blocks/job-panel/demo.jsx +230 -3
  227. package/registry/blocks/job-panel/job-panel.jsx +169 -3
  228. package/registry/blocks/json-editor/README.md +133 -0
  229. package/registry/blocks/json-editor/block.json +10 -0
  230. package/registry/blocks/json-editor/demo.jsx +92 -0
  231. package/registry/blocks/json-editor/index.js +7 -0
  232. package/registry/blocks/json-editor/json-editor.jsx +305 -0
  233. package/registry/blocks/json-editor/json-tree.jsx +393 -0
  234. package/registry/blocks/json-editor/tree.js +225 -0
  235. package/registry/blocks/map/README.md +221 -0
  236. package/registry/blocks/map/block.json +14 -0
  237. package/registry/blocks/map/demo.jsx +201 -0
  238. package/registry/blocks/map/geo.js +198 -0
  239. package/registry/blocks/map/index.js +8 -0
  240. package/registry/blocks/map/list.jsx +128 -0
  241. package/registry/blocks/map/map-view.jsx +715 -0
  242. package/registry/blocks/map/maplibre.js +30 -0
  243. package/registry/blocks/map/marks.jsx +146 -0
  244. package/registry/blocks/map/theme.js +142 -0
  245. package/registry/blocks/menubar/README.md +109 -0
  246. package/registry/blocks/menubar/block.json +10 -0
  247. package/registry/blocks/menubar/demo.jsx +128 -0
  248. package/registry/blocks/menubar/index.js +4 -0
  249. package/registry/blocks/menubar/menubar.jsx +199 -0
  250. package/registry/blocks/mind-map/README.md +206 -0
  251. package/registry/blocks/mind-map/block.json +10 -0
  252. package/registry/blocks/mind-map/demo.jsx +103 -0
  253. package/registry/blocks/mind-map/index.js +31 -0
  254. package/registry/blocks/mind-map/mind-map.jsx +1125 -0
  255. package/registry/blocks/mind-map/topic.jsx +143 -0
  256. package/registry/blocks/mind-map/tree.js +645 -0
  257. package/registry/blocks/navigation-menu/README.md +124 -0
  258. package/registry/blocks/navigation-menu/block.json +10 -0
  259. package/registry/blocks/navigation-menu/demo.jsx +84 -0
  260. package/registry/blocks/navigation-menu/index.js +4 -0
  261. package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
  262. package/registry/blocks/order-detail/README.md +109 -0
  263. package/registry/blocks/order-detail/block.json +10 -0
  264. package/registry/blocks/order-detail/demo.jsx +88 -0
  265. package/registry/blocks/order-detail/index.js +4 -0
  266. package/registry/blocks/order-detail/order-detail.jsx +354 -0
  267. package/registry/blocks/org-chart/README.md +145 -0
  268. package/registry/blocks/org-chart/block.json +10 -0
  269. package/registry/blocks/org-chart/demo.jsx +94 -0
  270. package/registry/blocks/org-chart/index.js +7 -0
  271. package/registry/blocks/org-chart/org-chart.jsx +631 -0
  272. package/registry/blocks/org-chart/org.js +245 -0
  273. package/registry/blocks/org-chart/person.jsx +96 -0
  274. package/registry/blocks/page-builder/README.md +257 -0
  275. package/registry/blocks/page-builder/block.json +14 -0
  276. package/registry/blocks/page-builder/demo.jsx +145 -0
  277. package/registry/blocks/page-builder/grapes.js +18 -0
  278. package/registry/blocks/page-builder/index.js +11 -0
  279. package/registry/blocks/page-builder/page-builder.jsx +704 -0
  280. package/registry/blocks/page-builder/page-view.jsx +33 -0
  281. package/registry/blocks/page-builder/page.js +118 -0
  282. package/registry/blocks/page-builder/panels.jsx +588 -0
  283. package/registry/blocks/page-builder/sections.js +209 -0
  284. package/registry/blocks/page-builder/theme.js +87 -0
  285. package/registry/blocks/page-builder/thumbs.jsx +189 -0
  286. package/registry/blocks/page-builder/tokens.js +329 -0
  287. package/registry/blocks/payment-methods/README.md +104 -0
  288. package/registry/blocks/payment-methods/block.json +10 -0
  289. package/registry/blocks/payment-methods/demo.jsx +71 -0
  290. package/registry/blocks/payment-methods/index.js +4 -0
  291. package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
  292. package/registry/blocks/pdf-document/README.md +213 -0
  293. package/registry/blocks/pdf-document/block.json +13 -0
  294. package/registry/blocks/pdf-document/demo.jsx +136 -0
  295. package/registry/blocks/pdf-document/index.js +33 -0
  296. package/registry/blocks/pdf-document/money.js +83 -0
  297. package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
  298. package/registry/blocks/pdf-document/primitives.jsx +271 -0
  299. package/registry/blocks/pdf-document/quote.jsx +179 -0
  300. package/registry/blocks/pdf-document/theme.js +193 -0
  301. package/registry/blocks/pdf-viewer/README.md +191 -0
  302. package/registry/blocks/pdf-viewer/block.json +14 -0
  303. package/registry/blocks/pdf-viewer/demo.jsx +252 -0
  304. package/registry/blocks/pdf-viewer/helpers.js +270 -0
  305. package/registry/blocks/pdf-viewer/index.js +8 -0
  306. package/registry/blocks/pdf-viewer/notes.jsx +195 -0
  307. package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
  308. package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
  309. package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
  310. package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
  311. package/registry/blocks/product-detail/README.md +217 -0
  312. package/registry/blocks/product-detail/block.json +10 -0
  313. package/registry/blocks/product-detail/demo.jsx +233 -0
  314. package/registry/blocks/product-detail/index.js +7 -0
  315. package/registry/blocks/product-detail/price.jsx +115 -0
  316. package/registry/blocks/product-detail/product-detail.jsx +348 -0
  317. package/registry/blocks/product-detail/product-media.jsx +102 -0
  318. package/registry/blocks/product-detail/product-options.jsx +144 -0
  319. package/registry/blocks/product-grid/README.md +162 -0
  320. package/registry/blocks/product-grid/block.json +10 -0
  321. package/registry/blocks/product-grid/demo.jsx +255 -0
  322. package/registry/blocks/product-grid/index.js +5 -0
  323. package/registry/blocks/product-grid/product-card.jsx +232 -0
  324. package/registry/blocks/product-grid/product-grid.jsx +235 -0
  325. package/registry/blocks/record-form/README.md +196 -0
  326. package/registry/blocks/record-form/block.json +10 -0
  327. package/registry/blocks/record-form/demo.jsx +525 -0
  328. package/registry/blocks/record-form/index.js +4 -0
  329. package/registry/blocks/record-form/record-fields.jsx +457 -0
  330. package/registry/blocks/record-form/record-form.jsx +415 -0
  331. package/registry/blocks/record-form/rules.js +81 -0
  332. package/registry/blocks/record-notes/README.md +139 -0
  333. package/registry/blocks/record-notes/block.json +10 -0
  334. package/registry/blocks/record-notes/demo.jsx +179 -0
  335. package/registry/blocks/record-notes/index.js +4 -0
  336. package/registry/blocks/record-notes/record-notes.jsx +266 -0
  337. package/registry/blocks/search-dialog/README.md +108 -0
  338. package/registry/blocks/search-dialog/block.json +10 -0
  339. package/registry/blocks/search-dialog/demo.jsx +116 -0
  340. package/registry/blocks/search-dialog/index.js +3 -0
  341. package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
  342. package/registry/blocks/settings-list/README.md +171 -0
  343. package/registry/blocks/settings-list/block.json +10 -0
  344. package/registry/blocks/settings-list/demo.jsx +333 -0
  345. package/registry/blocks/settings-list/index.js +4 -0
  346. package/registry/blocks/settings-list/row-state.jsx +93 -0
  347. package/registry/blocks/settings-list/settings-list.jsx +349 -0
  348. package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
  349. package/registry/blocks/setup-checklist/README.md +142 -0
  350. package/registry/blocks/setup-checklist/block.json +10 -0
  351. package/registry/blocks/setup-checklist/demo.jsx +159 -0
  352. package/registry/blocks/setup-checklist/index.js +4 -0
  353. package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
  354. package/registry/blocks/share-dialog/README.md +113 -0
  355. package/registry/blocks/share-dialog/block.json +10 -0
  356. package/registry/blocks/share-dialog/demo.jsx +140 -0
  357. package/registry/blocks/share-dialog/index.js +3 -0
  358. package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
  359. package/registry/blocks/sidebar/README.md +190 -0
  360. package/registry/blocks/sidebar/block.json +43 -0
  361. package/registry/blocks/sidebar/demo.jsx +577 -0
  362. package/registry/blocks/sidebar/index.js +4 -0
  363. package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
  364. package/registry/blocks/sidebar/sidebar.jsx +864 -0
  365. package/registry/blocks/signature-pad/README.md +137 -0
  366. package/registry/blocks/signature-pad/block.json +13 -0
  367. package/registry/blocks/signature-pad/colors.js +115 -0
  368. package/registry/blocks/signature-pad/demo.jsx +94 -0
  369. package/registry/blocks/signature-pad/index.js +6 -0
  370. package/registry/blocks/signature-pad/pad.js +7 -0
  371. package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
  372. package/registry/blocks/signature-pad/signature.js +68 -0
  373. package/registry/blocks/sketch-canvas/README.md +280 -0
  374. package/registry/blocks/sketch-canvas/block.json +13 -0
  375. package/registry/blocks/sketch-canvas/demo.jsx +159 -0
  376. package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
  377. package/registry/blocks/sketch-canvas/index.js +9 -0
  378. package/registry/blocks/sketch-canvas/palette.js +226 -0
  379. package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
  380. package/registry/blocks/sketch-canvas/sketch.js +179 -0
  381. package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
  382. package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
  383. package/registry/blocks/sketch-canvas/stamps.js +104 -0
  384. package/registry/blocks/sketch-canvas/theme.js +131 -0
  385. package/registry/blocks/spreadsheet/README.md +307 -0
  386. package/registry/blocks/spreadsheet/block.json +13 -0
  387. package/registry/blocks/spreadsheet/cells.jsx +455 -0
  388. package/registry/blocks/spreadsheet/chrome.jsx +325 -0
  389. package/registry/blocks/spreadsheet/demo.jsx +177 -0
  390. package/registry/blocks/spreadsheet/grid.js +387 -0
  391. package/registry/blocks/spreadsheet/index.js +34 -0
  392. package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
  393. package/registry/blocks/spreadsheet/types.js +473 -0
  394. package/registry/blocks/stat-cards/README.md +173 -0
  395. package/registry/blocks/stat-cards/block.json +10 -0
  396. package/registry/blocks/stat-cards/demo.jsx +257 -0
  397. package/registry/blocks/stat-cards/index.js +4 -0
  398. package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
  399. package/registry/blocks/stat-cards/usage.jsx +243 -0
  400. package/registry/blocks/task-list/README.md +176 -0
  401. package/registry/blocks/task-list/block.json +10 -0
  402. package/registry/blocks/task-list/demo.jsx +134 -0
  403. package/registry/blocks/task-list/index.js +5 -0
  404. package/registry/blocks/task-list/task-list.jsx +907 -0
  405. package/registry/blocks/task-model/README.md +455 -0
  406. package/registry/blocks/task-model/block.json +167 -0
  407. package/registry/blocks/task-model/changes.js +89 -0
  408. package/registry/blocks/task-model/dates.js +371 -0
  409. package/registry/blocks/task-model/demo.jsx +215 -0
  410. package/registry/blocks/task-model/dnd.jsx +240 -0
  411. package/registry/blocks/task-model/index.js +97 -0
  412. package/registry/blocks/task-model/model.js +919 -0
  413. package/registry/blocks/task-model/parts.jsx +449 -0
  414. package/registry/blocks/task-model/toolbar.jsx +271 -0
  415. package/registry/blocks/testimonials/README.md +139 -0
  416. package/registry/blocks/testimonials/block.json +11 -0
  417. package/registry/blocks/testimonials/demo.jsx +137 -0
  418. package/registry/blocks/testimonials/index.js +4 -0
  419. package/registry/blocks/testimonials/testimonials.jsx +430 -0
  420. package/registry/blocks/transaction-list/README.md +126 -0
  421. package/registry/blocks/transaction-list/block.json +10 -0
  422. package/registry/blocks/transaction-list/demo.jsx +79 -0
  423. package/registry/blocks/transaction-list/index.js +4 -0
  424. package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
  425. package/registry/blocks/whiteboard/README.md +179 -0
  426. package/registry/blocks/whiteboard/block.json +10 -0
  427. package/registry/blocks/whiteboard/demo.jsx +169 -0
  428. package/registry/blocks/whiteboard/index.js +6 -0
  429. package/registry/blocks/whiteboard/templates.js +150 -0
  430. package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
  431. package/src/install.mjs +18 -0
  432. package/src/shadcn.mjs +171 -0
  433. package/templates/next/files/README.md +145 -11
  434. package/templates/next/files/app/globals.css +55 -4
  435. package/templates/next/files/check/run.mjs +3 -3
  436. package/templates/next/files/components/parts/fixture.jsx +1 -1
  437. package/templates/next/files/components/parts/sample.js +15 -0
  438. package/templates/next/files/components/ui/avatar.jsx +141 -0
  439. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  440. package/templates/next/files/components/ui/button-group.jsx +70 -0
  441. package/templates/next/files/components/ui/button.jsx +132 -12
  442. package/templates/next/files/components/ui/calendar.jsx +609 -0
  443. package/templates/next/files/components/ui/carousel.jsx +281 -0
  444. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  445. package/templates/next/files/components/ui/combobox.jsx +608 -0
  446. package/templates/next/files/components/ui/command.jsx +577 -0
  447. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  448. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  449. package/templates/next/files/components/ui/distribution.jsx +117 -0
  450. package/templates/next/files/components/ui/feedback.jsx +143 -0
  451. package/templates/next/files/components/ui/field.jsx +115 -3
  452. package/templates/next/files/components/ui/file-input.jsx +234 -0
  453. package/templates/next/files/components/ui/icon.jsx +130 -8
  454. package/templates/next/files/components/ui/image.jsx +143 -0
  455. package/templates/next/files/components/ui/index.js +47 -2
  456. package/templates/next/files/components/ui/input-group.jsx +213 -0
  457. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  458. package/templates/next/files/components/ui/item.jsx +206 -0
  459. package/templates/next/files/components/ui/menu.jsx +454 -82
  460. package/templates/next/files/components/ui/notice.jsx +126 -14
  461. package/templates/next/files/components/ui/pagination.jsx +156 -0
  462. package/templates/next/files/components/ui/popover.jsx +284 -0
  463. package/templates/next/files/components/ui/radio.jsx +193 -0
  464. package/templates/next/files/components/ui/rating.jsx +131 -0
  465. package/templates/next/files/components/ui/resizable.jsx +338 -0
  466. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  467. package/templates/next/files/components/ui/separator.jsx +119 -0
  468. package/templates/next/files/components/ui/sheet.jsx +96 -11
  469. package/templates/next/files/components/ui/slider.jsx +174 -0
  470. package/templates/next/files/components/ui/stat.jsx +574 -0
  471. package/templates/next/files/components/ui/steps.jsx +338 -0
  472. package/templates/next/files/components/ui/swatch.jsx +33 -0
  473. package/templates/next/files/components/ui/table.jsx +130 -0
  474. package/templates/next/files/components/ui/toast.jsx +440 -0
  475. package/templates/next/files/components/ui/toggle.jsx +195 -0
  476. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  477. package/templates/next/files/lib/sample.js +4 -12
  478. package/templates/next/template.json +264 -8
@@ -0,0 +1,509 @@
1
+ "use client";
2
+
3
+ import { useId, useState } from "react";
4
+ import { Button, Checkbox, Field, Icon, Image, Input, Kicker, Notice, RadioGroup, Textarea, Toggle, cx } from "../../ui";
5
+
6
+ // ContactSection — a public "contact us" section: a form (name, email,
7
+ // message; optional phone, company, subject, a topic picked from chips
8
+ // or radios, a consent box) and/or the ways to reach you (email, phone,
9
+ // address, hours, offices). Three layouts: the form alone, the form
10
+ // beside an info panel, and info cards (alone, above the form or beside
11
+ // it). The form validates in place, submits through `onSubmit(values)`
12
+ // — async, returning { ok } — and shows the failure, or a sent state.
13
+ //
14
+ // <ContactSection title="Talk to us" details={DETAILS}
15
+ // onSubmit={async (v) => sendMessage(v)} />
16
+ //
17
+ // README.md beside this file lists every prop.
18
+
19
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
20
+ const OPTIONAL = ["phone", "company", "subject"];
21
+
22
+ const optionOf = (o) => (typeof o === "string" ? { value: o, label: o } : o);
23
+
24
+ function Header({ kicker, title, description, center }) {
25
+ if (!kicker && !title && !description) return null;
26
+ return (
27
+ <div className={cx("grid gap-3", center ? "mx-auto max-w-2xl justify-items-center text-center" : "max-w-2xl")}>
28
+ {kicker ? <Kicker>{kicker}</Kicker> : null}
29
+ {title ? <h2 className="text-balance text-3xl font-semibold tracking-tight sm:text-4xl">{title}</h2> : null}
30
+ {description ? <p className="text-pretty text-base text-muted-foreground sm:text-lg">{description}</p> : null}
31
+ </div>
32
+ );
33
+ }
34
+
35
+ // A detail's value: a link when it has an href (mailto:, tel:, a map).
36
+ // raw: a plain <a>, not Button: it inherits the colour of the panel it
37
+ // sits on (a filled panel is primary), and these hrefs leave the app.
38
+ function Value({ detail, className }) {
39
+ if (!detail.href) return <span className={className}>{detail.value}</span>;
40
+ return (
41
+ <a href={detail.href} className={cx("break-words rounded-sm underline-offset-4 outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring", className)}>
42
+ {detail.value}
43
+ </a>
44
+ );
45
+ }
46
+
47
+ function DetailRows({ details, filled }) {
48
+ if (!details?.length) return null;
49
+ return (
50
+ <ul className="grid gap-5">
51
+ {details.map((d, i) => (
52
+ <li key={d.label ?? i} className="flex min-w-0 items-start gap-4">
53
+ <span className={cx("grid size-10 shrink-0 place-items-center rounded-lg", filled ? "bg-primary-foreground/15" : "bg-muted text-foreground")}>
54
+ <Icon name={d.icon ?? "info"} size={18} />
55
+ </span>
56
+ <div className="grid min-w-0 gap-0.5">
57
+ {d.label ? <p className={cx("text-sm", filled ? "opacity-80" : "text-muted-foreground")}>{d.label}</p> : null}
58
+ <Value detail={d} className="font-medium" />
59
+ {d.description ? <p className={cx("text-sm", filled ? "opacity-80" : "text-muted-foreground")}>{d.description}</p> : null}
60
+ </div>
61
+ </li>
62
+ ))}
63
+ </ul>
64
+ );
65
+ }
66
+
67
+ function Offices({ offices, filled }) {
68
+ if (!offices?.length) return null;
69
+ return (
70
+ <div className="grid gap-6 sm:grid-cols-2">
71
+ {offices.map((o, i) => (
72
+ <div key={o.name ?? i} className="grid min-w-0 content-start gap-1">
73
+ <p className="flex items-center gap-2 font-semibold">
74
+ <Icon name={o.icon ?? "building"} size={16} className={filled ? "opacity-80" : "text-muted-foreground"} />
75
+ {o.name}
76
+ </p>
77
+ {(o.lines ?? []).map((line, k) => (
78
+ <p key={k} className={cx("text-sm", filled ? "opacity-80" : "text-muted-foreground")}>
79
+ {line}
80
+ </p>
81
+ ))}
82
+ </div>
83
+ ))}
84
+ </div>
85
+ );
86
+ }
87
+
88
+ function Panel({ title, body, details, offices, look }) {
89
+ const filled = look === "filled";
90
+ return (
91
+ <aside
92
+ className={cx(
93
+ "grid min-w-0 content-start gap-8 rounded-xl p-6 sm:p-8",
94
+ filled ? "bg-primary text-primary-foreground" : "border border-border bg-muted/40",
95
+ )}
96
+ >
97
+ {title || body ? (
98
+ <div className="grid gap-2">
99
+ {title ? <h3 className="text-xl font-semibold">{title}</h3> : null}
100
+ {body ? <p className={cx("text-pretty", filled ? "opacity-80" : "text-muted-foreground")}>{body}</p> : null}
101
+ </div>
102
+ ) : null}
103
+ <DetailRows details={details} filled={filled} />
104
+ <Offices offices={offices} filled={filled} />
105
+ </aside>
106
+ );
107
+ }
108
+
109
+ function DetailCards({ details, center, columns }) {
110
+ if (!details?.length) return null;
111
+ const cols = columns ?? Math.min(details.length, 3);
112
+ return (
113
+ <ul className={cx("grid gap-4", cols === 1 ? "grid-cols-1" : cols === 2 ? "sm:grid-cols-2" : cols === 4 ? "sm:grid-cols-2 lg:grid-cols-4" : "sm:grid-cols-2 lg:grid-cols-3")}>
114
+ {details.map((d, i) => (
115
+ <li
116
+ key={d.label ?? i}
117
+ className={cx("grid min-w-0 content-start gap-3 rounded-lg border border-border bg-card p-6 text-card-foreground", center && "justify-items-center text-center")}
118
+ >
119
+ <span className={cx("grid size-12 place-items-center bg-primary text-primary-foreground", center ? "rounded-full" : "rounded-lg")}>
120
+ <Icon name={d.icon ?? "info"} size={22} />
121
+ </span>
122
+ {d.label ? <h3 className="font-semibold">{d.label}</h3> : null}
123
+ {d.description ? <p className="text-pretty text-sm text-muted-foreground">{d.description}</p> : null}
124
+ {d.value ? <Value detail={d} className="font-medium text-primary" /> : null}
125
+ </li>
126
+ ))}
127
+ </ul>
128
+ );
129
+ }
130
+
131
+ // The phone, email and hours on one line above a form.
132
+ function DetailLine({ details, center }) {
133
+ if (!details?.length) return null;
134
+ return (
135
+ <ul className={cx("flex flex-wrap gap-x-6 gap-y-2 text-sm", center && "justify-center")}>
136
+ {details.map((d, i) => (
137
+ <li key={d.label ?? i} className="flex min-w-0 items-center gap-2">
138
+ <Icon name={d.icon ?? "info"} size={16} className="shrink-0 text-muted-foreground" />
139
+ {d.label ? <span className="sr-only">{d.label}: </span> : null}
140
+ <Value detail={d} className="font-medium" />
141
+ </li>
142
+ ))}
143
+ </ul>
144
+ );
145
+ }
146
+
147
+ function blank(names, fields, topics) {
148
+ const v = { email: "", message: "" };
149
+ if (names === "one") v.name = "";
150
+ else Object.assign(v, { firstName: "", lastName: "" });
151
+ for (const f of fields) v[f] = "";
152
+ if (topics) v.topic = "";
153
+ return v;
154
+ }
155
+
156
+ function ContactForm({
157
+ onSubmit,
158
+ names,
159
+ fields,
160
+ topics,
161
+ consent,
162
+ messageRows,
163
+ messageLabel,
164
+ submitLabel,
165
+ sent,
166
+ defaultValues,
167
+ labels,
168
+ }) {
169
+ const uid = useId();
170
+ const id = (k) => `${uid}-${k}`;
171
+ const start = () => ({ ...blank(names, fields, topics), ...defaultValues, ...(consent ? { consent: false } : {}) });
172
+ const [values, setValues] = useState(start);
173
+ const [errors, setErrors] = useState({});
174
+ const [status, setStatus] = useState("idle");
175
+ const [failure, setFailure] = useState(null);
176
+ const L = { firstName: "First name", lastName: "Last name", name: "Name", email: "Email", phone: "Phone", company: "Company", subject: "Subject", ...labels };
177
+
178
+ const set = (k, v) => {
179
+ setValues((prev) => ({ ...prev, [k]: v }));
180
+ if (errors[k]) setErrors((prev) => ({ ...prev, [k]: undefined }));
181
+ };
182
+
183
+ function validate() {
184
+ const e = {};
185
+ if (names === "one" && !values.name?.trim()) e.name = "Tell us your name.";
186
+ if (names !== "one" && !values.firstName?.trim()) e.firstName = "Tell us your first name.";
187
+ if (!values.email?.trim()) e.email = "We need an email to reply to.";
188
+ else if (!EMAIL.test(values.email.trim())) e.email = "That email does not look right.";
189
+ if (topics?.required && !values.topic) e.topic = "Pick one.";
190
+ if (!values.message?.trim()) e.message = "Write a line or two.";
191
+ if (consent && !values.consent) e.consent = "Please agree before sending.";
192
+ return e;
193
+ }
194
+
195
+ async function submit(ev) {
196
+ ev.preventDefault();
197
+ if (status === "sending") return;
198
+ const e = validate();
199
+ setErrors(e);
200
+ const first = Object.keys(e)[0];
201
+ if (first) {
202
+ // The first problem gets the focus, so a keyboard user lands on it.
203
+ const el = document.getElementById(id(first));
204
+ (el?.matches("input, textarea") ? el : el?.querySelector("input, button, textarea"))?.focus();
205
+ return;
206
+ }
207
+ setStatus("sending");
208
+ setFailure(null);
209
+ const out = { ...values };
210
+ for (const k of Object.keys(out)) if (typeof out[k] === "string") out[k] = out[k].trim();
211
+ let res;
212
+ try {
213
+ res = await onSubmit(out);
214
+ } catch (err) {
215
+ res = { ok: false, error: err?.message };
216
+ }
217
+ if (res?.ok) {
218
+ setStatus("sent");
219
+ } else {
220
+ setStatus("idle");
221
+ setFailure(res?.error || "Your message was not sent. Check your connection and try again.");
222
+ }
223
+ }
224
+
225
+ if (status === "sent")
226
+ return (
227
+ <div className="grid gap-4" aria-live="polite">
228
+ <Notice tone="success" title={sent?.title ?? "Message sent"}>
229
+ {sent?.body ?? "Thanks — we read every message and reply within one working day."}
230
+ </Notice>
231
+ <div>
232
+ <Button
233
+ variant="secondary"
234
+ icon="repeat"
235
+ onClick={() => {
236
+ setValues(start());
237
+ setErrors({});
238
+ setStatus("idle");
239
+ }}
240
+ >
241
+ Send another
242
+ </Button>
243
+ </div>
244
+ </div>
245
+ );
246
+
247
+ const topicOptions = (topics?.options ?? []).map(optionOf);
248
+ const sending = status === "sending";
249
+ return (
250
+ <form noValidate onSubmit={submit} className="grid gap-5" aria-busy={sending || undefined}>
251
+ {topics && topics.style !== "radio" ? (
252
+ <div className="grid gap-2">
253
+ <p id={id("topic-label")} className="text-sm font-medium">
254
+ {topics.label ?? "What is it about?"}
255
+ {topics.required ? <span aria-hidden="true" className="text-destructive"> *</span> : null}
256
+ </p>
257
+ <div id={id("topic")} role="group" aria-labelledby={id("topic-label")} className="flex flex-wrap gap-2">
258
+ {topicOptions.map((o) => (
259
+ <Toggle
260
+ key={o.value}
261
+ size="sm"
262
+ pressed={values.topic === o.value}
263
+ onPressedChange={(on) => set("topic", on ? o.value : "")}
264
+ className="max-w-full"
265
+ >
266
+ {o.label}
267
+ </Toggle>
268
+ ))}
269
+ </div>
270
+ {errors.topic ? (
271
+ <p role="alert" className="text-xs text-destructive">
272
+ {errors.topic}
273
+ </p>
274
+ ) : null}
275
+ </div>
276
+ ) : null}
277
+
278
+ {names === "one" ? (
279
+ <Field id={id("name")} label={L.name} required error={errors.name}>
280
+ <Input id={id("name")} name="name" autoComplete="name" value={values.name} onChange={(e) => set("name", e.target.value)} invalid={!!errors.name} />
281
+ </Field>
282
+ ) : (
283
+ <div className="grid gap-5 sm:grid-cols-2">
284
+ <Field id={id("firstName")} label={L.firstName} required error={errors.firstName}>
285
+ <Input
286
+ id={id("firstName")}
287
+ name="firstName"
288
+ autoComplete="given-name"
289
+ value={values.firstName}
290
+ onChange={(e) => set("firstName", e.target.value)}
291
+ invalid={!!errors.firstName}
292
+ />
293
+ </Field>
294
+ <Field id={id("lastName")} label={L.lastName}>
295
+ <Input id={id("lastName")} name="lastName" autoComplete="family-name" value={values.lastName} onChange={(e) => set("lastName", e.target.value)} />
296
+ </Field>
297
+ </div>
298
+ )}
299
+
300
+ <div className={cx("grid gap-5", fields.includes("phone") && "sm:grid-cols-2")}>
301
+ <Field id={id("email")} label={L.email} required error={errors.email}>
302
+ <Input
303
+ id={id("email")}
304
+ name="email"
305
+ type="email"
306
+ inputMode="email"
307
+ autoComplete="email"
308
+ placeholder="you@company.com"
309
+ value={values.email}
310
+ onChange={(e) => set("email", e.target.value)}
311
+ invalid={!!errors.email}
312
+ />
313
+ </Field>
314
+ {fields.includes("phone") ? (
315
+ <Field id={id("phone")} label={L.phone} hint="Optional">
316
+ <Input id={id("phone")} name="phone" type="tel" inputMode="tel" autoComplete="tel" value={values.phone} onChange={(e) => set("phone", e.target.value)} />
317
+ </Field>
318
+ ) : null}
319
+ </div>
320
+
321
+ {fields.includes("company") ? (
322
+ <Field id={id("company")} label={L.company} hint="Optional">
323
+ <Input id={id("company")} name="company" autoComplete="organization" value={values.company} onChange={(e) => set("company", e.target.value)} />
324
+ </Field>
325
+ ) : null}
326
+
327
+ {topics && topics.style === "radio" ? (
328
+ <Field id={id("topic")} label={topics.label ?? "What is it about?"} required={topics.required} error={errors.topic}>
329
+ <RadioGroup
330
+ id={id("topic")}
331
+ name="topic"
332
+ orientation="horizontal"
333
+ options={topicOptions}
334
+ value={values.topic}
335
+ onChange={(v) => set("topic", v)}
336
+ invalid={!!errors.topic}
337
+ />
338
+ </Field>
339
+ ) : null}
340
+
341
+ {fields.includes("subject") ? (
342
+ <Field id={id("subject")} label={L.subject}>
343
+ <Input id={id("subject")} name="subject" value={values.subject} onChange={(e) => set("subject", e.target.value)} />
344
+ </Field>
345
+ ) : null}
346
+
347
+ <Field id={id("message")} label={messageLabel ?? "Message"} required error={errors.message}>
348
+ <Textarea
349
+ id={id("message")}
350
+ name="message"
351
+ rows={messageRows}
352
+ placeholder="What can we help with?"
353
+ value={values.message}
354
+ onChange={(e) => set("message", e.target.value)}
355
+ invalid={!!errors.message}
356
+ />
357
+ </Field>
358
+
359
+ {consent ? (
360
+ <div className="grid gap-1">
361
+ <Checkbox
362
+ id={id("consent")}
363
+ name="consent"
364
+ checked={!!values.consent}
365
+ onChange={(e) => set("consent", e.target.checked)}
366
+ aria-invalid={errors.consent ? true : undefined}
367
+ aria-describedby={errors.consent ? id("consent-error") : undefined}
368
+ label={consent}
369
+ />
370
+ {errors.consent ? (
371
+ <p id={id("consent-error")} role="alert" className="text-xs text-destructive">
372
+ {errors.consent}
373
+ </p>
374
+ ) : null}
375
+ </div>
376
+ ) : null}
377
+
378
+ {failure ? (
379
+ <Notice tone="danger" title="Not sent">
380
+ {failure}
381
+ </Notice>
382
+ ) : null}
383
+
384
+ <div>
385
+ <Button type="submit" variant="primary" icon="send" loading={sending} className="w-full sm:w-auto">
386
+ {submitLabel ?? "Send message"}
387
+ </Button>
388
+ </div>
389
+ </form>
390
+ );
391
+ }
392
+
393
+ export function ContactSection({
394
+ layout = "split",
395
+ kicker,
396
+ title = "Get in touch",
397
+ description,
398
+ align,
399
+ details,
400
+ offices,
401
+ panel = "plain",
402
+ panelTitle,
403
+ panelBody,
404
+ cardsPosition = "above",
405
+ cardColumns,
406
+ image,
407
+ imageAlt = "",
408
+ imagePosition = "side",
409
+ onSubmit,
410
+ nameFields = "split",
411
+ fields = [],
412
+ topics,
413
+ consent,
414
+ messageLabel,
415
+ messageRows = 5,
416
+ submitLabel,
417
+ sent,
418
+ defaultValues,
419
+ labels,
420
+ label,
421
+ className,
422
+ }) {
423
+ const extra = (fields ?? []).filter((f) => OPTIONAL.includes(f));
424
+ const center = (align ?? (layout === "split" ? "start" : "center")) === "center";
425
+ const form = onSubmit ? (
426
+ <ContactForm
427
+ onSubmit={onSubmit}
428
+ names={nameFields === "one" ? "one" : "split"}
429
+ fields={extra}
430
+ topics={topics?.options?.length ? topics : null}
431
+ consent={consent}
432
+ messageRows={messageRows}
433
+ messageLabel={messageLabel}
434
+ submitLabel={submitLabel}
435
+ sent={sent}
436
+ defaultValues={defaultValues}
437
+ labels={labels}
438
+ />
439
+ ) : null;
440
+ const formCard = form ? <div className="min-w-0 rounded-xl border border-border bg-card p-5 text-card-foreground sm:p-8">{form}</div> : null;
441
+
442
+ let body;
443
+ if (layout === "cards") {
444
+ const cards = <DetailCards details={details} center={center && cardsPosition !== "beside"} columns={cardsPosition === "beside" && form ? 1 : cardColumns} />;
445
+ body = !form ? (
446
+ cards
447
+ ) : cardsPosition === "beside" ? (
448
+ <div className="grid gap-8 lg:grid-cols-[minmax(0,2fr)_minmax(0,3fr)]">
449
+ {cards}
450
+ {formCard}
451
+ </div>
452
+ ) : (
453
+ <div className="grid gap-10">
454
+ {cards}
455
+ <div className="mx-auto w-full max-w-2xl">{formCard}</div>
456
+ </div>
457
+ );
458
+ } else if (layout === "form") {
459
+ if (image && imagePosition === "background" && form)
460
+ body = (
461
+ <div className="relative isolate overflow-hidden rounded-xl">
462
+ <div className="absolute inset-0 -z-10">
463
+ <Image src={image} alt={imageAlt} rounded="none" className="h-full w-full" />
464
+ </div>
465
+ <div className="grid justify-items-center bg-background/70 px-4 py-10 sm:px-8 sm:py-16">
466
+ <div className="w-full max-w-xl">{formCard}</div>
467
+ </div>
468
+ </div>
469
+ );
470
+ else if (image && form)
471
+ body = (
472
+ <div className="grid items-stretch gap-8 md:grid-cols-2">
473
+ <div className="hidden md:block">
474
+ <Image src={image} alt={imageAlt} rounded="lg" className="h-full min-h-96 w-full" />
475
+ </div>
476
+ <div className="grid min-w-0 content-start gap-6">
477
+ <DetailLine details={details} />
478
+ {formCard}
479
+ </div>
480
+ </div>
481
+ );
482
+ else
483
+ body = (
484
+ <div className="mx-auto grid w-full max-w-2xl gap-6">
485
+ <DetailLine details={details} center={center} />
486
+ {formCard}
487
+ </div>
488
+ );
489
+ } else {
490
+ const side = <Panel title={panelTitle} body={panelBody} details={details} offices={offices} look={panel} />;
491
+ body = form ? (
492
+ <div className="grid gap-8 lg:grid-cols-[minmax(0,3fr)_minmax(0,2fr)]">
493
+ {formCard}
494
+ {side}
495
+ </div>
496
+ ) : (
497
+ side
498
+ );
499
+ }
500
+
501
+ return (
502
+ <section aria-label={label ?? (typeof title === "string" ? title : "Contact")} className={cx("px-4 py-16 sm:px-6 sm:py-20", className)}>
503
+ <div className="mx-auto grid w-full max-w-6xl gap-10 sm:gap-12">
504
+ <Header kicker={kicker} title={title} description={description} center={center} />
505
+ {body}
506
+ </div>
507
+ </section>
508
+ );
509
+ }
@@ -0,0 +1,93 @@
1
+ "use client";
2
+
3
+ // The ContactSection in every variant — the gallery's and the smoke
4
+ // test's surface. Not installed into apps: `makersclaw add
5
+ // contact-section` lays index.js and contact-section.jsx only. Pick a
6
+ // variant, and whether the next send succeeds or fails; nothing is sent.
7
+ import { useState } from "react";
8
+ import { Field, Select, ToggleGroup } from "../components/ui";
9
+ import { ContactSection } from "../components/blocks/contact-section";
10
+
11
+ const EMAIL = { icon: "mail", label: "Email", value: "hello@fieldline.io", href: "mailto:hello@fieldline.io" };
12
+ const PHONE = { icon: "phone", label: "Phone", value: "+44 20 7946 0321", href: "tel:+442079460321" };
13
+ const ADDRESS = { icon: "map", label: "Studio", value: "14 Canal Street, Manchester M1 3HE" };
14
+ const HOURS = { icon: "clock", label: "Hours", value: "Mon–Fri, 9:00–18:00 GMT" };
15
+
16
+ const CARDS = [
17
+ { ...EMAIL, label: "Email us", description: "For anything at all. A person replies within a working day." },
18
+ { ...PHONE, label: "Call sales", description: "Talk through a plan for your team, no slides." },
19
+ { ...ADDRESS, label: "Visit", description: "Coffee is on us. Book ahead so someone is in." },
20
+ ];
21
+
22
+ const QUICK = [
23
+ { icon: "message-circle", label: "Live chat", description: "Weekdays, usually under five minutes.", value: "Start a chat", href: "/chat" },
24
+ { icon: "life-buoy", label: "Help centre", description: "Guides for setup, billing and imports.", value: "Browse guides", href: "/help" },
25
+ { icon: "calendar", label: "Book a call", description: "Thirty minutes with someone from sales.", value: "Pick a time", href: "/book" },
26
+ ];
27
+
28
+ const OFFICES = [
29
+ { name: "Manchester", lines: ["14 Canal Street", "M1 3HE, United Kingdom", "+44 20 7946 0321"] },
30
+ { name: "Lisbon", lines: ["Rua da Prata 88", "1100-420 Lisboa, Portugal", "+351 21 555 0192"] },
31
+ ];
32
+
33
+ const TOPICS = ["Sales", "Support", "Partnerships", "Press"];
34
+ const CONSENT = "I agree to the privacy policy and to being contacted about this message.";
35
+ const HEAD = { kicker: "Contact", title: "Talk to a person", description: "Questions about plans, a migration, or a feature you need — write and we reply within one working day." };
36
+
37
+ const VARIANTS = [
38
+ { id: "01", label: "01 · Form beside contact info", props: { ...HEAD, layout: "split", details: [EMAIL, PHONE, ADDRESS], consent: CONSENT, panelTitle: "Other ways in", panelBody: "Prefer a call or a visit? Here is where to find us." } },
39
+ { id: "02", label: "02 · Form with a phone field", props: { ...HEAD, layout: "form", fields: ["phone"], details: [EMAIL, PHONE] } },
40
+ { id: "03", label: "03 · Form with a filled panel", props: { ...HEAD, layout: "split", panel: "filled", details: [EMAIL, PHONE, ADDRESS], panelTitle: "Contact information", panelBody: "Fill in the form and we reply within one working day." } },
41
+ { id: "04", label: "04 · Icon cards only", props: { ...HEAD, layout: "cards", align: "start", details: CARDS } },
42
+ { id: "05", label: "05 · Topic chips above the form", props: { ...HEAD, layout: "form", topics: { label: "What is it about?", options: TOPICS, style: "chips", required: true } } },
43
+ { id: "06", label: "06 · Round icon cards, centred", props: { ...HEAD, layout: "cards", details: CARDS } },
44
+ { id: "07", label: "07 · Form with offices", props: { ...HEAD, layout: "split", offices: OFFICES, consent: CONSENT, panelTitle: "Our offices" } },
45
+ { id: "08", label: "08 · Area of interest radios", props: { ...HEAD, layout: "split", panel: "filled", details: [EMAIL, PHONE], panelTitle: "Contact information", topics: { label: "Area of interest", options: TOPICS, style: "radio" } } },
46
+ { id: "09", label: "09 · Detailed info panel", props: { ...HEAD, layout: "split", panel: "filled", details: [EMAIL, PHONE, ADDRESS, HOURS], offices: OFFICES.slice(1), panelTitle: "Everything in one place", panelBody: "Email is fastest. For anything urgent on a paid plan, call." } },
47
+ { id: "10", label: "10 · Info cards above the form", props: { ...HEAD, layout: "cards", details: CARDS } },
48
+ { id: "11", label: "11 · Phone and email above the form", props: { ...HEAD, layout: "form", details: [PHONE, EMAIL, HOURS] } },
49
+ { id: "12", label: "12 · Form with a company field", props: { ...HEAD, layout: "form", fields: ["company"], nameFields: "one", consent: CONSENT } },
50
+ { id: "13", label: "13 · Info cards beside the form", props: { ...HEAD, layout: "cards", cardsPosition: "beside", align: "start", details: [EMAIL, PHONE, HOURS] } },
51
+ { id: "14", label: "14 · Subject and required marks", props: { ...HEAD, layout: "form", fields: ["subject", "phone"], consent: CONSENT } },
52
+ { id: "15", label: "15 · Contact options and a quick form", props: { ...HEAD, layout: "cards", details: QUICK, nameFields: "one", fields: ["phone"], messageLabel: "Your question", messageRows: 3, submitLabel: "Send" } },
53
+ ];
54
+
55
+ // Cards-only variants have no form: they get no onSubmit.
56
+ const NO_FORM = new Set(["04", "06"]);
57
+
58
+ const OUTCOMES = [
59
+ { value: "ok", label: "Send succeeds" },
60
+ { value: "fail", label: "Send fails" },
61
+ ];
62
+
63
+ export default function ContactSectionDemo() {
64
+ const [variant, setVariant] = useState("01");
65
+ const [outcome, setOutcome] = useState("ok");
66
+ const [last, setLast] = useState(null);
67
+ const v = VARIANTS.find((x) => x.id === variant) ?? VARIANTS[0];
68
+
69
+ async function send(values) {
70
+ await new Promise((r) => setTimeout(r, 900));
71
+ if (outcome === "fail") return { ok: false, error: "Our mail server did not answer. Your message is still here — try again in a minute." };
72
+ setLast(values);
73
+ return { ok: true };
74
+ }
75
+
76
+ return (
77
+ <div className="grid gap-2">
78
+ <div className="flex flex-wrap items-end gap-3 px-4 pt-4 sm:px-6">
79
+ <Field id="c-variant" label="Variant" className="w-full sm:w-80">
80
+ <Select id="c-variant" value={variant} onChange={(e) => setVariant(e.target.value)} options={VARIANTS.map((x) => ({ value: x.id, label: x.label }))} />
81
+ </Field>
82
+ <ToggleGroup aria-label="Next send" items={OUTCOMES} value={outcome} onChange={setOutcome} />
83
+ </div>
84
+ {last ? (
85
+ <p className="px-4 text-sm text-muted-foreground sm:px-6">
86
+ Last sent: <span className="font-medium text-foreground">{last.email}</span>
87
+ {last.topic ? ` · ${last.topic}` : ""}
88
+ </p>
89
+ ) : null}
90
+ <ContactSection key={variant} {...v.props} onSubmit={NO_FORM.has(variant) ? undefined : send} />
91
+ </div>
92
+ );
93
+ }
@@ -0,0 +1,4 @@
1
+ // The ContactSection block — `makersclaw add contact-section`. Fixed:
2
+ // compose it through its props (README.md beside this file); a section
3
+ // it cannot be is your own component in components/.
4
+ export { ContactSection } from "./contact-section";