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,124 @@
1
+ # Navigation Menu
2
+
3
+ A site's top nav. Plain links sit in the bar; a trigger opens a panel — a
4
+ mega-menu — of links, each with an icon, a title and a short
5
+ description, and an optional featured card. The panel opens on hover
6
+ (after a short delay, so a pointer passing by does not open it), on click
7
+ and on Enter. One panel at a time: moving to the next trigger keeps it
8
+ open, glides it under that trigger and slides the links across. Arrow
9
+ keys move along the bar, Escape closes and returns focus to the trigger,
10
+ Tab goes through the open panel in reading order. The current page is
11
+ marked: its link carries `aria-current="page"` (a screen reader says
12
+ "current page", and the row is filled to match), and its group's trigger
13
+ is highlighted. Below
14
+ the `md` breakpoint the bar is a menu button that opens a Sheet, each
15
+ group a Collapsible.
16
+
17
+ ```jsx
18
+ import { NavigationMenu } from "../components/blocks/navigation-menu"; // a Makersclaw app ("./blocks/navigation-menu" from components/)
19
+ import { NavigationMenu } from "@/components/makersclaw/blocks/navigation-menu"; // a shadcn project
20
+ ```
21
+
22
+ It is a client component: render it from a `"use client"` component (a
23
+ layout's header is the usual place).
24
+
25
+ ## The data
26
+
27
+ `items` is the bar, in order. Each entry is a link or a group:
28
+
29
+ ```js
30
+ { label: "Pricing", href: "/pricing" } // a link
31
+ {
32
+ label: "Product", // a group: a trigger and its panel
33
+ items: [{ label, href, icon?, description? }, …], // the panel's links
34
+ featured?: { title, href?, description?, kicker?, icon?, cta? }, // a card before them
35
+ columns?: 1 | 2, // default: 2 past three links
36
+ key?: "product", // default: made from the position and label
37
+ }
38
+ ```
39
+
40
+ `icon` is a name from the kit's `Icon`. Keep a `description` short:
41
+ the panel clips it at two lines.
42
+
43
+ ## Props
44
+
45
+ - `items` — the bar, as above.
46
+ - `currentHref` — the page you are on (`usePathname()` in a Next app). A
47
+ link whose `href` equals it, or is its parent path, is marked current;
48
+ a group holding it is highlighted. Hash links match exactly.
49
+ - `onNavigate(link, event)` — called when any link in the bar, a panel or
50
+ the phone sheet is followed, before navigation. `event.preventDefault()`
51
+ stops it. The panel and the sheet close either way.
52
+ - `brand` — the node on the left (a logo that links home). Shown at every
53
+ width.
54
+ - `actions` — nodes on the right, e.g. "Sign in" and "Start free"
55
+ Buttons. In the bar from `md` up; in the sheet's footer on a phone.
56
+ - `label` — what a screen reader calls the nav, default `"Main"`.
57
+ - `menuLabel` — the phone's menu button and the sheet's title, default
58
+ `"Menu"`.
59
+ - `openDelay` — ms the pointer rests on a trigger before it opens,
60
+ default `150`. Moving between triggers while one is open is immediate.
61
+ - `closeDelay` — ms after the pointer leaves the trigger and panel before
62
+ it closes, default `300`.
63
+ - `className` — layout around it (width, padding). Never colour.
64
+
65
+ ## Example
66
+
67
+ ```jsx
68
+ // components/SiteHeader.jsx
69
+ "use client";
70
+ import { usePathname } from "next/navigation";
71
+ import { Button, Icon } from "./ui";
72
+ import { NavigationMenu } from "./blocks/navigation-menu";
73
+
74
+ const NAV = [
75
+ {
76
+ label: "Product",
77
+ items: [
78
+ { label: "Analytics", href: "/product/analytics", icon: "chart", description: "See which accounts are warming up." },
79
+ { label: "Automations", href: "/product/automations", icon: "zap", description: "Route leads without a spreadsheet." },
80
+ { label: "Integrations", href: "/product/integrations", icon: "link", description: "Sync with your CRM and calendar." },
81
+ { label: "Security", href: "/product/security", icon: "lock", description: "SSO, audit logs and SOC 2." },
82
+ ],
83
+ featured: { kicker: "New", title: "Forecasts that explain themselves", href: "/changelog/forecasts", cta: "Read the release" },
84
+ },
85
+ { label: "Pricing", href: "/pricing" },
86
+ { label: "Docs", href: "/docs" },
87
+ ];
88
+
89
+ export default function SiteHeader() {
90
+ const pathname = usePathname();
91
+ return (
92
+ <header className="border-b border-border bg-background px-4">
93
+ <NavigationMenu
94
+ items={NAV}
95
+ currentHref={pathname}
96
+ brand={
97
+ <Button href="/" variant="quiet" size="sm" className="gap-2 font-semibold">
98
+ <Icon name="zap" /> Fieldline
99
+ </Button>
100
+ }
101
+ actions={
102
+ <>
103
+ <Button href="/login" variant="quiet" size="sm">Sign in</Button>
104
+ <Button href="/signup" variant="primary" size="sm">Start free</Button>
105
+ </>
106
+ }
107
+ />
108
+ </header>
109
+ );
110
+ }
111
+ ```
112
+
113
+ ## What it will not do
114
+
115
+ - Nest: a panel holds links, not another menu. A deeper tree is a page.
116
+ - Hold arbitrary content in a panel: links and one featured card. A
117
+ panel of your own is a `Popover` in your own component.
118
+ - Stick to the top or blur on scroll: put `sticky top-0` on the element
119
+ around it.
120
+ - Know the route by itself: pass `currentHref`.
121
+
122
+ A nav it cannot be is your own component in `components/`, built from
123
+ the kit — not an edit to this block. Its files are fixed: `npm run check`
124
+ refuses a change, and `makersclaw add navigation-menu` restores them.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "navigation-menu",
3
+ "title": "Navigation Menu",
4
+ "description": "A site's top nav: plain links, and triggers that open a mega-menu panel of links (icon, title, one-line description) with an optional featured card; hover with intent, click, arrow keys and Escape; a menu button and a sheet of collapsible groups on a phone.",
5
+ "useWhen": "The header of a public-facing site or a product with many destinations: a marketing site, a docs hub, a customer portal. Not for an app's own sidebar or a row of tabs that switch views on one page.",
6
+ "tags": ["navigation", "nav", "menu", "mega-menu", "header", "navbar", "top nav", "dropdown", "links", "site", "marketing", "mobile menu"],
7
+ "exports": ["NavigationMenu"],
8
+ "files": ["index.js", "navigation-menu.jsx"],
9
+ "requires": []
10
+ }
@@ -0,0 +1,84 @@
1
+ "use client";
2
+
3
+ // The NavigationMenu over a product site's pages — the gallery's and the
4
+ // smoke test's surface. Not installed into apps: `makersclaw add
5
+ // navigation-menu` lays index.js and navigation-menu.jsx only. Links are
6
+ // #hashes and a followed one only moves the "current page".
7
+ import { useState } from "react";
8
+ import { Button, Icon } from "../components/ui";
9
+ import { NavigationMenu } from "../components/blocks/navigation-menu";
10
+
11
+ const NAV = [
12
+ {
13
+ label: "Product",
14
+ items: [
15
+ { label: "Analytics", href: "#analytics", icon: "chart", description: "See which accounts are warming up, week by week." },
16
+ { label: "Automations", href: "#automations", icon: "zap", description: "Route leads and follow up without a spreadsheet." },
17
+ { label: "Shared inbox", href: "#inbox", icon: "inbox", description: "Every reply from every rep, in one queue." },
18
+ { label: "Integrations", href: "#integrations", icon: "link", description: "Sync with your CRM, calendar and billing." },
19
+ { label: "Security", href: "#security", icon: "lock", description: "SSO, audit logs and SOC 2 Type II." },
20
+ { label: "Reports", href: "#reports", icon: "file", description: "Board-ready pipeline reports, every Monday." },
21
+ ],
22
+ featured: {
23
+ kicker: "New in 4.2",
24
+ icon: "sparkles",
25
+ title: "Forecasts that explain themselves",
26
+ description: "Every number now shows the deals behind it.",
27
+ href: "#forecasts",
28
+ cta: "Read the release",
29
+ },
30
+ },
31
+ {
32
+ label: "Solutions",
33
+ items: [
34
+ { label: "For founders", href: "#founders", icon: "star", description: "Run your first sales motion without hiring ops." },
35
+ { label: "For sales teams", href: "#sales", icon: "users", description: "One pipeline the whole team trusts." },
36
+ { label: "For agencies", href: "#agencies", icon: "folder", description: "A workspace per client, one login for you." },
37
+ ],
38
+ },
39
+ { label: "Pricing", href: "#pricing" },
40
+ { label: "Docs", href: "#docs" },
41
+ {
42
+ label: "Company",
43
+ items: [
44
+ { label: "About", href: "#about", icon: "info", description: "Twelve people in Lisbon and Toronto." },
45
+ { label: "Careers", href: "#careers", icon: "user", description: "Four open roles, all remote." },
46
+ { label: "Customers", href: "#customers", icon: "heart", description: "How Northwind doubled its reply rate." },
47
+ { label: "Contact", href: "#contact", icon: "mail", description: "Talk to a person, usually within an hour." },
48
+ ],
49
+ },
50
+ ];
51
+
52
+ export default function NavigationMenuDemo() {
53
+ const [current, setCurrent] = useState("#pricing");
54
+ return (
55
+ <div className="grid gap-6">
56
+ <header className="rounded-lg border border-border bg-card px-3">
57
+ <NavigationMenu
58
+ items={NAV}
59
+ currentHref={current}
60
+ onNavigate={(link) => setCurrent(link.href)}
61
+ brand={
62
+ <Button href="#home" variant="quiet" size="sm" className="gap-2 text-base font-semibold">
63
+ <Icon name="zap" size={18} className="text-primary" />
64
+ Fieldline
65
+ </Button>
66
+ }
67
+ actions={
68
+ <>
69
+ <Button href="#signin" variant="quiet" size="sm">
70
+ Sign in
71
+ </Button>
72
+ <Button href="#signup" variant="primary" size="sm">
73
+ Start free
74
+ </Button>
75
+ </>
76
+ }
77
+ />
78
+ </header>
79
+ <p className="text-sm text-muted-foreground">
80
+ Current page: <span className="font-medium text-foreground">{current}</span>. Hover or click a trigger; arrow keys move along the bar.
81
+ </p>
82
+ </div>
83
+ );
84
+ }
@@ -0,0 +1,4 @@
1
+ // The NavigationMenu block — `makersclaw add navigation-menu`. Fixed:
2
+ // compose it through its props (README.md beside this file); a nav it
3
+ // cannot be is your own component in components/.
4
+ export { NavigationMenu } from "./navigation-menu";
@@ -0,0 +1,448 @@
1
+ "use client";
2
+
3
+ import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
4
+ import { Button, Collapsible, Icon, IconButton, Item, Kicker, Sheet, cx, panelClass, usePopoverPosition } from "../../ui";
5
+
6
+ // NavigationMenu — a site's top nav: plain links, and triggers that open
7
+ // one shared panel (a mega-menu) of links with an icon, a title and a
8
+ // short description, plus an optional featured card. The block owns
9
+ // what a hand-drawn nav gets wrong: hover with intent (a delay to open,
10
+ // a longer one to close, so the pointer can cross the gap), click and
11
+ // Enter too, one panel at a time that stays open and slides when the
12
+ // pointer moves to the next trigger, arrow keys along the bar, Escape
13
+ // back to the trigger, Tab through the open panel in reading order,
14
+ // aria-expanded and aria-current. Below the md breakpoint it is a menu
15
+ // button opening a Sheet, each group a Collapsible.
16
+ //
17
+ // <NavigationMenu items={NAV} currentHref={pathname} brand={<Logo />}
18
+ // actions={<Button href="/signup" variant="primary">Start free</Button>} />
19
+ //
20
+ // README.md beside this file lists every prop.
21
+
22
+ const OPEN_DELAY = 150;
23
+ const CLOSE_DELAY = 300;
24
+ const SLIDE_PX = 24;
25
+ const LINKS = "a[href]";
26
+
27
+ function isActive(href, current) {
28
+ if (!href || current == null) return false;
29
+ if (href === current) return true;
30
+ return href !== "/" && !href.startsWith("#") && current.startsWith(href.endsWith("/") ? href : `${href}/`);
31
+ }
32
+
33
+ function reducedMotion() {
34
+ return typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
35
+ }
36
+
37
+ // A group's featured card as onNavigate hears it: keyed inside the group.
38
+ const featuredOf = (group) => ({ ...group.featured, key: `${group.key}/featured` });
39
+
40
+ // Items as the block uses them: a key for each, a group's links keyed
41
+ // inside it, and whether the current page is in it.
42
+ function normalize(items, current) {
43
+ return (items ?? []).filter(Boolean).map((it, i) => {
44
+ const key = it.key ?? `${i}-${it.label}`;
45
+ if (!Array.isArray(it.items)) return { ...it, key, kind: "link", active: isActive(it.href, current) };
46
+ const links = it.items.filter(Boolean).map((l, j) => ({ ...l, key: `${key}/${l.key ?? j}`, active: isActive(l.href, current) }));
47
+ return { ...it, key, kind: "group", items: links, active: links.some((l) => l.active) || isActive(it.featured?.href, current) };
48
+ });
49
+ }
50
+
51
+ export function NavigationMenu({
52
+ items,
53
+ currentHref,
54
+ onNavigate,
55
+ brand,
56
+ actions,
57
+ label = "Main",
58
+ menuLabel = "Menu",
59
+ openDelay = OPEN_DELAY,
60
+ closeDelay = CLOSE_DELAY,
61
+ className,
62
+ }) {
63
+ const entries = normalize(items, currentHref);
64
+ const groups = entries.filter((e) => e.kind === "group");
65
+
66
+ const id = useId();
67
+ const panelId = `${id}-panel`;
68
+ const root = useRef(null);
69
+ const list = useRef(null);
70
+ const panel = useRef(null);
71
+ const content = useRef(null);
72
+ const triggers = useRef(new Map());
73
+ const timer = useRef(0);
74
+ const hoverOpenedAt = useRef(0);
75
+ const focusOnOpen = useRef(null); // "first" | "last" once a key opened it
76
+ const was = useRef({ key: null, w: 0, h: 0, x: 0, index: -1 });
77
+
78
+ const [openKey, setOpenKey] = useState(null);
79
+ const [shownKey, setShownKey] = useState(null); // stays through the fade-out
80
+ const [sheetOpen, setSheetOpen] = useState(false);
81
+
82
+ const shown = groups.find((g) => g.key === (openKey ?? shownKey)) ?? null;
83
+
84
+ // The panel sits under the trigger that opened it (the bar, before any
85
+ // has). The hook reads the ref on every commit, so this re-anchors it.
86
+ const anchor = useRef(null);
87
+ anchor.current = triggers.current.get(openKey ?? shownKey) ?? list.current;
88
+ usePopoverPosition(anchor, panel, { side: "bottom", align: "start", offset: 6 });
89
+
90
+ function clearTimer() {
91
+ clearTimeout(timer.current);
92
+ timer.current = 0;
93
+ }
94
+ function show(key) {
95
+ clearTimer();
96
+ setOpenKey(key);
97
+ if (key) setShownKey(key);
98
+ }
99
+ function scheduleClose() {
100
+ clearTimer();
101
+ timer.current = setTimeout(() => setOpenKey(null), closeDelay);
102
+ }
103
+ useEffect(() => () => clearTimeout(timer.current), []);
104
+
105
+ // The panel follows the state; when it moves from one group to another
106
+ // its box eases to the new size and the links slide in from the side
107
+ // the pointer came from.
108
+ useLayoutEffect(() => {
109
+ const p = panel.current;
110
+ if (!p) return;
111
+ const isShown = p.matches(":popover-open");
112
+ if (!openKey) {
113
+ if (isShown) p.hidePopover();
114
+ was.current = { key: null, w: 0, h: 0, x: 0, index: -1 };
115
+ return;
116
+ }
117
+ if (!isShown) p.showPopover();
118
+ const index = entries.findIndex((e) => e.key === openKey);
119
+ const w = p.offsetWidth;
120
+ const h = p.offsetHeight;
121
+ const x = p.getBoundingClientRect().left;
122
+ const prev = was.current;
123
+ if (prev.key && prev.key !== openKey && !reducedMotion()) {
124
+ const from = index > prev.index ? 1 : -1;
125
+ p.animate(
126
+ [
127
+ { width: `${prev.w}px`, height: `${prev.h}px`, transform: `translateX(${prev.x - x}px)` },
128
+ { width: `${w}px`, height: `${h}px`, transform: "none" },
129
+ ],
130
+ { duration: 200, easing: "ease-out" },
131
+ );
132
+ content.current?.animate(
133
+ [
134
+ { transform: `translateX(${from * SLIDE_PX}px)`, opacity: 0 },
135
+ { transform: "none", opacity: 1 },
136
+ ],
137
+ { duration: 200, easing: "ease-out" },
138
+ );
139
+ }
140
+ was.current = { key: openKey, w, h, x, index };
141
+ const want = focusOnOpen.current;
142
+ focusOnOpen.current = null;
143
+ if (want) {
144
+ const links = [...p.querySelectorAll(LINKS)];
145
+ (want === "last" ? links.at(-1) : links[0])?.focus({ preventScroll: true });
146
+ }
147
+ });
148
+
149
+ // A press anywhere outside the bar and its panel closes it; Escape
150
+ // closes it wherever focus is (a hover-opened panel has none), and
151
+ // brings focus back to the trigger when it was inside.
152
+ useEffect(() => {
153
+ if (!openKey) return;
154
+ function onDown(e) {
155
+ if (!root.current?.contains(e.target)) setOpenKey(null);
156
+ }
157
+ function onKey(e) {
158
+ if (e.key !== "Escape") return;
159
+ e.preventDefault();
160
+ if (root.current?.contains(document.activeElement)) closeAndFocus(openKey);
161
+ else setOpenKey(null);
162
+ }
163
+ document.addEventListener("pointerdown", onDown);
164
+ document.addEventListener("keydown", onKey);
165
+ return () => {
166
+ document.removeEventListener("pointerdown", onDown);
167
+ document.removeEventListener("keydown", onKey);
168
+ };
169
+ }, [openKey]);
170
+
171
+ function tops() {
172
+ return [...(list.current?.querySelectorAll("[data-nav-top]") ?? [])];
173
+ }
174
+
175
+ function closeAndFocus(key) {
176
+ setOpenKey(null);
177
+ triggers.current.get(key)?.focus({ preventScroll: true });
178
+ }
179
+
180
+ // Along the bar: arrows and Home/End move between its items. While a
181
+ // panel is open, arriving on another trigger opens that one instead.
182
+ function onBarKeyDown(e) {
183
+ const all = tops();
184
+ const i = all.indexOf(e.target);
185
+ if (i < 0) return;
186
+ let next = null;
187
+ if (e.key === "ArrowRight") next = (i + 1) % all.length;
188
+ else if (e.key === "ArrowLeft") next = (i - 1 + all.length) % all.length;
189
+ else if (e.key === "Home") next = 0;
190
+ else if (e.key === "End") next = all.length - 1;
191
+ if (next === null) return;
192
+ e.preventDefault();
193
+ const el = all[next];
194
+ el.focus();
195
+ if (openKey) show(el.dataset.navGroup ?? null);
196
+ }
197
+
198
+ function onTriggerKeyDown(e, key) {
199
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
200
+ e.preventDefault();
201
+ focusOnOpen.current = e.key === "ArrowUp" ? "last" : "first";
202
+ if (openKey === key) {
203
+ const links = [...(panel.current?.querySelectorAll(LINKS) ?? [])];
204
+ (e.key === "ArrowUp" ? links.at(-1) : links[0])?.focus();
205
+ focusOnOpen.current = null;
206
+ } else show(key);
207
+ } else if (e.key === "Tab" && !e.shiftKey && openKey === key) {
208
+ // The panel sits after the bar in the page; Tab goes into it first.
209
+ const first = panel.current?.querySelector(LINKS);
210
+ if (first) {
211
+ e.preventDefault();
212
+ first.focus();
213
+ }
214
+ }
215
+ }
216
+
217
+ function onPanelKeyDown(e) {
218
+ if (!openKey) return;
219
+ const links = [...(panel.current?.querySelectorAll(LINKS) ?? [])];
220
+ const i = links.indexOf(document.activeElement);
221
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
222
+ e.preventDefault();
223
+ if (e.key === "ArrowUp" && i <= 0) triggers.current.get(openKey)?.focus();
224
+ else links[e.key === "ArrowDown" ? Math.min(i + 1, links.length - 1) : i - 1]?.focus();
225
+ } else if (e.key === "Tab" && e.shiftKey && i === 0) {
226
+ e.preventDefault();
227
+ triggers.current.get(openKey)?.focus();
228
+ } else if (e.key === "Tab" && !e.shiftKey && i === links.length - 1) {
229
+ // Out of the panel's end: on to the bar's next item. After the bar's
230
+ // last one, the page's own order carries on and the blur closes it.
231
+ const all = tops();
232
+ const after = all[all.indexOf(triggers.current.get(openKey)) + 1];
233
+ if (after) {
234
+ e.preventDefault();
235
+ setOpenKey(null);
236
+ after.focus();
237
+ }
238
+ }
239
+ }
240
+
241
+
242
+ // Focus leaving the bar and its panel altogether closes the panel.
243
+ function onRootBlur(e) {
244
+ if (openKey && e.relatedTarget && !root.current?.contains(e.relatedTarget)) setOpenKey(null);
245
+ }
246
+
247
+ // A followed link: the surface hears of it (and may preventDefault),
248
+ // then the panel or the sheet closes. Only a link with an href is one.
249
+ function follow(link) {
250
+ if (!link.href) return undefined;
251
+ return (e) => {
252
+ onNavigate?.(link, e);
253
+ setOpenKey(null);
254
+ setSheetOpen(false);
255
+ };
256
+ }
257
+
258
+ function onTriggerEnter(e, key) {
259
+ if (e.pointerType !== "mouse") return;
260
+ clearTimer();
261
+ if (openKey) {
262
+ show(key);
263
+ return;
264
+ }
265
+ timer.current = setTimeout(() => {
266
+ hoverOpenedAt.current = Date.now();
267
+ show(key);
268
+ }, openDelay);
269
+ }
270
+
271
+ function onTriggerClick(key) {
272
+ // A click just after hover opened it confirms the hover, not a close.
273
+ if (openKey === key && Date.now() - hoverOpenedAt.current > 400) setOpenKey(null);
274
+ else show(key);
275
+ }
276
+
277
+ const topClass =
278
+ "aria-[current=page]:bg-accent data-[active=true]:bg-accent aria-expanded:bg-accent";
279
+
280
+ return (
281
+ <nav ref={root} aria-label={label} onBlur={onRootBlur} className={cx("flex min-h-14 items-center gap-2", className)}>
282
+ {brand ? <div className="flex shrink-0 items-center">{brand}</div> : null}
283
+
284
+ <ul ref={list} role="list" onKeyDown={onBarKeyDown} className="hidden items-center gap-1 md:flex">
285
+ {entries.map((e) =>
286
+ e.kind === "link" ? (
287
+ <li key={e.key} onPointerEnter={(ev) => ev.pointerType === "mouse" && openKey && scheduleClose()}>
288
+ <Button
289
+ href={e.href}
290
+ variant="quiet"
291
+ size="sm"
292
+ data-nav-top=""
293
+ aria-current={e.active ? "page" : undefined}
294
+ onClick={follow(e)}
295
+ className={topClass}
296
+ >
297
+ {e.label}
298
+ </Button>
299
+ </li>
300
+ ) : (
301
+ <li key={e.key} onPointerEnter={(ev) => onTriggerEnter(ev, e.key)} onPointerLeave={(ev) => ev.pointerType === "mouse" && scheduleClose()}>
302
+ <Button
303
+ ref={(el) => (el ? triggers.current.set(e.key, el) : triggers.current.delete(e.key))}
304
+ variant="quiet"
305
+ size="sm"
306
+ data-nav-top=""
307
+ data-nav-group={e.key}
308
+ data-active={e.active ? "true" : undefined}
309
+ aria-expanded={openKey === e.key}
310
+ aria-controls={panelId}
311
+ onClick={() => onTriggerClick(e.key)}
312
+ onKeyDown={(ev) => onTriggerKeyDown(ev, e.key)}
313
+ className={cx(topClass, "gap-1")}
314
+ >
315
+ {e.label}
316
+ <Icon
317
+ name="chevron-down"
318
+ size={14}
319
+ className={cx("text-muted-foreground transition-transform duration-200 motion-reduce:transition-none", openKey === e.key && "rotate-180")}
320
+ />
321
+ </Button>
322
+ </li>
323
+ ),
324
+ )}
325
+ </ul>
326
+
327
+ {/* The one panel, after the bar so Tab reaches it in reading order. */}
328
+ <div
329
+ ref={panel}
330
+ id={panelId}
331
+ popover="manual"
332
+ role="region"
333
+ aria-label={shown?.label}
334
+ onKeyDown={onPanelKeyDown}
335
+ onPointerEnter={(ev) => ev.pointerType === "mouse" && clearTimer()}
336
+ onPointerLeave={(ev) => ev.pointerType === "mouse" && scheduleClose()}
337
+ onTransitionEnd={(ev) => ev.target === ev.currentTarget && !openKey && setShownKey(null)}
338
+ className={panelClass("auto", "overflow-hidden p-2")}
339
+ >
340
+ <div ref={content}>{shown ? <Panel group={shown} follow={follow} /> : null}</div>
341
+ </div>
342
+
343
+ <div className="ml-auto flex items-center gap-2">
344
+ {actions ? <div className="hidden items-center gap-2 md:flex">{actions}</div> : null}
345
+ <IconButton
346
+ icon="menu"
347
+ label={menuLabel}
348
+ aria-expanded={sheetOpen}
349
+ onClick={() => setSheetOpen(true)}
350
+ className="md:hidden"
351
+ />
352
+ </div>
353
+
354
+ <Sheet open={sheetOpen} onClose={() => setSheetOpen(false)} title={menuLabel} footer={actions ? <div className="flex w-full flex-wrap gap-2 [&>*]:flex-1">{actions}</div> : null}>
355
+ <div className="grid">
356
+ {entries.map((e) =>
357
+ e.kind === "link" ? (
358
+ <div key={e.key} className="-mx-2.5">
359
+ <Item size="sm" href={e.href} title={e.label} aria-current={e.active ? "page" : undefined} onClick={follow(e)} />
360
+ </div>
361
+ ) : (
362
+ <Collapsible key={e.key} title={e.label} defaultOpen={e.active}>
363
+ <ul role="list" className="-mx-2.5 grid gap-0.5">
364
+ {e.items.map((l) => (
365
+ <li key={l.key}>
366
+ <Item
367
+ size="sm"
368
+ href={l.href}
369
+ icon={l.icon}
370
+ title={l.label}
371
+ description={l.description}
372
+ aria-current={l.active ? "page" : undefined}
373
+ onClick={follow(l)}
374
+ />
375
+ </li>
376
+ ))}
377
+ {e.featured ? (
378
+ <li>
379
+ <Item
380
+ size="sm"
381
+ variant="muted"
382
+ href={e.featured.href}
383
+ icon={e.featured.icon ?? "sparkles"}
384
+ title={e.featured.title}
385
+ description={e.featured.description}
386
+ onClick={follow(featuredOf(e))}
387
+ className="mt-1"
388
+ />
389
+ </li>
390
+ ) : null}
391
+ </ul>
392
+ </Collapsible>
393
+ ),
394
+ )}
395
+ </div>
396
+ </Sheet>
397
+ </nav>
398
+ );
399
+ }
400
+
401
+ // One group's panel (never wider than the window: panelClass caps it and
402
+ // the grid shrinks): its links in a grid (two columns past three links,
403
+ // or `columns`), the featured card first when there is one.
404
+ function Panel({ group, follow }) {
405
+ const cols = group.columns ?? (group.items.length > 3 ? 2 : 1);
406
+ return (
407
+ <div className="flex gap-2">
408
+ {group.featured ? <Featured card={group.featured} onClick={follow(featuredOf(group))} /> : null}
409
+ <ul role="list" className={cx("grid min-w-0 content-start gap-1", cols === 2 ? "w-[38rem] grid-cols-2" : "w-80 grid-cols-1")}>
410
+ {group.items.map((l) => (
411
+ <li key={l.key}>
412
+ <Item
413
+ href={l.href}
414
+ icon={l.icon}
415
+ title={l.label}
416
+ description={l.description}
417
+ aria-current={l.active ? "page" : undefined}
418
+ onClick={follow(l)}
419
+ />
420
+ </li>
421
+ ))}
422
+ </ul>
423
+ </div>
424
+ );
425
+ }
426
+
427
+ // The featured card: a filled panel with a kicker, a title, a line and
428
+ // its own link — the thing the group most wants read.
429
+ function Featured({ card, onClick }) {
430
+ return (
431
+ <div className="flex w-56 shrink-0 flex-col justify-end gap-2 rounded-md bg-muted p-4">
432
+ {card.icon ? (
433
+ <span className="mb-auto flex size-9 items-center justify-center rounded-md bg-background text-foreground">
434
+ <Icon name={card.icon} size={18} />
435
+ </span>
436
+ ) : null}
437
+ {card.kicker ? <Kicker>{card.kicker}</Kicker> : null}
438
+ <p className="text-base font-semibold leading-tight text-foreground">{card.title}</p>
439
+ {card.description ? <p className="text-sm text-muted-foreground">{card.description}</p> : null}
440
+ {card.href ? (
441
+ <Button href={card.href} variant="link" size="sm" onClick={onClick}>
442
+ {card.cta ?? "Learn more"}
443
+ <Icon name="arrow-right" size={14} />
444
+ </Button>
445
+ ) : null}
446
+ </div>
447
+ );
448
+ }