makersclaw 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/THIRD-PARTY-NOTICES.md +180 -0
  2. package/package.json +3 -2
  3. package/r/annotate.json +62 -0
  4. package/r/approval-request.json +52 -0
  5. package/r/audio-player.json +74 -0
  6. package/r/auth-form.json +55 -0
  7. package/r/board.json +10 -6
  8. package/r/calendar-view.json +105 -0
  9. package/r/cart.json +62 -0
  10. package/r/chart.json +83 -0
  11. package/r/chat.json +95 -0
  12. package/r/code-editor.json +94 -0
  13. package/r/comment-box.json +64 -0
  14. package/r/contact-section.json +53 -0
  15. package/r/core.json +205 -8
  16. package/r/csv-import.json +63 -0
  17. package/r/data-table.json +69 -0
  18. package/r/diagram.json +74 -0
  19. package/r/doc-editor.json +82 -0
  20. package/r/doc-page.json +61 -0
  21. package/r/email-render.json +73 -0
  22. package/r/faq.json +50 -0
  23. package/r/file-upload.json +54 -0
  24. package/r/flow-canvas.json +93 -0
  25. package/r/footer.json +52 -0
  26. package/r/gantt.json +70 -0
  27. package/r/job-panel.json +12 -7
  28. package/r/json-editor.json +66 -0
  29. package/r/map.json +89 -0
  30. package/r/menubar.json +52 -0
  31. package/r/mind-map.json +67 -0
  32. package/r/navigation-menu.json +52 -0
  33. package/r/order-detail.json +54 -0
  34. package/r/org-chart.json +66 -0
  35. package/r/page-builder.json +105 -0
  36. package/r/payment-methods.json +51 -0
  37. package/r/pdf-document.json +79 -0
  38. package/r/pdf-viewer.json +88 -0
  39. package/r/product-detail.json +76 -0
  40. package/r/product-grid.json +65 -0
  41. package/r/record-form.json +67 -0
  42. package/r/record-notes.json +55 -0
  43. package/r/registry.json +3411 -29
  44. package/r/search-dialog.json +51 -0
  45. package/r/settings-list.json +66 -0
  46. package/r/setup-checklist.json +51 -0
  47. package/r/share-dialog.json +52 -0
  48. package/r/sidebar.json +69 -0
  49. package/r/signature-pad.json +72 -0
  50. package/r/sketch-canvas.json +99 -0
  51. package/r/spreadsheet.json +90 -0
  52. package/r/stat-cards.json +66 -0
  53. package/r/task-list.json +63 -0
  54. package/r/task-model.json +98 -0
  55. package/r/testimonials.json +52 -0
  56. package/r/transaction-list.json +53 -0
  57. package/r/whiteboard.json +66 -0
  58. package/registry/blocks/annotate/README.md +179 -0
  59. package/registry/blocks/annotate/annotate-data.js +250 -0
  60. package/registry/blocks/annotate/annotate.jsx +646 -0
  61. package/registry/blocks/annotate/block.json +10 -0
  62. package/registry/blocks/annotate/demo.jsx +135 -0
  63. package/registry/blocks/annotate/index.js +15 -0
  64. package/registry/blocks/approval-request/README.md +116 -0
  65. package/registry/blocks/approval-request/approval-request.jsx +386 -0
  66. package/registry/blocks/approval-request/block.json +10 -0
  67. package/registry/blocks/approval-request/demo.jsx +127 -0
  68. package/registry/blocks/approval-request/index.js +4 -0
  69. package/registry/blocks/audio-player/README.md +167 -0
  70. package/registry/blocks/audio-player/audio-player.jsx +623 -0
  71. package/registry/blocks/audio-player/block.json +14 -0
  72. package/registry/blocks/audio-player/colors.js +109 -0
  73. package/registry/blocks/audio-player/demo.jsx +209 -0
  74. package/registry/blocks/audio-player/index.js +6 -0
  75. package/registry/blocks/audio-player/time.js +67 -0
  76. package/registry/blocks/audio-player/wavesurfer.js +9 -0
  77. package/registry/blocks/auth-form/README.md +126 -0
  78. package/registry/blocks/auth-form/auth-form.jsx +568 -0
  79. package/registry/blocks/auth-form/block.json +10 -0
  80. package/registry/blocks/auth-form/demo.jsx +131 -0
  81. package/registry/blocks/auth-form/index.js +3 -0
  82. package/registry/blocks/board/README.md +55 -5
  83. package/registry/blocks/board/block.json +2 -2
  84. package/registry/blocks/board/board.jsx +230 -86
  85. package/registry/blocks/board/demo.jsx +103 -24
  86. package/registry/blocks/calendar-view/README.md +180 -0
  87. package/registry/blocks/calendar-view/agenda.jsx +147 -0
  88. package/registry/blocks/calendar-view/block.json +76 -0
  89. package/registry/blocks/calendar-view/calendar-model.js +442 -0
  90. package/registry/blocks/calendar-view/calendar.jsx +627 -0
  91. package/registry/blocks/calendar-view/demo.jsx +195 -0
  92. package/registry/blocks/calendar-view/draft.jsx +49 -0
  93. package/registry/blocks/calendar-view/index.js +39 -0
  94. package/registry/blocks/calendar-view/month.jsx +346 -0
  95. package/registry/blocks/calendar-view/paint.js +69 -0
  96. package/registry/blocks/calendar-view/time-grid.jsx +527 -0
  97. package/registry/blocks/calendar-view/tray.jsx +87 -0
  98. package/registry/blocks/cart/README.md +146 -0
  99. package/registry/blocks/cart/block.json +10 -0
  100. package/registry/blocks/cart/cart.jsx +597 -0
  101. package/registry/blocks/cart/demo.jsx +98 -0
  102. package/registry/blocks/cart/index.js +4 -0
  103. package/registry/blocks/cart/money.js +28 -0
  104. package/registry/blocks/chart/README.md +316 -0
  105. package/registry/blocks/chart/block.json +10 -0
  106. package/registry/blocks/chart/cartesian.jsx +642 -0
  107. package/registry/blocks/chart/core.jsx +262 -0
  108. package/registry/blocks/chart/demo.jsx +357 -0
  109. package/registry/blocks/chart/heatmap.jsx +336 -0
  110. package/registry/blocks/chart/index.js +8 -0
  111. package/registry/blocks/chart/pie.jsx +245 -0
  112. package/registry/blocks/chart/sparkline.jsx +88 -0
  113. package/registry/blocks/chat/README.md +273 -0
  114. package/registry/blocks/chat/attachment.jsx +95 -0
  115. package/registry/blocks/chat/block.json +10 -0
  116. package/registry/blocks/chat/chat.jsx +132 -0
  117. package/registry/blocks/chat/composer.jsx +364 -0
  118. package/registry/blocks/chat/demo.jsx +578 -0
  119. package/registry/blocks/chat/header.jsx +34 -0
  120. package/registry/blocks/chat/index.js +9 -0
  121. package/registry/blocks/chat/message.jsx +450 -0
  122. package/registry/blocks/chat/scroller.jsx +247 -0
  123. package/registry/blocks/chat/text.jsx +104 -0
  124. package/registry/blocks/code-editor/README.md +210 -0
  125. package/registry/blocks/code-editor/block.json +22 -0
  126. package/registry/blocks/code-editor/code-editor.jsx +534 -0
  127. package/registry/blocks/code-editor/codemirror.js +38 -0
  128. package/registry/blocks/code-editor/demo.jsx +205 -0
  129. package/registry/blocks/code-editor/index.js +8 -0
  130. package/registry/blocks/code-editor/json.js +317 -0
  131. package/registry/blocks/code-editor/sql.js +136 -0
  132. package/registry/blocks/code-editor/text.js +101 -0
  133. package/registry/blocks/code-editor/theme.js +186 -0
  134. package/registry/blocks/comment-box/README.md +123 -0
  135. package/registry/blocks/comment-box/block.json +10 -0
  136. package/registry/blocks/comment-box/comment-body.jsx +217 -0
  137. package/registry/blocks/comment-box/comment-box.jsx +198 -0
  138. package/registry/blocks/comment-box/comment-time.jsx +77 -0
  139. package/registry/blocks/comment-box/demo.jsx +141 -0
  140. package/registry/blocks/comment-box/index.js +8 -0
  141. package/registry/blocks/contact-section/README.md +152 -0
  142. package/registry/blocks/contact-section/block.json +11 -0
  143. package/registry/blocks/contact-section/contact-section.jsx +509 -0
  144. package/registry/blocks/contact-section/demo.jsx +93 -0
  145. package/registry/blocks/contact-section/index.js +4 -0
  146. package/registry/blocks/csv-import/README.md +133 -0
  147. package/registry/blocks/csv-import/block.json +13 -0
  148. package/registry/blocks/csv-import/csv-import.jsx +479 -0
  149. package/registry/blocks/csv-import/demo.jsx +106 -0
  150. package/registry/blocks/csv-import/import.js +200 -0
  151. package/registry/blocks/csv-import/index.js +7 -0
  152. package/registry/blocks/data-table/README.md +386 -0
  153. package/registry/blocks/data-table/block.json +10 -0
  154. package/registry/blocks/data-table/data-table.jsx +1164 -0
  155. package/registry/blocks/data-table/demo.jsx +588 -0
  156. package/registry/blocks/data-table/index.js +5 -0
  157. package/registry/blocks/data-table/model.js +169 -0
  158. package/registry/blocks/diagram/README.md +108 -0
  159. package/registry/blocks/diagram/block.json +13 -0
  160. package/registry/blocks/diagram/demo.jsx +113 -0
  161. package/registry/blocks/diagram/diagram.jsx +481 -0
  162. package/registry/blocks/diagram/index.js +7 -0
  163. package/registry/blocks/diagram/mermaid.js +52 -0
  164. package/registry/blocks/diagram/palette.js +313 -0
  165. package/registry/blocks/diagram/source.js +98 -0
  166. package/registry/blocks/doc-editor/README.md +215 -0
  167. package/registry/blocks/doc-editor/block.json +15 -0
  168. package/registry/blocks/doc-editor/demo.jsx +225 -0
  169. package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
  170. package/registry/blocks/doc-editor/doc.js +309 -0
  171. package/registry/blocks/doc-editor/index.js +7 -0
  172. package/registry/blocks/doc-editor/schema.jsx +56 -0
  173. package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
  174. package/registry/blocks/doc-editor/theme.js +82 -0
  175. package/registry/blocks/doc-page/README.md +119 -0
  176. package/registry/blocks/doc-page/autosave.js +104 -0
  177. package/registry/blocks/doc-page/block.json +10 -0
  178. package/registry/blocks/doc-page/demo.jsx +137 -0
  179. package/registry/blocks/doc-page/doc-page.jsx +276 -0
  180. package/registry/blocks/doc-page/index.js +4 -0
  181. package/registry/blocks/email-render/README.md +151 -0
  182. package/registry/blocks/email-render/block.json +14 -0
  183. package/registry/blocks/email-render/demo.jsx +153 -0
  184. package/registry/blocks/email-render/doc-email.jsx +210 -0
  185. package/registry/blocks/email-render/email.jsx +221 -0
  186. package/registry/blocks/email-render/index.js +10 -0
  187. package/registry/blocks/email-render/render.js +50 -0
  188. package/registry/blocks/email-render/theme.js +215 -0
  189. package/registry/blocks/faq/README.md +101 -0
  190. package/registry/blocks/faq/block.json +11 -0
  191. package/registry/blocks/faq/demo.jsx +89 -0
  192. package/registry/blocks/faq/faq.jsx +220 -0
  193. package/registry/blocks/faq/index.js +4 -0
  194. package/registry/blocks/file-upload/README.md +138 -0
  195. package/registry/blocks/file-upload/block.json +10 -0
  196. package/registry/blocks/file-upload/demo.jsx +204 -0
  197. package/registry/blocks/file-upload/file-upload.jsx +635 -0
  198. package/registry/blocks/file-upload/index.js +4 -0
  199. package/registry/blocks/flow-canvas/README.md +420 -0
  200. package/registry/blocks/flow-canvas/block.json +13 -0
  201. package/registry/blocks/flow-canvas/board.js +819 -0
  202. package/registry/blocks/flow-canvas/chrome.jsx +649 -0
  203. package/registry/blocks/flow-canvas/context.jsx +35 -0
  204. package/registry/blocks/flow-canvas/demo.jsx +249 -0
  205. package/registry/blocks/flow-canvas/edges.jsx +107 -0
  206. package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
  207. package/registry/blocks/flow-canvas/index.js +41 -0
  208. package/registry/blocks/flow-canvas/nodes.jsx +392 -0
  209. package/registry/blocks/flow-canvas/theme.js +174 -0
  210. package/registry/blocks/footer/README.md +133 -0
  211. package/registry/blocks/footer/block.json +11 -0
  212. package/registry/blocks/footer/demo.jsx +119 -0
  213. package/registry/blocks/footer/footer.jsx +406 -0
  214. package/registry/blocks/footer/index.js +4 -0
  215. package/registry/blocks/gantt/README.md +220 -0
  216. package/registry/blocks/gantt/block.json +10 -0
  217. package/registry/blocks/gantt/demo.jsx +148 -0
  218. package/registry/blocks/gantt/gantt.jsx +923 -0
  219. package/registry/blocks/gantt/index.js +7 -0
  220. package/registry/blocks/gantt/rows.jsx +468 -0
  221. package/registry/blocks/gantt/schedule.js +278 -0
  222. package/registry/blocks/job-panel/README.md +80 -0
  223. package/registry/blocks/job-panel/block.json +3 -3
  224. package/registry/blocks/job-panel/demo.jsx +230 -3
  225. package/registry/blocks/job-panel/job-panel.jsx +169 -3
  226. package/registry/blocks/json-editor/README.md +133 -0
  227. package/registry/blocks/json-editor/block.json +10 -0
  228. package/registry/blocks/json-editor/demo.jsx +92 -0
  229. package/registry/blocks/json-editor/index.js +7 -0
  230. package/registry/blocks/json-editor/json-editor.jsx +305 -0
  231. package/registry/blocks/json-editor/json-tree.jsx +393 -0
  232. package/registry/blocks/json-editor/tree.js +225 -0
  233. package/registry/blocks/map/README.md +221 -0
  234. package/registry/blocks/map/block.json +14 -0
  235. package/registry/blocks/map/demo.jsx +201 -0
  236. package/registry/blocks/map/geo.js +198 -0
  237. package/registry/blocks/map/index.js +8 -0
  238. package/registry/blocks/map/list.jsx +128 -0
  239. package/registry/blocks/map/map-view.jsx +715 -0
  240. package/registry/blocks/map/maplibre.js +30 -0
  241. package/registry/blocks/map/marks.jsx +146 -0
  242. package/registry/blocks/map/theme.js +142 -0
  243. package/registry/blocks/menubar/README.md +109 -0
  244. package/registry/blocks/menubar/block.json +10 -0
  245. package/registry/blocks/menubar/demo.jsx +128 -0
  246. package/registry/blocks/menubar/index.js +4 -0
  247. package/registry/blocks/menubar/menubar.jsx +199 -0
  248. package/registry/blocks/mind-map/README.md +206 -0
  249. package/registry/blocks/mind-map/block.json +10 -0
  250. package/registry/blocks/mind-map/demo.jsx +103 -0
  251. package/registry/blocks/mind-map/index.js +31 -0
  252. package/registry/blocks/mind-map/mind-map.jsx +1125 -0
  253. package/registry/blocks/mind-map/topic.jsx +143 -0
  254. package/registry/blocks/mind-map/tree.js +645 -0
  255. package/registry/blocks/navigation-menu/README.md +124 -0
  256. package/registry/blocks/navigation-menu/block.json +10 -0
  257. package/registry/blocks/navigation-menu/demo.jsx +84 -0
  258. package/registry/blocks/navigation-menu/index.js +4 -0
  259. package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
  260. package/registry/blocks/order-detail/README.md +109 -0
  261. package/registry/blocks/order-detail/block.json +10 -0
  262. package/registry/blocks/order-detail/demo.jsx +88 -0
  263. package/registry/blocks/order-detail/index.js +4 -0
  264. package/registry/blocks/order-detail/order-detail.jsx +354 -0
  265. package/registry/blocks/org-chart/README.md +145 -0
  266. package/registry/blocks/org-chart/block.json +10 -0
  267. package/registry/blocks/org-chart/demo.jsx +94 -0
  268. package/registry/blocks/org-chart/index.js +7 -0
  269. package/registry/blocks/org-chart/org-chart.jsx +631 -0
  270. package/registry/blocks/org-chart/org.js +245 -0
  271. package/registry/blocks/org-chart/person.jsx +96 -0
  272. package/registry/blocks/page-builder/README.md +257 -0
  273. package/registry/blocks/page-builder/block.json +14 -0
  274. package/registry/blocks/page-builder/demo.jsx +145 -0
  275. package/registry/blocks/page-builder/grapes.js +18 -0
  276. package/registry/blocks/page-builder/index.js +11 -0
  277. package/registry/blocks/page-builder/page-builder.jsx +704 -0
  278. package/registry/blocks/page-builder/page-view.jsx +33 -0
  279. package/registry/blocks/page-builder/page.js +118 -0
  280. package/registry/blocks/page-builder/panels.jsx +588 -0
  281. package/registry/blocks/page-builder/sections.js +209 -0
  282. package/registry/blocks/page-builder/theme.js +87 -0
  283. package/registry/blocks/page-builder/thumbs.jsx +189 -0
  284. package/registry/blocks/page-builder/tokens.js +329 -0
  285. package/registry/blocks/payment-methods/README.md +104 -0
  286. package/registry/blocks/payment-methods/block.json +10 -0
  287. package/registry/blocks/payment-methods/demo.jsx +71 -0
  288. package/registry/blocks/payment-methods/index.js +4 -0
  289. package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
  290. package/registry/blocks/pdf-document/README.md +213 -0
  291. package/registry/blocks/pdf-document/block.json +13 -0
  292. package/registry/blocks/pdf-document/demo.jsx +136 -0
  293. package/registry/blocks/pdf-document/index.js +33 -0
  294. package/registry/blocks/pdf-document/money.js +83 -0
  295. package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
  296. package/registry/blocks/pdf-document/primitives.jsx +271 -0
  297. package/registry/blocks/pdf-document/quote.jsx +179 -0
  298. package/registry/blocks/pdf-document/theme.js +193 -0
  299. package/registry/blocks/pdf-viewer/README.md +191 -0
  300. package/registry/blocks/pdf-viewer/block.json +14 -0
  301. package/registry/blocks/pdf-viewer/demo.jsx +252 -0
  302. package/registry/blocks/pdf-viewer/helpers.js +270 -0
  303. package/registry/blocks/pdf-viewer/index.js +8 -0
  304. package/registry/blocks/pdf-viewer/notes.jsx +195 -0
  305. package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
  306. package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
  307. package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
  308. package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
  309. package/registry/blocks/product-detail/README.md +217 -0
  310. package/registry/blocks/product-detail/block.json +10 -0
  311. package/registry/blocks/product-detail/demo.jsx +233 -0
  312. package/registry/blocks/product-detail/index.js +7 -0
  313. package/registry/blocks/product-detail/price.jsx +115 -0
  314. package/registry/blocks/product-detail/product-detail.jsx +348 -0
  315. package/registry/blocks/product-detail/product-media.jsx +102 -0
  316. package/registry/blocks/product-detail/product-options.jsx +144 -0
  317. package/registry/blocks/product-grid/README.md +162 -0
  318. package/registry/blocks/product-grid/block.json +10 -0
  319. package/registry/blocks/product-grid/demo.jsx +255 -0
  320. package/registry/blocks/product-grid/index.js +5 -0
  321. package/registry/blocks/product-grid/product-card.jsx +232 -0
  322. package/registry/blocks/product-grid/product-grid.jsx +235 -0
  323. package/registry/blocks/record-form/README.md +196 -0
  324. package/registry/blocks/record-form/block.json +10 -0
  325. package/registry/blocks/record-form/demo.jsx +525 -0
  326. package/registry/blocks/record-form/index.js +4 -0
  327. package/registry/blocks/record-form/record-fields.jsx +457 -0
  328. package/registry/blocks/record-form/record-form.jsx +415 -0
  329. package/registry/blocks/record-form/rules.js +81 -0
  330. package/registry/blocks/record-notes/README.md +139 -0
  331. package/registry/blocks/record-notes/block.json +10 -0
  332. package/registry/blocks/record-notes/demo.jsx +179 -0
  333. package/registry/blocks/record-notes/index.js +4 -0
  334. package/registry/blocks/record-notes/record-notes.jsx +266 -0
  335. package/registry/blocks/search-dialog/README.md +108 -0
  336. package/registry/blocks/search-dialog/block.json +10 -0
  337. package/registry/blocks/search-dialog/demo.jsx +116 -0
  338. package/registry/blocks/search-dialog/index.js +3 -0
  339. package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
  340. package/registry/blocks/settings-list/README.md +171 -0
  341. package/registry/blocks/settings-list/block.json +10 -0
  342. package/registry/blocks/settings-list/demo.jsx +333 -0
  343. package/registry/blocks/settings-list/index.js +4 -0
  344. package/registry/blocks/settings-list/row-state.jsx +93 -0
  345. package/registry/blocks/settings-list/settings-list.jsx +349 -0
  346. package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
  347. package/registry/blocks/setup-checklist/README.md +142 -0
  348. package/registry/blocks/setup-checklist/block.json +10 -0
  349. package/registry/blocks/setup-checklist/demo.jsx +159 -0
  350. package/registry/blocks/setup-checklist/index.js +4 -0
  351. package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
  352. package/registry/blocks/share-dialog/README.md +113 -0
  353. package/registry/blocks/share-dialog/block.json +10 -0
  354. package/registry/blocks/share-dialog/demo.jsx +140 -0
  355. package/registry/blocks/share-dialog/index.js +3 -0
  356. package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
  357. package/registry/blocks/sidebar/README.md +190 -0
  358. package/registry/blocks/sidebar/block.json +43 -0
  359. package/registry/blocks/sidebar/demo.jsx +577 -0
  360. package/registry/blocks/sidebar/index.js +4 -0
  361. package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
  362. package/registry/blocks/sidebar/sidebar.jsx +864 -0
  363. package/registry/blocks/signature-pad/README.md +137 -0
  364. package/registry/blocks/signature-pad/block.json +13 -0
  365. package/registry/blocks/signature-pad/colors.js +115 -0
  366. package/registry/blocks/signature-pad/demo.jsx +94 -0
  367. package/registry/blocks/signature-pad/index.js +6 -0
  368. package/registry/blocks/signature-pad/pad.js +7 -0
  369. package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
  370. package/registry/blocks/signature-pad/signature.js +68 -0
  371. package/registry/blocks/sketch-canvas/README.md +280 -0
  372. package/registry/blocks/sketch-canvas/block.json +13 -0
  373. package/registry/blocks/sketch-canvas/demo.jsx +159 -0
  374. package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
  375. package/registry/blocks/sketch-canvas/index.js +9 -0
  376. package/registry/blocks/sketch-canvas/palette.js +226 -0
  377. package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
  378. package/registry/blocks/sketch-canvas/sketch.js +179 -0
  379. package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
  380. package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
  381. package/registry/blocks/sketch-canvas/stamps.js +104 -0
  382. package/registry/blocks/sketch-canvas/theme.js +131 -0
  383. package/registry/blocks/spreadsheet/README.md +307 -0
  384. package/registry/blocks/spreadsheet/block.json +13 -0
  385. package/registry/blocks/spreadsheet/cells.jsx +455 -0
  386. package/registry/blocks/spreadsheet/chrome.jsx +325 -0
  387. package/registry/blocks/spreadsheet/demo.jsx +177 -0
  388. package/registry/blocks/spreadsheet/grid.js +387 -0
  389. package/registry/blocks/spreadsheet/index.js +34 -0
  390. package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
  391. package/registry/blocks/spreadsheet/types.js +473 -0
  392. package/registry/blocks/stat-cards/README.md +173 -0
  393. package/registry/blocks/stat-cards/block.json +10 -0
  394. package/registry/blocks/stat-cards/demo.jsx +257 -0
  395. package/registry/blocks/stat-cards/index.js +4 -0
  396. package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
  397. package/registry/blocks/stat-cards/usage.jsx +243 -0
  398. package/registry/blocks/task-list/README.md +176 -0
  399. package/registry/blocks/task-list/block.json +10 -0
  400. package/registry/blocks/task-list/demo.jsx +134 -0
  401. package/registry/blocks/task-list/index.js +5 -0
  402. package/registry/blocks/task-list/task-list.jsx +907 -0
  403. package/registry/blocks/task-model/README.md +455 -0
  404. package/registry/blocks/task-model/block.json +167 -0
  405. package/registry/blocks/task-model/changes.js +89 -0
  406. package/registry/blocks/task-model/dates.js +371 -0
  407. package/registry/blocks/task-model/demo.jsx +215 -0
  408. package/registry/blocks/task-model/dnd.jsx +240 -0
  409. package/registry/blocks/task-model/index.js +97 -0
  410. package/registry/blocks/task-model/model.js +919 -0
  411. package/registry/blocks/task-model/parts.jsx +449 -0
  412. package/registry/blocks/task-model/toolbar.jsx +271 -0
  413. package/registry/blocks/testimonials/README.md +139 -0
  414. package/registry/blocks/testimonials/block.json +11 -0
  415. package/registry/blocks/testimonials/demo.jsx +137 -0
  416. package/registry/blocks/testimonials/index.js +4 -0
  417. package/registry/blocks/testimonials/testimonials.jsx +430 -0
  418. package/registry/blocks/transaction-list/README.md +126 -0
  419. package/registry/blocks/transaction-list/block.json +10 -0
  420. package/registry/blocks/transaction-list/demo.jsx +79 -0
  421. package/registry/blocks/transaction-list/index.js +4 -0
  422. package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
  423. package/registry/blocks/whiteboard/README.md +179 -0
  424. package/registry/blocks/whiteboard/block.json +10 -0
  425. package/registry/blocks/whiteboard/demo.jsx +169 -0
  426. package/registry/blocks/whiteboard/index.js +6 -0
  427. package/registry/blocks/whiteboard/templates.js +150 -0
  428. package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
  429. package/src/install.mjs +18 -0
  430. package/src/shadcn.mjs +8 -0
  431. package/templates/next/files/README.md +145 -11
  432. package/templates/next/files/app/globals.css +55 -4
  433. package/templates/next/files/check/run.mjs +3 -3
  434. package/templates/next/files/components/ui/avatar.jsx +141 -0
  435. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  436. package/templates/next/files/components/ui/button-group.jsx +70 -0
  437. package/templates/next/files/components/ui/button.jsx +132 -12
  438. package/templates/next/files/components/ui/calendar.jsx +609 -0
  439. package/templates/next/files/components/ui/carousel.jsx +281 -0
  440. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  441. package/templates/next/files/components/ui/combobox.jsx +608 -0
  442. package/templates/next/files/components/ui/command.jsx +577 -0
  443. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  444. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  445. package/templates/next/files/components/ui/distribution.jsx +117 -0
  446. package/templates/next/files/components/ui/feedback.jsx +143 -0
  447. package/templates/next/files/components/ui/field.jsx +115 -3
  448. package/templates/next/files/components/ui/file-input.jsx +234 -0
  449. package/templates/next/files/components/ui/icon.jsx +130 -8
  450. package/templates/next/files/components/ui/image.jsx +143 -0
  451. package/templates/next/files/components/ui/index.js +47 -2
  452. package/templates/next/files/components/ui/input-group.jsx +213 -0
  453. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  454. package/templates/next/files/components/ui/item.jsx +206 -0
  455. package/templates/next/files/components/ui/menu.jsx +454 -82
  456. package/templates/next/files/components/ui/notice.jsx +126 -14
  457. package/templates/next/files/components/ui/pagination.jsx +156 -0
  458. package/templates/next/files/components/ui/popover.jsx +284 -0
  459. package/templates/next/files/components/ui/radio.jsx +193 -0
  460. package/templates/next/files/components/ui/rating.jsx +131 -0
  461. package/templates/next/files/components/ui/resizable.jsx +338 -0
  462. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  463. package/templates/next/files/components/ui/separator.jsx +119 -0
  464. package/templates/next/files/components/ui/sheet.jsx +96 -11
  465. package/templates/next/files/components/ui/slider.jsx +174 -0
  466. package/templates/next/files/components/ui/stat.jsx +574 -0
  467. package/templates/next/files/components/ui/steps.jsx +338 -0
  468. package/templates/next/files/components/ui/swatch.jsx +33 -0
  469. package/templates/next/files/components/ui/table.jsx +130 -0
  470. package/templates/next/files/components/ui/toast.jsx +440 -0
  471. package/templates/next/files/components/ui/toggle.jsx +195 -0
  472. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  473. package/templates/next/template.json +264 -8
@@ -0,0 +1,336 @@
1
+ "use client";
2
+
3
+ import { useMemo, useRef, useState } from "react";
4
+ import { Tooltip, cx } from "../../ui";
5
+ import { ChartEmpty, defaultFormat, humanize, num } from "./core";
6
+
7
+ // HeatmapChart — two dimensions as a grid (hour × day, weekday × week),
8
+ // each cell shaded by its value on a sequential ramp of one chart colour.
9
+ // Unlike the other charts it is HTML, not SVG: a real table, so a screen
10
+ // reader walks it by row and column, and each cell is a control the arrow
11
+ // keys move between and the kit's Tooltip names. A grid wider than its box
12
+ // scrolls sideways inside it; the row labels stay put.
13
+ //
14
+ // ScaleLegend is its key ("Less ▪▪▪▪▪ More"); scaleStep and scaleShade are
15
+ // the ramp itself, for a block that paints cells of its own.
16
+
17
+ // ---- the ramp ----------------------------------------------------------------
18
+
19
+ function toneVar(t) {
20
+ const n = typeof t === "number" ? t : Number(String(t ?? "").replace(/^chart-/, ""));
21
+ return `var(--color-chart-${Number.isInteger(n) && n >= 1 && n <= 5 ? n : 1})`;
22
+ }
23
+
24
+ /**
25
+ * Which of `steps` shades a value falls in: 0 (the lowest) … steps − 1.
26
+ * null for a value that is missing or not a number. Values outside
27
+ * [min, max] take the end shades.
28
+ */
29
+ export function scaleStep(value, min, max, steps = 5) {
30
+ const v = num(value);
31
+ if (v == null) return null;
32
+ const n = Math.max(1, Math.round(steps) || 1);
33
+ const lo = num(min) ?? 0;
34
+ const hi = num(max) ?? lo;
35
+ if (!(hi > lo)) return v > lo ? n - 1 : 0;
36
+ const t = (v - lo) / (hi - lo);
37
+ return Math.min(n - 1, Math.max(0, Math.floor(t * n)));
38
+ }
39
+
40
+ // The lowest shade still reads as "some"; the highest is the colour itself.
41
+ const FLOOR = 10;
42
+
43
+ /** The fill and the text class for one shade of a ramp. */
44
+ function shadeFor(step, steps, t) {
45
+ if (step == null) return { style: undefined, className: "bg-muted/40 text-muted-foreground" };
46
+ const n = Math.max(1, Math.round(steps) || 1);
47
+ const share = n === 1 ? 1 : step / (n - 1);
48
+ const mix = Math.round(FLOOR + (100 - FLOOR) * share);
49
+ return {
50
+ // The chart colour thinned toward transparent: over a card or the page
51
+ // it reads as the colour mixed with that background.
52
+ style: { backgroundColor: `color-mix(in oklab, ${toneVar(t)} ${mix}%, transparent)` },
53
+ // Dark shades carry the background's colour as text, light ones the
54
+ // foreground's, so a number on a cell stays readable either way.
55
+ className: share >= 0.7 ? "text-background" : "text-foreground",
56
+ };
57
+ }
58
+
59
+ /**
60
+ * The shade a value wears, for a cell drawn outside HeatmapChart:
61
+ * const s = scaleShade(12, { min: 0, max: 40 });
62
+ * <span style={s.style} className={cx("size-3 rounded-sm", s.className)} />
63
+ * → { step, style, className } — `style` is the fill, `className` the text
64
+ * colour that reads on it (and a muted fill when the value is missing).
65
+ */
66
+ export function scaleShade(value, { min = 0, max = 1, steps = 5, tone = "chart-1" } = {}) {
67
+ const step = scaleStep(value, min, max, steps);
68
+ return { step, ...shadeFor(step, steps, tone) };
69
+ }
70
+
71
+ /**
72
+ * The key to a heatmap: the words (or numbers) at the ends and one swatch
73
+ * per shade between them.
74
+ * labels ["Less", "More"], or leave out for `format(min)` … `format(max)`
75
+ */
76
+ export function ScaleLegend({
77
+ min = 0,
78
+ max = 1,
79
+ steps = 5,
80
+ labels,
81
+ tone = "chart-1",
82
+ format = defaultFormat,
83
+ shape = "square",
84
+ label = "Scale",
85
+ className,
86
+ }) {
87
+ const n = Math.max(1, Math.round(steps) || 1);
88
+ const ends = [labels?.[0] ?? min, labels?.[1] ?? max].map((v) => (typeof v === "number" ? format(v) : v));
89
+ return (
90
+ <div
91
+ role="img"
92
+ aria-label={`${label}: ${n} shades from ${ends[0]} to ${ends[1]}`}
93
+ className={cx("inline-flex items-center gap-1.5 text-xs text-muted-foreground", className)}
94
+ >
95
+ <span data-nums>{ends[0]}</span>
96
+ <span className="flex items-center gap-0.5">
97
+ {Array.from({ length: n }, (_, i) => (
98
+ <span
99
+ key={i}
100
+ style={shadeFor(i, n, tone).style}
101
+ className={cx("h-3 shrink-0", shape === "pill" ? "w-3 rounded-full" : "w-4 rounded-sm")}
102
+ />
103
+ ))}
104
+ </span>
105
+ <span data-nums>{ends[1]}</span>
106
+ </div>
107
+ );
108
+ }
109
+
110
+ // ---- the chart ---------------------------------------------------------------
111
+
112
+ function normalizeColumns(columns) {
113
+ return (columns ?? []).filter((c) => c != null).map((c) =>
114
+ typeof c === "string" || typeof c === "number"
115
+ ? { key: String(c), label: humanize(c) || String(c) }
116
+ : { ...c, key: String(c.key), label: c.label ?? (humanize(c.key) || String(c.key)) },
117
+ );
118
+ }
119
+
120
+ const sum = (vals) => {
121
+ const nums = vals.map(num).filter((v) => v != null);
122
+ return nums.length ? nums.reduce((a, b) => a + b, 0) : null;
123
+ };
124
+
125
+ export function HeatmapChart({
126
+ data,
127
+ y = "name",
128
+ columns,
129
+ formatY = (v) => (v == null ? "—" : String(v)),
130
+ tone = "chart-1",
131
+ min,
132
+ max,
133
+ steps = 5,
134
+ showValues = false,
135
+ format = defaultFormat,
136
+ cellShape = "square",
137
+ rowTotals = false,
138
+ colTotals = false,
139
+ totalLabel = "Total",
140
+ tooltip = true,
141
+ formatTooltip,
142
+ legend = true,
143
+ legendLabels,
144
+ onSelect,
145
+ label = "Heatmap",
146
+ description,
147
+ yLabel,
148
+ emptyLabel = "No data yet",
149
+ emptyBody,
150
+ className,
151
+ }) {
152
+ const bodyRef = useRef(null);
153
+ const [active, setActive] = useState([0, 0]);
154
+
155
+ const rows = Array.isArray(data) ? data : [];
156
+ const cols = useMemo(() => normalizeColumns(columns), [columns]);
157
+
158
+ const range = useMemo(() => {
159
+ let lo = Infinity;
160
+ let hi = -Infinity;
161
+ for (const r of rows) for (const c of cols) {
162
+ const v = num(r?.[c.key]);
163
+ if (v == null) continue;
164
+ if (v < lo) lo = v;
165
+ if (v > hi) hi = v;
166
+ }
167
+ if (lo === Infinity) return { lo: 0, hi: 1 };
168
+ return { lo: Math.min(0, lo), hi };
169
+ }, [rows, cols]);
170
+ const lo = num(min) ?? range.lo;
171
+ const hi = num(max) ?? range.hi;
172
+
173
+ if (!rows.length || !cols.length) {
174
+ return (
175
+ <div className={className}>
176
+ <ChartEmpty height={160} title={emptyLabel} body={emptyBody} />
177
+ </div>
178
+ );
179
+ }
180
+
181
+ const nr = rows.length;
182
+ const nc = cols.length;
183
+ const pill = cellShape === "pill";
184
+ const rowName = (r) => formatY(r?.[y], r);
185
+ const tipOf = (v, r, c) =>
186
+ formatTooltip ? formatTooltip(v, r, c) : `${rowName(r)} · ${c.label}: ${v == null ? "no data" : format(v)}`;
187
+
188
+ const [ar, ac] = [Math.min(active[0], nr - 1), Math.min(active[1], nc - 1)];
189
+
190
+ function go(r, c) {
191
+ const nextR = Math.max(0, Math.min(nr - 1, r));
192
+ const nextC = Math.max(0, Math.min(nc - 1, c));
193
+ setActive([nextR, nextC]);
194
+ bodyRef.current?.querySelector(`[data-cell="${nextR}-${nextC}"]`)?.focus();
195
+ }
196
+
197
+ function onKeyDown(e) {
198
+ const at = e.target.closest?.("[data-cell]")?.getAttribute("data-cell");
199
+ if (!at) return;
200
+ const [r, c] = at.split("-").map(Number);
201
+ const moves = {
202
+ ArrowRight: [r, c + 1],
203
+ ArrowLeft: [r, c - 1],
204
+ ArrowDown: [r + 1, c],
205
+ ArrowUp: [r - 1, c],
206
+ Home: e.ctrlKey || e.metaKey ? [0, 0] : [r, 0],
207
+ End: e.ctrlKey || e.metaKey ? [nr - 1, nc - 1] : [r, nc - 1],
208
+ };
209
+ if (moves[e.key]) {
210
+ e.preventDefault();
211
+ go(...moves[e.key]);
212
+ } else if ((e.key === "Enter" || e.key === " ") && onSelect) {
213
+ e.preventDefault();
214
+ onSelect(rows[r], cols[c].key, num(rows[r]?.[cols[c].key]));
215
+ }
216
+ }
217
+
218
+ // What a screen reader hears after the label: the size, the range, the peak.
219
+ let peak = null;
220
+ for (const r of rows) for (const c of cols) {
221
+ const v = num(r?.[c.key]);
222
+ if (v != null && (!peak || v > peak.v)) peak = { v, r, c };
223
+ }
224
+ const said =
225
+ description ??
226
+ `${nr} rows by ${nc} columns, values from ${format(lo)} to ${format(hi)}${peak ? `; highest ${format(peak.v)} at ${rowName(peak.r)}, ${peak.c.label}` : ""}.`;
227
+
228
+ const cellBox = pill ? "h-5 min-w-6 rounded-full px-1" : "h-8 min-w-9 rounded-md px-1";
229
+ const totalCell = "px-1.5 text-right text-xs font-semibold text-foreground whitespace-nowrap";
230
+ const colSums = colTotals ? cols.map((c) => sum(rows.map((r) => r?.[c.key]))) : null;
231
+
232
+ return (
233
+ <div className={cx("grid gap-3", className)}>
234
+ <div className="overflow-x-auto">
235
+ <table className="w-full border-separate border-spacing-1">
236
+ <caption className="sr-only">
237
+ {label}. {said}
238
+ </caption>
239
+ <thead>
240
+ <tr>
241
+ <th scope="col" className="sticky left-0 z-[1] bg-card">
242
+ <span className="sr-only">{yLabel ?? (humanize(y) || "Row")}</span>
243
+ </th>
244
+ {cols.map((c) => (
245
+ <th key={c.key} scope="col" className="px-0.5 text-center text-2xs font-normal whitespace-nowrap text-muted-foreground">
246
+ {c.label}
247
+ </th>
248
+ ))}
249
+ {rowTotals ? (
250
+ <th scope="col" className="px-1.5 text-right text-2xs font-semibold text-foreground">
251
+ {totalLabel}
252
+ </th>
253
+ ) : null}
254
+ </tr>
255
+ </thead>
256
+ <tbody ref={bodyRef} onKeyDown={onKeyDown}>
257
+ {rows.map((r, ri) => (
258
+ <tr key={`${ri}-${String(r?.[y])}`}>
259
+ <th
260
+ scope="row"
261
+ className="sticky left-0 z-[1] bg-card pr-2 text-left text-xs font-normal whitespace-nowrap text-muted-foreground"
262
+ >
263
+ {rowName(r)}
264
+ </th>
265
+ {cols.map((c, ci) => {
266
+ const v = num(r?.[c.key]);
267
+ const shade = shadeFor(scaleStep(v, lo, hi, steps), steps, tone);
268
+ const tip = tipOf(v, r, c);
269
+ const cell = (
270
+ <div
271
+ data-cell={`${ri}-${ci}`}
272
+ tabIndex={ri === ar && ci === ac ? 0 : -1}
273
+ aria-label={tip}
274
+ onFocus={() => setActive([ri, ci])}
275
+ onClick={onSelect ? () => onSelect(r, c.key, v) : undefined}
276
+ style={shade.style}
277
+ className={cx(
278
+ "flex w-full items-center justify-center text-2xs font-medium outline-none",
279
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
280
+ onSelect && "cursor-pointer",
281
+ cellBox,
282
+ shade.className,
283
+ )}
284
+ >
285
+ {showValues && v != null ? <span data-nums aria-hidden="true">{format(v)}</span> : null}
286
+ </div>
287
+ );
288
+ return (
289
+ <td key={c.key} className="p-0 [&>span]:flex">
290
+ {tooltip ? (
291
+ <Tooltip label={tip} delay={150}>
292
+ {cell}
293
+ </Tooltip>
294
+ ) : (
295
+ cell
296
+ )}
297
+ </td>
298
+ );
299
+ })}
300
+ {rowTotals ? (
301
+ <td data-nums className={totalCell}>
302
+ {format(sum(cols.map((c) => r?.[c.key])) ?? 0)}
303
+ </td>
304
+ ) : null}
305
+ </tr>
306
+ ))}
307
+ </tbody>
308
+ {colTotals ? (
309
+ <tfoot>
310
+ <tr>
311
+ <th scope="row" className="sticky left-0 z-[1] bg-card pr-2 text-left text-xs font-semibold text-foreground">
312
+ {totalLabel}
313
+ </th>
314
+ {colSums.map((s, i) => (
315
+ <td key={cols[i].key} data-nums className="px-0.5 text-center text-2xs font-semibold text-foreground whitespace-nowrap">
316
+ {format(s ?? 0)}
317
+ </td>
318
+ ))}
319
+ {rowTotals ? (
320
+ <td data-nums className={totalCell}>
321
+ {format(sum(colSums) ?? 0)}
322
+ </td>
323
+ ) : null}
324
+ </tr>
325
+ </tfoot>
326
+ ) : null}
327
+ </table>
328
+ </div>
329
+ {legend ? (
330
+ <div className="flex justify-end">
331
+ <ScaleLegend min={lo} max={hi} steps={steps} tone={tone} labels={legendLabels} format={format} shape={cellShape} />
332
+ </div>
333
+ ) : null}
334
+ </div>
335
+ );
336
+ }
@@ -0,0 +1,8 @@
1
+ // The Chart block — `makersclaw add chart`. Fixed: compose it through its
2
+ // props (README.md beside this file); a chart it cannot be is your own
3
+ // component in components/.
4
+ export { LineChart, AreaChart, BarChart } from "./cartesian";
5
+ export { PieChart } from "./pie";
6
+ export { Sparkline } from "./sparkline";
7
+ export { ChartLegend } from "./core";
8
+ export { HeatmapChart, ScaleLegend, scaleStep, scaleShade } from "./heatmap";
@@ -0,0 +1,245 @@
1
+ "use client";
2
+
3
+ import { useMemo, useState } from "react";
4
+ import { cx } from "../../ui";
5
+ import { ChartEmpty, ChartLegend, DataTable, TooltipBox, defaultFormat, humanize, num, tone, toneOf, useReveal, useWidth } from "./core";
6
+
7
+ // PieChart — parts of one whole, one slice per row; `donut` opens the
8
+ // middle and writes the total (or your words) there. Pointer, touch or the
9
+ // arrow keys pick a slice: it lifts, and the tooltip gives its value and
10
+ // share. The legend hides a slice and the rest re-share the whole.
11
+
12
+ const TAU = Math.PI * 2;
13
+
14
+ function point(cx0, cy0, r, a) {
15
+ return [cx0 + r * Math.cos(a), cy0 + r * Math.sin(a)];
16
+ }
17
+
18
+ const f = (n) => Math.round(n * 100) / 100;
19
+
20
+ function slicePath(c, r, inner, a0, a1) {
21
+ // A whole circle cannot be one arc: draw it as two halves.
22
+ if (a1 - a0 >= TAU - 1e-6) {
23
+ const mid = a0 + Math.PI;
24
+ return slicePath(c, r, inner, a0, mid) + slicePath(c, r, inner, mid, a1);
25
+ }
26
+ const large = a1 - a0 > Math.PI ? 1 : 0;
27
+ const [x0, y0] = point(c.x, c.y, r, a0);
28
+ const [x1, y1] = point(c.x, c.y, r, a1);
29
+ if (!inner) return `M${f(c.x)},${f(c.y)}L${f(x0)},${f(y0)}A${f(r)},${f(r)} 0 ${large} 1 ${f(x1)},${f(y1)}Z`;
30
+ const [x2, y2] = point(c.x, c.y, inner, a1);
31
+ const [x3, y3] = point(c.x, c.y, inner, a0);
32
+ return `M${f(x0)},${f(y0)}A${f(r)},${f(r)} 0 ${large} 1 ${f(x1)},${f(y1)}L${f(x2)},${f(y2)}A${f(inner)},${f(inner)} 0 ${large} 0 ${f(x3)},${f(y3)}Z`;
33
+ }
34
+
35
+ export function PieChart({
36
+ data,
37
+ value = "value",
38
+ name = "name",
39
+ format = defaultFormat,
40
+ formatName = (v) => (v == null ? "" : String(v)),
41
+ label = "Chart",
42
+ description,
43
+ height = 240,
44
+ donut = false,
45
+ centerLabel,
46
+ totalLabel = "Total",
47
+ legend = true,
48
+ legendValues = "percent",
49
+ tooltip = true,
50
+ onSelect,
51
+ emptyLabel = "No data yet",
52
+ emptyBody,
53
+ className,
54
+ }) {
55
+ const [boxRef, width] = useWidth();
56
+ const [hidden, setHidden] = useState(() => new Set());
57
+ const [active, setActive] = useState(null);
58
+ const [keyed, setKeyed] = useState(false);
59
+ const shown = useReveal(width > 0);
60
+
61
+ const rows = Array.isArray(data) ? data : [];
62
+ const slices = useMemo(
63
+ () =>
64
+ rows.map((r, i) => ({
65
+ row: r,
66
+ key: String(r?.[name] ?? i),
67
+ label: formatName(r?.[name], r) || humanize(r?.[name]),
68
+ tone: toneOf(r, i),
69
+ value: Math.max(0, num(r?.[value]) ?? 0),
70
+ })),
71
+ [rows, name, value], // eslint-disable-line react-hooks/exhaustive-deps
72
+ );
73
+ const live = slices.filter((s) => !hidden.has(s.key) && s.value > 0);
74
+ const total = live.reduce((sum, s) => sum + s.value, 0);
75
+ const pct = (v) => (total ? `${Math.round((v / total) * 1000) / 10}%` : "0%");
76
+
77
+ const size = Math.max(0, Math.min(width, height));
78
+ const c = { x: width / 2, y: height / 2 };
79
+ const r = Math.max(0, size / 2 - 6);
80
+ const inner = donut ? r * 0.62 : 0;
81
+
82
+ let a = -Math.PI / 2;
83
+ const arcs = live.map((s) => {
84
+ const span = total ? (s.value / total) * TAU : 0;
85
+ // A gap between slices by angle, not a stroke: no guess at the colour
86
+ // of whatever the chart sits on.
87
+ const pad = live.length > 1 ? Math.min(0.012, span / 4) : 0;
88
+ const out = { ...s, a0: a, a1: a + span, pad };
89
+ a += span;
90
+ return out;
91
+ });
92
+
93
+ function onKeyDown(e) {
94
+ if (!arcs.length) return;
95
+ let next = null;
96
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") next = active == null ? 0 : (active + 1) % arcs.length;
97
+ else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = active == null ? arcs.length - 1 : (active - 1 + arcs.length) % arcs.length;
98
+ else if (e.key === "Home") next = 0;
99
+ else if (e.key === "End") next = arcs.length - 1;
100
+ else if (e.key === "Escape") return setActive(null);
101
+ else if ((e.key === "Enter" || e.key === " ") && onSelect && active != null) {
102
+ e.preventDefault();
103
+ onSelect(arcs[active].row, active);
104
+ return;
105
+ }
106
+ if (next == null) return;
107
+ e.preventDefault();
108
+ setKeyed(true);
109
+ setActive(next);
110
+ }
111
+
112
+ const summary = arcs.length
113
+ ? `${arcs.length} parts of ${format(total)}: ${arcs
114
+ .slice()
115
+ .sort((p, q) => q.value - p.value)
116
+ .map((s) => `${s.label} ${format(s.value)} (${pct(s.value)})`)
117
+ .join(", ")}.`
118
+ : "";
119
+
120
+ const legendNode = legend ? (
121
+ <ChartLegend
122
+ items={slices.map((s) => ({
123
+ key: s.key,
124
+ label: s.label,
125
+ tone: s.tone,
126
+ value: hidden.has(s.key) ? null : legendValues === "value" ? format(s.value) : legendValues === "percent" ? pct(s.value) : null,
127
+ }))}
128
+ hidden={hidden}
129
+ onToggle={(key) => {
130
+ setActive(null);
131
+ setHidden((h) => {
132
+ const next = new Set(h);
133
+ if (next.has(key)) next.delete(key);
134
+ else next.add(key);
135
+ return next;
136
+ });
137
+ }}
138
+ label={`${label}: parts`}
139
+ />
140
+ ) : null;
141
+
142
+ if (!rows.length) {
143
+ return (
144
+ <div className={cx("grid gap-3", className)}>
145
+ <ChartEmpty height={height} title={emptyLabel} body={emptyBody} />
146
+ </div>
147
+ );
148
+ }
149
+
150
+ const hit = active != null ? arcs[active] : null;
151
+ let tipAt = null;
152
+ // A donut says it in its middle; a pie needs the box.
153
+ if (hit && tooltip && !donut) {
154
+ const mid = (hit.a0 + hit.a1) / 2;
155
+ const [tx, ty] = point(c.x, c.y, (r + inner) / 2 + (donut ? 0 : r * 0.15), mid);
156
+ tipAt = { x: tx, y: ty, flip: tx > c.x, middle: true };
157
+ }
158
+ const centre =
159
+ centerLabel !== undefined
160
+ ? typeof centerLabel === "object" && centerLabel !== null && !("$$typeof" in centerLabel)
161
+ ? centerLabel
162
+ : { value: centerLabel }
163
+ : { value: format(total), label: totalLabel };
164
+
165
+ return (
166
+ <div className={cx("grid min-w-0 gap-3", className)}>
167
+ <div
168
+ ref={boxRef}
169
+ tabIndex={0}
170
+ role="group"
171
+ aria-label={`${label}. Arrow keys read each part.`}
172
+ onKeyDown={onKeyDown}
173
+ onFocus={(e) => {
174
+ if (e.currentTarget.matches(":focus-visible") && active == null && arcs.length) {
175
+ setKeyed(true);
176
+ setActive(0);
177
+ }
178
+ }}
179
+ onBlur={() => {
180
+ setKeyed(false);
181
+ setActive(null);
182
+ }}
183
+ className="relative min-w-0 rounded-md outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
184
+ style={{ height }}
185
+ >
186
+ {width > 0 ? (
187
+ <svg
188
+ role="img"
189
+ aria-label={`${label}. ${description ?? summary}`}
190
+ width={width}
191
+ height={height}
192
+ viewBox={`0 0 ${width} ${height}`}
193
+ className={cx("block touch-pan-y select-none", onSelect && "cursor-pointer")}
194
+ onPointerLeave={() => !keyed && setActive(null)}
195
+ >
196
+ {/* raw: an SVG drawing — no kit part draws a chart. */}
197
+ {arcs.length === 0 ? (
198
+ <circle cx={c.x} cy={c.y} r={r} className="fill-muted" />
199
+ ) : null}
200
+ <g
201
+ style={{ transform: shown ? "none" : "rotate(-60deg) scale(0.9)", transformOrigin: `${c.x}px ${c.y}px`, opacity: shown ? 1 : 0 }}
202
+ className="motion-safe:transition-all motion-safe:duration-700 motion-safe:ease-out"
203
+ >
204
+ {arcs.map((s, i) => (
205
+ <path
206
+ key={s.key}
207
+ d={slicePath(c, active === i ? r + 4 : r, inner, s.a0 + s.pad, s.a1 - s.pad)}
208
+ className={cx(tone(s.tone, "fill"), active != null && active !== i && "opacity-60", "motion-safe:transition-opacity")}
209
+ onPointerEnter={() => {
210
+ setKeyed(false);
211
+ setActive(i);
212
+ }}
213
+ onPointerDown={() => setActive(i)}
214
+ onClick={() => onSelect?.(s.row, i)}
215
+ />
216
+ ))}
217
+ </g>
218
+ {donut && centre ? (
219
+ <g aria-hidden="true" textAnchor="middle">
220
+ <text x={c.x} y={c.y} dy={centre.label ? "-0.1em" : "0.35em"} className="fill-foreground text-2xl font-semibold" data-nums>
221
+ {hit ? format(hit.value) : centre.value}
222
+ </text>
223
+ {centre.label || hit ? (
224
+ <text x={c.x} y={c.y} dy="1.6em" className="fill-muted-foreground text-xs">
225
+ {hit ? `${hit.label} · ${pct(hit.value)}` : centre.label}
226
+ </text>
227
+ ) : null}
228
+ </g>
229
+ ) : null}
230
+ </svg>
231
+ ) : null}
232
+ {tipAt ? <TooltipBox at={tipAt} title={hit.label} rows={[{ key: hit.key, label: pct(hit.value), tone: hit.tone, value: format(hit.value) }]} /> : null}
233
+ <div className="sr-only" aria-live="polite">
234
+ {keyed && hit ? `${hit.label}: ${format(hit.value)}, ${pct(hit.value)}` : ""}
235
+ </div>
236
+ </div>
237
+ {legendNode}
238
+ <DataTable
239
+ caption={label}
240
+ head={["", "Value", "Share"]}
241
+ body={slices.map((s) => [s.label, format(s.value), hidden.has(s.key) ? "hidden" : pct(s.value)])}
242
+ />
243
+ </div>
244
+ );
245
+ }
@@ -0,0 +1,88 @@
1
+ "use client";
2
+
3
+ import { useId } from "react";
4
+ import { cx } from "../../ui";
5
+ import { defaultFormat, idFrom, num, tone, useReveal, useWidth } from "./core";
6
+
7
+ // Sparkline — a trend with no axes, the size of a line of text: beside a
8
+ // KPI, in a table cell. Its scale is its own low to high (not zero), so
9
+ // the shape shows the change. A screen reader hears the first, last, low
10
+ // and high values; there is nothing to hover.
11
+
12
+ const f = (n) => Math.round(n * 100) / 100;
13
+
14
+ export function Sparkline({
15
+ data,
16
+ value = "value",
17
+ label = "Trend",
18
+ format = defaultFormat,
19
+ tone: t = "chart-1",
20
+ area = true,
21
+ dot = true,
22
+ height = 36,
23
+ className,
24
+ }) {
25
+ const uid = idFrom(useId());
26
+ const [boxRef, width] = useWidth();
27
+ const shown = useReveal(width > 0);
28
+
29
+ const vals = (Array.isArray(data) ? data : []).map((d) => num(typeof d === "object" && d !== null ? d[value] : d)).filter((v) => v != null);
30
+ const n = vals.length;
31
+ const lo = n ? Math.min(...vals) : 0;
32
+ const hi = n ? Math.max(...vals) : 0;
33
+ const pad = 3;
34
+ const px = (i) => pad + (n === 1 ? (width - pad * 2) / 2 : (i * (width - pad * 2)) / (n - 1));
35
+ const py = (v) => pad + (hi === lo ? (height - pad * 2) / 2 : (1 - (v - lo) / (hi - lo)) * (height - pad * 2));
36
+ const line = vals.map((v, i) => `${i ? "L" : "M"}${f(px(i))},${f(py(v))}`).join("");
37
+ const words = n
38
+ ? `${label}: from ${format(vals[0])} to ${format(vals[n - 1])}, low ${format(lo)}, high ${format(hi)}.`
39
+ : `${label}: no data yet.`;
40
+
41
+ return (
42
+ <div ref={boxRef} className={cx("min-w-0", className)} style={{ height }}>
43
+ {width > 0 ? (
44
+ <svg role="img" aria-label={words} width={width} height={height} viewBox={`0 0 ${width} ${height}`} className="block overflow-visible">
45
+ {/* raw: an SVG drawing — no kit part draws a chart. */}
46
+ {n === 0 ? (
47
+ <line x1={pad} x2={width - pad} y1={height / 2} y2={height / 2} className="stroke-border" strokeDasharray="3 3" />
48
+ ) : (
49
+ <>
50
+ <defs>
51
+ <clipPath id={`${uid}-clip`}>
52
+ <rect
53
+ x={0}
54
+ y={-4}
55
+ width={width + 4}
56
+ height={height + 8}
57
+ style={{ transform: shown ? "none" : "scaleX(0)", transformOrigin: "0 0" }}
58
+ className="motion-safe:transition-transform motion-safe:duration-700 motion-safe:ease-out"
59
+ />
60
+ </clipPath>
61
+ {/* An alpha mask, not a colour: the fill fades downward. */}
62
+ <linearGradient id={`${uid}-g`} x1="0" y1="0" x2="0" y2="1">
63
+ <stop offset="0" stopOpacity="1" />
64
+ <stop offset="1" stopOpacity="0" />
65
+ </linearGradient>
66
+ <mask id={`${uid}-fade`} style={{ maskType: "alpha" }} maskUnits="userSpaceOnUse" x={0} y={0} width={width} height={height}>
67
+ <rect x={0} y={0} width={width} height={height} fill={`url(#${uid}-g)`} />
68
+ </mask>
69
+ </defs>
70
+ <g clipPath={`url(#${uid}-clip)`}>
71
+ {area && n > 1 ? (
72
+ <path
73
+ d={`${line}L${f(px(n - 1))},${height}L${f(px(0))},${height}Z`}
74
+ className={tone(t, "fill")}
75
+ fillOpacity={0.3}
76
+ mask={`url(#${uid}-fade)`}
77
+ />
78
+ ) : null}
79
+ <path d={line} fill="none" className={tone(t, "stroke")} strokeWidth={1.75} strokeLinejoin="round" strokeLinecap="round" />
80
+ {dot ? <circle cx={px(n - 1)} cy={py(vals[n - 1])} r={2.5} className={tone(t, "fill")} /> : null}
81
+ </g>
82
+ </>
83
+ )}
84
+ </svg>
85
+ ) : null}
86
+ </div>
87
+ );
88
+ }