makersclaw 0.7.0 → 0.8.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 (419) hide show
  1. package/README.md +17 -4
  2. package/package.json +1 -1
  3. package/r/activity-log.json +52 -0
  4. package/r/agent-changes.json +51 -0
  5. package/r/agent-chat.json +53 -0
  6. package/r/agent-column.json +85 -0
  7. package/r/agent-dock.json +57 -0
  8. package/r/agent-kit.json +49 -0
  9. package/r/agent-marks.json +49 -0
  10. package/r/agent-pane.json +93 -0
  11. package/r/ai-action.json +56 -0
  12. package/r/annotate.json +4 -4
  13. package/r/approval-request.json +2 -2
  14. package/r/approval.json +54 -0
  15. package/r/ask-bar.json +50 -0
  16. package/r/audio-player.json +2 -2
  17. package/r/auth-form.json +2 -2
  18. package/r/automation-editor.json +66 -0
  19. package/r/automation-list.json +57 -0
  20. package/r/automation-model.json +118 -0
  21. package/r/automations-screen.json +71 -0
  22. package/r/board.json +2 -2
  23. package/r/calendar-view.json +3 -3
  24. package/r/cart.json +2 -2
  25. package/r/chart.json +5 -5
  26. package/r/chat-pane.json +84 -0
  27. package/r/chat.json +3 -3
  28. package/r/code-editor.json +2 -2
  29. package/r/comment-box.json +3 -3
  30. package/r/connect-card.json +51 -0
  31. package/r/contact-section.json +2 -2
  32. package/r/core.json +18 -6
  33. package/r/cost.json +51 -0
  34. package/r/csv-import.json +3 -3
  35. package/r/data-picker.json +60 -0
  36. package/r/data-table.json +2 -2
  37. package/r/diagram.json +2 -2
  38. package/r/doc-editor.json +2 -2
  39. package/r/doc-page.json +3 -3
  40. package/r/email-render.json +2 -2
  41. package/r/faq.json +2 -2
  42. package/r/file-upload.json +2 -2
  43. package/r/first-run.json +63 -0
  44. package/r/fix-note.json +57 -0
  45. package/r/flow-canvas.json +3 -3
  46. package/r/flow-editor.json +79 -0
  47. package/r/footer.json +3 -3
  48. package/r/gantt.json +3 -3
  49. package/r/job-panel.json +2 -2
  50. package/r/json-editor.json +3 -3
  51. package/r/library-shelf.json +56 -0
  52. package/r/map.json +2 -2
  53. package/r/margin-notes.json +67 -0
  54. package/r/menubar.json +2 -2
  55. package/r/mind-map.json +4 -4
  56. package/r/navigation-menu.json +2 -2
  57. package/r/needs-you.json +55 -0
  58. package/r/order-detail.json +2 -2
  59. package/r/org-chart.json +4 -4
  60. package/r/pace-bar.json +69 -0
  61. package/r/page-builder.json +3 -3
  62. package/r/payment-methods.json +2 -2
  63. package/r/pdf-document.json +2 -2
  64. package/r/pdf-viewer.json +3 -3
  65. package/r/product-detail.json +2 -2
  66. package/r/product-grid.json +3 -3
  67. package/r/record-form.json +2 -2
  68. package/r/record-grid.json +52 -0
  69. package/r/record-notes.json +4 -4
  70. package/r/registry.json +4089 -1510
  71. package/r/run-history.json +52 -0
  72. package/r/run-view.json +80 -0
  73. package/r/schedule-card.json +54 -0
  74. package/r/schedule-engine.json +79 -0
  75. package/r/schedule-gantt.json +83 -0
  76. package/r/schedule-ruler.json +64 -0
  77. package/r/search-dialog.json +2 -2
  78. package/r/settings-list.json +2 -2
  79. package/r/setup-checklist.json +2 -2
  80. package/r/share-dialog.json +2 -2
  81. package/r/sidebar.json +3 -3
  82. package/r/signature-pad.json +2 -2
  83. package/r/sketch-canvas.json +3 -3
  84. package/r/source-receipt.json +52 -0
  85. package/r/spreadsheet.json +3 -3
  86. package/r/stat-cards.json +3 -3
  87. package/r/step-picker.json +53 -0
  88. package/r/step-settings.json +72 -0
  89. package/r/suggestion.json +58 -0
  90. package/r/sum-bar.json +64 -0
  91. package/r/task-list.json +3 -3
  92. package/r/task-model.json +2 -2
  93. package/r/testimonials.json +2 -2
  94. package/r/tier-map.json +67 -0
  95. package/r/time-grid.json +73 -0
  96. package/r/time-strip.json +64 -0
  97. package/r/top-bar.json +66 -0
  98. package/r/transaction-list.json +2 -2
  99. package/r/trigger-picker.json +61 -0
  100. package/r/whiteboard.json +4 -4
  101. package/r/workflow-view.json +55 -0
  102. package/registry/blocks/activity-log/README.md +112 -0
  103. package/registry/blocks/activity-log/activity-log.jsx +351 -0
  104. package/registry/blocks/activity-log/block.json +33 -0
  105. package/registry/blocks/activity-log/demo.jsx +48 -0
  106. package/registry/blocks/activity-log/index.js +4 -0
  107. package/registry/blocks/agent-changes/README.md +94 -0
  108. package/registry/blocks/agent-changes/agent-changes.jsx +118 -0
  109. package/registry/blocks/agent-changes/block.json +28 -0
  110. package/registry/blocks/agent-changes/demo.jsx +39 -0
  111. package/registry/blocks/agent-changes/index.js +3 -0
  112. package/registry/blocks/agent-chat/README.md +145 -0
  113. package/registry/blocks/agent-chat/agent-chat.jsx +415 -0
  114. package/registry/blocks/agent-chat/block.json +30 -0
  115. package/registry/blocks/agent-chat/demo.jsx +165 -0
  116. package/registry/blocks/agent-chat/index.js +3 -0
  117. package/registry/blocks/agent-column/README.md +197 -0
  118. package/registry/blocks/agent-column/agent-column.jsx +492 -0
  119. package/registry/blocks/agent-column/block.json +67 -0
  120. package/registry/blocks/agent-column/column-picker.jsx +163 -0
  121. package/registry/blocks/agent-column/demo.jsx +50 -0
  122. package/registry/blocks/agent-column/index.js +7 -0
  123. package/registry/blocks/agent-column/model.js +164 -0
  124. package/registry/blocks/agent-column/receipt.jsx +483 -0
  125. package/registry/blocks/agent-column/spreadsheet-type.jsx +24 -0
  126. package/registry/blocks/agent-dock/README.md +210 -0
  127. package/registry/blocks/agent-dock/agent-dock.jsx +356 -0
  128. package/registry/blocks/agent-dock/block.json +47 -0
  129. package/registry/blocks/agent-dock/demo.jsx +153 -0
  130. package/registry/blocks/agent-dock/dock-model.js +118 -0
  131. package/registry/blocks/agent-dock/index.js +5 -0
  132. package/registry/blocks/agent-kit/README.md +73 -0
  133. package/registry/blocks/agent-kit/agent-kit.jsx +86 -0
  134. package/registry/blocks/agent-kit/block.json +10 -0
  135. package/registry/blocks/agent-kit/demo.jsx +35 -0
  136. package/registry/blocks/agent-kit/index.js +3 -0
  137. package/registry/blocks/agent-marks/README.md +80 -0
  138. package/registry/blocks/agent-marks/agent-marks.jsx +133 -0
  139. package/registry/blocks/agent-marks/block.json +27 -0
  140. package/registry/blocks/agent-marks/demo.jsx +49 -0
  141. package/registry/blocks/agent-marks/index.js +3 -0
  142. package/registry/blocks/agent-pane/README.md +225 -0
  143. package/registry/blocks/agent-pane/agent-pane.jsx +244 -0
  144. package/registry/blocks/agent-pane/block.json +41 -0
  145. package/registry/blocks/agent-pane/composer.jsx +6 -0
  146. package/registry/blocks/agent-pane/demo.jsx +233 -0
  147. package/registry/blocks/agent-pane/dock-context.js +10 -0
  148. package/registry/blocks/agent-pane/index.js +4 -0
  149. package/registry/blocks/agent-pane/prose.jsx +84 -0
  150. package/registry/blocks/agent-pane/questions.jsx +134 -0
  151. package/registry/blocks/agent-pane/transcript.jsx +268 -0
  152. package/registry/blocks/agent-pane/work.jsx +368 -0
  153. package/registry/blocks/ai-action/README.md +94 -0
  154. package/registry/blocks/ai-action/ai-action.jsx +188 -0
  155. package/registry/blocks/ai-action/block.json +34 -0
  156. package/registry/blocks/ai-action/demo.jsx +93 -0
  157. package/registry/blocks/ai-action/index.js +3 -0
  158. package/registry/blocks/annotate/README.md +14 -11
  159. package/registry/blocks/approval/README.md +145 -0
  160. package/registry/blocks/approval/approval.jsx +163 -0
  161. package/registry/blocks/approval/block.json +31 -0
  162. package/registry/blocks/approval/demo.jsx +121 -0
  163. package/registry/blocks/approval/index.js +3 -0
  164. package/registry/blocks/ask-bar/README.md +105 -0
  165. package/registry/blocks/ask-bar/ask-bar.jsx +166 -0
  166. package/registry/blocks/ask-bar/block.json +26 -0
  167. package/registry/blocks/ask-bar/demo.jsx +78 -0
  168. package/registry/blocks/ask-bar/index.js +3 -0
  169. package/registry/blocks/automation-editor/README.md +291 -0
  170. package/registry/blocks/automation-editor/automation-editor.jsx +656 -0
  171. package/registry/blocks/automation-editor/block.json +39 -0
  172. package/registry/blocks/automation-editor/demo.jsx +284 -0
  173. package/registry/blocks/automation-editor/index.js +4 -0
  174. package/registry/blocks/automation-editor/run-inputs.jsx +82 -0
  175. package/registry/blocks/automation-list/README.md +129 -0
  176. package/registry/blocks/automation-list/automation-list.jsx +476 -0
  177. package/registry/blocks/automation-list/block.json +35 -0
  178. package/registry/blocks/automation-list/demo.jsx +67 -0
  179. package/registry/blocks/automation-list/index.js +3 -0
  180. package/registry/blocks/automation-model/README.md +109 -0
  181. package/registry/blocks/automation-model/block.json +135 -0
  182. package/registry/blocks/automation-model/catalog.js +256 -0
  183. package/registry/blocks/automation-model/check.js +161 -0
  184. package/registry/blocks/automation-model/demo.jsx +42 -0
  185. package/registry/blocks/automation-model/edit.js +262 -0
  186. package/registry/blocks/automation-model/fixes.js +287 -0
  187. package/registry/blocks/automation-model/glyph.jsx +13 -0
  188. package/registry/blocks/automation-model/graph.js +410 -0
  189. package/registry/blocks/automation-model/index.js +33 -0
  190. package/registry/blocks/automation-model/overlay.js +175 -0
  191. package/registry/blocks/automation-model/parts.jsx +94 -0
  192. package/registry/blocks/automation-model/schedule.js +53 -0
  193. package/registry/blocks/automation-model/templates.js +128 -0
  194. package/registry/blocks/automation-model/values.js +29 -0
  195. package/registry/blocks/automation-model/words.js +439 -0
  196. package/registry/blocks/automations-screen/README.md +207 -0
  197. package/registry/blocks/automations-screen/automations-screen.jsx +452 -0
  198. package/registry/blocks/automations-screen/block.json +47 -0
  199. package/registry/blocks/automations-screen/demo.jsx +364 -0
  200. package/registry/blocks/automations-screen/index.js +4 -0
  201. package/registry/blocks/automations-screen/screen-model.js +129 -0
  202. package/registry/blocks/chart/cartesian.jsx +1 -1
  203. package/registry/blocks/chart/core.jsx +33 -23
  204. package/registry/blocks/chart/pie.jsx +1 -1
  205. package/registry/blocks/chat/README.md +4 -1
  206. package/registry/blocks/chat/demo.jsx +2 -2
  207. package/registry/blocks/chat-pane/README.md +143 -0
  208. package/registry/blocks/chat-pane/block.json +48 -0
  209. package/registry/blocks/chat-pane/chat-attach.js +166 -0
  210. package/registry/blocks/chat-pane/chat-composer.jsx +195 -0
  211. package/registry/blocks/chat-pane/chat-context.js +17 -0
  212. package/registry/blocks/chat-pane/chat-model.js +43 -0
  213. package/registry/blocks/chat-pane/chat-pane.jsx +398 -0
  214. package/registry/blocks/chat-pane/chats-list.jsx +52 -0
  215. package/registry/blocks/chat-pane/demo.jsx +103 -0
  216. package/registry/blocks/chat-pane/index.js +9 -0
  217. package/registry/blocks/connect-card/README.md +99 -0
  218. package/registry/blocks/connect-card/block.json +10 -0
  219. package/registry/blocks/connect-card/connect-card.jsx +103 -0
  220. package/registry/blocks/connect-card/demo.jsx +49 -0
  221. package/registry/blocks/connect-card/index.js +3 -0
  222. package/registry/blocks/cost/README.md +115 -0
  223. package/registry/blocks/cost/block.json +10 -0
  224. package/registry/blocks/cost/cost.jsx +176 -0
  225. package/registry/blocks/cost/demo.jsx +66 -0
  226. package/registry/blocks/cost/index.js +3 -0
  227. package/registry/blocks/data-picker/README.md +81 -0
  228. package/registry/blocks/data-picker/block.json +38 -0
  229. package/registry/blocks/data-picker/data-picker.jsx +210 -0
  230. package/registry/blocks/data-picker/demo.jsx +34 -0
  231. package/registry/blocks/data-picker/fields.js +89 -0
  232. package/registry/blocks/data-picker/index.js +4 -0
  233. package/registry/blocks/data-table/demo.jsx +1 -1
  234. package/registry/blocks/first-run/README.md +118 -0
  235. package/registry/blocks/first-run/block.json +11 -0
  236. package/registry/blocks/first-run/demo.jsx +88 -0
  237. package/registry/blocks/first-run/first-run-model.js +51 -0
  238. package/registry/blocks/first-run/first-run.jsx +156 -0
  239. package/registry/blocks/first-run/index.js +5 -0
  240. package/registry/blocks/first-run/probe-rules.js +26 -0
  241. package/registry/blocks/fix-note/README.md +79 -0
  242. package/registry/blocks/fix-note/block.json +35 -0
  243. package/registry/blocks/fix-note/demo.jsx +30 -0
  244. package/registry/blocks/fix-note/fix-note.jsx +235 -0
  245. package/registry/blocks/fix-note/index.js +3 -0
  246. package/registry/blocks/flow-canvas/README.md +15 -8
  247. package/registry/blocks/flow-editor/README.md +108 -0
  248. package/registry/blocks/flow-editor/block.json +44 -0
  249. package/registry/blocks/flow-editor/demo.jsx +115 -0
  250. package/registry/blocks/flow-editor/flow-canvas.jsx +568 -0
  251. package/registry/blocks/flow-editor/flow-editor.jsx +154 -0
  252. package/registry/blocks/flow-editor/index.js +6 -0
  253. package/registry/blocks/flow-editor/minimap.jsx +78 -0
  254. package/registry/blocks/flow-editor/outline.jsx +134 -0
  255. package/registry/blocks/footer/README.md +3 -2
  256. package/registry/blocks/library-shelf/README.md +117 -0
  257. package/registry/blocks/library-shelf/block.json +28 -0
  258. package/registry/blocks/library-shelf/demo.jsx +68 -0
  259. package/registry/blocks/library-shelf/index.js +3 -0
  260. package/registry/blocks/library-shelf/library-shelf.jsx +211 -0
  261. package/registry/blocks/library-shelf/probe-rules.js +15 -0
  262. package/registry/blocks/margin-notes/README.md +222 -0
  263. package/registry/blocks/margin-notes/block.json +10 -0
  264. package/registry/blocks/margin-notes/demo.jsx +144 -0
  265. package/registry/blocks/margin-notes/index.js +20 -0
  266. package/registry/blocks/margin-notes/margin-model.js +224 -0
  267. package/registry/blocks/margin-notes/margin-notes.jsx +465 -0
  268. package/registry/blocks/mind-map/README.md +4 -2
  269. package/registry/blocks/needs-you/README.md +177 -0
  270. package/registry/blocks/needs-you/block.json +34 -0
  271. package/registry/blocks/needs-you/demo.jsx +143 -0
  272. package/registry/blocks/needs-you/index.js +3 -0
  273. package/registry/blocks/needs-you/needs-you.jsx +441 -0
  274. package/registry/blocks/org-chart/README.md +4 -2
  275. package/registry/blocks/pace-bar/README.md +230 -0
  276. package/registry/blocks/pace-bar/block.json +10 -0
  277. package/registry/blocks/pace-bar/demo.jsx +255 -0
  278. package/registry/blocks/pace-bar/index.js +22 -0
  279. package/registry/blocks/pace-bar/pace-bar.jsx +461 -0
  280. package/registry/blocks/pace-bar/pace-model.js +288 -0
  281. package/registry/blocks/page-builder/README.md +1 -1
  282. package/registry/blocks/page-builder/demo.jsx +3 -3
  283. package/registry/blocks/pdf-viewer/README.md +4 -1
  284. package/registry/blocks/record-grid/README.md +100 -0
  285. package/registry/blocks/record-grid/block.json +28 -0
  286. package/registry/blocks/record-grid/demo.jsx +43 -0
  287. package/registry/blocks/record-grid/index.js +3 -0
  288. package/registry/blocks/record-grid/record-grid.jsx +251 -0
  289. package/registry/blocks/run-history/README.md +138 -0
  290. package/registry/blocks/run-history/block.json +10 -0
  291. package/registry/blocks/run-history/demo.jsx +74 -0
  292. package/registry/blocks/run-history/index.js +3 -0
  293. package/registry/blocks/run-history/run-history.jsx +218 -0
  294. package/registry/blocks/run-view/README.md +174 -0
  295. package/registry/blocks/run-view/block.json +50 -0
  296. package/registry/blocks/run-view/demo.jsx +286 -0
  297. package/registry/blocks/run-view/index.js +5 -0
  298. package/registry/blocks/run-view/run-controls.jsx +266 -0
  299. package/registry/blocks/run-view/run-view.jsx +236 -0
  300. package/registry/blocks/run-view/runs-list.jsx +99 -0
  301. package/registry/blocks/schedule-card/README.md +121 -0
  302. package/registry/blocks/schedule-card/block.json +10 -0
  303. package/registry/blocks/schedule-card/demo.jsx +82 -0
  304. package/registry/blocks/schedule-card/index.js +3 -0
  305. package/registry/blocks/schedule-card/schedule-card.jsx +136 -0
  306. package/registry/blocks/schedule-engine/README.md +137 -0
  307. package/registry/blocks/schedule-engine/block.json +10 -0
  308. package/registry/blocks/schedule-engine/demo.jsx +82 -0
  309. package/registry/blocks/schedule-engine/engine.js +769 -0
  310. package/registry/blocks/schedule-engine/index.js +9 -0
  311. package/registry/blocks/schedule-engine/ops.js +71 -0
  312. package/registry/blocks/schedule-engine/place.js +294 -0
  313. package/registry/blocks/schedule-engine/tree.js +79 -0
  314. package/registry/blocks/schedule-engine/waits.js +80 -0
  315. package/registry/blocks/schedule-gantt/README.md +159 -0
  316. package/registry/blocks/schedule-gantt/block.json +10 -0
  317. package/registry/blocks/schedule-gantt/demo.jsx +223 -0
  318. package/registry/blocks/schedule-gantt/gantt-model.js +219 -0
  319. package/registry/blocks/schedule-gantt/geometry.js +176 -0
  320. package/registry/blocks/schedule-gantt/index.js +26 -0
  321. package/registry/blocks/schedule-gantt/schedule-gantt.jsx +882 -0
  322. package/registry/blocks/schedule-gantt/sheet.jsx +372 -0
  323. package/registry/blocks/schedule-gantt/track.jsx +190 -0
  324. package/registry/blocks/schedule-ruler/README.md +148 -0
  325. package/registry/blocks/schedule-ruler/block.json +10 -0
  326. package/registry/blocks/schedule-ruler/demo.jsx +181 -0
  327. package/registry/blocks/schedule-ruler/index.js +21 -0
  328. package/registry/blocks/schedule-ruler/ruler-model.js +239 -0
  329. package/registry/blocks/schedule-ruler/schedule-ruler.jsx +548 -0
  330. package/registry/blocks/sidebar/README.md +23 -13
  331. package/registry/blocks/sketch-canvas/README.md +15 -9
  332. package/registry/blocks/source-receipt/README.md +97 -0
  333. package/registry/blocks/source-receipt/block.json +30 -0
  334. package/registry/blocks/source-receipt/demo.jsx +71 -0
  335. package/registry/blocks/source-receipt/index.js +3 -0
  336. package/registry/blocks/source-receipt/source-receipt.jsx +107 -0
  337. package/registry/blocks/spreadsheet/spreadsheet.jsx +15 -1
  338. package/registry/blocks/step-picker/README.md +78 -0
  339. package/registry/blocks/step-picker/block.json +31 -0
  340. package/registry/blocks/step-picker/demo.jsx +23 -0
  341. package/registry/blocks/step-picker/index.js +3 -0
  342. package/registry/blocks/step-picker/step-picker.jsx +144 -0
  343. package/registry/blocks/step-settings/README.md +100 -0
  344. package/registry/blocks/step-settings/block.json +44 -0
  345. package/registry/blocks/step-settings/demo.jsx +93 -0
  346. package/registry/blocks/step-settings/fields.jsx +58 -0
  347. package/registry/blocks/step-settings/flow-settings.jsx +115 -0
  348. package/registry/blocks/step-settings/index.js +5 -0
  349. package/registry/blocks/step-settings/step-settings.jsx +290 -0
  350. package/registry/blocks/suggestion/README.md +171 -0
  351. package/registry/blocks/suggestion/block.json +40 -0
  352. package/registry/blocks/suggestion/demo.jsx +91 -0
  353. package/registry/blocks/suggestion/index.js +3 -0
  354. package/registry/blocks/suggestion/suggestion.jsx +436 -0
  355. package/registry/blocks/sum-bar/README.md +122 -0
  356. package/registry/blocks/sum-bar/block.json +10 -0
  357. package/registry/blocks/sum-bar/demo.jsx +110 -0
  358. package/registry/blocks/sum-bar/index.js +5 -0
  359. package/registry/blocks/sum-bar/sum-bar.jsx +209 -0
  360. package/registry/blocks/sum-bar/sum-model.js +126 -0
  361. package/registry/blocks/tier-map/README.md +217 -0
  362. package/registry/blocks/tier-map/block.json +10 -0
  363. package/registry/blocks/tier-map/demo.jsx +222 -0
  364. package/registry/blocks/tier-map/index.js +24 -0
  365. package/registry/blocks/tier-map/tier-map.jsx +574 -0
  366. package/registry/blocks/tier-map/tier-model.js +318 -0
  367. package/registry/blocks/time-grid/README.md +305 -0
  368. package/registry/blocks/time-grid/block.json +10 -0
  369. package/registry/blocks/time-grid/demo.jsx +279 -0
  370. package/registry/blocks/time-grid/grid-model.js +322 -0
  371. package/registry/blocks/time-grid/index.js +25 -0
  372. package/registry/blocks/time-grid/time-grid.jsx +1325 -0
  373. package/registry/blocks/time-strip/README.md +141 -0
  374. package/registry/blocks/time-strip/block.json +10 -0
  375. package/registry/blocks/time-strip/demo.jsx +129 -0
  376. package/registry/blocks/time-strip/index.js +19 -0
  377. package/registry/blocks/time-strip/strip-model.js +178 -0
  378. package/registry/blocks/time-strip/time-strip.jsx +260 -0
  379. package/registry/blocks/top-bar/README.md +149 -0
  380. package/registry/blocks/top-bar/block.json +35 -0
  381. package/registry/blocks/top-bar/demo.jsx +78 -0
  382. package/registry/blocks/top-bar/index.js +5 -0
  383. package/registry/blocks/top-bar/probe-rules.js +74 -0
  384. package/registry/blocks/top-bar/top-bar-model.js +152 -0
  385. package/registry/blocks/top-bar/top-bar.jsx +244 -0
  386. package/registry/blocks/trigger-picker/README.md +98 -0
  387. package/registry/blocks/trigger-picker/block.json +38 -0
  388. package/registry/blocks/trigger-picker/demo.jsx +59 -0
  389. package/registry/blocks/trigger-picker/index.js +3 -0
  390. package/registry/blocks/trigger-picker/trigger-picker.jsx +374 -0
  391. package/registry/blocks/whiteboard/README.md +20 -14
  392. package/registry/blocks/workflow-view/README.md +123 -0
  393. package/registry/blocks/workflow-view/block.json +10 -0
  394. package/registry/blocks/workflow-view/demo.jsx +90 -0
  395. package/registry/blocks/workflow-view/index.js +3 -0
  396. package/registry/blocks/workflow-view/workflow-view.jsx +203 -0
  397. package/src/cli.mjs +2 -2
  398. package/src/install.mjs +100 -22
  399. package/src/registry.mjs +37 -3
  400. package/templates/next/browser/lib/data.js +6 -1
  401. package/templates/next/files/README.md +909 -26
  402. package/templates/next/files/app/shell.jsx +54 -37
  403. package/templates/next/files/check/automation-format.ts +2103 -0
  404. package/templates/next/files/check/automation-package.ts +142 -0
  405. package/templates/next/files/check/run.mjs +1043 -12
  406. package/templates/next/files/components/ui/field.jsx +17 -4
  407. package/templates/next/files/components/ui/icon.jsx +13 -0
  408. package/templates/next/files/components/ui/index.js +3 -1
  409. package/templates/next/files/components/ui/layout.jsx +382 -0
  410. package/templates/next/files/components/ui/notice.jsx +70 -0
  411. package/templates/next/files/components/ui/page.jsx +124 -0
  412. package/templates/next/files/components/ui/stat.jsx +22 -7
  413. package/templates/next/files/components/ui/toast.jsx +6 -3
  414. package/templates/next/files/lib/automations.js +660 -0
  415. package/templates/next/files/lib/claw.js +244 -5
  416. package/templates/next/files/lib/door.js +92 -0
  417. package/templates/next/files/lib/hooks.js +1694 -6
  418. package/templates/next/files/lib/platform.js +611 -14
  419. package/templates/next/template.json +22 -3
@@ -23,10 +23,14 @@ const CONTROL = `w-full ${BOX}`;
23
23
  const ownWidth = (className) => /(?:^|\s)!?(?:w|size)-/.test(className ?? "");
24
24
 
25
25
  /** Label, control, hint and error in one stack. Pass `id`; the label
26
- * points at it. `error` (a string) marks the control invalid. */
26
+ * points at it. `error` (a string) marks the control invalid.
27
+ * Two Fields side by side in a grid row are stretched to the taller one;
28
+ * `content-start` keeps the shorter one's label and control at the top
29
+ * where they were (without it the grid spread them apart, and Start
30
+ * date's box sat lower than Target date's when only Target had a hint). */
27
31
  export function Field({ id, label, hint, error, required, className, children }) {
28
32
  return (
29
- <div className={cx("grid gap-1.5", className)}>
33
+ <div className={cx("grid content-start gap-1.5", className)}>
30
34
  {label ? (
31
35
  <label htmlFor={id} className="text-sm font-medium text-foreground">
32
36
  {label}
@@ -177,15 +181,24 @@ export function Textarea({ className, invalid, rows = 4, autoGrow = false, minRo
177
181
  * `options` is empty it renders `empty` (a short muted line, or nothing
178
182
  * when `empty` is null) rather than a disabled dropdown. For "pick a
179
183
  * saved record or make a new one" use RecordSwitcher (components/parts).
184
+ * A width in `className` (w-40, w-fit, w-[12rem], size-10) sets the width of
185
+ * the whole control, as it does on an Input (0.8.1).
180
186
  */
181
187
  export function Select({ options, empty = "Nothing to choose yet.", className, invalid, children, ...rest }) {
182
188
  if (options && options.length === 0 && !children) {
183
189
  return empty ? <p className="text-sm text-muted-foreground">{empty}</p> : null;
184
190
  }
191
+ // As Input: a width in className (w-40, w-auto, w-[12rem], size-10) is
192
+ // honoured. The chevron sits on the wrapper, so the width goes to the
193
+ // wrapper and the select fills it; the rest of className stays on the
194
+ // select. Without one it is as wide as its column, as before.
195
+ const tokens = String(className ?? "").split(/\s+/).filter(Boolean);
196
+ const own = tokens.filter((t) => /^!?(?:w|size)-/.test(t));
197
+ const others = tokens.filter((t) => !own.includes(t));
185
198
  return (
186
- <span className="relative block">
199
+ <span className={cx("relative block", own.join(" "))}>
187
200
  <select
188
- className={cx(CONTROL, "appearance-none pr-9", className)}
201
+ className={cx(CONTROL, "appearance-none pr-9", others.join(" "))}
189
202
  aria-invalid={invalid ? true : undefined}
190
203
  {...rest}
191
204
  >
@@ -186,6 +186,19 @@ const PATHS = {
186
186
  "calendar-check": "M3 5h18v16H3zM16 3v4M8 3v4M3 10h18M9 15.5l2 2 4-4",
187
187
  "trash-2": "M3 6h18M8 6V4h8v2m-9 0 1 14h8l1-14M10 11v6M14 11v6",
188
188
  network: "M9 2h6v6H9zM2 16h6v6H2zM16 16h6v6h-6zM12 8v4M5 16v-4h14v4",
189
+ // Automations (flow-editor and the blocks around it): one glyph per kind
190
+ // of step, drawn to the same 24 box. calendar-clock is a schedule's
191
+ // trigger, split a condition's fork, braces a set of values, timer a
192
+ // wait, plug a connected tool, bot the agent, workflow another
193
+ // automation, book-open a read of the company brain.
194
+ "calendar-clock": "M12 21H5V5h14v7M3 10h18M8 3v4M16 3v4M17.5 14a4 4 0 1 0 .01 0M17.5 16v2l1.2.8",
195
+ split: "M3 12h5c3 0 3-6 6-6h6M8 12c3 0 3 6 6 6h6M17 3l3 3-3 3M17 15l3 3-3 3",
196
+ braces: "M8 3H7a2 2 0 0 0-2 2v4a2 2 0 0 1-2 2 2 2 0 0 1 2 2v4a2 2 0 0 0 2 2h1M16 3h1a2 2 0 0 1 2 2v4a2 2 0 0 0 2 2 2 2 0 0 0-2 2v4a2 2 0 0 1-2 2h-1",
197
+ timer: "M10 2h4M12 8v5l3 2M12 6a8 8 0 1 0 0 16 8 8 0 0 0 0-16Z",
198
+ plug: "M9 2v5M15 2v5M6 7h12v4a6 6 0 0 1-12 0V7ZM12 17v5",
199
+ bot: "M12 3v3M5 8h14v11H5ZM9 13h.01M15 13h.01M2 13v3M22 13v3M9 17h6",
200
+ workflow: "M3 4h7v7H3zM14 13h7v7h-7zM10 7.5h2.5a2 2 0 0 1 2 2V13",
201
+ "book-open": "M12 6c-2-2-5-3-9-3v15c4 0 7 1 9 3 2-2 5-3 9-3V3c-4 0-7 1-9 3ZM12 6v15",
189
202
  };
190
203
 
191
204
  const BRANDS = {
@@ -5,7 +5,7 @@ export { cx } from "./cx";
5
5
  export { Icon, ICON_NAMES } from "./icon";
6
6
  export { Button, IconButton } from "./button";
7
7
  export { Field, Input, TimeInput, Textarea, Select, Switch, Checkbox } from "./field";
8
- export { Card, Notice, Badge, Kicker, Empty } from "./notice";
8
+ export { Card, ActionCard, Notice, Badge, Kicker, Empty } from "./notice";
9
9
  export { Sheet, Confirm } from "./sheet";
10
10
  export { Tabs, TabPanel } from "./tabs";
11
11
  export { Menu, MenuPanel } from "./menu";
@@ -48,6 +48,8 @@ export { Stat, StatGroup, Delta, StatusDot, Legend, Meter } from "./stat";
48
48
  export { Steps } from "./steps";
49
49
  export { Separator, Kbd, KbdGroup, AspectRatio } from "./separator";
50
50
  export { ScrollArea } from "./scroll-area";
51
+ export { AppLayout, DocumentLayout } from "./layout";
52
+ export { PageLayout } from "./page";
51
53
  export { Slider } from "./slider";
52
54
  export { InputGroup, PasswordInput } from "./input-group";
53
55
  export { Image } from "./image";
@@ -0,0 +1,382 @@
1
+ "use client";
2
+
3
+ import { createContext, useContext, useEffect, useRef, useState } from "react";
4
+ import { cx } from "./cx";
5
+ import { Button, IconButton } from "./button";
6
+ import { Sheet } from "./sheet";
7
+
8
+ // Layouts — who owns the window's height, and who scrolls.
9
+ //
10
+ // Every design-first build of 2026-10-07 shipped a shell of `min-h-dvh`
11
+ // that grew with its content: the page itself scrolled, no pane scrolled
12
+ // on its own, and a footer, an inspector or a button below a long
13
+ // article sat past the end of the iframe, where nothing could reach it.
14
+ // So the kit owns the window's height, once, and the app's code never
15
+ // sizes anything by the window (`npm run check` refuses min-h-dvh,
16
+ // h-screen, 100vh, h-[80vh]… outside the kit, rule 12).
17
+ //
18
+ // AppLayout — the app frame. Exactly one owns the viewport: the
19
+ // outermost. A layout inside another fills the slot it is in instead,
20
+ // whatever `height` says, so there is never a second viewport owner. The
21
+ // shell (app/shell.jsx) is the outermost one in every app the template
22
+ // lays; a surface that needs an inspector or a fill of its own returns
23
+ // an AppLayout as its outermost element, and it fills the shell's
24
+ // content edge to edge (the content's padding drops for it).
25
+ //
26
+ // header the top bar, always in view (title, the surface's
27
+ // commands). The bar draws its own bottom border
28
+ // navigation the surfaces, a page tree: a rail beside the content
29
+ // from md (768px); below md a Sheet from the leading
30
+ // edge, opened by the menu button in the top bar. A
31
+ // press on a link or a button inside closes it
32
+ // navigationLabel the Sheet's title and the menu button's words
33
+ // ("Navigation")
34
+ // navigationWidth the rail, in px (176; 160 to 320)
35
+ // children the content. It scrolls inside its own region
36
+ // contentMode scroll (the default): the content region scrolls ·
37
+ // fill: the region is a bounded flex column and the
38
+ // child owns its own scrolling (a canvas, a grid, a
39
+ // spreadsheet, an editor that scrolls itself)
40
+ // contentLabel the content region's name for a screen reader ("Content")
41
+ // contentClassName spacing and token backgrounds for the content
42
+ // region (p-4 sm:p-6, bg-card). Never a height or an
43
+ // overflow: the layout owns those
44
+ // scrollKey when it changes the content scrolls back to its top
45
+ // and the navigation Sheet closes: pass the route
46
+ // (usePathname()), since the frame stays mounted while
47
+ // the surfaces change inside it
48
+ // inspector the details, review or feedback panel beside the
49
+ // content, scrolling on its own
50
+ // inspectorLabel the inspector region's name ("Details")
51
+ // inspectorWidth in px (360; 240 to 560). Builds have needed 300 and 440
52
+ // inspectorAt md · lg (the default) · xl: the width from which the
53
+ // inspector sits beside the content
54
+ // inspectorIn window (the default): inspectorAt is the window's
55
+ // width (768 · 1024 · 1280 px) · frame: it is the
56
+ // width of the body between the rail and the dock
57
+ // (42 · 48 · 64 rem), so an agent dock that takes a
58
+ // quarter of the window makes the inspector go under
59
+ // the work when there is no room, not squeeze it
60
+ // footer under the content, always in view (the save state,
61
+ // the composer, the commands for what is above)
62
+ // dock a column beside the whole body (rail, content and
63
+ // inspector), under the header, that the app's own
64
+ // block draws: the agent's dock (blocks/agent-dock).
65
+ // It sizes itself, remembers its width and, where the
66
+ // body is too narrow, lays itself over the app as a
67
+ // sheet; the layout only gives it a place in the row
68
+ // and takes no part in its width. Nothing when it is
69
+ // not given
70
+ // height viewport (the default): the frame is the window's
71
+ // height · parent: it fills a bounded parent. Nested,
72
+ // it is parent whatever this says
73
+ // className the frame's own tokens; never a height or an overflow
74
+ //
75
+ // Below `inspectorAt`, where there is no room for two columns:
76
+ // - contentMode scroll: the content and the inspector share ONE scroll
77
+ // region, the inspector after the content. Everything is reachable
78
+ // by scrolling, and nothing is hidden behind a button.
79
+ // - contentMode fill: the content keeps the room and the inspector is
80
+ // a bounded pane under it (at most 45% of the height), scrolling on
81
+ // its own. A fill child has no flow to stack into, and a pane with
82
+ // no bound under it is cut off (workspace-layout's fault, 2026-10-07).
83
+ // The footer stays under both, in view.
84
+ //
85
+ // In print the frame lets go: no bound, no overflow, no navigation, no
86
+ // header, inspector or footer; the content flows onto pages. A page meant
87
+ // for print or export is a DocumentLayout inside the content.
88
+
89
+ const Nested = createContext(false);
90
+
91
+ const px = (value, fallback, min, max) => {
92
+ const n = Number(value);
93
+ return `${Number.isFinite(n) && n > 0 ? Math.min(max, Math.max(min, Math.round(n))) : fallback}px`;
94
+ };
95
+
96
+ // Tailwind reads class names whole from the source, so every breakpoint
97
+ // is written out.
98
+ const BESIDE = {
99
+ md: {
100
+ main: "md:grid md:grid-cols-[minmax(0,1fr)_var(--app-inspector)] md:grid-rows-[minmax(0,1fr)_auto]",
101
+ flow: "md:contents",
102
+ content: "md:col-start-1 md:row-start-1",
103
+ scrolls: "md:min-h-0 md:overflow-y-auto md:overscroll-contain",
104
+ inspector: "md:col-start-2 md:row-span-2 md:row-start-1 md:max-h-none md:min-h-0 md:overflow-y-auto md:border-l md:border-t-0",
105
+ footer: "md:col-start-1 md:row-start-2",
106
+ },
107
+ lg: {
108
+ main: "lg:grid lg:grid-cols-[minmax(0,1fr)_var(--app-inspector)] lg:grid-rows-[minmax(0,1fr)_auto]",
109
+ flow: "lg:contents",
110
+ content: "lg:col-start-1 lg:row-start-1",
111
+ scrolls: "lg:min-h-0 lg:overflow-y-auto lg:overscroll-contain",
112
+ inspector: "lg:col-start-2 lg:row-span-2 lg:row-start-1 lg:max-h-none lg:min-h-0 lg:overflow-y-auto lg:border-l lg:border-t-0",
113
+ footer: "lg:col-start-1 lg:row-start-2",
114
+ },
115
+ xl: {
116
+ main: "xl:grid xl:grid-cols-[minmax(0,1fr)_var(--app-inspector)] xl:grid-rows-[minmax(0,1fr)_auto]",
117
+ flow: "xl:contents",
118
+ content: "xl:col-start-1 xl:row-start-1",
119
+ scrolls: "xl:min-h-0 xl:overflow-y-auto xl:overscroll-contain",
120
+ inspector: "xl:col-start-2 xl:row-span-2 xl:row-start-1 xl:max-h-none xl:min-h-0 xl:overflow-y-auto xl:border-l xl:border-t-0",
121
+ footer: "xl:col-start-1 xl:row-start-2",
122
+ },
123
+ };
124
+
125
+ // The same classes by the width of the body's own column (a container
126
+ // query on the frame between the rail and the dock), for an app whose dock
127
+ // takes a quarter of the window: md is a body 42rem wide, lg 48rem, xl 64rem.
128
+ const BESIDE_FRAME = {
129
+ md: {
130
+ main: "@2xl:grid @2xl:grid-cols-[minmax(0,1fr)_var(--app-inspector)] @2xl:grid-rows-[minmax(0,1fr)_auto]",
131
+ flow: "@2xl:contents",
132
+ content: "@2xl:col-start-1 @2xl:row-start-1",
133
+ scrolls: "@2xl:min-h-0 @2xl:overflow-y-auto @2xl:overscroll-contain",
134
+ inspector: "@2xl:col-start-2 @2xl:row-span-2 @2xl:row-start-1 @2xl:max-h-none @2xl:min-h-0 @2xl:overflow-y-auto @2xl:border-l @2xl:border-t-0",
135
+ footer: "@2xl:col-start-1 @2xl:row-start-2",
136
+ },
137
+ lg: {
138
+ main: "@3xl:grid @3xl:grid-cols-[minmax(0,1fr)_var(--app-inspector)] @3xl:grid-rows-[minmax(0,1fr)_auto]",
139
+ flow: "@3xl:contents",
140
+ content: "@3xl:col-start-1 @3xl:row-start-1",
141
+ scrolls: "@3xl:min-h-0 @3xl:overflow-y-auto @3xl:overscroll-contain",
142
+ inspector: "@3xl:col-start-2 @3xl:row-span-2 @3xl:row-start-1 @3xl:max-h-none @3xl:min-h-0 @3xl:overflow-y-auto @3xl:border-l @3xl:border-t-0",
143
+ footer: "@3xl:col-start-1 @3xl:row-start-2",
144
+ },
145
+ xl: {
146
+ main: "@5xl:grid @5xl:grid-cols-[minmax(0,1fr)_var(--app-inspector)] @5xl:grid-rows-[minmax(0,1fr)_auto]",
147
+ flow: "@5xl:contents",
148
+ content: "@5xl:col-start-1 @5xl:row-start-1",
149
+ scrolls: "@5xl:min-h-0 @5xl:overflow-y-auto @5xl:overscroll-contain",
150
+ inspector: "@5xl:col-start-2 @5xl:row-span-2 @5xl:row-start-1 @5xl:max-h-none @5xl:min-h-0 @5xl:overflow-y-auto @5xl:border-l @5xl:border-t-0",
151
+ footer: "@5xl:col-start-1 @5xl:row-start-2",
152
+ },
153
+ };
154
+
155
+ // inspectorIn="frame": the body's column is the container the BESIDE_FRAME
156
+ // classes answer to. Off, it is nothing: the children, in the same place.
157
+ function FrameBox({ on, children }) {
158
+ if (!on) return children;
159
+ return (
160
+ <div data-layout-frame className={cx("@container flex min-h-0 min-w-0 flex-1 flex-col", LETS_GO)}>
161
+ {children}
162
+ </div>
163
+ );
164
+ }
165
+
166
+ const REGION = "outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring";
167
+
168
+ // The inspector holds its width and its contents fit it (UI review X4: a
169
+ // shelf's row ran out of the panel and its title was cut at the edge). A
170
+ // grid with no grid-cols-* has one `auto` column, and `auto` grows to its
171
+ // widest child's minimum width, past the panel; the usual inspector is
172
+ // exactly `<div className="grid content-start gap-3 p-4">`. So the panel's
173
+ // own direct children may not grow it (min-w-0), a direct child that is a
174
+ // grid with no columns of its own gets the one column that can shrink
175
+ // (minmax(0,1fr)), and nothing paints past the panel's edge (overflow-x
176
+ // hidden: a wide child wraps or truncates, it does not sideways-scroll).
177
+ const INSPECTOR_FIT =
178
+ "min-w-0 max-w-full overflow-x-hidden [&>*]:min-w-0 [&>.grid:not([class*=grid-cols])]:grid-cols-[minmax(0,1fr)]";
179
+ const LETS_GO = "print:block print:h-auto print:min-h-0 print:overflow-visible";
180
+
181
+ export function AppLayout({
182
+ header,
183
+ navigation,
184
+ navigationLabel = "Navigation",
185
+ navigationWidth,
186
+ children,
187
+ contentMode = "scroll",
188
+ contentLabel = "Content",
189
+ contentClassName,
190
+ scrollKey,
191
+ inspector,
192
+ inspectorLabel = "Details",
193
+ inspectorWidth,
194
+ inspectorAt = "lg",
195
+ inspectorIn = "window",
196
+ footer,
197
+ dock,
198
+ height = "viewport",
199
+ className,
200
+ }) {
201
+ const nested = useContext(Nested);
202
+ const bounded = nested || height === "parent";
203
+ const fill = contentMode === "fill";
204
+ const byFrame = inspectorIn === "frame";
205
+ const table = byFrame ? BESIDE_FRAME : BESIDE;
206
+ const at = table[inspectorAt] ?? table.lg;
207
+ const hasInspector = inspector != null && inspector !== false;
208
+ const hasNavigation = navigation != null && navigation !== false;
209
+ const shared = hasInspector && !fill; // below `at`: content and inspector in one scroll region
210
+ const [open, setOpen] = useState(false);
211
+ const flowRef = useRef(null);
212
+ const contentRef = useRef(null);
213
+
214
+ useEffect(() => {
215
+ if (flowRef.current) flowRef.current.scrollTop = 0;
216
+ if (contentRef.current) contentRef.current.scrollTop = 0;
217
+ setOpen(false);
218
+ }, [scrollKey]);
219
+
220
+ return (
221
+ <Nested.Provider value={true}>
222
+ <div
223
+ data-app-layout={bounded ? "parent" : "viewport"}
224
+ style={{ "--app-nav": px(navigationWidth, 176, 160, 320), "--app-inspector": px(inspectorWidth, 360, 240, 560) }}
225
+ className={cx(
226
+ "flex min-w-0 flex-col overflow-hidden bg-background text-foreground",
227
+ bounded ? "h-full min-h-0 flex-1" : "h-dvh",
228
+ LETS_GO,
229
+ className,
230
+ )}
231
+ >
232
+ {header != null && header !== false ? (
233
+ <div data-layout-header className="flex shrink-0 items-center gap-1 border-b border-border print:hidden">
234
+ {hasNavigation ? (
235
+ <IconButton icon="menu" label={`Open ${navigationLabel.toLowerCase()}`} onClick={() => setOpen(true)} className="ml-1 md:hidden" />
236
+ ) : null}
237
+ <div className="min-w-0 flex-1">{header}</div>
238
+ </div>
239
+ ) : hasNavigation ? (
240
+ <div data-layout-header className="flex shrink-0 items-center border-b border-border px-1 py-1 md:hidden print:hidden">
241
+ <Button variant="quiet" size="sm" icon="menu" onClick={() => setOpen(true)}>
242
+ {navigationLabel}
243
+ </Button>
244
+ </div>
245
+ ) : null}
246
+
247
+ {hasNavigation ? (
248
+ <Sheet open={open} onClose={() => setOpen(false)} title={navigationLabel} side="start">
249
+ {open ? (
250
+ <div
251
+ onClick={(e) => {
252
+ if (e.target instanceof Element && e.target.closest("a,button")) setOpen(false);
253
+ }}
254
+ >
255
+ {navigation}
256
+ </div>
257
+ ) : null}
258
+ </Sheet>
259
+ ) : null}
260
+
261
+ <div data-layout-body className={cx("flex min-h-0 min-w-0 flex-1", LETS_GO)}>
262
+ {hasNavigation ? (
263
+ <div
264
+ data-layout-navigation
265
+ className="hidden shrink-0 flex-col overflow-y-auto overscroll-contain border-r border-border md:flex md:w-(--app-nav) print:hidden"
266
+ >
267
+ {navigation}
268
+ </div>
269
+ ) : null}
270
+
271
+ <FrameBox on={byFrame && hasInspector}>
272
+ <div data-layout-main className={cx("flex min-h-0 min-w-0 flex-1 flex-col", hasInspector && at.main, LETS_GO)}>
273
+ <div
274
+ ref={flowRef}
275
+ data-layout-flow
276
+ className={cx(
277
+ "flex min-h-0 min-w-0 flex-1 flex-col",
278
+ shared && "overflow-y-auto overscroll-contain",
279
+ hasInspector && at.flow,
280
+ LETS_GO,
281
+ )}
282
+ >
283
+ <div
284
+ ref={contentRef}
285
+ data-layout-content
286
+ role="region"
287
+ aria-label={contentLabel}
288
+ tabIndex={0}
289
+ className={cx(
290
+ "flex min-w-0 flex-col",
291
+ REGION,
292
+ fill
293
+ ? "min-h-0 flex-1 overflow-hidden"
294
+ : shared
295
+ ? cx("shrink-0", at.scrolls)
296
+ : "min-h-0 flex-1 overflow-y-auto overscroll-contain",
297
+ hasInspector && at.content,
298
+ LETS_GO,
299
+ contentClassName,
300
+ // A surface that is a frame of its own runs to the edges.
301
+ "has-[>[data-app-layout]]:p-0",
302
+ )}
303
+ >
304
+ {children}
305
+ </div>
306
+ {hasInspector ? (
307
+ <div
308
+ data-layout-inspector
309
+ role="region"
310
+ aria-label={inspectorLabel}
311
+ tabIndex={0}
312
+ className={cx(
313
+ "shrink-0 border-t border-border print:hidden",
314
+ INSPECTOR_FIT,
315
+ REGION,
316
+ fill && "max-h-[45%] overflow-y-auto overscroll-contain",
317
+ at.inspector,
318
+ )}
319
+ >
320
+ {inspector}
321
+ </div>
322
+ ) : null}
323
+ </div>
324
+ {footer != null && footer !== false ? (
325
+ <div data-layout-footer className={cx("shrink-0 border-t border-border print:hidden", hasInspector && at.footer)}>
326
+ {footer}
327
+ </div>
328
+ ) : null}
329
+ </div>
330
+ </FrameBox>
331
+ {dock != null && dock !== false ? dock : null}
332
+ </div>
333
+ </div>
334
+ </Nested.Provider>
335
+ );
336
+ }
337
+
338
+ // DocumentLayout — a page that flows: a report, an invoice, an article
339
+ // meant for print or export. It owns no height and scrolls nothing; it
340
+ // sits in the AppLayout's content (contentMode scroll), which scrolls it,
341
+ // and in print the frame lets go and it flows onto pages.
342
+ //
343
+ // children the document
344
+ // toolbar a bar held at the top while the document scrolls under it
345
+ // (Print, Export, the zoom); never printed
346
+ // width prose (the default: a measure for reading) · page (A4,
347
+ // 210mm) · letter (8.5in) · full. In print it is the paper's
348
+ // paper true: drawn as a sheet on the desk on screen (bg-card, a
349
+ // hairline, padding); plain in print
350
+ // align start (the default) · center
351
+ // label the document's name for a screen reader ("Document")
352
+ // className the document's own spacing and tokens; never a height
353
+ const WIDTHS = {
354
+ prose: "max-w-prose",
355
+ page: "max-w-[210mm]",
356
+ letter: "max-w-[8.5in]",
357
+ full: "max-w-none",
358
+ };
359
+
360
+ export function DocumentLayout({ children, toolbar, width = "prose", paper = false, align = "start", label = "Document", className }) {
361
+ return (
362
+ <div data-document-layout className="flex min-w-0 flex-col">
363
+ {toolbar != null && toolbar !== false ? (
364
+ <div data-document-toolbar className="sticky top-0 z-10 border-b border-border bg-background print:hidden">
365
+ {toolbar}
366
+ </div>
367
+ ) : null}
368
+ <article
369
+ aria-label={label}
370
+ className={cx(
371
+ "w-full min-w-0 print:max-w-none",
372
+ WIDTHS[width] ?? WIDTHS.prose,
373
+ align === "center" && "mx-auto",
374
+ paper && "my-6 rounded-lg border border-border bg-card p-8 text-card-foreground shadow-sm print:my-0 print:rounded-none print:border-0 print:p-0 print:shadow-none",
375
+ className,
376
+ )}
377
+ >
378
+ {children}
379
+ </article>
380
+ </div>
381
+ );
382
+ }
@@ -53,6 +53,76 @@ export function Card({
53
53
  );
54
54
  }
55
55
 
56
+ const STATUS_ICON = {
57
+ success: { name: "circle-check", box: "text-success" },
58
+ warning: { name: "warning", box: "text-warning" },
59
+ danger: { name: "warning", box: "text-destructive" },
60
+ neutral: { name: "info", box: "text-muted-foreground" },
61
+ };
62
+
63
+ /** A card that is one step the member takes: a title (with an icon), what
64
+ * it does, optionally the state it is in, and ONE action under it.
65
+ * Stacked, always: the status line above a full-width button, so neither
66
+ * squeezes the other and the button's label has the room it needs.
67
+ *
68
+ * Cards in a row are the same height, and their buttons line up (UI
69
+ * review X6). A card stretches to the height of its row, and the status
70
+ * and the action are pinned to the card's bottom: title, words, children,
71
+ * then whatever room is left, then the status, then the button. So in a
72
+ * row of four the buttons sit on one line, however long each card's words
73
+ * are, and a status line in only some of them sits just above its button.
74
+ * It was `self-start` (each card only as tall as its own words) from 0.8.1's
75
+ * first cut: that meant ragged heights and buttons at different heights.
76
+ * The big empty block it was meant to stop came from a squeezed row (check
77
+ * rule 16, squeeze), not from stretching, and it cannot come back here:
78
+ * the spare room is a gap above the footer, never a blank box below it.
79
+ * icon a kit icon name, before the title
80
+ * title the step ("Connect your mailbox")
81
+ * description what it does, in a sentence or two (muted)
82
+ * children anything between the description and the state (a price
83
+ * line, a form, a list of rows)
84
+ * status { tone: success · warning · danger · neutral, children } the
85
+ * state it is in, with its mark, above the action. Say
86
+ * "Connected" only when the thing exists (an account, a file).
87
+ * action the one button (or a link), laid full width below
88
+ * fit true: only as tall as its own words (self-start), for ONE
89
+ * card on its own beside something unrelated. Never for
90
+ * cards in a row: check rule 19 (stretch) refuses a row of
91
+ * ActionCards that sets self-start, or items-start on the row
92
+ * For a card that holds a table or a list, use Card (padding none). For
93
+ * a screen's boxes in general: Card, ActionCard, Notice, never a hand-drawn
94
+ * bordered div. */
95
+ export function ActionCard({ icon, title, description, status, action, className, children, fit = false, as: Tag = "section" }) {
96
+ const mark = status ? (STATUS_ICON[status.tone] ?? STATUS_ICON.neutral) : null;
97
+ return (
98
+ <Tag
99
+ className={cx(
100
+ "flex min-w-0 flex-col gap-2.5 rounded-lg border border-border bg-card p-4 text-sm text-card-foreground",
101
+ fit && "self-start",
102
+ className,
103
+ )}
104
+ >
105
+ <h2 className="flex min-w-0 items-center gap-2 font-semibold leading-tight">
106
+ {icon ? <Icon name={icon} size={16} className="shrink-0 text-muted-foreground" /> : null}
107
+ <span className="min-w-0">{title}</span>
108
+ </h2>
109
+ {description ? <p className="text-muted-foreground">{description}</p> : null}
110
+ {children}
111
+ {status || action ? (
112
+ <div className="mt-auto grid gap-2.5">
113
+ {status ? (
114
+ <div className="flex items-start gap-2 border-t border-border pt-2.5 text-[13px]">
115
+ <Icon name={mark.name} size={14} className={cx("mt-0.5 shrink-0", mark.box)} />
116
+ <div className="min-w-0">{status.children}</div>
117
+ </div>
118
+ ) : null}
119
+ {action ? <div className="grid">{action}</div> : null}
120
+ </div>
121
+ ) : null}
122
+ </Tag>
123
+ );
124
+ }
125
+
56
126
  /** One line the user should read, with an optional action. `tone`
57
127
  * neutral · info · success · warning · danger. Colour is the signal, so
58
128
  * status tones are for status only — never decoration. */
@@ -0,0 +1,124 @@
1
+ "use client";
2
+
3
+ import { cx } from "./cx";
4
+
5
+ // PageLayout — a screen's main area with an optional side column, taking the
6
+ // full height of the content it sits in. The MAIN is the column that scrolls.
7
+ // The SIDE is the fixed one: it holds its place, top to bottom, while the
8
+ // main scrolls, and it is short.
9
+ //
10
+ // Why (UI review X12, 2026-10-12): Project Roadmap's Today ended at 680px in
11
+ // a 1240px window. The screen drew its own two-column grid inside the
12
+ // scrolling content, so it was only as tall as its words: the side column's
13
+ // divider stopped halfway down and the bottom half of the window was empty.
14
+ // Every screen with a side drew that grid by hand. This is the one.
15
+ // `npm run check` (rule 23, page) refuses a hand-drawn main + side with a
16
+ // ruled <aside>.
17
+ //
18
+ // What goes in the side, and what never does (UI review X13, 2026-10-12:
19
+ // Newsletter Engine's first run was a short intro on the left and a long
20
+ // "Name it" form in the right column. "this can only work if one column is
21
+ // fixed, usually the 3rd column, and the middle one is scrolling"): the side
22
+ // is a summary, the next step, a small panel, a few facts, a short list. It
23
+ // never needs a scroll of its own. A form, a paste box, a long list, a
24
+ // shelf of examples belong in the MAIN, where the page scrolls: a step that
25
+ // opens reveals its own card there. The side's own scroll is a last resort
26
+ // for a window shorter than the side (the bar is thin to say so), never how
27
+ // a long thing is meant to be read. `npm run check` (rule 27, sidelong)
28
+ // refuses a side column that holds a form or a long list.
29
+ //
30
+ // It lives INSIDE an AppLayout (the shell or the screen's own): the layout
31
+ // owns the window's height, this fills the content region it is given. Use
32
+ // the AppLayout's `contentMode="fill"` and give its content no padding
33
+ // (omit `contentClassName`): the columns pad themselves, so the divider can
34
+ // run to the edges. In contentMode scroll it fills the same.
35
+ //
36
+ // children the main area
37
+ // side the side column, the FIXED one: short things (a summary, the
38
+ // next step, a record's facts, a small panel). It stays put
39
+ // while the main scrolls; never a long form or a long list.
40
+ // Without it the page is one scrolling column
41
+ // sideWidth px (304; 220 to 560)
42
+ // sideAt md · lg (the default) · xl: the width of THIS page from
43
+ // which the side sits beside the main (42 · 48 · 64 rem). It
44
+ // is the page's own width, not the window's: an open agent
45
+ // dock takes a quarter of the window, and the page must not
46
+ // be squeezed by it. Narrower, the side goes under the main in
47
+ // one scroll, nothing hidden behind a button
48
+ // mainLabel the main area's name for a screen reader ("Content")
49
+ // sideLabel the side's name ("Details")
50
+ // padded default true: p-4 sm:p-6 on the main, p-4 on the side. false
51
+ // for a page that draws its own edges
52
+ // fill true: the main is a flex column, so a child with `flex-1`
53
+ // (a list, a table) grows into the height instead of stopping
54
+ // where its rows end. With the side beside it, or alone; with
55
+ // the side under it (narrow) the page is one scroll and there
56
+ // is no height to grow into
57
+ // className, mainClassName, sideClassName spacing and token backgrounds
58
+ // (bg-muted). Never a height or an overflow: the layout owns those
59
+ const px = (value, fallback, min, max) => {
60
+ const n = Number(value);
61
+ return `${Number.isFinite(n) && n > 0 ? Math.min(max, Math.max(min, Math.round(n))) : fallback}px`;
62
+ };
63
+
64
+ // Tailwind reads class names whole from the source, so every size is written
65
+ // out. md is a page 42rem wide, lg 48rem, xl 64rem (the AppLayout's
66
+ // inspectorIn="frame" sizes).
67
+ const BESIDE = {
68
+ md: {
69
+ grid: "@2xl:grid-cols-[minmax(0,1fr)_var(--page-side)] @2xl:grid-rows-[minmax(0,1fr)] @2xl:overflow-hidden",
70
+ column: "@2xl:min-h-0 @2xl:overflow-y-auto @2xl:overscroll-contain",
71
+ side: "@2xl:border-l @2xl:border-t-0 @2xl:[scrollbar-width:thin]",
72
+ },
73
+ lg: {
74
+ grid: "@3xl:grid-cols-[minmax(0,1fr)_var(--page-side)] @3xl:grid-rows-[minmax(0,1fr)] @3xl:overflow-hidden",
75
+ column: "@3xl:min-h-0 @3xl:overflow-y-auto @3xl:overscroll-contain",
76
+ side: "@3xl:border-l @3xl:border-t-0 @3xl:[scrollbar-width:thin]",
77
+ },
78
+ xl: {
79
+ grid: "@5xl:grid-cols-[minmax(0,1fr)_var(--page-side)] @5xl:grid-rows-[minmax(0,1fr)] @5xl:overflow-hidden",
80
+ column: "@5xl:min-h-0 @5xl:overflow-y-auto @5xl:overscroll-contain",
81
+ side: "@5xl:border-l @5xl:border-t-0 @5xl:[scrollbar-width:thin]",
82
+ },
83
+ };
84
+
85
+ const REGION = "outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring";
86
+ const LETS_GO = "print:block print:h-auto print:min-h-0 print:overflow-visible";
87
+
88
+ export function PageLayout({ children, side, sideWidth, sideAt = "lg", mainLabel = "Content", sideLabel = "Details", padded = true, fill = false, className, mainClassName, sideClassName }) {
89
+ const has = side != null && side !== false;
90
+ const at = BESIDE[sideAt] ?? BESIDE.lg;
91
+ return (
92
+ <div data-page-layout className={cx("@container flex min-h-0 min-w-0 flex-1 flex-col", LETS_GO, className)}>
93
+ <div
94
+ data-page-scroll
95
+ style={{ "--page-side": px(sideWidth, 304, 220, 560) }}
96
+ className={cx(
97
+ "grid min-h-0 min-w-0 flex-1 grid-cols-[minmax(0,1fr)] content-start",
98
+ has ? cx("overflow-y-auto overscroll-contain", at.grid) : "grid-rows-[minmax(0,1fr)] overflow-hidden",
99
+ LETS_GO,
100
+ )}
101
+ >
102
+ <div
103
+ data-page-main
104
+ role="region"
105
+ aria-label={mainLabel}
106
+ tabIndex={0}
107
+ className={cx("min-w-0", REGION, has ? at.column : "min-h-0 overflow-y-auto overscroll-contain", fill && "flex flex-col", padded && "p-4 sm:p-6", LETS_GO, mainClassName)}
108
+ >
109
+ {children}
110
+ </div>
111
+ {has ? (
112
+ <aside
113
+ data-page-side
114
+ aria-label={sideLabel}
115
+ tabIndex={0}
116
+ className={cx("min-w-0 border-t border-border print:hidden", REGION, at.column, at.side, padded && "p-4", sideClassName)}
117
+ >
118
+ {side}
119
+ </aside>
120
+ ) : null}
121
+ </div>
122
+ </div>
123
+ );
124
+ }