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,623 @@
1
+ "use client";
2
+
3
+ // AudioPlayer — a waveform player in the workspace theme (wavesurfer.js
4
+ // underneath). Play, skip, speed and mute; regions (spans of the audio in
5
+ // a tone: a topic, a speaker turn, a clip) and markers (moments: a
6
+ // comment, a flag); a hover time readout; drag across the waveform to
7
+ // mark a new region; keyboard throughout.
8
+ //
9
+ // What is ours and what is wavesurfer's: wavesurfer decodes the audio,
10
+ // plays it and paints the waveform on its canvas. Everything drawn over
11
+ // or around the waveform — regions, markers, the hover line, the drag
12
+ // selection, the controls, the loading and error states — is ours, in the
13
+ // kit and in tokens, so it follows the theme like any other block. The
14
+ // canvas's own colours are read from the tokens at run time (colors.js).
15
+ //
16
+ // Client only in effect, not in import: the modules load anywhere, the
17
+ // wavesurfer instance is created in an effect. The server (and the first
18
+ // paint) shows the frame with a skeleton waveform.
19
+ import { useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef, useState } from "react";
20
+ import { Button, Empty, IconButton, Menu, Notice, Tooltip, cx } from "../../ui";
21
+ import { useWavesurfer } from "./wavesurfer";
22
+ import { readTokens, waveColours, watchTheme } from "./colors";
23
+ import { RATES, clamp, cleanMarkers, cleanRegions, formatRange, formatRate, formatTime, regionAt, spokenTime } from "./time";
24
+
25
+ /** A ref for the player's handle: `const player = useAudioPlayer()`, then
26
+ * `<AudioPlayer playerRef={player} />` and `player.current?.seek(42)`. */
27
+ export function useAudioPlayer() {
28
+ return useRef(null);
29
+ }
30
+
31
+ // Tailwind needs whole class names in the source: one per tone.
32
+ const TONE = {
33
+ primary: { dot: "bg-primary", band: "bg-primary/10", active: "bg-primary/20", line: "bg-primary/60" },
34
+ "chart-2": { dot: "bg-chart-2", band: "bg-chart-2/10", active: "bg-chart-2/25", line: "bg-chart-2/60" },
35
+ "chart-3": { dot: "bg-chart-3", band: "bg-chart-3/10", active: "bg-chart-3/25", line: "bg-chart-3/60" },
36
+ "chart-4": { dot: "bg-chart-4", band: "bg-chart-4/10", active: "bg-chart-4/25", line: "bg-chart-4/60" },
37
+ "chart-5": { dot: "bg-chart-5", band: "bg-chart-5/10", active: "bg-chart-5/25", line: "bg-chart-5/60" },
38
+ success: { dot: "bg-success", band: "bg-success/10", active: "bg-success/20", line: "bg-success/60" },
39
+ warning: { dot: "bg-warning", band: "bg-warning/10", active: "bg-warning/20", line: "bg-warning/60" },
40
+ info: { dot: "bg-info", band: "bg-info/10", active: "bg-info/20", line: "bg-info/60" },
41
+ destructive: { dot: "bg-destructive", band: "bg-destructive/10", active: "bg-destructive/20", line: "bg-destructive/60" },
42
+ muted: { dot: "bg-muted-foreground", band: "bg-muted-foreground/10", active: "bg-muted-foreground/20", line: "bg-muted-foreground/50" },
43
+ };
44
+ const tone = (t, fallback = "primary") => TONE[t] ?? TONE[fallback];
45
+
46
+ const WAVE_HEIGHT = 72;
47
+ const DRAG_PX = 4; // a press that moves less than this is a click (seek)
48
+ const MIN_REGION = 0.5; // seconds: a shorter drag is treated as a click
49
+ const EDITABLE = /^(INPUT|TEXTAREA|SELECT)$/;
50
+
51
+ // The skeleton's bars: a fixed, gentle shape (no randomness: the server
52
+ // and the first client paint must match).
53
+ const SKELETON = Array.from({ length: 72 }, (_, i) => 22 + Math.round(38 * Math.abs(Math.sin(i * 0.37) * Math.cos(i * 0.11))));
54
+
55
+ export function AudioPlayer({
56
+ src,
57
+ peaks,
58
+ duration: knownDuration,
59
+ title,
60
+ description,
61
+ regions,
62
+ markers,
63
+ onAddMarker,
64
+ onRegionCreate,
65
+ onMarkerClick,
66
+ onRegionClick,
67
+ onActiveRegionChange,
68
+ onReady,
69
+ onPlay,
70
+ onPause,
71
+ onFinish,
72
+ onSeek,
73
+ onTimeUpdate,
74
+ onError,
75
+ rates = RATES,
76
+ defaultRate = 1,
77
+ skipSeconds = 15,
78
+ emptyTitle = "No recording yet",
79
+ emptyBody = "When there is audio to play, it shows up here.",
80
+ emptyAction,
81
+ bare = false,
82
+ playerRef,
83
+ className,
84
+ }) {
85
+ const rootRef = useRef(null);
86
+ const waveRef = useRef(null);
87
+ const surfaceRef = useRef(null);
88
+ const tipId = useId();
89
+
90
+ // A Blob plays through an object URL, made here and revoked when it goes.
91
+ const isBlob = typeof Blob !== "undefined" && src instanceof Blob;
92
+ const [blobUrl, setBlobUrl] = useState(null);
93
+ useEffect(() => {
94
+ if (!isBlob) return setBlobUrl(null);
95
+ const u = URL.createObjectURL(src);
96
+ setBlobUrl(u);
97
+ return () => URL.revokeObjectURL(u);
98
+ }, [src, isBlob]);
99
+ const url = typeof src === "string" && src ? src : isBlob ? blobUrl ?? undefined : undefined;
100
+ const hasAudio = Boolean((typeof src === "string" && src) || isBlob || peaks);
101
+
102
+ // The instance. Every key is always passed (the hook's effect depends on
103
+ // the list of values; its length must not change) and none of them is a
104
+ // colour: colours are set after, so a theme change repaints instead of
105
+ // rebuilding the player.
106
+ const { wavesurfer: ws, isReady, isPlaying, currentTime } = useWavesurfer({
107
+ container: waveRef,
108
+ url,
109
+ peaks,
110
+ duration: knownDuration,
111
+ height: WAVE_HEIGHT,
112
+ barWidth: 2,
113
+ barGap: 2,
114
+ barRadius: 2,
115
+ cursorWidth: 2,
116
+ normalize: true,
117
+ interact: false,
118
+ hideScrollbar: true,
119
+ autoScroll: false,
120
+ });
121
+
122
+ const [duration, setDuration] = useState(knownDuration > 0 ? knownDuration : 0);
123
+ const [error, setError] = useState(null);
124
+ const [rate, setRate] = useState(defaultRate);
125
+ const [muted, setMuted] = useState(false);
126
+ const [notice, setNotice] = useState(null);
127
+ const [pending, setPending] = useState({ markers: [], regions: [] });
128
+ const [hover, setHover] = useState(null); // ratio 0..1 under the pointer
129
+ const [draft, setDraft] = useState(null); // { a, b } ratios while dragging a region
130
+ const [width, setWidth] = useState(0);
131
+ const drag = useRef(null);
132
+
133
+ // The latest callbacks, so the instance's listeners never go stale.
134
+ const cbs = useRef({});
135
+ cbs.current = { onReady, onPlay, onPause, onFinish, onTimeUpdate, onError };
136
+
137
+ // Settings the instance must keep across a reload (a new src).
138
+ const settings = useRef({ rate, muted });
139
+ settings.current = { rate, muted };
140
+
141
+ useEffect(() => {
142
+ if (!ws) return;
143
+ setError(null);
144
+ const off = [
145
+ ws.on("ready", (d) => {
146
+ setDuration(d);
147
+ setError(null);
148
+ ws.setPlaybackRate(settings.current.rate);
149
+ ws.setMuted(settings.current.muted);
150
+ cbs.current.onReady?.({ duration: d });
151
+ }),
152
+ ws.on("decode", (d) => setDuration(d)),
153
+ ws.on("play", () => cbs.current.onPlay?.()),
154
+ ws.on("pause", () => cbs.current.onPause?.()),
155
+ ws.on("finish", () => cbs.current.onFinish?.()),
156
+ ws.on("timeupdate", (t) => cbs.current.onTimeUpdate?.(t)),
157
+ ws.on("error", (e) => {
158
+ setError(e ?? new Error("The audio could not be loaded."));
159
+ cbs.current.onError?.(e);
160
+ }),
161
+ ];
162
+ return () => off.forEach((f) => f());
163
+ }, [ws]);
164
+
165
+ // The canvas's colours, from the tokens where the player sits; again
166
+ // whenever the theme or the scheme changes.
167
+ useEffect(() => {
168
+ if (!ws) return;
169
+ return watchTheme(rootRef.current, () => {
170
+ const c = waveColours(readTokens(rootRef.current, ["foreground", "muted-foreground", "primary"]));
171
+ const opts = Object.fromEntries(Object.entries(c).filter(([, v]) => v));
172
+ if (Object.keys(opts).length) ws.setOptions(opts);
173
+ });
174
+ }, [ws]);
175
+
176
+ // The waveform's width in pixels: for hiding labels that would not fit.
177
+ useEffect(() => {
178
+ const el = surfaceRef.current;
179
+ if (!el || typeof ResizeObserver === "undefined") return;
180
+ const ro = new ResizeObserver(([e]) => setWidth(e.contentRect.width));
181
+ ro.observe(el);
182
+ return () => ro.disconnect();
183
+ }, []);
184
+
185
+ const ready = Boolean(ws && isReady && duration > 0 && !error);
186
+ const shownRegions = useMemo(() => cleanRegions([...(regions ?? []), ...pending.regions], duration), [regions, pending.regions, duration]);
187
+ const shownMarkers = useMemo(() => cleanMarkers([...(markers ?? []), ...pending.markers], duration), [markers, pending.markers, duration]);
188
+ const active = ready ? regionAt(shownRegions, currentTime) : null;
189
+
190
+ // The region under the playhead, told once per change (transcript sync).
191
+ const lastActive = useRef(undefined);
192
+ useEffect(() => {
193
+ const id = active?.id ?? null;
194
+ if (lastActive.current === id) return;
195
+ lastActive.current = id;
196
+ onActiveRegionChange?.(active ?? null);
197
+ }, [active, onActiveRegionChange]);
198
+
199
+ // ---- actions --------------------------------------------------------------
200
+
201
+ const seek = useCallback(
202
+ (t) => {
203
+ if (!ws || !(duration > 0)) return;
204
+ const to = clamp(t, 0, duration);
205
+ ws.setTime(to);
206
+ onSeek?.(to);
207
+ },
208
+ [ws, duration, onSeek],
209
+ );
210
+ const skip = useCallback((d) => ws && seek(ws.getCurrentTime() + d), [ws, seek]);
211
+ // play() can be refused by the browser (no user gesture yet): not an error to show.
212
+ const quiet = (p) => p?.catch?.(() => {});
213
+ const toggle = useCallback(() => ready && quiet(ws.playPause()), [ready, ws]);
214
+ const changeRate = useCallback(
215
+ (r) => {
216
+ setRate(r);
217
+ ws?.setPlaybackRate(r);
218
+ },
219
+ [ws],
220
+ );
221
+ const toggleMute = useCallback(() => {
222
+ setMuted((m) => {
223
+ ws?.setMuted(!m);
224
+ return !m;
225
+ });
226
+ }, [ws]);
227
+ const playRange = useCallback(
228
+ (start, end) => {
229
+ if (!ready) return;
230
+ onSeek?.(start);
231
+ quiet(ws.play(clamp(start, 0, duration), end == null ? undefined : clamp(end, 0, duration)));
232
+ },
233
+ [ready, ws, duration, onSeek],
234
+ );
235
+ const retry = useCallback(() => {
236
+ if (!ws || !url) return;
237
+ setError(null);
238
+ ws.load(url).catch(() => {});
239
+ }, [ws, url]);
240
+
241
+ // Optimistic: the marker shows at once, dimmed, and goes if the save fails.
242
+ const addMarker = useCallback(async () => {
243
+ if (!onAddMarker || !ready) return;
244
+ const time = ws.getCurrentTime();
245
+ const temp = { id: `pending-${Date.now()}`, time, label: "Saving…", tone: "muted", pending: true };
246
+ setPending((p) => ({ ...p, markers: [...p.markers, temp] }));
247
+ setNotice(null);
248
+ let res;
249
+ try {
250
+ res = await onAddMarker({ time });
251
+ } catch (e) {
252
+ res = { ok: false, error: e?.message };
253
+ }
254
+ setPending((p) => ({ ...p, markers: p.markers.filter((m) => m.id !== temp.id) }));
255
+ if (!res?.ok) setNotice(`Couldn't add the marker at ${formatTime(time)}. ${res?.error || "Try again."}`);
256
+ }, [onAddMarker, ready, ws]);
257
+
258
+ const createRegion = useCallback(
259
+ async (start, end) => {
260
+ if (!onRegionCreate) return;
261
+ const temp = { id: `pending-${Date.now()}`, start, end, label: "Saving…", tone: "muted", pending: true };
262
+ setPending((p) => ({ ...p, regions: [...p.regions, temp] }));
263
+ setNotice(null);
264
+ let res;
265
+ try {
266
+ res = await onRegionCreate({ start, end });
267
+ } catch (e) {
268
+ res = { ok: false, error: e?.message };
269
+ }
270
+ setPending((p) => ({ ...p, regions: p.regions.filter((r) => r.id !== temp.id) }));
271
+ if (!res?.ok) setNotice(`Couldn't save the region ${formatRange(start, end)}. ${res?.error || "Try again."}`);
272
+ },
273
+ [onRegionCreate],
274
+ );
275
+
276
+ useImperativeHandle(
277
+ playerRef,
278
+ () => ({
279
+ play: () => ready && quiet(ws.play()),
280
+ pause: () => ws?.pause(),
281
+ toggle,
282
+ seek,
283
+ skip,
284
+ playRange,
285
+ playRegion: (id) => {
286
+ const r = shownRegions.find((x) => x.id === id);
287
+ if (r) playRange(r.start, r.end);
288
+ },
289
+ setRate: changeRate,
290
+ setMuted: (m) => {
291
+ setMuted(Boolean(m));
292
+ ws?.setMuted(Boolean(m));
293
+ },
294
+ addMarker,
295
+ getTime: () => ws?.getCurrentTime() ?? 0,
296
+ getDuration: () => duration,
297
+ isPlaying: () => Boolean(ws?.isPlaying()),
298
+ isReady: () => ready,
299
+ }),
300
+ [ready, ws, toggle, seek, skip, playRange, shownRegions, changeRate, addMarker, duration],
301
+ );
302
+
303
+ // ---- pointer and keys on the waveform ---------------------------------------
304
+
305
+ const ratioAt = (e) => {
306
+ const r = surfaceRef.current?.getBoundingClientRect();
307
+ return r && r.width ? clamp((e.clientX - r.left) / r.width, 0, 1) : 0;
308
+ };
309
+
310
+ function onPointerDown(e) {
311
+ if (!ready || e.button > 0) return;
312
+ e.currentTarget.setPointerCapture?.(e.pointerId);
313
+ drag.current = { x: e.clientX, start: ratioAt(e), moved: false };
314
+ }
315
+ function onPointerMove(e) {
316
+ const ratio = ratioAt(e);
317
+ if (e.pointerType !== "touch") setHover(ratio);
318
+ const d = drag.current;
319
+ if (!d) return;
320
+ if (!d.moved && Math.abs(e.clientX - d.x) < DRAG_PX) return;
321
+ d.moved = true;
322
+ if (onRegionCreate) setDraft({ a: d.start, b: ratio });
323
+ else seek(ratio * duration); // no regions to make: a drag scrubs
324
+ }
325
+ function onPointerUp(e) {
326
+ const d = drag.current;
327
+ drag.current = null;
328
+ if (!d) return;
329
+ const ratio = ratioAt(e);
330
+ if (!d.moved) return seek(ratio * duration);
331
+ if (onRegionCreate) {
332
+ setDraft(null);
333
+ const start = Math.min(d.start, ratio) * duration;
334
+ const end = Math.max(d.start, ratio) * duration;
335
+ if (end - start >= MIN_REGION) createRegion(start, end);
336
+ else seek(ratio * duration);
337
+ }
338
+ }
339
+ function onPointerCancel() {
340
+ drag.current = null;
341
+ setDraft(null);
342
+ }
343
+
344
+ function onSurfaceKey(e) {
345
+ if (!ready) return;
346
+ const small = 5;
347
+ const moves = { ArrowLeft: -small, ArrowRight: small, PageDown: -skipSeconds, PageUp: skipSeconds };
348
+ if (e.key in moves) {
349
+ e.preventDefault();
350
+ skip(moves[e.key]);
351
+ } else if (e.key === "Home") {
352
+ e.preventDefault();
353
+ seek(0);
354
+ } else if (e.key === "End") {
355
+ e.preventDefault();
356
+ seek(duration);
357
+ } else if (e.key === " " || e.key === "Enter") {
358
+ e.preventDefault();
359
+ toggle();
360
+ }
361
+ }
362
+
363
+ // Player-wide letters, like a video player: K play/pause, J/L skip, M
364
+ // marker. Never while typing, never with a modifier (those are the app's).
365
+ function onRootKey(e) {
366
+ if (!ready || e.metaKey || e.ctrlKey || e.altKey || e.defaultPrevented) return;
367
+ const t = e.target;
368
+ if (EDITABLE.test(t?.tagName ?? "") || t?.isContentEditable) return;
369
+ const k = e.key.toLowerCase();
370
+ if (k === "k") toggle();
371
+ else if (k === "j") skip(-skipSeconds);
372
+ else if (k === "l") skip(skipSeconds);
373
+ else if (k === "m" && onAddMarker) addMarker();
374
+ else return;
375
+ e.preventDefault();
376
+ }
377
+
378
+ // ---- render -----------------------------------------------------------------
379
+
380
+ const frame = bare ? "" : "rounded-lg border border-border bg-card p-4 sm:p-5";
381
+
382
+ if (!hasAudio) {
383
+ return (
384
+ <div className={cx(frame, className)}>
385
+ <Header title={title} description={description} />
386
+ <Empty icon="mic" title={emptyTitle} body={emptyBody} action={emptyAction} className={title || description ? "mt-4" : ""} />
387
+ </div>
388
+ );
389
+ }
390
+
391
+ const pct = (t) => `${(duration > 0 ? (t / duration) * 100 : 0).toFixed(3)}%`;
392
+ const draftSpan = draft ? { from: Math.min(draft.a, draft.b), to: Math.max(draft.a, draft.b) } : null;
393
+ const loading = !ready && !error;
394
+
395
+ return (
396
+ <div ref={rootRef} className={cx(frame, "text-card-foreground", className)} onKeyDown={onRootKey}>
397
+ <Header title={title} description={description} />
398
+
399
+ {/* Markers: pins above the waveform. */}
400
+ <div className={cx("relative h-6", (title || description) && "mt-3")}>
401
+ {ready
402
+ ? shownMarkers.map((m) => (
403
+ <div key={m.id} className="absolute top-0 -translate-x-1/2" style={{ left: pct(m.time) }}>
404
+ <Tooltip label={`${formatTime(m.time)} · ${m.label ?? "Marker"}`} delay={150}>
405
+ {/* raw: a pin placed on the timeline at its moment — a kit Button cannot be positioned by time or be this small */}
406
+ <button
407
+ type="button"
408
+ disabled={m.pending}
409
+ aria-label={`${m.label ?? "Marker"}, at ${spokenTime(m.time)}`}
410
+ onClick={() => {
411
+ seek(m.time);
412
+ onMarkerClick?.(m);
413
+ }}
414
+ className="group grid size-6 place-items-center rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default"
415
+ >
416
+ <span
417
+ className={cx(
418
+ "size-2.5 rounded-full ring-2 ring-card transition-transform duration-150 group-hover:scale-125 group-focus-visible:scale-125 motion-reduce:transition-none",
419
+ tone(m.tone).dot,
420
+ m.pending && "animate-pulse motion-reduce:animate-none",
421
+ Math.abs(currentTime - m.time) < 0.75 && "scale-125",
422
+ )}
423
+ />
424
+ </button>
425
+ </Tooltip>
426
+ </div>
427
+ ))
428
+ : null}
429
+ </div>
430
+
431
+ {/* The waveform: wavesurfer's canvas, with our layer over it. */}
432
+ <div className="relative" style={{ height: WAVE_HEIGHT }}>
433
+ <div ref={waveRef} className={cx("w-full transition-opacity duration-150 motion-reduce:transition-none", loading && "opacity-0")} />
434
+
435
+ {loading ? (
436
+ <div aria-hidden="true" className="pointer-events-none absolute inset-0 flex items-center gap-[2px] overflow-hidden">
437
+ {SKELETON.map((h, i) => (
438
+ <span key={i} className="w-[2px] flex-1 animate-pulse rounded-full bg-muted motion-reduce:animate-none" style={{ height: `${h}%` }} />
439
+ ))}
440
+ </div>
441
+ ) : null}
442
+
443
+ {error ? (
444
+ <div className="absolute inset-0 flex items-center">
445
+ <span aria-hidden="true" className="h-px w-full bg-border" />
446
+ </div>
447
+ ) : null}
448
+
449
+ {/* raw: the seek surface — a slider over a canvas; the kit Slider is a native range input and cannot host the waveform, regions or markers */}
450
+ <div
451
+ ref={surfaceRef}
452
+ role="slider"
453
+ tabIndex={ready ? 0 : -1}
454
+ aria-label="Seek"
455
+ aria-valuemin={0}
456
+ aria-valuemax={Math.round(duration)}
457
+ aria-valuenow={Math.round(currentTime)}
458
+ aria-valuetext={`${spokenTime(currentTime)} of ${spokenTime(duration)}`}
459
+ aria-disabled={!ready || undefined}
460
+ aria-describedby={tipId}
461
+ onKeyDown={onSurfaceKey}
462
+ onPointerDown={onPointerDown}
463
+ onPointerMove={onPointerMove}
464
+ onPointerUp={onPointerUp}
465
+ onPointerCancel={onPointerCancel}
466
+ onPointerLeave={() => setHover(null)}
467
+ className={cx(
468
+ "absolute inset-0 z-10 touch-pan-y rounded-md outline-none select-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card",
469
+ ready ? (onRegionCreate ? "cursor-crosshair" : "cursor-pointer") : "cursor-default",
470
+ )}
471
+ >
472
+ {ready
473
+ ? shownRegions.map((r) => (
474
+ <span
475
+ key={r.id}
476
+ aria-hidden="true"
477
+ className={cx("pointer-events-none absolute inset-y-0 transition-colors duration-150 motion-reduce:transition-none", active?.id === r.id ? tone(r.tone).active : tone(r.tone).band)}
478
+ style={{ left: pct(r.start), width: pct(r.end - r.start) }}
479
+ />
480
+ ))
481
+ : null}
482
+ {ready
483
+ ? shownMarkers.map((m) => (
484
+ <span key={m.id} aria-hidden="true" className={cx("pointer-events-none absolute inset-y-0 w-px", tone(m.tone).line)} style={{ left: pct(m.time) }} />
485
+ ))
486
+ : null}
487
+
488
+ {draftSpan ? (
489
+ <span
490
+ aria-hidden="true"
491
+ className="pointer-events-none absolute inset-y-0 border-x border-primary bg-primary/15"
492
+ style={{ left: `${draftSpan.from * 100}%`, width: `${(draftSpan.to - draftSpan.from) * 100}%` }}
493
+ />
494
+ ) : null}
495
+
496
+ {ready && hover != null ? (
497
+ <>
498
+ <span aria-hidden="true" className="pointer-events-none absolute inset-y-0 w-px bg-foreground/40" style={{ left: `${hover * 100}%` }} />
499
+ <span
500
+ aria-hidden="true"
501
+ className="pointer-events-none absolute -top-1 z-30 -translate-x-1/2 -translate-y-full rounded-md bg-foreground px-1.5 py-0.5 text-xs font-medium whitespace-nowrap text-background tabular-nums shadow-sm"
502
+ style={{ left: `${clamp(hover * 100, 4, 96)}%` }}
503
+ >
504
+ {draftSpan ? formatRange(draftSpan.from * duration, draftSpan.to * duration) : formatTime(hover * duration)}
505
+ </span>
506
+ </>
507
+ ) : null}
508
+ </div>
509
+ <span id={tipId} className="sr-only">
510
+ {onRegionCreate ? "Click to jump, drag to mark a region. " : "Click or drag to jump. "}
511
+ Arrow keys move 5 seconds, Page Up and Page Down {skipSeconds}, Space plays or pauses.
512
+ </span>
513
+ </div>
514
+
515
+ {/* Regions: labels in a lane under the waveform; a click plays one. */}
516
+ {ready && shownRegions.length ? (
517
+ <div className="relative mt-1.5 h-7">
518
+ {shownRegions.map((r) => {
519
+ const px = ((r.end - r.start) / duration) * width;
520
+ const on = active?.id === r.id;
521
+ return (
522
+ <div key={r.id} className="absolute inset-y-0 px-px" style={{ left: pct(r.start), width: pct(r.end - r.start) }}>
523
+ <Tooltip label={`${r.label ?? "Region"} · ${formatRange(r.start, r.end)}`} delay={300}>
524
+ {/* raw: a segment of the timeline, sized to its span — a kit Button has a fixed height and padding */}
525
+ <button
526
+ type="button"
527
+ disabled={r.pending}
528
+ aria-label={`Play ${r.label ?? "region"}, ${spokenTime(r.start)} to ${spokenTime(r.end)}`}
529
+ aria-current={on || undefined}
530
+ onClick={() => {
531
+ playRange(r.start, r.end);
532
+ onRegionClick?.(r);
533
+ }}
534
+ className="group flex h-7 w-full min-w-0 flex-col gap-1 rounded-sm pt-0.5 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default"
535
+ >
536
+ <span className={cx("h-1 w-full rounded-full transition-opacity duration-150 motion-reduce:transition-none", tone(r.tone).dot, on ? "opacity-100" : "opacity-60 group-hover:opacity-100", r.pending && "animate-pulse motion-reduce:animate-none")} />
537
+ {px >= 44 ? (
538
+ <span className={cx("block w-full truncate text-xs leading-4", on ? "font-medium text-foreground" : "text-muted-foreground group-hover:text-foreground")}>{r.label ?? "Region"}</span>
539
+ ) : null}
540
+ </button>
541
+ </Tooltip>
542
+ </div>
543
+ );
544
+ })}
545
+ </div>
546
+ ) : null}
547
+
548
+ {error ? (
549
+ <Notice
550
+ tone="danger"
551
+ title="Couldn't play this recording"
552
+ className="mt-3"
553
+ action={
554
+ url ? (
555
+ <Button size="sm" variant="secondary" icon="refresh" onClick={retry}>
556
+ Try again
557
+ </Button>
558
+ ) : null
559
+ }
560
+ >
561
+ The file may be missing, or in a format this browser can't play.
562
+ </Notice>
563
+ ) : null}
564
+
565
+ {notice ? (
566
+ <Notice tone="danger" className="mt-3" onDismiss={() => setNotice(null)}>
567
+ {notice}
568
+ </Notice>
569
+ ) : null}
570
+
571
+ {/* Controls: one row on a wide screen; on a phone the transport gets
572
+ its own centred row and the time sits under it with the rest. */}
573
+ <div className="mt-3 flex flex-wrap items-center gap-x-2 gap-y-2">
574
+ <div className="flex w-full items-center justify-center gap-2 sm:w-auto sm:justify-start">
575
+ <Tooltip label={`Back ${skipSeconds}s · J`}>
576
+ <IconButton icon="rotate-ccw" label={`Back ${skipSeconds} seconds`} disabled={!ready} onClick={() => skip(-skipSeconds)} />
577
+ </Tooltip>
578
+ <Tooltip label={isPlaying ? "Pause · K" : "Play · K"}>
579
+ <IconButton icon={isPlaying ? "pause" : "play"} variant="primary" label={isPlaying ? "Pause" : "Play"} disabled={!ready} onClick={toggle} />
580
+ </Tooltip>
581
+ <Tooltip label={`Forward ${skipSeconds}s · L`}>
582
+ <IconButton icon="rotate-cw" label={`Forward ${skipSeconds} seconds`} disabled={!ready} onClick={() => skip(skipSeconds)} />
583
+ </Tooltip>
584
+ </div>
585
+
586
+ <p className="px-1 text-sm whitespace-nowrap text-muted-foreground tabular-nums sm:ml-1">
587
+ <span className="text-foreground">{formatTime(currentTime)}</span>
588
+ <span aria-hidden="true"> / </span>
589
+ <span className="sr-only"> of </span>
590
+ {ready || knownDuration ? formatTime(duration) : "–:––"}
591
+ </p>
592
+
593
+ <div className="ml-auto flex items-center gap-1">
594
+ {onAddMarker ? (
595
+ <Tooltip label="Add a marker here · M">
596
+ <Button size="sm" variant="quiet" icon="flag" disabled={!ready} onClick={addMarker}>
597
+ Marker
598
+ </Button>
599
+ </Tooltip>
600
+ ) : null}
601
+ <Menu
602
+ label={`Playback speed, ${formatRate(rate)}`}
603
+ trigger={<span className="px-1 text-sm font-medium tabular-nums">{formatRate(rate)}</span>}
604
+ items={[{ type: "radio", label: "Speed", value: String(rate), onValueChange: (v) => changeRate(Number(v)), options: rates.map((r) => ({ value: String(r), label: r === 1 ? "Normal" : formatRate(r) })) }]}
605
+ />
606
+ <Tooltip label={muted ? "Unmute" : "Mute"}>
607
+ <IconButton icon={muted ? "volume-x" : "volume"} label={muted ? "Unmute" : "Mute"} size="sm" onClick={toggleMute} aria-pressed={muted} />
608
+ </Tooltip>
609
+ </div>
610
+ </div>
611
+ </div>
612
+ );
613
+ }
614
+
615
+ function Header({ title, description }) {
616
+ if (!title && !description) return null;
617
+ return (
618
+ <div className="min-w-0">
619
+ {title ? <h3 className="truncate text-sm font-medium text-foreground">{title}</h3> : null}
620
+ {description ? <p className="mt-0.5 truncate text-xs text-muted-foreground">{description}</p> : null}
621
+ </div>
622
+ );
623
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "audio-player",
3
+ "title": "AudioPlayer",
4
+ "description": "A waveform audio player (wavesurfer.js) in the workspace theme: play, skip back and forward, speed, mute; regions (spans of the audio in a theme tone, labelled in a lane under the waveform, click to play one) and markers (pins at moments, click to jump); a hover time readout; drag across the waveform to mark a new region; add a marker at the playhead; keyboard like a video player (K, J, L, M, arrows). Time events and a handle (seek, play a range) for syncing a transcript.",
5
+ "useWhen": "A screen plays a recording: a call or meeting recording, a voice note, a podcast clip, a voicemail, a sound file on a record. The call-review block is built on it. Not for video, not for recording audio from the microphone.",
6
+ "tags": ["audio", "player", "waveform", "wavesurfer", "recording", "call", "voice note", "podcast", "regions", "markers", "playback", "speed", "transcript"],
7
+ "exports": ["AudioPlayer", "useAudioPlayer", "formatTime", "formatRange", "spokenTime", "regionAt", "TONES", "RATES"],
8
+ "files": ["index.js", "audio-player.jsx", "wavesurfer.js", "colors.js", "time.js"],
9
+ "requires": [],
10
+ "dependencies": {
11
+ "wavesurfer.js": "8.0.0",
12
+ "@wavesurfer/react": "1.0.12"
13
+ }
14
+ }