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,113 @@
1
+ # ShareDialog
2
+
3
+ Who can see a record, and how to let more people in. An invite field
4
+ that takes several emails at once (with an access level), the people who
5
+ already have access (each with a menu: can view, can edit, remove),
6
+ sharing switches ("Allow comments"), and a link with a copy button that
7
+ turns to a check. Each section shows when you give its data or callback.
8
+ `ShareDialog` puts it in the kit's `Sheet` (a dialog; a bottom sheet on a
9
+ phone); `SharePanel` is the same body inline, for a settings page.
10
+
11
+ Every change goes out through an async callback that returns `{ ok: true }`
12
+ or `{ ok: false, error }`. A role change or a switch shows at once and goes
13
+ back when the save fails, with the reason on screen.
14
+
15
+ ```jsx
16
+ import { ShareDialog, SharePanel } from "../components/blocks/share-dialog"; // a Makersclaw app ("./blocks/share-dialog" from components/)
17
+ import { ShareDialog, SharePanel } from "@/components/makersclaw/blocks/share-dialog"; // a shadcn project
18
+ ```
19
+
20
+ A client component: render it from a `"use client"` component.
21
+
22
+ ## The data
23
+
24
+ `people` is who has access now: `[{ id?, name?, email, src?, role, roleLabel?, locked?, pending? }]`.
25
+
26
+ - `role` is one of `roles`' values. A role outside them (an owner) shows
27
+ as a badge, with `roleLabel` as its words.
28
+ - `locked: true` — no menu for this person (the owner, yourself).
29
+ - `pending: true` — invited, not joined yet: "Invite sent" or an
30
+ "Invited" badge.
31
+ - `src` — a photo; the kit's `Avatar` shows initials without one.
32
+
33
+ ## Props
34
+
35
+ Both components take these. Everything is optional; a section shows only
36
+ when its data or callback is there.
37
+
38
+ - `people` — the list above. `[]` shows `empty`; leave it out to hide the
39
+ section.
40
+ - `roles` — the access levels, in order: `[{ value, label }]`. Default
41
+ `[{ value: "view", label: "Can view" }, { value: "edit", label: "Can edit" }]`.
42
+ - `onInvite(emails, role)` — shows the invite field. Async, `{ ok, error }`.
43
+ The field splits on commas, spaces and semicolons, drops duplicates and
44
+ people who already have access, and refuses anything that is not an
45
+ email before it calls you. Add the invited people to `people` yourself
46
+ (with `pending: true`). With two or more `roles`, a picker beside the
47
+ field chooses the role.
48
+ - `inviteRole` — every invite gets this role, and no picker shows.
49
+ - `onRoleChange(person, role)` — each person's access becomes a menu.
50
+ Async, `{ ok, error }`. Update `people` on success.
51
+ - `onRemove(person)` — "Remove access" in that menu. Async. Take the
52
+ person out of `people` on success.
53
+ - `link` — a URL to share: a read-only field with a copy button, then a
54
+ "Copy link" button. Copying uses the browser's clipboard. A blocked
55
+ clipboard shows a message.
56
+ - `onCopy(link)` — called after a copy (analytics, "link created"). Async
57
+ and optional; a failure shows.
58
+ - `previewHref` or `onPreview` — a "Preview" button beside "Copy link".
59
+ - `settings` — switches: `[{ id, label, description?, icon?, checked, disabled? }]`.
60
+ - `onSettingChange(id, next)` — async, `{ ok, error }`. The switch goes
61
+ back when it fails.
62
+ - `youId` — the `id` (or email) of the person looking: "(you)" after their name.
63
+ - `inviteLabel` · `invitePlaceholder` · `peopleLabel` · `linkLabel` ·
64
+ `empty` — the words. Defaults: "Invite by email", "Emails, separated by
65
+ commas", "People with access", "Share link", "Only you have access so far."
66
+ - `className` — on the panel.
67
+
68
+ `ShareDialog` also takes:
69
+
70
+ - `open` · `onClose()` — controlled. Esc, a press outside and the ✕ close it.
71
+ - `title` — default "Share". `description` — a line under it.
72
+ - `footer` — buttons under the body (a "Done").
73
+
74
+ ## Example
75
+
76
+ ```jsx
77
+ "use client";
78
+ import { useState } from "react";
79
+ import { Button } from "../components/ui";
80
+ import { ShareDialog } from "../components/blocks/share-dialog";
81
+
82
+ export function ShareProject({ project, members, invite, setRole, remove }) {
83
+ const [open, setOpen] = useState(false);
84
+ return (
85
+ <>
86
+ <Button icon="share" onClick={() => setOpen(true)}>Share</Button>
87
+ <ShareDialog
88
+ open={open}
89
+ onClose={() => setOpen(false)}
90
+ title={`Share “${project.name}”`}
91
+ people={members}
92
+ onInvite={(emails, role) => invite(project.id, emails, role)} // server actions returning { ok, error }
93
+ onRoleChange={(person, role) => setRole(project.id, person.id, role)}
94
+ onRemove={(person) => remove(project.id, person.id)}
95
+ link={`https://app.example.com/p/${project.id}`}
96
+ />
97
+ </>
98
+ );
99
+ }
100
+ ```
101
+
102
+ ## What it will not do
103
+
104
+ - Send the invite email or create the access row: `onInvite` does.
105
+ - Search your directory as you type. The field takes addresses; for a
106
+ people picker, use the kit's `Combobox`.
107
+ - Make the link public or private by itself. Put that switch in `settings`
108
+ and change `link` from your callback.
109
+ - Show a person's access per page or field. It has one role per person.
110
+
111
+ ## Credits
112
+
113
+ Ported from blocks.so (https://blocks.so, dialogs 08 and 09, MIT) and Creative Tim UI (https://github.com/creativetimofficial/ui, modals-03, MIT), rewritten on the Makersclaw kit.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "share-dialog",
3
+ "title": "ShareDialog",
4
+ "description": "Who can see a record and how to let more people in: invite by email (comma separated, with an access level), each person with their access in a menu (can view, can edit, remove), sharing switches, and a link with a copy button that turns to a check. A dialog, or the same body inline (SharePanel). Every change is an async callback; a failure shows and the old value comes back.",
5
+ "useWhen": "A record, project, document or workspace can be shared: an \"Invite\" or \"Share\" button, a members list with roles, a public link to copy.",
6
+ "tags": ["share", "invite", "members", "collaborators", "access", "permissions", "roles", "team", "link", "copy link", "dialog", "modal"],
7
+ "exports": ["ShareDialog", "SharePanel"],
8
+ "files": ["index.js", "share-dialog.jsx"],
9
+ "requires": []
10
+ }
@@ -0,0 +1,140 @@
1
+ "use client";
2
+
3
+ // ShareDialog, every variant — the gallery's and the smoke test's
4
+ // surface. Not installed into apps: `makersclaw add share-dialog` lays
5
+ // index.js and share-dialog.jsx only. People live in memory; turn on
6
+ // "Fail the next save" to watch a change go back with its reason.
7
+ import { useState } from "react";
8
+ import { Button, Card, Field, Select, Switch } from "../components/ui";
9
+ import { ShareDialog, SharePanel } from "../components/blocks/share-dialog";
10
+
11
+ const wait = (ms) => new Promise((r) => setTimeout(r, ms));
12
+
13
+ const TEAM = [
14
+ { id: "u1", name: "Amara Okafor", email: "amara@harbourline.co", role: "owner", roleLabel: "Owner", locked: true },
15
+ { id: "u2", name: "Jonas Lindqvist", email: "jonas@harbourline.co", role: "edit" },
16
+ { id: "u3", name: "Priya Raman", email: "priya@harbourline.co", role: "view" },
17
+ { id: "u4", name: "Mateo Alvarez", email: "mateo@fieldnotes.studio", role: "view" },
18
+ ];
19
+
20
+ const MEMBERS = [
21
+ { id: "m1", name: "Amara Okafor", email: "amara@harbourline.co", role: "member" },
22
+ { id: "m2", name: "Jonas Lindqvist", email: "jonas@harbourline.co", role: "member" },
23
+ { id: "m3", name: "Priya Raman", email: "priya@harbourline.co", role: "admin" },
24
+ { id: "m4", name: "Wen Zhao", email: "wen@harbourline.co", role: "member" },
25
+ ];
26
+
27
+ const WORKSPACE_ROLES = [
28
+ { value: "member", label: "Member" },
29
+ { value: "admin", label: "Admin" },
30
+ ];
31
+
32
+ const VARIANTS = [
33
+ { key: "invite", label: "Invite members — roles as badges" },
34
+ { key: "link", label: "Share & collaborate — link and switch" },
35
+ { key: "full", label: "Share with new members — access menus" },
36
+ { key: "empty", label: "Nobody else yet — inline panel" },
37
+ ];
38
+
39
+ export default function ShareDialogDemo() {
40
+ const [key, setKey] = useState("full");
41
+ const [open, setOpen] = useState(false);
42
+ const [fail, setFail] = useState(false);
43
+ const [team, setTeam] = useState(TEAM);
44
+ const [members, setMembers] = useState(MEMBERS);
45
+ const [solo, setSolo] = useState([]);
46
+ const [comments, setComments] = useState(true);
47
+ const [log, setLog] = useState(null);
48
+
49
+ // One fake server: waits, then fails once when asked to.
50
+ async function save(what, apply) {
51
+ await wait(600);
52
+ if (fail) {
53
+ setFail(false);
54
+ return { ok: false, error: "The server did not answer. Try again." };
55
+ }
56
+ apply?.();
57
+ setLog(what);
58
+ return { ok: true };
59
+ }
60
+
61
+ const invite = (list, setList) => (emails, role) =>
62
+ save(`invited ${emails.join(", ")} as ${role}`, () =>
63
+ setList((xs) => [...xs, ...emails.map((email) => ({ id: email, email, role, pending: true }))]),
64
+ );
65
+
66
+ const variantProps = {
67
+ invite: {
68
+ title: "Invite members",
69
+ description: "Add people to the Harbourline workspace. Check your company's policy before inviting anyone outside it.",
70
+ people: members,
71
+ roles: WORKSPACE_ROLES,
72
+ inviteRole: "member",
73
+ onInvite: invite(members, setMembers),
74
+ invitePlaceholder: "name@company.com",
75
+ inviteLabel: "Email",
76
+ peopleLabel: "People with existing access",
77
+ },
78
+ link: {
79
+ title: "Share & collaborate",
80
+ description: "Anyone with the link can open the Q4 launch plan.",
81
+ link: "https://harbourline.app/p/q4-launch-plan?share=8fk2",
82
+ previewHref: "#preview",
83
+ onCopy: (l) => save(`copied ${l}`),
84
+ settings: [{ id: "comments", label: "Allow comments and suggestions", icon: "message-circle", checked: comments }],
85
+ onSettingChange: (id, next) => save(`${id} → ${next ? "on" : "off"}`, () => setComments(next)),
86
+ },
87
+ full: {
88
+ title: "Share with new members",
89
+ description: "Give teammates and outside collaborators access to the Q4 launch plan.",
90
+ people: team,
91
+ youId: "u1",
92
+ onInvite: invite(team, setTeam),
93
+ onRoleChange: (p, role) => save(`${p.email} → ${role}`, () => setTeam((xs) => xs.map((x) => (x.id === p.id ? { ...x, role } : x)))),
94
+ onRemove: (p) => save(`removed ${p.email}`, () => setTeam((xs) => xs.filter((x) => x.id !== p.id))),
95
+ link: "https://harbourline.app/p/q4-launch-plan",
96
+ onCopy: (l) => save(`copied ${l}`),
97
+ },
98
+ empty: {
99
+ people: solo,
100
+ onInvite: invite(solo, setSolo),
101
+ onRoleChange: (p, role) => save(`${p.email} → ${role}`, () => setSolo((xs) => xs.map((x) => (x.id === p.id ? { ...x, role } : x)))),
102
+ onRemove: (p) => save(`removed ${p.email}`, () => setSolo((xs) => xs.filter((x) => x.id !== p.id))),
103
+ },
104
+ };
105
+ const props = variantProps[key];
106
+
107
+ return (
108
+ <div className="grid gap-6">
109
+ <div className="flex flex-wrap items-end gap-x-6 gap-y-2">
110
+ <Field id="share-variant" label="Variant" className="w-full sm:w-80">
111
+ <Select id="share-variant" value={key} onChange={(e) => setKey(e.target.value)} options={VARIANTS.map((v) => ({ value: v.key, label: v.label }))} />
112
+ </Field>
113
+ <Switch id="share-fail" label="Fail the next save" checked={fail} onChange={(e) => setFail(e.target.checked)} />
114
+ </div>
115
+
116
+ {key === "empty" ? (
117
+ <Card title="Sharing" description="Nobody else can see the Q4 launch plan yet." className="max-w-xl">
118
+ <SharePanel key={key} {...props} />
119
+ </Card>
120
+ ) : (
121
+ <>
122
+ <div>
123
+ <Button variant="primary" icon={key === "invite" ? "user-plus" : "share"} onClick={() => setOpen(true)}>
124
+ {key === "invite" ? "Invite members" : "Share"}
125
+ </Button>
126
+ </div>
127
+ <ShareDialog key={key} open={open} onClose={() => setOpen(false)} {...props} />
128
+ {/* The same body inline, so the page shows it without opening the dialog. */}
129
+ <Card title={props.title} description={props.description} className="max-w-lg">
130
+ <SharePanel {...props} />
131
+ </Card>
132
+ </>
133
+ )}
134
+
135
+ <p className="min-h-5 break-all text-xs text-muted-foreground" aria-live="polite">
136
+ {log ? `Saved — ${log}` : "Invite, change access or copy the link to see what the callbacks receive."}
137
+ </p>
138
+ </div>
139
+ );
140
+ }
@@ -0,0 +1,3 @@
1
+ // The ShareDialog block — `makersclaw add share-dialog`. Fixed: compose
2
+ // it through its props (README.md beside this file).
3
+ export { ShareDialog, SharePanel } from "./share-dialog";
@@ -0,0 +1,384 @@
1
+ "use client";
2
+
3
+ import { useEffect, useId, useRef, useState } from "react";
4
+ import { Avatar, Badge, Button, Icon, InputGroup, Item, Menu, Notice, Select, Sheet, Switch, cx } from "../../ui";
5
+
6
+ // ShareDialog — who can see a thing, and how to let more people in:
7
+ // invite by email, each person's access, a link to copy, a few sharing
8
+ // switches. SharePanel is the same body without the dialog, for a
9
+ // settings page. Every change goes out through an async callback that
10
+ // returns { ok } or { ok: false, error }; the dialog shows the failure
11
+ // and puts the old value back. See README.md beside this file.
12
+
13
+ const DEFAULT_ROLES = [
14
+ { value: "view", label: "Can view" },
15
+ { value: "edit", label: "Can edit" },
16
+ ];
17
+
18
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
19
+
20
+ function failure(result) {
21
+ return result && result.ok === false ? result.error || "That did not save. Try again." : null;
22
+ }
23
+
24
+ async function attempt(fn) {
25
+ try {
26
+ return failure(await fn());
27
+ } catch (e) {
28
+ return e?.message || String(e);
29
+ }
30
+ }
31
+
32
+ /** "a@x.com, b@y.com; c@z.com" → { good: [...], bad: [...] }, deduped. */
33
+ function parseEmails(text) {
34
+ const all = String(text)
35
+ .split(/[\s,;]+/)
36
+ .map((s) => s.trim())
37
+ .filter(Boolean);
38
+ const seen = new Set();
39
+ const good = [];
40
+ const bad = [];
41
+ for (const e of all) {
42
+ const k = e.toLowerCase();
43
+ if (seen.has(k)) continue;
44
+ seen.add(k);
45
+ (EMAIL.test(e) ? good : bad).push(e);
46
+ }
47
+ return { good, bad };
48
+ }
49
+
50
+ function InviteRow({ onInvite, roles, inviteRole, placeholder, people, label }) {
51
+ const id = useId();
52
+ const [text, setText] = useState("");
53
+ const [role, setRole] = useState(inviteRole ?? roles[0]?.value);
54
+ const [busy, setBusy] = useState(false);
55
+ const [error, setError] = useState(null);
56
+ const [note, setNote] = useState(null);
57
+
58
+ async function submit(e) {
59
+ e.preventDefault();
60
+ if (busy) return;
61
+ setNote(null);
62
+ const { good, bad } = parseEmails(text);
63
+ if (!good.length && !bad.length) {
64
+ setError("Type at least one email address.");
65
+ return;
66
+ }
67
+ if (bad.length) {
68
+ setError(`${bad.join(", ")} ${bad.length === 1 ? "is not an email address" : "are not email addresses"}.`);
69
+ return;
70
+ }
71
+ const have = new Set((people ?? []).map((p) => String(p.email ?? "").toLowerCase()));
72
+ const fresh = good.filter((e) => !have.has(e.toLowerCase()));
73
+ if (!fresh.length) {
74
+ setError(good.length === 1 ? `${good[0]} already has access.` : "Everyone listed already has access.");
75
+ return;
76
+ }
77
+ setError(null);
78
+ setBusy(true);
79
+ const failed = await attempt(() => onInvite(fresh, role));
80
+ setBusy(false);
81
+ if (failed) {
82
+ setError(failed);
83
+ return;
84
+ }
85
+ setText("");
86
+ setNote(fresh.length === 1 ? `Invited ${fresh[0]}.` : `Invited ${fresh.length} people.`);
87
+ }
88
+
89
+ const picker =
90
+ roles.length > 1 && !inviteRole ? (
91
+ <Select
92
+ aria-label="Access for the people you invite"
93
+ value={role}
94
+ onChange={(e) => setRole(e.target.value)}
95
+ options={roles}
96
+ disabled={busy}
97
+ className="sm:w-36"
98
+ />
99
+ ) : null;
100
+
101
+ return (
102
+ <form onSubmit={submit} className="grid gap-2" noValidate>
103
+ <label htmlFor={id} className="text-sm font-medium text-foreground">
104
+ {label}
105
+ </label>
106
+ <div className="flex flex-col gap-2 sm:flex-row">
107
+ <div className="min-w-0 flex-1">
108
+ <InputGroup
109
+ id={id}
110
+ icon="user-plus"
111
+ type="text"
112
+ inputMode="email"
113
+ autoComplete="off"
114
+ placeholder={placeholder}
115
+ value={text}
116
+ onChange={(e) => {
117
+ setText(e.target.value);
118
+ if (error) setError(null);
119
+ }}
120
+ invalid={Boolean(error)}
121
+ aria-describedby={error ? `${id}-error` : note ? `${id}-note` : undefined}
122
+ disabled={busy}
123
+ />
124
+ </div>
125
+ {picker}
126
+ <Button type="submit" variant="primary" loading={busy}>
127
+ Invite
128
+ </Button>
129
+ </div>
130
+ {error ? (
131
+ <p id={`${id}-error`} role="alert" className="text-xs text-destructive">
132
+ {error}
133
+ </p>
134
+ ) : note ? (
135
+ <p id={`${id}-note`} role="status" className="text-xs text-muted-foreground">
136
+ {note}
137
+ </p>
138
+ ) : null}
139
+ </form>
140
+ );
141
+ }
142
+
143
+ function PersonRow({ person, roles, onRoleChange, onRemove, onError, you }) {
144
+ const [role, setRole] = useState(person.role);
145
+ const [busy, setBusy] = useState(false);
146
+ useEffect(() => setRole(person.role), [person.role]);
147
+
148
+ const known = roles.find((r) => r.value === role);
149
+ const editable = !person.locked && known && (onRoleChange || onRemove);
150
+
151
+ async function change(next) {
152
+ if (next === role || busy) return;
153
+ const before = role;
154
+ setRole(next); // shows at once; goes back if the save fails
155
+ setBusy(true);
156
+ const failed = await attempt(() => onRoleChange(person, next));
157
+ setBusy(false);
158
+ if (failed) {
159
+ setRole(before);
160
+ onError(`${person.name ?? person.email}: ${failed}`);
161
+ }
162
+ }
163
+
164
+ async function remove() {
165
+ setBusy(true);
166
+ const failed = await attempt(() => onRemove(person));
167
+ setBusy(false);
168
+ if (failed) onError(`${person.name ?? person.email} still has access: ${failed}`);
169
+ }
170
+
171
+ const roleLabel = known?.label ?? person.roleLabel ?? String(role ?? "");
172
+
173
+ const items = editable
174
+ ? [
175
+ onRoleChange && { type: "radio", label: "Access", value: role, onValueChange: change, options: roles },
176
+ onRoleChange && onRemove && { type: "separator" },
177
+ onRemove && { label: "Remove access", icon: "trash", tone: "danger", onSelect: remove },
178
+ ]
179
+ : [];
180
+
181
+ const meta = editable ? (
182
+ <Menu
183
+ label={`${roleLabel}, access for ${person.name ?? person.email}`}
184
+ trigger={
185
+ <span className="inline-flex items-center gap-1 text-sm">
186
+ {busy ? <span className="text-muted-foreground">Saving…</span> : roleLabel}
187
+ <Icon name="chevron-down" size={14} className="text-muted-foreground" />
188
+ </span>
189
+ }
190
+ items={items}
191
+ />
192
+ ) : (
193
+ <Badge variant="outline">{roleLabel}</Badge>
194
+ );
195
+
196
+ return (
197
+ <li>
198
+ <Item
199
+ size="sm"
200
+ media={<Avatar name={person.name ?? person.email} src={person.src} size="sm" />}
201
+ title={
202
+ <>
203
+ {person.name ?? person.email}
204
+ {you ? <span className="font-normal text-muted-foreground"> (you)</span> : null}
205
+ </>
206
+ }
207
+ description={person.name ? person.email : person.pending ? "Invite sent" : undefined}
208
+ meta={person.pending && person.name ? <Badge variant="soft">Invited</Badge> : undefined}
209
+ actions={meta}
210
+ className={cx(busy && "opacity-70")}
211
+ />
212
+ </li>
213
+ );
214
+ }
215
+
216
+ function LinkRow({ link, onCopy, onPreview, previewHref, label }) {
217
+ const id = useId();
218
+ const [copied, setCopied] = useState(false);
219
+ const [error, setError] = useState(null);
220
+ const timer = useRef(null);
221
+ useEffect(() => () => clearTimeout(timer.current), []);
222
+
223
+ async function copy() {
224
+ setError(null);
225
+ let failed = null;
226
+ try {
227
+ if (!navigator.clipboard?.writeText) throw new Error("This browser blocks copying. Select the link and copy it by hand.");
228
+ await navigator.clipboard.writeText(link);
229
+ failed = await attempt(() => onCopy?.(link));
230
+ } catch (e) {
231
+ failed = e?.message || "Copying failed. Select the link and copy it by hand.";
232
+ }
233
+ if (failed) {
234
+ setError(failed);
235
+ return;
236
+ }
237
+ setCopied(true);
238
+ clearTimeout(timer.current);
239
+ timer.current = setTimeout(() => setCopied(false), 1600);
240
+ }
241
+
242
+ return (
243
+ <div className="grid gap-2">
244
+ <label htmlFor={id} className="text-sm font-medium text-foreground">
245
+ {label}
246
+ </label>
247
+ <InputGroup
248
+ id={id}
249
+ icon="link"
250
+ readOnly
251
+ value={link}
252
+ onFocus={(e) => e.target.select()}
253
+ action={{ label: copied ? "Copied" : "Copy link", icon: copied ? "check" : "copy", onClick: copy }}
254
+ />
255
+ <p role="status" className={cx("text-xs", error ? "text-destructive" : "text-muted-foreground", !error && !copied && "sr-only")}>
256
+ {error ?? (copied ? "Link copied." : "")}
257
+ </p>
258
+ <div className="flex flex-col gap-2 sm:flex-row">
259
+ <Button variant="secondary" icon={copied ? "check" : "copy"} onClick={copy} className="sm:flex-1">
260
+ {copied ? "Copied" : "Copy link"}
261
+ </Button>
262
+ {previewHref || onPreview ? (
263
+ <Button variant="secondary" icon="external" href={previewHref} onClick={onPreview} target={previewHref ? "_blank" : undefined} rel={previewHref ? "noreferrer" : undefined} className="sm:flex-1">
264
+ Preview
265
+ </Button>
266
+ ) : null}
267
+ </div>
268
+ </div>
269
+ );
270
+ }
271
+
272
+ function SettingRow({ setting, onSettingChange, onError }) {
273
+ const id = useId();
274
+ const [on, setOn] = useState(Boolean(setting.checked));
275
+ const [busy, setBusy] = useState(false);
276
+ useEffect(() => setOn(Boolean(setting.checked)), [setting.checked]);
277
+
278
+ async function toggle(e) {
279
+ const next = e.target.checked;
280
+ setOn(next);
281
+ setBusy(true);
282
+ const failed = await attempt(() => onSettingChange?.(setting.id, next));
283
+ setBusy(false);
284
+ if (failed) {
285
+ setOn(!next);
286
+ onError(`${setting.label}: ${failed}`);
287
+ }
288
+ }
289
+
290
+ return (
291
+ <div className="flex items-center justify-between gap-4 rounded-md border border-border px-3">
292
+ <div className="min-w-0 py-2">
293
+ <label htmlFor={id} className="flex items-center gap-2 text-sm font-medium">
294
+ {setting.icon ? <Icon name={setting.icon} size={16} className="shrink-0 text-muted-foreground" /> : null}
295
+ {setting.label}
296
+ </label>
297
+ {setting.description ? <p className="text-xs text-muted-foreground">{setting.description}</p> : null}
298
+ </div>
299
+ <Switch id={id} checked={on} onChange={toggle} disabled={busy || setting.disabled} />
300
+ </div>
301
+ );
302
+ }
303
+
304
+ /** The body: invite, people, settings, link — each shows when its data or
305
+ * callback is given. */
306
+ export function SharePanel({
307
+ people,
308
+ roles = DEFAULT_ROLES,
309
+ onInvite,
310
+ inviteRole,
311
+ onRoleChange,
312
+ onRemove,
313
+ link,
314
+ onCopy,
315
+ onPreview,
316
+ previewHref,
317
+ settings,
318
+ onSettingChange,
319
+ youId,
320
+ inviteLabel = "Invite by email",
321
+ invitePlaceholder = "Emails, separated by commas",
322
+ peopleLabel = "People with access",
323
+ linkLabel = "Share link",
324
+ empty = "Only you have access so far.",
325
+ className,
326
+ }) {
327
+ const [error, setError] = useState(null);
328
+ const list = people ?? null;
329
+
330
+ return (
331
+ <div className={cx("grid gap-5", className)}>
332
+ {onInvite ? <InviteRow onInvite={onInvite} roles={roles} inviteRole={inviteRole} placeholder={invitePlaceholder} people={list} label={inviteLabel} /> : null}
333
+
334
+ {settings?.length ? (
335
+ <div className="grid gap-2">
336
+ {settings.map((s) => (
337
+ <SettingRow key={s.id} setting={s} onSettingChange={onSettingChange} onError={setError} />
338
+ ))}
339
+ </div>
340
+ ) : null}
341
+
342
+ {list ? (
343
+ <section className="grid gap-1" aria-label={peopleLabel}>
344
+ <h3 className="text-sm font-medium">{peopleLabel}</h3>
345
+ {list.length ? (
346
+ <ul className="grid divide-y divide-border">
347
+ {list.map((p) => (
348
+ <PersonRow
349
+ key={p.id ?? p.email}
350
+ person={p}
351
+ roles={roles}
352
+ onRoleChange={onRoleChange}
353
+ onRemove={onRemove}
354
+ onError={setError}
355
+ you={youId != null && (p.id ?? p.email) === youId}
356
+ />
357
+ ))}
358
+ </ul>
359
+ ) : (
360
+ <p className="py-3 text-sm text-muted-foreground">{empty}</p>
361
+ )}
362
+ </section>
363
+ ) : null}
364
+
365
+ {error ? (
366
+ <Notice tone="danger" onDismiss={() => setError(null)}>
367
+ {error}
368
+ </Notice>
369
+ ) : null}
370
+
371
+ {link ? <LinkRow link={link} onCopy={onCopy} onPreview={onPreview} previewHref={previewHref} label={linkLabel} /> : null}
372
+ </div>
373
+ );
374
+ }
375
+
376
+ /** SharePanel in the kit's Sheet: a dialog on a wide window, a bottom
377
+ * sheet on a phone. Controlled: `open` + `onClose`. */
378
+ export function ShareDialog({ open, onClose, title = "Share", description, footer, className, ...panel }) {
379
+ return (
380
+ <Sheet open={open} onClose={onClose} side="center" title={title} description={description} footer={footer} className={className}>
381
+ {open ? <SharePanel {...panel} /> : null}
382
+ </Sheet>
383
+ );
384
+ }