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,449 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { Avatar, Button, Calendar, Icon, Menu, Popover, StatusDot, cx } from "../../ui";
5
+ import { addDays, dayOf, dueBucket, endOfWeek, formatDay, formatTime, minutesOf, withTime } from "./dates";
6
+ import { NONE, PRIORITIES, createTaskContext, isDone } from "./model";
7
+
8
+ // The small pieces every task view draws the same way: a status, the
9
+ // people on it, its due date, its priority, a compact chip. Each is a
10
+ // label by default and a picker when given `onChange` — the view hands
11
+ // the picked value to its commit. Tokens only: a status says its tone,
12
+ // a project its hue (chart-1…5).
13
+
14
+ const ctxOf = (ctx) => (ctx && ctx.statusById ? ctx : createTaskContext(ctx ?? {}));
15
+
16
+ export const TONE_TEXT = {
17
+ neutral: "text-muted-foreground",
18
+ primary: "text-primary",
19
+ info: "text-info",
20
+ success: "text-success",
21
+ warning: "text-warning",
22
+ danger: "text-destructive",
23
+ };
24
+
25
+ export const HUE_EDGE = {
26
+ 1: "border-s-chart-1",
27
+ 2: "border-s-chart-2",
28
+ 3: "border-s-chart-3",
29
+ 4: "border-s-chart-4",
30
+ 5: "border-s-chart-5",
31
+ };
32
+
33
+ export const HUE_BG = {
34
+ 1: "bg-chart-1",
35
+ 2: "bg-chart-2",
36
+ 3: "bg-chart-3",
37
+ 4: "bg-chart-4",
38
+ 5: "bg-chart-5",
39
+ };
40
+
41
+ // A trigger that looks like its label until hovered: the pickers' face.
42
+ const PICK = "rounded-md px-1.5 hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring";
43
+
44
+ /** A status as a dot and its words. With `onChange(id)`, a menu of the
45
+ * statuses. `size` sm (a row) · md. `hideLabel` for a dense cell. */
46
+ export function StatusPill({ status, ctx, onChange, size = "sm", hideLabel = false, className }) {
47
+ const c = ctxOf(ctx);
48
+ const s = c.statusById.get(String(status));
49
+ const face = (
50
+ <span className={cx("relative inline-flex min-w-0 items-center gap-1.5", size === "sm" ? "text-xs" : "text-sm")}>
51
+ <StatusDot tone={s ? s.tone ?? (s.hue ? undefined : "neutral") : "neutral"} hue={s?.hue} size={size === "sm" ? "sm" : "md"} />
52
+ <span className={cx("truncate", hideLabel && "sr-only", s ? "text-foreground" : "text-muted-foreground")}>{s?.label ?? "No status"}</span>
53
+ </span>
54
+ );
55
+ if (!onChange) return <span className={cx("inline-flex min-w-0", className)}>{face}</span>;
56
+ return (
57
+ <Menu
58
+ label={`Status: ${s?.label ?? "none"}. Change status`}
59
+ trigger={face}
60
+ align="start"
61
+ className={cx(PICK, className)}
62
+ items={[
63
+ {
64
+ type: "radio",
65
+ value: s?.id ?? "",
66
+ onValueChange: (v) => v !== s?.id && onChange(v),
67
+ options: c.statuses.map((x) => ({ value: x.id, label: x.label })),
68
+ },
69
+ ]}
70
+ />
71
+ );
72
+ }
73
+
74
+ /** The round check that completes a task (not the square one that
75
+ * selects it). Shows the done state; `onToggle()` when pressed. */
76
+ export function CompleteToggle({ done, onToggle, label = "task", disabled, size = "md", className }) {
77
+ const box = size === "sm" ? "size-4" : "size-[18px]";
78
+ return (
79
+ // raw: a completion check is round and toggles a status, not a form
80
+ // value — the kit's Checkbox is the square selection box beside it.
81
+ <button
82
+ type="button"
83
+ role="checkbox"
84
+ aria-checked={Boolean(done)}
85
+ aria-label={done ? `Mark ${label} not done` : `Complete ${label}`}
86
+ disabled={disabled || !onToggle}
87
+ onClick={onToggle}
88
+ className={cx(
89
+ "group/check inline-flex size-9 shrink-0 items-center justify-center rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default",
90
+ className,
91
+ )}
92
+ >
93
+ <span
94
+ className={cx(
95
+ "inline-flex items-center justify-center rounded-full border transition-colors duration-150",
96
+ box,
97
+ done ? "border-success bg-success text-background" : "border-muted-foreground/50 text-transparent group-hover/check:border-success group-hover/check:text-success",
98
+ )}
99
+ >
100
+ <Icon name="check" size={size === "sm" ? 10 : 12} />
101
+ </span>
102
+ </button>
103
+ );
104
+ }
105
+
106
+ /** The people on a task: overlapping faces, or a dashed "assign" circle.
107
+ * With `onChange(ids)`, a menu of people to tick (it stays open). */
108
+ export function AssigneeStack({ ids, ctx, onChange, max = 3, size = "xs", className }) {
109
+ const c = ctxOf(ctx);
110
+ const list = (ids ?? []).map((id) => c.personById.get(String(id)) ?? { id, name: String(id) });
111
+ // Spans, not the kit's AvatarGroup (a div): the faces sit inside the
112
+ // picker's button, where a div is invalid HTML.
113
+ const shown = list.slice(0, max);
114
+ const rest = list.length - shown.length;
115
+ const face = list.length ? (
116
+ <span className="inline-flex items-center -space-x-1.5" title={list.map((p) => p.name).join(", ")}>
117
+ {shown.map((p) => (
118
+ <Avatar key={p.id} name={p.name} src={p.src} size={size} className="ring-2 ring-card" />
119
+ ))}
120
+ {rest > 0 ? (
121
+ <span data-nums className="relative inline-flex size-6 items-center justify-center rounded-full bg-muted text-2xs font-medium text-muted-foreground ring-2 ring-card">
122
+ +{rest}
123
+ </span>
124
+ ) : null}
125
+ </span>
126
+ ) : (
127
+ <span aria-hidden="true" className="inline-flex size-6 items-center justify-center rounded-full border border-dashed border-muted-foreground/50 text-muted-foreground">
128
+ <Icon name="user" size={12} />
129
+ </span>
130
+ );
131
+ if (!onChange) {
132
+ return list.length ? (
133
+ <span className={cx("inline-flex", className)}>{face}</span>
134
+ ) : (
135
+ <span className={cx("relative inline-flex", className)}>
136
+ {face}
137
+ <span className="sr-only">Unassigned</span>
138
+ </span>
139
+ );
140
+ }
141
+ const set = new Set((ids ?? []).map(String));
142
+ return (
143
+ <Menu
144
+ label={list.length ? `Assigned to ${list.map((p) => p.name).join(", ")}. Change` : "Assign"}
145
+ trigger={face}
146
+ className={cx(PICK, className)}
147
+ items={
148
+ c.people.length
149
+ ? c.people.map((p) => ({
150
+ type: "checkbox",
151
+ label: p.name,
152
+ checked: set.has(p.id),
153
+ onCheckedChange: (on) => onChange(on ? [...set, p.id] : [...set].filter((x) => x !== p.id)),
154
+ }))
155
+ : [{ type: "label", label: "No people to assign yet" }]
156
+ }
157
+ />
158
+ );
159
+ }
160
+
161
+ /** One person: a face and a name (a group header, a workload row). */
162
+ export function PersonLabel({ id, ctx, size = "xs", className }) {
163
+ const c = ctxOf(ctx);
164
+ if (!id || id === NONE) {
165
+ return (
166
+ <span className={cx("inline-flex items-center gap-2", className)}>
167
+ <span aria-hidden="true" className="inline-flex size-6 items-center justify-center rounded-full border border-dashed border-muted-foreground/50 text-muted-foreground">
168
+ <Icon name="user" size={12} />
169
+ </span>
170
+ <span className="truncate">Unassigned</span>
171
+ </span>
172
+ );
173
+ }
174
+ const p = c.personById.get(String(id)) ?? { name: String(id) };
175
+ return (
176
+ <span className={cx("inline-flex min-w-0 items-center gap-2", className)}>
177
+ <Avatar name={p.name} src={p.src} size={size} />
178
+ <span className="truncate">{p.name}</span>
179
+ </span>
180
+ );
181
+ }
182
+
183
+ const DUE_TONE = { overdue: "text-destructive", today: "text-warning" };
184
+
185
+ /** A due date the way a person says it ("Today", "Fri", "Oct 30"), red
186
+ * when overdue and amber today — unless the task is done. With
187
+ * `onChange(day | null)`, a calendar with quick picks; an empty one
188
+ * shows only its glyph until the row is hovered (`quiet`, default) —
189
+ * pass quiet={false} to always say `placeholder`. */
190
+ export function DueLabel({ value, done = false, ctx, onChange, placeholder = "Due date", quiet = true, className }) {
191
+ const c = ctxOf(ctx);
192
+ const [open, setOpen] = useState(false);
193
+ const day = dayOf(value);
194
+ const bucket = dueBucket(value, c.today, { done, weekStartsOn: c.weekStartsOn });
195
+ const time = formatTime(value);
196
+ const words = day ? `${formatDay(day, c.today)}${time ? ` ${time}` : ""}` : "";
197
+ const face = (
198
+ <span className={cx("inline-flex items-center gap-1 whitespace-nowrap text-xs", day ? DUE_TONE[bucket] ?? "text-muted-foreground" : "text-muted-foreground")}>
199
+ <Icon name="calendar" size={14} className={day ? undefined : "opacity-60"} />
200
+ {day ? (
201
+ <span data-nums>{words}</span>
202
+ ) : onChange ? (
203
+ <span className={quiet ? "sr-only sm:not-sr-only sm:opacity-0 sm:transition-opacity sm:duration-150 sm:group-hover/row:opacity-100 sm:group-focus-within/row:opacity-100" : undefined}>{placeholder}</span>
204
+ ) : null}
205
+ </span>
206
+ );
207
+ if (!onChange) {
208
+ return day ? (
209
+ <span className={cx("inline-flex", className)} title={bucket === "overdue" ? "Overdue" : undefined}>
210
+ {face}
211
+ </span>
212
+ ) : null;
213
+ }
214
+ const pick = (d) => {
215
+ setOpen(false);
216
+ onChange(d ? withTime(d, minutesOf(value)) : null);
217
+ };
218
+ const quick = [
219
+ { label: "Today", day: c.today },
220
+ { label: "Tomorrow", day: addDays(c.today, 1) },
221
+ { label: "Next week", day: addDays(endOfWeek(c.today, c.weekStartsOn), 1) },
222
+ ];
223
+ return (
224
+ <Popover
225
+ label={day ? `Due ${words}. Change due date` : "Set a due date"}
226
+ open={open}
227
+ onOpenChange={setOpen}
228
+ width="auto"
229
+ align="end"
230
+ className="p-2"
231
+ trigger={(props) => (
232
+ // raw: Popover hands its trigger props (ref, popoverTarget) to a
233
+ // button of ours; the face is a date's words, not a kit Button.
234
+ <button type="button" {...props} aria-label={day ? `Due ${words}. Change due date` : "Set a due date"} className={cx("inline-flex min-h-9 items-center outline-none", PICK, className)}>
235
+ {face}
236
+ </button>
237
+ )}
238
+ >
239
+ <div className="grid gap-2">
240
+ <div className="flex flex-wrap gap-1">
241
+ {quick.map((q) => (
242
+ <Button key={q.label} size="sm" variant={q.day === day ? "secondary" : "quiet"} onClick={() => pick(q.day)}>
243
+ {q.label}
244
+ </Button>
245
+ ))}
246
+ </div>
247
+ <Calendar value={day} onChange={(d) => pick(d)} today={c.today} weekStartsOn={c.weekStartsOn} size="sm" autoFocus={open} label="Due date" />
248
+ {day ? (
249
+ <Button size="sm" variant="quiet" icon="x" align="start" onClick={() => pick(null)}>
250
+ Remove due date
251
+ </Button>
252
+ ) : null}
253
+ </div>
254
+ </Popover>
255
+ );
256
+ }
257
+
258
+ /** A priority as a flag in its tone. With `onChange(id | null)`, a menu. */
259
+ export function PriorityFlag({ value, onChange, showLabel = false, className }) {
260
+ const p = PRIORITIES.find((x) => x.id === value);
261
+ const face = (
262
+ <span className={cx("relative inline-flex items-center gap-1 text-xs", p ? TONE_TEXT[p.tone] : "text-muted-foreground")}>
263
+ <Icon name="flag" size={14} className={p ? undefined : "opacity-40"} />
264
+ {showLabel && p ? <span className="text-foreground">{p.label}</span> : null}
265
+ {!p ? <span className="sr-only">No priority</span> : null}
266
+ </span>
267
+ );
268
+ if (!onChange) {
269
+ if (!p) return null;
270
+ return (
271
+ // relative: its sr-only label is absolute, and without a positioned
272
+ // parent inside a sideways-scrolling row it escaped the scroller and
273
+ // widened the page (task-model at 390px, 2026-09-24).
274
+ <span className={cx("relative inline-flex", className)} title={`${p.label} priority`}>
275
+ {face}
276
+ <span className="sr-only">{p.label} priority</span>
277
+ </span>
278
+ );
279
+ }
280
+ return (
281
+ <Menu
282
+ label={p ? `${p.label} priority. Change priority` : "Set priority"}
283
+ trigger={face}
284
+ className={cx(PICK, !p && "opacity-0 transition-opacity duration-150 group-hover/row:opacity-100 group-focus-within/row:opacity-100 focus-visible:opacity-100 [@media(hover:none)]:opacity-100", className)}
285
+ items={[
286
+ {
287
+ type: "radio",
288
+ value: p?.id ?? NONE,
289
+ onValueChange: (v) => onChange(v === NONE ? null : v),
290
+ options: [...PRIORITIES.map((x) => ({ value: x.id, label: x.label })), { value: NONE, label: "No priority" }],
291
+ },
292
+ ]}
293
+ />
294
+ );
295
+ }
296
+
297
+ /** Tags as quiet chips; the first `max`, then "+N". */
298
+ export function TagList({ tags, max = 2, className }) {
299
+ const list = tags ?? [];
300
+ if (!list.length) return null;
301
+ const shown = list.slice(0, max);
302
+ const rest = list.length - shown.length;
303
+ return (
304
+ <span className={cx("inline-flex min-w-0 items-center gap-1", className)}>
305
+ {shown.map((t) => (
306
+ <span key={t} className="max-w-28 truncate rounded-sm bg-muted px-1.5 py-0.5 text-2xs text-muted-foreground">
307
+ {t}
308
+ </span>
309
+ ))}
310
+ {rest > 0 ? (
311
+ <span className="text-2xs text-muted-foreground" title={list.slice(max).join(", ")}>
312
+ +{rest}
313
+ </span>
314
+ ) : null}
315
+ </span>
316
+ );
317
+ }
318
+
319
+ /** "2/5" subtasks done, with the list glyph. */
320
+ export function SubtaskCount({ done, total, className }) {
321
+ if (!total) return null;
322
+ return (
323
+ <span className={cx("inline-flex items-center gap-1 text-xs text-muted-foreground", className)} title={`${done} of ${total} subtasks done`}>
324
+ <Icon name="list" size={14} />
325
+ <span data-nums>
326
+ {done}/{total}
327
+ </span>
328
+ </span>
329
+ );
330
+ }
331
+
332
+ /** A thin progress line (0–100) for a row or a bar. */
333
+ export function ProgressLine({ value, className }) {
334
+ const v = Math.max(0, Math.min(100, Number(value) || 0));
335
+ return (
336
+ <span className={cx("relative block h-1 w-full overflow-hidden rounded-full bg-muted", className)} role="img" aria-label={`${Math.round(v)}% done`}>
337
+ <span className={cx("absolute inset-y-0 start-0 rounded-full", v >= 100 ? "bg-success" : "bg-primary")} style={{ width: `${v}%` }} />
338
+ </span>
339
+ );
340
+ }
341
+
342
+ /** A task as one compact line: the chip a calendar day, a gantt label or
343
+ * a workload cell draws. Status dot, title, time (when it has one), the
344
+ * first face; a project's hue on its leading edge. `onOpen(task)` makes
345
+ * it a button. Spread drag props (`dragProps`) onto it for dragging. */
346
+ export function TaskChip({ task, ctx, onOpen, showTime = true, showPeople = true, dragging = false, lifted = false, dragProps, className }) {
347
+ const c = ctxOf(ctx);
348
+ const s = c.statusById.get(String(task.status));
349
+ const project = c.projectById.get(String(task.project));
350
+ const done = isDone(task, c);
351
+ const time = showTime ? formatTime(task.start ?? task.due) : "";
352
+ const first = task.assignees?.[0] ? c.personById.get(task.assignees[0]) : null;
353
+ const Tag = onOpen ? "button" : "div";
354
+ return (
355
+ // raw: a chip is a draggable, openable card-let; a kit Button would
356
+ // centre and pad it as an action.
357
+ <Tag
358
+ type={onOpen ? "button" : undefined}
359
+ onClick={onOpen ? () => onOpen(task) : undefined}
360
+ {...dragProps}
361
+ className={cx(
362
+ "flex w-full min-w-0 items-center gap-1.5 rounded-md border border-border bg-card px-2 py-1 text-left text-xs text-card-foreground outline-none transition-[box-shadow,opacity] duration-150",
363
+ project?.hue && HUE_EDGE[project.hue] ? cx("border-s-[3px]", HUE_EDGE[project.hue]) : null,
364
+ onOpen && "hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring",
365
+ dragging && "opacity-40",
366
+ lifted && "cursor-grabbing shadow-lg ring-1 ring-border",
367
+ className,
368
+ )}
369
+ >
370
+ <StatusDot tone={s?.tone ?? (s?.hue ? undefined : "neutral")} hue={s?.hue} size="sm" />
371
+ {time ? (
372
+ <span data-nums className="shrink-0 text-muted-foreground">
373
+ {time}
374
+ </span>
375
+ ) : null}
376
+ <span className={cx("min-w-0 flex-1 truncate font-medium", done && "text-muted-foreground line-through")}>{task.title || "Untitled"}</span>
377
+ {showPeople && first ? <Avatar name={first.name} src={first.src} size="xs" /> : null}
378
+ </Tag>
379
+ );
380
+ }
381
+
382
+ /** A group's heading face: the status dot, a person, a flag, a project
383
+ * hue, or the plain words — whatever the view is grouped by. */
384
+ export function GroupLabel({ group, by, ctx, className }) {
385
+ const c = ctxOf(ctx);
386
+ const kind = by ? c.fields.find((f) => f.key === by)?.kind : null;
387
+ if (kind === "people") return <PersonLabel id={group.key} ctx={c} className={cx("text-sm font-semibold", className)} />;
388
+ let lead = null;
389
+ if (kind === "status") lead = <StatusDot tone={group.tone ?? (group.hue ? undefined : "neutral")} hue={group.hue} />;
390
+ else if (kind === "priority") lead = <Icon name="flag" size={14} className={group.tone ? TONE_TEXT[group.tone] : "text-muted-foreground opacity-50"} />;
391
+ else if (kind === "project" && group.hue && HUE_BG[group.hue]) lead = <span aria-hidden="true" className={cx("size-2 shrink-0 rounded-sm", HUE_BG[group.hue])} />;
392
+ else if (kind === "date") lead = <Icon name="calendar" size={14} className={group.tone ? TONE_TEXT[group.tone] : "text-muted-foreground"} />;
393
+ return (
394
+ <span className={cx("inline-flex min-w-0 items-center gap-2 text-sm font-semibold", className)}>
395
+ {lead}
396
+ <span className="truncate">{group.label}</span>
397
+ </span>
398
+ );
399
+ }
400
+
401
+ /** DataTable columns for toTableRows rows: name, status, assignees, due,
402
+ * priority, project, estimate, progress, tags — sortable, drawn with the
403
+ * parts above. `keys` picks and orders them. Pass `onChange(change)` to
404
+ * make status / people / due / priority cells pickers. */
405
+ export function taskColumns(ctx, { keys = ["title", "status", "assignees", "due", "priority"], onChange } = {}) {
406
+ const c = ctxOf(ctx);
407
+ const set = (row, patch) => onChange?.({ type: "update", id: row.id, patch });
408
+ const edit = typeof onChange === "function";
409
+ const all = {
410
+ title: { key: "title", header: "Name", sortable: true, hideable: false, cell: (r) => <span className={cx("font-medium", r.done && "text-muted-foreground line-through")}>{r.title}</span> },
411
+ status: {
412
+ key: "status",
413
+ header: "Status",
414
+ sortable: true,
415
+ sortValue: (r) => r.statusIndex,
416
+ searchValue: (r) => r.statusLabel,
417
+ cell: (r) => <StatusPill status={r.status} ctx={c} onChange={edit ? (v) => set(r, { status: v }) : undefined} />,
418
+ },
419
+ assignees: {
420
+ key: "assignees",
421
+ header: "Assignee",
422
+ sortable: true,
423
+ sortValue: (r) => r.assigneeNames || null,
424
+ searchValue: (r) => r.assigneeNames,
425
+ cell: (r) => <AssigneeStack ids={r.assignees} ctx={c} onChange={edit ? (v) => set(r, { assignees: v }) : undefined} />,
426
+ },
427
+ due: {
428
+ key: "due",
429
+ header: "Due",
430
+ sortable: true,
431
+ sortValue: (r) => r.dueDay,
432
+ cell: (r) => <DueLabel value={r.due} done={r.done} ctx={c} onChange={edit ? (v) => set(r, { due: v }) : undefined} />,
433
+ },
434
+ start: { key: "start", header: "Start", sortable: true, sortValue: (r) => dayOf(r.start), cell: (r) => (r.start ? formatDay(r.start, c.today) : "") },
435
+ priority: {
436
+ key: "priority",
437
+ header: "Priority",
438
+ sortable: true,
439
+ sortValue: (r) => r.priorityRank,
440
+ searchValue: (r) => r.priorityLabel,
441
+ cell: (r) => <PriorityFlag value={r.priority} showLabel onChange={edit ? (v) => set(r, { priority: v }) : undefined} />,
442
+ },
443
+ project: { key: "project", header: "Project", sortable: true, sortValue: (r) => r.projectName || null, searchValue: (r) => r.projectName, cell: (r) => r.projectName },
444
+ estimate: { key: "estimate", header: "Estimate", sortable: true, align: "end", cell: (r) => (r.estimate ? `${r.estimate}h` : "") },
445
+ progress: { key: "progress", header: "Progress", sortable: true, width: "8rem", cell: (r) => (typeof r.progress === "number" ? <ProgressLine value={r.progress} /> : null) },
446
+ tags: { key: "tags", header: "Tags", searchValue: (r) => (r.tags ?? []).join(" "), cell: (r) => <TagList tags={r.tags} /> },
447
+ };
448
+ return keys.map((k) => all[k]).filter(Boolean);
449
+ }