makersclaw 0.2.0 → 0.3.1

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 (475) 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/cli.mjs +19 -6
  430. package/src/install.mjs +18 -0
  431. package/src/registry.mjs +38 -4
  432. package/src/shadcn.mjs +14 -1
  433. package/templates/next/files/README.md +145 -11
  434. package/templates/next/files/app/globals.css +55 -4
  435. package/templates/next/files/check/run.mjs +3 -3
  436. package/templates/next/files/components/ui/avatar.jsx +141 -0
  437. package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
  438. package/templates/next/files/components/ui/button-group.jsx +70 -0
  439. package/templates/next/files/components/ui/button.jsx +132 -12
  440. package/templates/next/files/components/ui/calendar.jsx +609 -0
  441. package/templates/next/files/components/ui/carousel.jsx +281 -0
  442. package/templates/next/files/components/ui/collapsible.jsx +208 -0
  443. package/templates/next/files/components/ui/combobox.jsx +608 -0
  444. package/templates/next/files/components/ui/command.jsx +577 -0
  445. package/templates/next/files/components/ui/context-menu.jsx +191 -0
  446. package/templates/next/files/components/ui/date-picker.jsx +360 -0
  447. package/templates/next/files/components/ui/distribution.jsx +117 -0
  448. package/templates/next/files/components/ui/feedback.jsx +143 -0
  449. package/templates/next/files/components/ui/field.jsx +115 -3
  450. package/templates/next/files/components/ui/file-input.jsx +234 -0
  451. package/templates/next/files/components/ui/icon.jsx +130 -8
  452. package/templates/next/files/components/ui/image.jsx +143 -0
  453. package/templates/next/files/components/ui/index.js +47 -2
  454. package/templates/next/files/components/ui/input-group.jsx +213 -0
  455. package/templates/next/files/components/ui/input-otp.jsx +170 -0
  456. package/templates/next/files/components/ui/item.jsx +206 -0
  457. package/templates/next/files/components/ui/menu.jsx +454 -82
  458. package/templates/next/files/components/ui/notice.jsx +126 -14
  459. package/templates/next/files/components/ui/pagination.jsx +156 -0
  460. package/templates/next/files/components/ui/popover.jsx +284 -0
  461. package/templates/next/files/components/ui/radio.jsx +193 -0
  462. package/templates/next/files/components/ui/rating.jsx +131 -0
  463. package/templates/next/files/components/ui/resizable.jsx +338 -0
  464. package/templates/next/files/components/ui/scroll-area.jsx +123 -0
  465. package/templates/next/files/components/ui/separator.jsx +119 -0
  466. package/templates/next/files/components/ui/sheet.jsx +96 -11
  467. package/templates/next/files/components/ui/slider.jsx +174 -0
  468. package/templates/next/files/components/ui/stat.jsx +574 -0
  469. package/templates/next/files/components/ui/steps.jsx +338 -0
  470. package/templates/next/files/components/ui/swatch.jsx +33 -0
  471. package/templates/next/files/components/ui/table.jsx +130 -0
  472. package/templates/next/files/components/ui/toast.jsx +440 -0
  473. package/templates/next/files/components/ui/toggle.jsx +195 -0
  474. package/templates/next/files/components/ui/tooltip.jsx +270 -0
  475. package/templates/next/template.json +264 -8
@@ -0,0 +1,123 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+ import { cx } from "./cx";
5
+
6
+ // ScrollArea — a box whose content scrolls inside it: a long list in a
7
+ // rail, a row of cards wider than the screen. The browser's own
8
+ // scrolling (touch, wheel, keys, momentum), with thin scrollbars in the
9
+ // workspace's colours. Give it a bound through className (max-h-80, h-64)
10
+ // or it simply grows.
11
+ //
12
+ // orientation vertical · horizontal · both
13
+ // fade true: the edges with more content past them fade out, so
14
+ // it is plain there is more — only while there is
15
+ // label the region's name for a screen reader ("Recent activity")
16
+ // ref the scrolling element itself (not the outer box): read and
17
+ // set scrollTop, call scrollTo — a message list that sticks
18
+ // to the bottom, a feed that keeps its place
19
+ // onScroll and every other prop (aria-busy, id, data-*) go on the
20
+ // scrolling element too
21
+ //
22
+ // When the content overflows, the box joins the tab order (a region with
23
+ // the label) so a keyboard can scroll it — Safari does not do that for a
24
+ // scroller on its own. When it fits, it is an ordinary box.
25
+
26
+ const AXES = {
27
+ vertical: "overflow-y-auto overflow-x-hidden",
28
+ horizontal: "overflow-x-auto overflow-y-hidden",
29
+ both: "overflow-auto",
30
+ };
31
+
32
+ // Each edge fades over 2rem while there is content past it.
33
+ const FADES =
34
+ "data-[more-top]:mask-t-from-[calc(100%-2rem)] data-[more-bottom]:mask-b-from-[calc(100%-2rem)] " +
35
+ "data-[more-left]:mask-l-from-[calc(100%-2rem)] data-[more-right]:mask-r-from-[calc(100%-2rem)]";
36
+
37
+ export function ScrollArea({ orientation = "vertical", fade = false, label, className, children, ref: outer, ...rest }) {
38
+ const ref = useRef(null);
39
+ const setRef = useCallback(
40
+ (el) => {
41
+ ref.current = el;
42
+ if (typeof outer === "function") return outer(el);
43
+ if (outer) outer.current = el;
44
+ },
45
+ [outer],
46
+ );
47
+ const [edges, setEdges] = useState({ scrolls: false, top: false, bottom: false, left: false, right: false });
48
+
49
+ useEffect(() => {
50
+ const el = ref.current;
51
+ if (!el) return;
52
+ const measure = () => {
53
+ const x = Math.abs(el.scrollLeft);
54
+ const overX = el.scrollWidth - el.clientWidth > 1;
55
+ const overY = el.scrollHeight - el.clientHeight > 1;
56
+ const next = {
57
+ scrolls: (orientation !== "horizontal" && overY) || (orientation !== "vertical" && overX),
58
+ top: overY && el.scrollTop > 1,
59
+ bottom: overY && el.scrollTop + el.clientHeight < el.scrollHeight - 1,
60
+ left: overX && x > 1,
61
+ right: overX && x + el.clientWidth < el.scrollWidth - 1,
62
+ };
63
+ setEdges((prev) => (Object.keys(next).every((k) => prev[k] === next[k]) ? prev : next));
64
+ };
65
+ measure();
66
+ el.addEventListener("scroll", measure, { passive: true });
67
+ if (typeof ResizeObserver === "undefined") return () => el.removeEventListener("scroll", measure);
68
+ // The box and each child: content growing inside a fixed box changes
69
+ // the overflow without resizing the box.
70
+ const ro = new ResizeObserver(measure);
71
+ const watch = () => {
72
+ ro.disconnect();
73
+ ro.observe(el);
74
+ for (const child of el.children) ro.observe(child);
75
+ };
76
+ watch();
77
+ const mo = new MutationObserver(() => {
78
+ watch();
79
+ measure();
80
+ });
81
+ mo.observe(el, { childList: true });
82
+ return () => {
83
+ el.removeEventListener("scroll", measure);
84
+ ro.disconnect();
85
+ mo.disconnect();
86
+ };
87
+ }, [orientation]);
88
+
89
+ const show = (edge) => (fade && edges[edge] ? "" : undefined);
90
+
91
+ return (
92
+ // The ring sits on this outer box: a mask on the scroller would cut
93
+ // off a ring drawn around it.
94
+ <div
95
+ className={cx(
96
+ "flex min-h-0 min-w-0 flex-col rounded-md",
97
+ "has-[>[data-scroller]:focus-visible]:ring-2 has-[>[data-scroller]:focus-visible]:ring-ring",
98
+ className,
99
+ )}
100
+ >
101
+ <div
102
+ {...rest}
103
+ ref={setRef}
104
+ data-scroller=""
105
+ tabIndex={edges.scrolls ? 0 : undefined}
106
+ role={edges.scrolls && label ? "region" : undefined}
107
+ aria-label={edges.scrolls ? label : undefined}
108
+ data-more-top={show("top")}
109
+ data-more-bottom={show("bottom")}
110
+ data-more-left={show("left")}
111
+ data-more-right={show("right")}
112
+ className={cx(
113
+ "min-h-0 flex-1 rounded-[inherit] outline-none",
114
+ "scrollbar-thin scrollbar-thumb-border scrollbar-track-transparent",
115
+ AXES[orientation] ?? AXES.vertical,
116
+ fade && FADES,
117
+ )}
118
+ >
119
+ {children}
120
+ </div>
121
+ </div>
122
+ );
123
+ }
@@ -0,0 +1,119 @@
1
+ import { cx } from "./cx";
2
+
3
+ // Small static parts that shape a layout: a separator, a key cap, a box
4
+ // that keeps its ratio. Server-safe (no hooks).
5
+
6
+ /**
7
+ * A hairline between groups. Decorative by default — most lines only
8
+ * group what spacing already groups, and a screen reader should not
9
+ * announce them. Pass `decorative={false}` when the line divides two
10
+ * sections a reader should know about (role=separator).
11
+ *
12
+ * orientation horizontal (full width) · vertical (full height of a
13
+ * flex row: toolbar groups, breadcrumb-like rows)
14
+ * decorative true (hidden from readers) · false (a separator)
15
+ * label horizontal only: a word on the line ("or")
16
+ */
17
+ export function Separator({ orientation = "horizontal", decorative = true, label, className }) {
18
+ const vertical = orientation === "vertical";
19
+ const a11y = decorative
20
+ ? { role: "none" }
21
+ : { role: "separator", "aria-orientation": vertical ? "vertical" : undefined };
22
+ if (vertical) {
23
+ return <div {...a11y} className={cx("w-px shrink-0 self-stretch bg-border", className)} />;
24
+ }
25
+ if (label) {
26
+ return (
27
+ <div {...a11y} className={cx("flex items-center gap-3 text-xs text-muted-foreground", className)}>
28
+ <span className="h-px flex-1 bg-border" />
29
+ <span>{label}</span>
30
+ <span className="h-px flex-1 bg-border" />
31
+ </div>
32
+ );
33
+ }
34
+ return <div {...a11y} className={cx("h-px w-full shrink-0 bg-border", className)} />;
35
+ }
36
+
37
+ // Symbols a reader cannot say; each is shown to the eye and spelled out
38
+ // to the ear.
39
+ const KEY_NAMES = {
40
+ "⌘": "Command",
41
+ "⌥": "Option",
42
+ "⇧": "Shift",
43
+ "⌃": "Control",
44
+ "↵": "Enter",
45
+ "⏎": "Return",
46
+ "⌫": "Backspace",
47
+ "⌦": "Delete",
48
+ "⎋": "Escape",
49
+ "⇥": "Tab",
50
+ "↑": "Up",
51
+ "↓": "Down",
52
+ "←": "Left",
53
+ "→": "Right",
54
+ };
55
+
56
+ /** One key, as printed on the keyboard: ⌘, Esc, K. A native <kbd>. */
57
+ export function Kbd({ className, children }) {
58
+ const name = typeof children === "string" ? KEY_NAMES[children] : undefined;
59
+ return (
60
+ <kbd
61
+ className={cx(
62
+ "inline-flex h-5 min-w-5 items-center justify-center rounded-sm border border-border bg-muted px-1",
63
+ "font-sans text-2xs font-medium leading-none text-muted-foreground",
64
+ className,
65
+ )}
66
+ >
67
+ {name ? (
68
+ <>
69
+ <span aria-hidden="true">{children}</span>
70
+ <span className="sr-only">{name}</span>
71
+ </>
72
+ ) : (
73
+ children
74
+ )}
75
+ </kbd>
76
+ );
77
+ }
78
+
79
+ /** A combo pressed together (⌘ K). `keys` is ["⌘", "K"]; children work
80
+ * too. Nested <kbd>s, which is how HTML spells a key combination. */
81
+ export function KbdGroup({ keys, className, children }) {
82
+ return (
83
+ <kbd className={cx("inline-flex items-center gap-1 font-sans", className)}>
84
+ {keys ? keys.map((k, i) => <Kbd key={i}>{k}</Kbd>) : children}
85
+ </kbd>
86
+ );
87
+ }
88
+
89
+ const RATIOS = {
90
+ square: "aspect-square",
91
+ video: "aspect-video",
92
+ portrait: "aspect-3/4",
93
+ photo: "aspect-4/3",
94
+ wide: "aspect-21/9",
95
+ };
96
+
97
+ /**
98
+ * A box that keeps its shape as its width changes — a thumbnail, a video,
99
+ * a map. Its one child fills it (an <img> is cropped to cover).
100
+ *
101
+ * ratio square · video (16:9) · portrait (3:4) · photo (4:3) · wide
102
+ * (21:9), or a number (width / height, e.g. 2)
103
+ */
104
+ export function AspectRatio({ ratio = "video", className, children }) {
105
+ const named = typeof ratio === "string" ? RATIOS[ratio] : undefined;
106
+ return (
107
+ <div
108
+ className={cx(
109
+ "relative w-full overflow-hidden",
110
+ named ?? (typeof ratio === "number" ? undefined : RATIOS.video),
111
+ "[&>*]:absolute [&>*]:inset-0 [&>*]:size-full [&>img]:object-cover",
112
+ className,
113
+ )}
114
+ style={typeof ratio === "number" && ratio > 0 ? { aspectRatio: ratio } : undefined}
115
+ >
116
+ {children}
117
+ </div>
118
+ );
119
+ }
@@ -1,16 +1,24 @@
1
1
  "use client";
2
2
 
3
- import { useEffect, useRef } from "react";
3
+ import { useEffect, useId, useRef, useState } from "react";
4
4
  import { cx } from "./cx";
5
5
  import { Button, IconButton } from "./button";
6
+ import { Checkbox, Input } from "./field";
6
7
 
7
8
  // Sheet — the one overlay. A native <dialog> (focus trap, Esc, scroll
8
9
  // lock and the top layer come from the browser), docked to the side the
9
10
  // surface asks for. Mobile first: on a narrow window every side becomes
10
11
  // a bottom sheet the thumb can reach. Controlled: `open` + `onClose`.
11
12
  //
12
- // side end (a rail beside the work; the default) · center (a dialog)
13
- // · bottom
13
+ // side end (a rail beside the work; the default) · start (a drawer
14
+ // from the leading edge, as navigation opens) · center (a
15
+ // dialog) · bottom
16
+ // title, description the header; the title names the dialog
17
+ // footer a row of buttons under the body
18
+ // bare true: no header and a flush body (no padding) — for a panel
19
+ // that draws its own top, as CommandDialog does. Esc and a
20
+ // press outside still close it. Give it `label`.
21
+ // label the dialog's name for a screen reader when no `title` shows
14
22
  //
15
23
  // Confirm below is the "delete this?" case — never window.confirm().
16
24
 
@@ -18,12 +26,17 @@ const SIDES = {
18
26
  end:
19
27
  "inset-y-0 right-0 left-auto h-dvh max-h-none w-full max-w-md rounded-none border-l " +
20
28
  "max-sm:inset-x-0 max-sm:top-auto max-sm:bottom-0 max-sm:h-auto max-sm:max-h-[85dvh] max-sm:max-w-none max-sm:rounded-t-xl max-sm:border-l-0 max-sm:border-t",
29
+ start:
30
+ "inset-y-0 left-0 right-auto h-dvh max-h-none w-full max-w-md rounded-none border-r " +
31
+ "max-sm:inset-x-0 max-sm:top-auto max-sm:bottom-0 max-sm:h-auto max-sm:max-h-[85dvh] max-sm:max-w-none max-sm:rounded-t-xl max-sm:border-r-0 max-sm:border-t",
21
32
  center: "m-auto w-[calc(100%-2rem)] max-w-lg rounded-lg border max-sm:mb-0 max-sm:mt-auto max-sm:w-full max-sm:max-w-none max-sm:rounded-b-none max-sm:rounded-t-xl",
22
33
  bottom: "inset-x-0 top-auto bottom-0 w-full max-w-none max-h-[85dvh] rounded-t-xl border-t",
23
34
  };
24
35
 
25
- export function Sheet({ open, onClose, title, description, side = "end", footer, className, children }) {
36
+ export function Sheet({ open, onClose, title, description, side = "end", footer, bare = false, label, className, children }) {
26
37
  const ref = useRef(null);
38
+ const titleId = useId();
39
+ const named = Boolean(title) && !bare;
27
40
 
28
41
  useEffect(() => {
29
42
  const el = ref.current;
@@ -44,19 +57,20 @@ export function Sheet({ open, onClose, title, description, side = "end", footer,
44
57
  SIDES[side] ?? SIDES.end,
45
58
  className,
46
59
  )}
47
- aria-labelledby={title ? "sheet-title" : undefined}
60
+ aria-labelledby={named ? titleId : undefined}
61
+ aria-label={named ? undefined : label}
48
62
  >
49
63
  <div className="flex min-h-0 flex-1 flex-col">
50
- {title || onClose ? (
64
+ {!bare && (title || onClose) ? (
51
65
  <header className="flex items-start justify-between gap-3 border-b border-border px-4 py-3">
52
66
  <div className="min-w-0">
53
- {title ? <h2 id="sheet-title" className="text-base font-semibold leading-tight">{title}</h2> : null}
67
+ {title ? <h2 id={titleId} className="text-base font-semibold leading-tight">{title}</h2> : null}
54
68
  {description ? <p className="mt-0.5 text-sm text-muted-foreground">{description}</p> : null}
55
69
  </div>
56
70
  <IconButton icon="x" label="Close" size="sm" onClick={() => ref.current?.close()} className="-mr-2" />
57
71
  </header>
58
72
  ) : null}
59
- <div className="min-h-0 flex-1 overflow-y-auto px-4 py-4">{children}</div>
73
+ <div className={cx("min-h-0 flex-1 overflow-y-auto", !bare && "px-4 py-4")}>{children}</div>
60
74
  {footer ? <footer className="flex flex-wrap justify-end gap-2 border-t border-border px-4 py-3">{footer}</footer> : null}
61
75
  </div>
62
76
  </dialog>
@@ -64,8 +78,45 @@ export function Sheet({ open, onClose, title, description, side = "end", footer,
64
78
  }
65
79
 
66
80
  /** A yes/no with the consequence spelled out. `tone="danger"` for a
67
- * destructive confirm. Resolves through `onConfirm`; closes either way. */
68
- export function Confirm({ open, onClose, onConfirm, title, body, confirmLabel = "Confirm", cancelLabel = "Cancel", tone = "neutral", busy }) {
81
+ * destructive confirm. Resolves through `onConfirm`; closes either way.
82
+ *
83
+ * consequences lines that will happen ("14 contacts are deleted"), a
84
+ * muted bullet list under the body
85
+ * requireText the exact text to type ("acme-corp") before Confirm
86
+ * unlocks — for the one delete that cannot come back
87
+ * acknowledge a checkbox label that must be ticked first ("I have
88
+ * exported what I need")
89
+ *
90
+ * Confirm stays disabled until each gate given is met; both reset when
91
+ * the dialog opens again. Without them it is the plain yes/no. */
92
+ export function Confirm({
93
+ open,
94
+ onClose,
95
+ onConfirm,
96
+ title,
97
+ body,
98
+ confirmLabel = "Confirm",
99
+ cancelLabel = "Cancel",
100
+ tone = "neutral",
101
+ busy,
102
+ consequences,
103
+ requireText,
104
+ acknowledge,
105
+ }) {
106
+ const [typed, setTyped] = useState("");
107
+ const [ticked, setTicked] = useState(false);
108
+ const typeId = useId();
109
+ const tickId = useId();
110
+
111
+ useEffect(() => {
112
+ if (!open) return;
113
+ setTyped("");
114
+ setTicked(false);
115
+ }, [open]);
116
+
117
+ const lines = Array.isArray(consequences) ? consequences.filter(Boolean) : [];
118
+ const held = (requireText ? typed !== requireText : false) || (acknowledge ? !ticked : false);
119
+
69
120
  return (
70
121
  <Sheet
71
122
  open={open}
@@ -77,13 +128,47 @@ export function Confirm({ open, onClose, onConfirm, title, body, confirmLabel =
77
128
  <Button variant="quiet" onClick={onClose} disabled={busy}>
78
129
  {cancelLabel}
79
130
  </Button>
80
- <Button variant={tone === "danger" ? "danger" : "primary"} onClick={onConfirm} disabled={busy}>
131
+ <Button variant={tone === "danger" ? "danger" : "primary"} onClick={onConfirm} disabled={busy || held}>
81
132
  {busy ? "Working…" : confirmLabel}
82
133
  </Button>
83
134
  </>
84
135
  }
85
136
  >
86
137
  {body ? <p className="text-sm text-muted-foreground">{body}</p> : null}
138
+ {lines.length ? (
139
+ <ul className={cx("list-disc space-y-1 ps-5 text-sm text-muted-foreground marker:text-muted-foreground", body && "mt-3")}>
140
+ {lines.map((line, i) => (
141
+ <li key={i}>{line}</li>
142
+ ))}
143
+ </ul>
144
+ ) : null}
145
+ {requireText ? (
146
+ <div className={cx("grid gap-1.5", (body || lines.length) && "mt-4")}>
147
+ <label htmlFor={typeId} className="text-sm text-foreground">
148
+ Type <span className="break-all font-mono font-medium">{requireText}</span> to confirm
149
+ </label>
150
+ <Input
151
+ id={typeId}
152
+ value={typed}
153
+ onChange={(e) => setTyped(e.target.value)}
154
+ autoComplete="off"
155
+ autoCapitalize="off"
156
+ autoCorrect="off"
157
+ spellCheck={false}
158
+ disabled={busy}
159
+ />
160
+ </div>
161
+ ) : null}
162
+ {acknowledge ? (
163
+ <Checkbox
164
+ id={tickId}
165
+ checked={ticked}
166
+ onChange={(e) => setTicked(e.target.checked)}
167
+ label={acknowledge}
168
+ disabled={busy}
169
+ className={cx((body || lines.length || requireText) && "mt-2")}
170
+ />
171
+ ) : null}
87
172
  </Sheet>
88
173
  );
89
174
  }
@@ -0,0 +1,174 @@
1
+ "use client";
2
+
3
+ import { useRef, useState } from "react";
4
+ import { cx } from "./cx";
5
+
6
+ // Slider — pick a number (or a span of numbers) by dragging. The native
7
+ // <input type="range"> underneath, so keyboard (arrows, Page Up/Down,
8
+ // Home/End), touch, forms and screen readers are the browser's; the
9
+ // track, the filled part and the thumb are drawn from tokens. The input
10
+ // is 44px tall however thin the track looks: the thumb is what a thumb
11
+ // hits. Controlled (`value` + `onChange`) or not (`defaultValue`).
12
+ //
13
+ // value a number — or [low, high] for a range: two thumbs on one
14
+ // track, each its own native input (labels "Minimum" and
15
+ // "Maximum"; `thumbLabels` renames them). A range can never
16
+ // cross: low stops at high - `minGap`.
17
+ // onChange (value) → the number, or [low, high]; not an event
18
+ // min, max, step as the native input (0, 100, 1)
19
+ // showValue print the value beside the track, through `format`
20
+ // format (n) → string — "$40", "12 seats"; also what a screen
21
+ // reader says (aria-valuetext)
22
+ // label the accessible name when no <Field> label points at `id`
23
+ // name the form field; a range submits two values under it
24
+ //
25
+ // Use it where the exact number matters less than its place in a span
26
+ // (budget, seats, a threshold). A value someone will type — a price, a
27
+ // quantity to the unit — is an Input with type="number".
28
+
29
+ // The native input, stripped to a transparent strip with a drawn thumb.
30
+ // Written out per engine: Tailwind reads classes literally, never a
31
+ // built string. The wrapper sets --rail (the input's height: 44px, the
32
+ // target) and --thumb (the drawn thumb): WebKit puts the thumb at the top
33
+ // of its track, so the margin centres it, and the fill below measures on
34
+ // --thumb to meet the thumb's centre.
35
+ const RANGE =
36
+ "absolute inset-0 h-full w-full appearance-none bg-transparent outline-none cursor-pointer disabled:cursor-not-allowed " +
37
+ "[&::-webkit-slider-runnable-track]:h-full [&::-webkit-slider-runnable-track]:bg-transparent " +
38
+ "[&::-webkit-slider-thumb]:mt-[calc((var(--rail)-var(--thumb))/2)] [&::-webkit-slider-thumb]:size-[var(--thumb)] [&::-webkit-slider-thumb]:appearance-none " +
39
+ "[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-primary [&::-webkit-slider-thumb]:bg-background " +
40
+ "[&::-webkit-slider-thumb]:shadow-sm [&::-webkit-slider-thumb]:transition-shadow " +
41
+ "hover:[&::-webkit-slider-thumb]:ring-4 hover:[&::-webkit-slider-thumb]:ring-ring/15 " +
42
+ "active:[&::-webkit-slider-thumb]:ring-4 active:[&::-webkit-slider-thumb]:ring-ring/25 " +
43
+ "focus-visible:[&::-webkit-slider-thumb]:ring-2 focus-visible:[&::-webkit-slider-thumb]:ring-ring focus-visible:[&::-webkit-slider-thumb]:ring-offset-2 focus-visible:[&::-webkit-slider-thumb]:ring-offset-background " +
44
+ "[&::-moz-range-track]:bg-transparent [&::-moz-range-progress]:bg-transparent " +
45
+ "[&::-moz-range-thumb]:box-border [&::-moz-range-thumb]:size-[var(--thumb)] [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 " +
46
+ "[&::-moz-range-thumb]:border-primary [&::-moz-range-thumb]:bg-background [&::-moz-range-thumb]:shadow-sm [&::-moz-range-thumb]:transition-shadow " +
47
+ "hover:[&::-moz-range-thumb]:ring-4 hover:[&::-moz-range-thumb]:ring-ring/15 " +
48
+ "active:[&::-moz-range-thumb]:ring-4 active:[&::-moz-range-thumb]:ring-ring/25 " +
49
+ "focus-visible:[&::-moz-range-thumb]:ring-2 focus-visible:[&::-moz-range-thumb]:ring-ring focus-visible:[&::-moz-range-thumb]:ring-offset-2 focus-visible:[&::-moz-range-thumb]:ring-offset-background";
50
+
51
+ // Two inputs share one track: neither takes the pointer except at its
52
+ // own thumb, so each thumb drags on its own and the other stays put.
53
+ const TWIN =
54
+ "pointer-events-none [&::-webkit-slider-thumb]:pointer-events-auto [&::-moz-range-thumb]:pointer-events-auto";
55
+
56
+ const clamp = (n, lo, hi) => Math.min(hi, Math.max(lo, n));
57
+
58
+ export function Slider({
59
+ id,
60
+ value,
61
+ defaultValue,
62
+ onChange,
63
+ min = 0,
64
+ max = 100,
65
+ step = 1,
66
+ minGap = 0,
67
+ showValue,
68
+ format = String,
69
+ label,
70
+ thumbLabels = ["Minimum", "Maximum"],
71
+ name,
72
+ disabled,
73
+ className,
74
+ ...rest
75
+ }) {
76
+ const [own, setOwn] = useState(defaultValue ?? min);
77
+ const current = value ?? own;
78
+ const range = Array.isArray(current);
79
+ const [low, high] = range ? current : [min, current];
80
+ const lowRef = useRef(null);
81
+ const highRef = useRef(null);
82
+
83
+ function set(next) {
84
+ if (value === undefined) setOwn(next);
85
+ onChange?.(next);
86
+ }
87
+
88
+ const span = max - min || 1;
89
+ const p = (n) => (clamp(n, min, max) - min) / span;
90
+ // The native thumb travels inside the track, half a thumb in from each
91
+ // end; the fill measures on that same inner span so it meets the
92
+ // thumb's centre at every value.
93
+ const at = (f) => `calc(var(--thumb) / 2 + ${f} * (100% - var(--thumb)))`;
94
+ const fill = range
95
+ ? { left: at(p(low)), width: `calc(${p(high) - p(low)} * (100% - var(--thumb)))` }
96
+ : { left: 0, width: at(p(high)) };
97
+
98
+ // A press on the bare track (not a thumb) moves the nearer thumb there.
99
+ // A single slider needs none of this: its input takes the press itself.
100
+ function onTrackDown(e) {
101
+ if (!range || disabled || e.target !== e.currentTarget) return;
102
+ const box = e.currentTarget.getBoundingClientRect();
103
+ const thumb = parseFloat(getComputedStyle(e.currentTarget).getPropertyValue("--thumb")) * parseFloat(getComputedStyle(document.documentElement).fontSize) || 20;
104
+ const f = clamp((e.clientX - box.left - thumb / 2) / (box.width - thumb), 0, 1);
105
+ const n = clamp(Math.round((min + f * span - min) / step) * step + min, min, max);
106
+ if (Math.abs(n - low) <= Math.abs(n - high)) {
107
+ set([Math.min(n, high - minGap), high]);
108
+ lowRef.current?.focus();
109
+ } else {
110
+ set([low, Math.max(n, low + minGap)]);
111
+ highRef.current?.focus();
112
+ }
113
+ }
114
+
115
+ const shown = range ? `${format(low)} – ${format(high)}` : format(high);
116
+ const common = { type: "range", min, max, step, disabled, name };
117
+
118
+ return (
119
+ <div className={cx("flex w-full items-center gap-3", disabled && "opacity-50", className)}>
120
+ <div
121
+ className="relative h-[var(--rail)] min-w-0 flex-1"
122
+ style={{ "--rail": "2.75rem", "--thumb": "1.25rem" }}
123
+ onPointerDown={onTrackDown}
124
+ >
125
+ <span aria-hidden="true" className="pointer-events-none absolute inset-x-0 top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-muted" />
126
+ <span aria-hidden="true" className="pointer-events-none absolute top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-primary" style={fill} />
127
+ {range ? (
128
+ <>
129
+ <input
130
+ {...common}
131
+ ref={lowRef}
132
+ id={id}
133
+ value={low}
134
+ aria-label={label ? `${label}, ${thumbLabels[0].toLowerCase()}` : thumbLabels[0]}
135
+ aria-valuetext={format(low)}
136
+ onChange={(e) => set([Math.min(Number(e.target.value), high - minGap), high])}
137
+ // The upper half of the track belongs to whichever thumb can
138
+ // still move there: when both sit at the top, low must be on
139
+ // top or it could never be dragged back down.
140
+ className={cx(RANGE, TWIN, p(low) > 0.5 ? "z-20" : "z-10")}
141
+ {...rest}
142
+ />
143
+ <input
144
+ {...common}
145
+ ref={highRef}
146
+ id={id ? `${id}-max` : undefined}
147
+ value={high}
148
+ aria-label={label ? `${label}, ${thumbLabels[1].toLowerCase()}` : thumbLabels[1]}
149
+ aria-valuetext={format(high)}
150
+ onChange={(e) => set([low, Math.max(Number(e.target.value), low + minGap)])}
151
+ className={cx(RANGE, TWIN, "z-10")}
152
+ />
153
+ </>
154
+ ) : (
155
+ <input
156
+ {...common}
157
+ id={id}
158
+ value={high}
159
+ aria-label={label}
160
+ aria-valuetext={format === String ? undefined : format(high)}
161
+ onChange={(e) => set(Number(e.target.value))}
162
+ className={RANGE}
163
+ {...rest}
164
+ />
165
+ )}
166
+ </div>
167
+ {showValue ? (
168
+ <output htmlFor={range && id ? `${id} ${id}-max` : id} data-nums className="shrink-0 text-right text-sm text-foreground">
169
+ {shown}
170
+ </output>
171
+ ) : null}
172
+ </div>
173
+ );
174
+ }