makersclaw 0.8.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 (401) hide show
  1. package/README.md +9 -3
  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 +3 -3
  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 +2 -2
  26. package/r/chat-pane.json +84 -0
  27. package/r/chat.json +2 -2
  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 +13 -7
  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 +2 -2
  46. package/r/flow-editor.json +79 -0
  47. package/r/footer.json +2 -2
  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 +3 -3
  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 +3 -3
  60. package/r/pace-bar.json +69 -0
  61. package/r/page-builder.json +2 -2
  62. package/r/payment-methods.json +2 -2
  63. package/r/pdf-document.json +2 -2
  64. package/r/pdf-viewer.json +2 -2
  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 +4086 -1512
  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 +2 -2
  82. package/r/signature-pad.json +2 -2
  83. package/r/sketch-canvas.json +2 -2
  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 +3 -3
  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/approval/README.md +145 -0
  159. package/registry/blocks/approval/approval.jsx +163 -0
  160. package/registry/blocks/approval/block.json +31 -0
  161. package/registry/blocks/approval/demo.jsx +121 -0
  162. package/registry/blocks/approval/index.js +3 -0
  163. package/registry/blocks/ask-bar/README.md +105 -0
  164. package/registry/blocks/ask-bar/ask-bar.jsx +166 -0
  165. package/registry/blocks/ask-bar/block.json +26 -0
  166. package/registry/blocks/ask-bar/demo.jsx +78 -0
  167. package/registry/blocks/ask-bar/index.js +3 -0
  168. package/registry/blocks/automation-editor/README.md +291 -0
  169. package/registry/blocks/automation-editor/automation-editor.jsx +656 -0
  170. package/registry/blocks/automation-editor/block.json +39 -0
  171. package/registry/blocks/automation-editor/demo.jsx +284 -0
  172. package/registry/blocks/automation-editor/index.js +4 -0
  173. package/registry/blocks/automation-editor/run-inputs.jsx +82 -0
  174. package/registry/blocks/automation-list/README.md +129 -0
  175. package/registry/blocks/automation-list/automation-list.jsx +476 -0
  176. package/registry/blocks/automation-list/block.json +35 -0
  177. package/registry/blocks/automation-list/demo.jsx +67 -0
  178. package/registry/blocks/automation-list/index.js +3 -0
  179. package/registry/blocks/automation-model/README.md +109 -0
  180. package/registry/blocks/automation-model/block.json +135 -0
  181. package/registry/blocks/automation-model/catalog.js +256 -0
  182. package/registry/blocks/automation-model/check.js +161 -0
  183. package/registry/blocks/automation-model/demo.jsx +42 -0
  184. package/registry/blocks/automation-model/edit.js +262 -0
  185. package/registry/blocks/automation-model/fixes.js +287 -0
  186. package/registry/blocks/automation-model/glyph.jsx +13 -0
  187. package/registry/blocks/automation-model/graph.js +410 -0
  188. package/registry/blocks/automation-model/index.js +33 -0
  189. package/registry/blocks/automation-model/overlay.js +175 -0
  190. package/registry/blocks/automation-model/parts.jsx +94 -0
  191. package/registry/blocks/automation-model/schedule.js +53 -0
  192. package/registry/blocks/automation-model/templates.js +128 -0
  193. package/registry/blocks/automation-model/values.js +29 -0
  194. package/registry/blocks/automation-model/words.js +439 -0
  195. package/registry/blocks/automations-screen/README.md +207 -0
  196. package/registry/blocks/automations-screen/automations-screen.jsx +452 -0
  197. package/registry/blocks/automations-screen/block.json +47 -0
  198. package/registry/blocks/automations-screen/demo.jsx +364 -0
  199. package/registry/blocks/automations-screen/index.js +4 -0
  200. package/registry/blocks/automations-screen/screen-model.js +129 -0
  201. package/registry/blocks/chat-pane/README.md +143 -0
  202. package/registry/blocks/chat-pane/block.json +48 -0
  203. package/registry/blocks/chat-pane/chat-attach.js +166 -0
  204. package/registry/blocks/chat-pane/chat-composer.jsx +195 -0
  205. package/registry/blocks/chat-pane/chat-context.js +17 -0
  206. package/registry/blocks/chat-pane/chat-model.js +43 -0
  207. package/registry/blocks/chat-pane/chat-pane.jsx +398 -0
  208. package/registry/blocks/chat-pane/chats-list.jsx +52 -0
  209. package/registry/blocks/chat-pane/demo.jsx +103 -0
  210. package/registry/blocks/chat-pane/index.js +9 -0
  211. package/registry/blocks/connect-card/README.md +99 -0
  212. package/registry/blocks/connect-card/block.json +10 -0
  213. package/registry/blocks/connect-card/connect-card.jsx +103 -0
  214. package/registry/blocks/connect-card/demo.jsx +49 -0
  215. package/registry/blocks/connect-card/index.js +3 -0
  216. package/registry/blocks/cost/README.md +115 -0
  217. package/registry/blocks/cost/block.json +10 -0
  218. package/registry/blocks/cost/cost.jsx +176 -0
  219. package/registry/blocks/cost/demo.jsx +66 -0
  220. package/registry/blocks/cost/index.js +3 -0
  221. package/registry/blocks/data-picker/README.md +81 -0
  222. package/registry/blocks/data-picker/block.json +38 -0
  223. package/registry/blocks/data-picker/data-picker.jsx +210 -0
  224. package/registry/blocks/data-picker/demo.jsx +34 -0
  225. package/registry/blocks/data-picker/fields.js +89 -0
  226. package/registry/blocks/data-picker/index.js +4 -0
  227. package/registry/blocks/data-table/demo.jsx +1 -1
  228. package/registry/blocks/first-run/README.md +118 -0
  229. package/registry/blocks/first-run/block.json +11 -0
  230. package/registry/blocks/first-run/demo.jsx +88 -0
  231. package/registry/blocks/first-run/first-run-model.js +51 -0
  232. package/registry/blocks/first-run/first-run.jsx +156 -0
  233. package/registry/blocks/first-run/index.js +5 -0
  234. package/registry/blocks/first-run/probe-rules.js +26 -0
  235. package/registry/blocks/fix-note/README.md +79 -0
  236. package/registry/blocks/fix-note/block.json +35 -0
  237. package/registry/blocks/fix-note/demo.jsx +30 -0
  238. package/registry/blocks/fix-note/fix-note.jsx +235 -0
  239. package/registry/blocks/fix-note/index.js +3 -0
  240. package/registry/blocks/flow-editor/README.md +108 -0
  241. package/registry/blocks/flow-editor/block.json +44 -0
  242. package/registry/blocks/flow-editor/demo.jsx +115 -0
  243. package/registry/blocks/flow-editor/flow-canvas.jsx +568 -0
  244. package/registry/blocks/flow-editor/flow-editor.jsx +154 -0
  245. package/registry/blocks/flow-editor/index.js +6 -0
  246. package/registry/blocks/flow-editor/minimap.jsx +78 -0
  247. package/registry/blocks/flow-editor/outline.jsx +134 -0
  248. package/registry/blocks/library-shelf/README.md +117 -0
  249. package/registry/blocks/library-shelf/block.json +28 -0
  250. package/registry/blocks/library-shelf/demo.jsx +68 -0
  251. package/registry/blocks/library-shelf/index.js +3 -0
  252. package/registry/blocks/library-shelf/library-shelf.jsx +211 -0
  253. package/registry/blocks/library-shelf/probe-rules.js +15 -0
  254. package/registry/blocks/margin-notes/README.md +222 -0
  255. package/registry/blocks/margin-notes/block.json +10 -0
  256. package/registry/blocks/margin-notes/demo.jsx +144 -0
  257. package/registry/blocks/margin-notes/index.js +20 -0
  258. package/registry/blocks/margin-notes/margin-model.js +224 -0
  259. package/registry/blocks/margin-notes/margin-notes.jsx +465 -0
  260. package/registry/blocks/needs-you/README.md +177 -0
  261. package/registry/blocks/needs-you/block.json +34 -0
  262. package/registry/blocks/needs-you/demo.jsx +143 -0
  263. package/registry/blocks/needs-you/index.js +3 -0
  264. package/registry/blocks/needs-you/needs-you.jsx +441 -0
  265. package/registry/blocks/pace-bar/README.md +230 -0
  266. package/registry/blocks/pace-bar/block.json +10 -0
  267. package/registry/blocks/pace-bar/demo.jsx +255 -0
  268. package/registry/blocks/pace-bar/index.js +22 -0
  269. package/registry/blocks/pace-bar/pace-bar.jsx +461 -0
  270. package/registry/blocks/pace-bar/pace-model.js +288 -0
  271. package/registry/blocks/record-grid/README.md +100 -0
  272. package/registry/blocks/record-grid/block.json +28 -0
  273. package/registry/blocks/record-grid/demo.jsx +43 -0
  274. package/registry/blocks/record-grid/index.js +3 -0
  275. package/registry/blocks/record-grid/record-grid.jsx +251 -0
  276. package/registry/blocks/run-history/README.md +138 -0
  277. package/registry/blocks/run-history/block.json +10 -0
  278. package/registry/blocks/run-history/demo.jsx +74 -0
  279. package/registry/blocks/run-history/index.js +3 -0
  280. package/registry/blocks/run-history/run-history.jsx +218 -0
  281. package/registry/blocks/run-view/README.md +174 -0
  282. package/registry/blocks/run-view/block.json +50 -0
  283. package/registry/blocks/run-view/demo.jsx +286 -0
  284. package/registry/blocks/run-view/index.js +5 -0
  285. package/registry/blocks/run-view/run-controls.jsx +266 -0
  286. package/registry/blocks/run-view/run-view.jsx +236 -0
  287. package/registry/blocks/run-view/runs-list.jsx +99 -0
  288. package/registry/blocks/schedule-card/README.md +121 -0
  289. package/registry/blocks/schedule-card/block.json +10 -0
  290. package/registry/blocks/schedule-card/demo.jsx +82 -0
  291. package/registry/blocks/schedule-card/index.js +3 -0
  292. package/registry/blocks/schedule-card/schedule-card.jsx +136 -0
  293. package/registry/blocks/schedule-engine/README.md +137 -0
  294. package/registry/blocks/schedule-engine/block.json +10 -0
  295. package/registry/blocks/schedule-engine/demo.jsx +82 -0
  296. package/registry/blocks/schedule-engine/engine.js +769 -0
  297. package/registry/blocks/schedule-engine/index.js +9 -0
  298. package/registry/blocks/schedule-engine/ops.js +71 -0
  299. package/registry/blocks/schedule-engine/place.js +294 -0
  300. package/registry/blocks/schedule-engine/tree.js +79 -0
  301. package/registry/blocks/schedule-engine/waits.js +80 -0
  302. package/registry/blocks/schedule-gantt/README.md +159 -0
  303. package/registry/blocks/schedule-gantt/block.json +10 -0
  304. package/registry/blocks/schedule-gantt/demo.jsx +223 -0
  305. package/registry/blocks/schedule-gantt/gantt-model.js +219 -0
  306. package/registry/blocks/schedule-gantt/geometry.js +176 -0
  307. package/registry/blocks/schedule-gantt/index.js +26 -0
  308. package/registry/blocks/schedule-gantt/schedule-gantt.jsx +882 -0
  309. package/registry/blocks/schedule-gantt/sheet.jsx +372 -0
  310. package/registry/blocks/schedule-gantt/track.jsx +190 -0
  311. package/registry/blocks/schedule-ruler/README.md +148 -0
  312. package/registry/blocks/schedule-ruler/block.json +10 -0
  313. package/registry/blocks/schedule-ruler/demo.jsx +181 -0
  314. package/registry/blocks/schedule-ruler/index.js +21 -0
  315. package/registry/blocks/schedule-ruler/ruler-model.js +239 -0
  316. package/registry/blocks/schedule-ruler/schedule-ruler.jsx +548 -0
  317. package/registry/blocks/source-receipt/README.md +97 -0
  318. package/registry/blocks/source-receipt/block.json +30 -0
  319. package/registry/blocks/source-receipt/demo.jsx +71 -0
  320. package/registry/blocks/source-receipt/index.js +3 -0
  321. package/registry/blocks/source-receipt/source-receipt.jsx +107 -0
  322. package/registry/blocks/spreadsheet/spreadsheet.jsx +15 -1
  323. package/registry/blocks/step-picker/README.md +78 -0
  324. package/registry/blocks/step-picker/block.json +31 -0
  325. package/registry/blocks/step-picker/demo.jsx +23 -0
  326. package/registry/blocks/step-picker/index.js +3 -0
  327. package/registry/blocks/step-picker/step-picker.jsx +144 -0
  328. package/registry/blocks/step-settings/README.md +100 -0
  329. package/registry/blocks/step-settings/block.json +44 -0
  330. package/registry/blocks/step-settings/demo.jsx +93 -0
  331. package/registry/blocks/step-settings/fields.jsx +58 -0
  332. package/registry/blocks/step-settings/flow-settings.jsx +115 -0
  333. package/registry/blocks/step-settings/index.js +5 -0
  334. package/registry/blocks/step-settings/step-settings.jsx +290 -0
  335. package/registry/blocks/suggestion/README.md +171 -0
  336. package/registry/blocks/suggestion/block.json +40 -0
  337. package/registry/blocks/suggestion/demo.jsx +91 -0
  338. package/registry/blocks/suggestion/index.js +3 -0
  339. package/registry/blocks/suggestion/suggestion.jsx +436 -0
  340. package/registry/blocks/sum-bar/README.md +122 -0
  341. package/registry/blocks/sum-bar/block.json +10 -0
  342. package/registry/blocks/sum-bar/demo.jsx +110 -0
  343. package/registry/blocks/sum-bar/index.js +5 -0
  344. package/registry/blocks/sum-bar/sum-bar.jsx +209 -0
  345. package/registry/blocks/sum-bar/sum-model.js +126 -0
  346. package/registry/blocks/tier-map/README.md +217 -0
  347. package/registry/blocks/tier-map/block.json +10 -0
  348. package/registry/blocks/tier-map/demo.jsx +222 -0
  349. package/registry/blocks/tier-map/index.js +24 -0
  350. package/registry/blocks/tier-map/tier-map.jsx +574 -0
  351. package/registry/blocks/tier-map/tier-model.js +318 -0
  352. package/registry/blocks/time-grid/README.md +305 -0
  353. package/registry/blocks/time-grid/block.json +10 -0
  354. package/registry/blocks/time-grid/demo.jsx +279 -0
  355. package/registry/blocks/time-grid/grid-model.js +322 -0
  356. package/registry/blocks/time-grid/index.js +25 -0
  357. package/registry/blocks/time-grid/time-grid.jsx +1325 -0
  358. package/registry/blocks/time-strip/README.md +141 -0
  359. package/registry/blocks/time-strip/block.json +10 -0
  360. package/registry/blocks/time-strip/demo.jsx +129 -0
  361. package/registry/blocks/time-strip/index.js +19 -0
  362. package/registry/blocks/time-strip/strip-model.js +178 -0
  363. package/registry/blocks/time-strip/time-strip.jsx +260 -0
  364. package/registry/blocks/top-bar/README.md +149 -0
  365. package/registry/blocks/top-bar/block.json +35 -0
  366. package/registry/blocks/top-bar/demo.jsx +78 -0
  367. package/registry/blocks/top-bar/index.js +5 -0
  368. package/registry/blocks/top-bar/probe-rules.js +74 -0
  369. package/registry/blocks/top-bar/top-bar-model.js +152 -0
  370. package/registry/blocks/top-bar/top-bar.jsx +244 -0
  371. package/registry/blocks/trigger-picker/README.md +98 -0
  372. package/registry/blocks/trigger-picker/block.json +38 -0
  373. package/registry/blocks/trigger-picker/demo.jsx +59 -0
  374. package/registry/blocks/trigger-picker/index.js +3 -0
  375. package/registry/blocks/trigger-picker/trigger-picker.jsx +374 -0
  376. package/registry/blocks/workflow-view/README.md +123 -0
  377. package/registry/blocks/workflow-view/block.json +10 -0
  378. package/registry/blocks/workflow-view/demo.jsx +90 -0
  379. package/registry/blocks/workflow-view/index.js +3 -0
  380. package/registry/blocks/workflow-view/workflow-view.jsx +203 -0
  381. package/src/install.mjs +77 -16
  382. package/src/registry.mjs +3 -0
  383. package/templates/next/browser/lib/data.js +6 -1
  384. package/templates/next/files/README.md +627 -24
  385. package/templates/next/files/check/automation-format.ts +2103 -0
  386. package/templates/next/files/check/automation-package.ts +142 -0
  387. package/templates/next/files/check/run.mjs +968 -9
  388. package/templates/next/files/components/ui/field.jsx +17 -4
  389. package/templates/next/files/components/ui/icon.jsx +13 -0
  390. package/templates/next/files/components/ui/index.js +2 -1
  391. package/templates/next/files/components/ui/layout.jsx +77 -2
  392. package/templates/next/files/components/ui/notice.jsx +70 -0
  393. package/templates/next/files/components/ui/page.jsx +124 -0
  394. package/templates/next/files/components/ui/stat.jsx +22 -7
  395. package/templates/next/files/components/ui/toast.jsx +6 -3
  396. package/templates/next/files/lib/automations.js +660 -0
  397. package/templates/next/files/lib/claw.js +241 -5
  398. package/templates/next/files/lib/door.js +92 -0
  399. package/templates/next/files/lib/hooks.js +1627 -8
  400. package/templates/next/files/lib/platform.js +529 -21
  401. package/templates/next/template.json +13 -3
@@ -0,0 +1,574 @@
1
+ "use client";
2
+
3
+ import { createContext, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
4
+ import { Button, Card, Empty, Icon, Notice, Skeleton, cx } from "../../ui";
5
+ import { barOf, buildTierModel, countText, elbowOf, fitKey, neighbour, openPath, tiersOf, togglePath, toneOf } from "./tier-model";
6
+
7
+ // A map of cards in tiers, from a flat list where each item names its parent.
8
+ // The first tier is the tops; pressing a card opens its kids as the next tier
9
+ // beneath it (pressing it again closes them), so ONE LAYER OPENS AT A TIME.
10
+ // Items with no place in the tree sit together in an "unparented" group;
11
+ // drafts (`ghost`) sit in a group of their own, dashed, and can serve drafts.
12
+ //
13
+ // Props in, callbacks out (`onSelect`, `onOpenChange`): the block never reads
14
+ // or writes data. The elbow lines are CSS only: every tier is a grid of equal
15
+ // columns and the lines are placed in percent of its width, so nothing is
16
+ // measured, there is no observer, and the server draws what the browser
17
+ // draws. Below the width a tier needs to sit in one row, it stacks and the
18
+ // lines become a rail down its left. README.md beside this file lists every
19
+ // prop.
20
+
21
+ // ---- layout classes (literal, so Tailwind sees every one)
22
+ //
23
+ // Each table is keyed by a tier's fit key (tier-model.js `fitKey`): the most
24
+ // equal columns this tier, or any tier above it, needs. The width a key asks
25
+ // for is `thresholdRem` (11 rem a column); test/tier-map.test.mjs checks the
26
+ // numbers below against it. Key 9 is a tier too wide to ever sit in a row.
27
+
28
+ // A tier's grid: from its width, one row of equal columns (--cols); below it, a stack.
29
+ const GRID = {
30
+ 1: "@min-[0rem]:grid-cols-(--cols) @min-[0rem]:gap-y-0",
31
+ 2: "@min-[22rem]:grid-cols-(--cols) @min-[22rem]:gap-y-0",
32
+ 3: "@min-[33rem]:grid-cols-(--cols) @min-[33rem]:gap-y-0",
33
+ 4: "@min-[44rem]:grid-cols-(--cols) @min-[44rem]:gap-y-0",
34
+ 5: "@min-[55rem]:grid-cols-(--cols) @min-[55rem]:gap-y-0",
35
+ 6: "@min-[66rem]:grid-cols-(--cols) @min-[66rem]:gap-y-0",
36
+ 7: "@min-[77rem]:grid-cols-(--cols) @min-[77rem]:gap-y-0",
37
+ 8: "@min-[88rem]:grid-cols-(--cols) @min-[88rem]:gap-y-0",
38
+ 9: "",
39
+ };
40
+
41
+ // A card's cell stops being a box from the tier's width, so its card and its kids are the tier's own grid items.
42
+ const CELL = {
43
+ 1: "@min-[0rem]:contents",
44
+ 2: "@min-[22rem]:contents",
45
+ 3: "@min-[33rem]:contents",
46
+ 4: "@min-[44rem]:contents",
47
+ 5: "@min-[55rem]:contents",
48
+ 6: "@min-[66rem]:contents",
49
+ 7: "@min-[77rem]:contents",
50
+ 8: "@min-[88rem]:contents",
51
+ 9: "",
52
+ };
53
+
54
+ // The card itself, from the tier's width: its own column (--c) in row 1, centred in it.
55
+ const SLOT = {
56
+ 1: "@min-[0rem]:col-start-(--c) @min-[0rem]:row-start-1 @min-[0rem]:justify-items-center @min-[0rem]:px-1.5",
57
+ 2: "@min-[22rem]:col-start-(--c) @min-[22rem]:row-start-1 @min-[22rem]:justify-items-center @min-[22rem]:px-1.5",
58
+ 3: "@min-[33rem]:col-start-(--c) @min-[33rem]:row-start-1 @min-[33rem]:justify-items-center @min-[33rem]:px-1.5",
59
+ 4: "@min-[44rem]:col-start-(--c) @min-[44rem]:row-start-1 @min-[44rem]:justify-items-center @min-[44rem]:px-1.5",
60
+ 5: "@min-[55rem]:col-start-(--c) @min-[55rem]:row-start-1 @min-[55rem]:justify-items-center @min-[55rem]:px-1.5",
61
+ 6: "@min-[66rem]:col-start-(--c) @min-[66rem]:row-start-1 @min-[66rem]:justify-items-center @min-[66rem]:px-1.5",
62
+ 7: "@min-[77rem]:col-start-(--c) @min-[77rem]:row-start-1 @min-[77rem]:justify-items-center @min-[77rem]:px-1.5",
63
+ 8: "@min-[88rem]:col-start-(--c) @min-[88rem]:row-start-1 @min-[88rem]:justify-items-center @min-[88rem]:px-1.5",
64
+ 9: "",
65
+ };
66
+
67
+ // The block under an open card: from the parent tier's width, a whole row of its own (row 2).
68
+ const KIDS = {
69
+ 1: "@min-[0rem]:row-start-2 @min-[0rem]:mt-0",
70
+ 2: "@min-[22rem]:row-start-2 @min-[22rem]:mt-0",
71
+ 3: "@min-[33rem]:row-start-2 @min-[33rem]:mt-0",
72
+ 4: "@min-[44rem]:row-start-2 @min-[44rem]:mt-0",
73
+ 5: "@min-[55rem]:row-start-2 @min-[55rem]:mt-0",
74
+ 6: "@min-[66rem]:row-start-2 @min-[66rem]:mt-0",
75
+ 7: "@min-[77rem]:row-start-2 @min-[77rem]:mt-0",
76
+ 8: "@min-[88rem]:row-start-2 @min-[88rem]:mt-0",
77
+ 9: "",
78
+ };
79
+
80
+ // ...flush left once its own tier sits in a row; before that it hangs indented off the rail.
81
+ const INDENT = {
82
+ 1: "@min-[0rem]:ml-0",
83
+ 2: "@min-[22rem]:ml-0",
84
+ 3: "@min-[33rem]:ml-0",
85
+ 4: "@min-[44rem]:ml-0",
86
+ 5: "@min-[55rem]:ml-0",
87
+ 6: "@min-[66rem]:ml-0",
88
+ 7: "@min-[77rem]:ml-0",
89
+ 8: "@min-[88rem]:ml-0",
90
+ 9: "",
91
+ };
92
+
93
+ // The strip of lines above the kids: only from the parent tier's width.
94
+ const HEAD = {
95
+ 1: "hidden @min-[0rem]:block",
96
+ 2: "hidden @min-[22rem]:block",
97
+ 3: "hidden @min-[33rem]:block",
98
+ 4: "hidden @min-[44rem]:block",
99
+ 5: "hidden @min-[55rem]:block",
100
+ 6: "hidden @min-[66rem]:block",
101
+ 7: "hidden @min-[77rem]:block",
102
+ 8: "hidden @min-[88rem]:block",
103
+ 9: "hidden",
104
+ };
105
+
106
+ // The bar across the kids' tops: only from the kids' tier width.
107
+ const BAR = {
108
+ 1: "hidden @min-[0rem]:block",
109
+ 2: "hidden @min-[22rem]:block",
110
+ 3: "hidden @min-[33rem]:block",
111
+ 4: "hidden @min-[44rem]:block",
112
+ 5: "hidden @min-[55rem]:block",
113
+ 6: "hidden @min-[66rem]:block",
114
+ 7: "hidden @min-[77rem]:block",
115
+ 8: "hidden @min-[88rem]:block",
116
+ 9: "hidden",
117
+ };
118
+
119
+ // The line from a parent that sits in a row to the rail of kids that stack.
120
+ const LOW = {
121
+ 1: "hidden @max-[0rem]:block",
122
+ 2: "hidden @max-[22rem]:block",
123
+ 3: "hidden @max-[33rem]:block",
124
+ 4: "hidden @max-[44rem]:block",
125
+ 5: "hidden @max-[55rem]:block",
126
+ 6: "hidden @max-[66rem]:block",
127
+ 7: "hidden @max-[77rem]:block",
128
+ 8: "hidden @max-[88rem]:block",
129
+ 9: "block",
130
+ };
131
+
132
+ // A kid's elbow to the rail, only while its own tier is stacked.
133
+ const STUB = {
134
+ 1: "@min-[0rem]:before:hidden @min-[0rem]:after:hidden",
135
+ 2: "@min-[22rem]:before:hidden @min-[22rem]:after:hidden",
136
+ 3: "@min-[33rem]:before:hidden @min-[33rem]:after:hidden",
137
+ 4: "@min-[44rem]:before:hidden @min-[44rem]:after:hidden",
138
+ 5: "@min-[55rem]:before:hidden @min-[55rem]:after:hidden",
139
+ 6: "@min-[66rem]:before:hidden @min-[66rem]:after:hidden",
140
+ 7: "@min-[77rem]:before:hidden @min-[77rem]:after:hidden",
141
+ 8: "@min-[88rem]:before:hidden @min-[88rem]:after:hidden",
142
+ 9: "",
143
+ };
144
+
145
+ // The elbow to the rail while a tier is stacked (the kids of a stacked tier
146
+ // hang off a line down their left). The last kid's line ends at its elbow.
147
+ const RAIL_CELL =
148
+ "relative before:absolute before:-left-3 before:top-6 before:w-3 before:border-t before:border-input after:absolute after:-left-3 after:bottom-0 after:border-l after:border-input";
149
+ // A kid's line starts 0.75 rem above it, at the bottom of the card (or the
150
+ // kid) above; the last kid's line stops at its elbow.
151
+ const RAIL_TOP = "after:-top-3";
152
+ const RAIL_END = "after:bottom-auto after:h-9";
153
+ const railOf = (i, count) => cx(RAIL_CELL, RAIL_TOP, i === count - 1 && RAIL_END);
154
+
155
+ const FILL = {
156
+ ink: "bg-foreground",
157
+ quiet: "bg-muted-foreground",
158
+ info: "bg-info",
159
+ success: "bg-success",
160
+ warning: "bg-warning",
161
+ danger: "bg-destructive",
162
+ };
163
+
164
+ const GROUP_HEAD = "text-2xs font-medium uppercase tracking-wider text-muted-foreground";
165
+ const CARD_BOX = "w-full min-w-0 max-w-[26rem]";
166
+
167
+ // ---- one context for the tiers
168
+
169
+ const Ctx = createContext(null);
170
+ const useTiers = () => useContext(Ctx);
171
+
172
+ const sameId = (a, b) => a != null && b != null && String(a) === String(b);
173
+
174
+ // ---- the card
175
+
176
+ /**
177
+ * One card. `state` is what the map knows about it:
178
+ * { id, item, open, selected, count, tier, ghost, serves, pressable,
179
+ * holderProps, primaryProps, toggleProps, select, toggle }
180
+ * A `renderCard` of your own spreads `holderProps` on its root and
181
+ * `primaryProps` (and `toggleProps`) on the buttons that take the focus.
182
+ */
183
+ function TierCard({ node, serves }) {
184
+ const t = useTiers();
185
+ const { item } = node;
186
+ const open = t.openIds.has(node.id);
187
+ const kids = node.kids.length;
188
+ const selected = sameId(t.selected, node.id);
189
+ const ghost = node.ghost;
190
+ const hasOpen = node.group === "tree" && kids > 0;
191
+ const pressable = Boolean(t.onSelect) || Boolean(item.href) || hasOpen;
192
+ const roving = t.tabId === node.id ? 0 : -1;
193
+ const kidsId = `${t.uid}-kids-${node.id}`;
194
+
195
+ const toggle = () => t.toggle(node.id);
196
+ const select = () => {
197
+ if (t.onSelect) t.onSelect(item);
198
+ else if (hasOpen) toggle();
199
+ };
200
+ const state = {
201
+ id: node.id,
202
+ item,
203
+ open,
204
+ selected,
205
+ count: kids,
206
+ tier: node.tier,
207
+ ghost,
208
+ serves,
209
+ pressable,
210
+ select,
211
+ toggle: hasOpen ? toggle : undefined,
212
+ holderProps: { "data-tier-id": node.id },
213
+ primaryProps: {
214
+ "data-tier-card": node.id,
215
+ tabIndex: roving,
216
+ onClick: select,
217
+ onFocus: () => t.setTab(node.id),
218
+ "aria-current": selected ? "true" : undefined,
219
+ "aria-expanded": hasOpen && !t.onSelect ? open : undefined,
220
+ "aria-controls": hasOpen && !t.onSelect && open ? kidsId : undefined,
221
+ },
222
+ toggleProps: hasOpen
223
+ ? { "data-tier-toggle": node.id, tabIndex: roving, onClick: toggle, onFocus: () => t.setTab(node.id), "aria-expanded": open, "aria-controls": open ? kidsId : undefined }
224
+ : null,
225
+ };
226
+
227
+ const custom = t.renderCard ? t.renderCard(item, state) : null;
228
+ if (custom != null && custom !== false) return custom;
229
+
230
+ const bar = barOf(item);
231
+ const tone = toneOf(item.tone, bar?.share);
232
+ const lead = item.mark != null || item.kicker != null || item.by != null;
233
+ const body = (
234
+ <>
235
+ {lead ? (
236
+ <span className="flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground">
237
+ {item.mark != null ? <span className="inline-flex shrink-0 items-center">{item.mark}</span> : null}
238
+ {item.kicker != null ? <span className="min-w-0 truncate">{item.kicker}</span> : null}
239
+ {item.by != null ? <span className="ml-auto inline-flex shrink-0 items-center">{item.by}</span> : null}
240
+ </span>
241
+ ) : null}
242
+ <span className="block font-semibold leading-snug [overflow-wrap:anywhere]">{item.title}</span>
243
+ {bar ? (
244
+ <span className="flex items-center gap-2 text-xs">
245
+ <span aria-hidden="true" className="relative h-1.5 min-w-0 flex-1 overflow-hidden rounded-full bg-muted">
246
+ <span className={cx("absolute inset-y-0 left-0 w-(--fill) rounded-full", FILL[tone])} style={{ "--fill": `${bar.pct}%` }} />
247
+ </span>
248
+ <span data-nums className="shrink-0 font-semibold">
249
+ {bar.pct}%
250
+ </span>
251
+ </span>
252
+ ) : null}
253
+ {serves ? <span className="block text-xs text-muted-foreground [overflow-wrap:anywhere]">{serves}</span> : null}
254
+ {item.foot != null ? <span className="block text-xs text-muted-foreground [overflow-wrap:anywhere]">{item.foot}</span> : null}
255
+ </>
256
+ );
257
+ const look = cx(
258
+ "grid w-full min-w-0 gap-1.5 p-3 text-left text-sm outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
259
+ pressable ? "hover:bg-accent" : "cursor-default",
260
+ );
261
+ const primary = item.href ? (
262
+ <a href={item.href} {...state.primaryProps} className={look}>
263
+ {body}
264
+ </a>
265
+ ) : (
266
+ <button type="button" {...state.primaryProps} aria-disabled={pressable ? undefined : "true"} className={look}>
267
+ {body}
268
+ </button>
269
+ );
270
+ const ring = selected ? "ring-2 ring-ring" : open ? "ring-1 ring-primary" : "";
271
+
272
+ return (
273
+ <div {...state.holderProps} className={CARD_BOX}>
274
+ <Card as="div" padding="none" className={cx(ring, ghost && "border-dashed")}>
275
+ {primary}
276
+ {state.toggleProps ? (
277
+ <button
278
+ type="button"
279
+ {...state.toggleProps}
280
+ className="flex w-full min-w-0 items-center gap-1.5 border-t border-border px-3 py-1.5 text-left text-xs text-muted-foreground outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
281
+ >
282
+ <Icon name="chevron-right" size={14} className={cx("shrink-0 transition-transform motion-reduce:transition-none", open && "rotate-90")} />
283
+ <span className="min-w-0">
284
+ {countText(kids, t.childrenLabel)}
285
+ {open ? ` · ${t.openWord}` : ""}
286
+ </span>
287
+ </button>
288
+ ) : null}
289
+ </Card>
290
+ </div>
291
+ );
292
+ }
293
+
294
+ export { TierCard };
295
+
296
+ // ---- the tiers
297
+
298
+ function Tier({ ids, depth, above, hangs }) {
299
+ const t = useTiers();
300
+ const count = ids.length;
301
+ const n = fitKey(Math.max(count, above));
302
+ const openId = t.path[depth] ?? null;
303
+ return (
304
+ <div className={cx("grid grid-cols-1 gap-y-3", GRID[n])} style={{ "--cols": `repeat(${count}, minmax(0, 1fr))` }}>
305
+ {ids.map((id, i) => {
306
+ const node = t.model.nodes.get(id);
307
+ return (
308
+ <div
309
+ key={id}
310
+ className={cx("min-w-0", hangs ? cx(railOf(i, count), STUB[n]) : "relative", CELL[n])}
311
+ style={{ "--c": i + 1 }}
312
+ >
313
+ <div className={cx("grid min-w-0 justify-items-start", SLOT[n])}>
314
+ <TierCard node={node} />
315
+ </div>
316
+ {id === openId ? <Kids node={node} depth={depth} fit={n} index={i} count={count} /> : null}
317
+ </div>
318
+ );
319
+ })}
320
+ </div>
321
+ );
322
+ }
323
+
324
+ // What hangs under an open card: the strip of lines (from the width its tier
325
+ // sits in a row) and the next tier.
326
+ function Kids({ node, depth, fit, index, count }) {
327
+ const t = useTiers();
328
+ const kidFit = fitKey(Math.max(node.kids.length, fit));
329
+ const e = elbowOf(index, count, node.kids.length);
330
+ return (
331
+ <div id={`${t.uid}-kids-${node.id}`} className={cx("col-span-full mt-3 min-w-0", KIDS[fit])}>
332
+ <div aria-hidden="true" className={cx("relative h-8", HEAD[fit])} style={{ "--p": `${e.parent}%` }}>
333
+ <span className="absolute left-(--p) top-0 h-1/2 border-l border-input" />
334
+ <div className={cx("absolute inset-0", LOW[kidFit])}>
335
+ <span className="absolute left-3 top-1/2 w-(--back) border-t border-input" style={{ "--back": `calc(${e.parent}% - 0.75rem)` }} />
336
+ <span className="absolute left-3 top-1/2 bottom-0 border-l border-input" />
337
+ </div>
338
+ <div className={cx("absolute inset-0", BAR[kidFit])}>
339
+ <span className="absolute left-(--from) top-1/2 w-(--across) border-t border-input" style={{ "--from": `${e.from}%`, "--across": `${e.to - e.from}%` }} />
340
+ {e.kids.map((at, i) => (
341
+ <span key={i} className="absolute left-(--at) top-1/2 bottom-0 border-l border-input" style={{ "--at": `${at}%` }} />
342
+ ))}
343
+ </div>
344
+ </div>
345
+ <div className={cx("ml-6 min-w-0", INDENT[kidFit])}>
346
+ <Tier ids={node.kids} depth={depth + 1} above={fit} hangs />
347
+ </div>
348
+ </div>
349
+ );
350
+ }
351
+
352
+ // ---- the drafts: a forest that is always open, a rail down each tree
353
+
354
+ function GhostBranch({ id }) {
355
+ const t = useTiers();
356
+ const node = t.model.nodes.get(id);
357
+ const parent = node.parent != null ? t.model.nodes.get(node.parent) : null;
358
+ const serves = node.up == null && parent && t.servesLabel ? `${t.servesLabel} ${parent.item.title}` : null;
359
+ return (
360
+ <div className="grid min-w-0 content-start gap-3">
361
+ <TierCard node={node} serves={serves} />
362
+ {node.kids.length ? (
363
+ <div className="ml-6 grid min-w-0 gap-3">
364
+ {node.kids.map((kid, i) => (
365
+ <div key={kid} className={cx("min-w-0", railOf(i, node.kids.length))}>
366
+ <GhostBranch id={kid} />
367
+ </div>
368
+ ))}
369
+ </div>
370
+ ) : null}
371
+ </div>
372
+ );
373
+ }
374
+
375
+ // ---- the whole map
376
+
377
+ /**
378
+ * The map. Props: `items`, `tops`, `topsLabel`, `label`, `childrenLabel`,
379
+ * `openWord`, `unparentedLabel`, `unparentedNote`, `ghostLabel`, `ghostNote`,
380
+ * `servesLabel`, `open`, `defaultOpen`, `onOpenChange`, `onSelect`,
381
+ * `selected`, `renderCard`, `loading`, `error`, `onRetry`, `empty`,
382
+ * `className`.
383
+ */
384
+ export function TierMap({
385
+ items,
386
+ tops,
387
+ topsLabel,
388
+ label = "Tiers",
389
+ childrenLabel = "below",
390
+ openWord = "open",
391
+ unparentedLabel = "Not under anything",
392
+ unparentedNote,
393
+ ghostLabel = "Drafts",
394
+ ghostNote,
395
+ servesLabel = "Serves",
396
+ open,
397
+ defaultOpen,
398
+ onOpenChange,
399
+ onSelect,
400
+ selected,
401
+ renderCard,
402
+ loading = false,
403
+ error,
404
+ onRetry,
405
+ empty,
406
+ className,
407
+ }) {
408
+ const uid = useId().replace(/:/g, "");
409
+ const root = useRef(null);
410
+ const model = useMemo(() => buildTierModel(items, { tops }), [items, tops]);
411
+ const [inner, setInner] = useState(() => (Array.isArray(defaultOpen) ? defaultOpen : []));
412
+ const [tab, setTab] = useState(null);
413
+ const [focusReq, setFocusReq] = useState(null);
414
+
415
+ const path = useMemo(() => openPath(model, open !== undefined ? open : inner), [model, open, inner]);
416
+ const openIds = useMemo(() => new Set(path), [path]);
417
+
418
+ // The cards on screen, in the order the keys walk them.
419
+ const shown = useMemo(() => {
420
+ const ids = [];
421
+ for (const tier of tiersOf(model, path)) ids.push(...tier.ids);
422
+ ids.push(...model.unparented, ...model.ghostOrder.map((g) => g.id));
423
+ return ids;
424
+ }, [model, path]);
425
+ const tabId = tab != null && shown.includes(tab) ? tab : shown[0] ?? null;
426
+
427
+ function commit(next) {
428
+ if (open === undefined) setInner(next);
429
+ if (onOpenChange) onOpenChange(next);
430
+ }
431
+ function toggle(id) {
432
+ const next = togglePath(model, path, id);
433
+ if (next !== path) commit(next);
434
+ }
435
+
436
+ // A key moves the focus to a card that may not be drawn yet (↓ on a closed
437
+ // card opens it first), so the move waits for the render that draws it.
438
+ const pathKey = path.join("\u0000");
439
+ useEffect(() => {
440
+ if (focusReq == null || !root.current) return;
441
+ const cards = root.current.querySelectorAll("[data-tier-card]");
442
+ for (const el of cards) {
443
+ if (el.getAttribute("data-tier-card") === focusReq) {
444
+ el.focus();
445
+ break;
446
+ }
447
+ }
448
+ setFocusReq(null);
449
+ }, [focusReq, pathKey]);
450
+
451
+ function onKeyDown(e) {
452
+ if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey) return;
453
+ const holder = e.target instanceof Element ? e.target.closest("[data-tier-id]") : null;
454
+ if (!holder) return;
455
+ const id = holder.getAttribute("data-tier-id");
456
+ const node = model.nodes.get(id);
457
+ if (!node) return;
458
+ const go = (to) => {
459
+ if (to == null) return;
460
+ e.preventDefault();
461
+ setTab(to);
462
+ setFocusReq(to);
463
+ };
464
+ if (e.key === "ArrowDown") {
465
+ if (!node.kids.length) return;
466
+ if (node.group === "tree" && !openIds.has(id)) toggle(id);
467
+ go(node.kids[0]);
468
+ } else if (e.key === "Escape") {
469
+ if (node.group !== "tree") return;
470
+ if (openIds.has(id)) {
471
+ e.preventDefault();
472
+ toggle(id);
473
+ } else if (node.up != null) {
474
+ e.preventDefault();
475
+ toggle(node.up);
476
+ go(node.up);
477
+ }
478
+ } else if (["ArrowLeft", "ArrowRight", "ArrowUp", "Home", "End"].includes(e.key)) {
479
+ go(neighbour(model, id, e.key));
480
+ }
481
+ }
482
+
483
+ const ctx = {
484
+ model,
485
+ path,
486
+ openIds,
487
+ uid,
488
+ tabId,
489
+ setTab,
490
+ toggle,
491
+ onSelect,
492
+ selected,
493
+ renderCard,
494
+ childrenLabel,
495
+ openWord,
496
+ servesLabel,
497
+ };
498
+
499
+ if (loading) {
500
+ return (
501
+ <div aria-busy="true" aria-label={`${label}, loading`} className={cx("@container min-w-0", className)}>
502
+ <div className="grid grid-cols-[repeat(auto-fill,minmax(min(100%,12rem),1fr))] gap-3">
503
+ {[0, 1, 2].map((i) => (
504
+ <Skeleton key={i} shape="rect" className="h-24 w-full" />
505
+ ))}
506
+ </div>
507
+ </div>
508
+ );
509
+ }
510
+ if (error) {
511
+ return (
512
+ <div className={cx("@container min-w-0", className)}>
513
+ <Notice
514
+ tone="danger"
515
+ action={
516
+ onRetry ? (
517
+ <Button size="sm" onClick={onRetry}>
518
+ Try again
519
+ </Button>
520
+ ) : undefined
521
+ }
522
+ >
523
+ {typeof error === "string" || typeof error === "object" ? error : "The map could not be loaded."}
524
+ </Notice>
525
+ </div>
526
+ );
527
+ }
528
+ if (!model.order.length) {
529
+ return <div className={cx("@container min-w-0", className)}>{empty ?? <Empty icon="network" title="Nothing to map yet" body="Cards appear here once there is something to put on the map." />}</div>;
530
+ }
531
+
532
+ const parked = model.unparented;
533
+ const drafts = model.ghostOrder.length;
534
+ return (
535
+ <Ctx.Provider value={ctx}>
536
+ <div ref={root} role="group" aria-label={label} onKeyDown={onKeyDown} className={cx("@container grid min-w-0 gap-8", className)}>
537
+ {model.tops.length ? (
538
+ <section aria-label={typeof topsLabel === "string" ? topsLabel : label} className="grid min-w-0 gap-3">
539
+ {topsLabel ? <h3 className={GROUP_HEAD}>{topsLabel}</h3> : null}
540
+ <Tier ids={model.tops} depth={0} above={1} hangs={false} />
541
+ </section>
542
+ ) : null}
543
+ {parked.length ? (
544
+ <section aria-label={typeof unparentedLabel === "string" ? unparentedLabel : "Unparented"} className="grid min-w-0 gap-3">
545
+ <h3 className={GROUP_HEAD}>
546
+ {unparentedLabel} {"·"} {parked.length}
547
+ </h3>
548
+ <div className="grid min-w-0 gap-4 @2xl:grid-cols-[minmax(0,1fr)_minmax(0,22rem)] @2xl:items-start">
549
+ <div className="grid grid-cols-[repeat(auto-fill,minmax(min(100%,14rem),1fr))] gap-3">
550
+ {parked.map((id) => (
551
+ <div key={id} className="grid min-w-0 justify-items-start">
552
+ <TierCard node={model.nodes.get(id)} />
553
+ </div>
554
+ ))}
555
+ </div>
556
+ {unparentedNote ? <div className="grid min-w-0 content-start gap-2 text-sm text-muted-foreground">{unparentedNote}</div> : null}
557
+ </div>
558
+ </section>
559
+ ) : null}
560
+ {drafts ? (
561
+ <section aria-label={typeof ghostLabel === "string" ? ghostLabel : "Drafts"} className="grid min-w-0 gap-3">
562
+ <h3 className={GROUP_HEAD}>{ghostLabel}</h3>
563
+ {ghostNote ? <div className="text-sm text-muted-foreground">{ghostNote}</div> : null}
564
+ <div className="grid grid-cols-[repeat(auto-fill,minmax(min(100%,16rem),1fr))] gap-3">
565
+ {model.ghostRoots.map((id) => (
566
+ <GhostBranch key={id} id={id} />
567
+ ))}
568
+ </div>
569
+ </section>
570
+ ) : null}
571
+ </div>
572
+ </Ctx.Provider>
573
+ );
574
+ }