@jxsuite/studio 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/data/css-meta.json +28 -27
  2. package/dist/chunks/{cf-account-picker-nwnwdm6p.js → cf-account-picker-3f08rry6.js} +21 -18
  3. package/dist/chunks/{cf-settings-adg74qsk.js → cf-settings-m79r7p5y.js} +4 -4
  4. package/dist/chunks/{components-5y78e05d.js → components-xm826zjw.js} +3 -3
  5. package/dist/chunks/{content-source-4rzvmp0m.js → content-source-jt7rbcbc.js} +22 -22
  6. package/dist/chunks/{convert-to-repeater-jxsv62v7.js → convert-to-repeater-vg38bq99.js} +22 -22
  7. package/dist/chunks/{editor-3qhbg51x.js → editor-ddy019sn.js} +2 -2
  8. package/dist/chunks/entry-commands-64nb2a9a.js +42 -0
  9. package/dist/chunks/{extension-sections-2mrptyek.js → extension-sections-r73an5s6.js} +30 -29
  10. package/dist/chunks/{file-ops-knfqshrm.js → file-ops-3xan8mnj.js} +21 -21
  11. package/dist/chunks/{files-y6fr4he9.js → files-egsb0ry8.js} +28 -28
  12. package/dist/chunks/{format-host-1k4qrcqd.js → format-host-mym8qnd0.js} +3 -3
  13. package/dist/chunks/{fs-events-3y6y0nrm.js → fs-events-z2gg8qjt.js} +4 -4
  14. package/dist/chunks/{git-panel-2rkrsjva.js → git-panel-a05atk6q.js} +20 -20
  15. package/dist/chunks/{grid-view-1p6hsyjx.css → grid-view-3g1h2re8.css} +956 -139
  16. package/dist/chunks/{grid-view-a7b87n2c.js → grid-view-qaqer9kr.js} +24 -24
  17. package/dist/chunks/{icons-yy10wk9r.js → icons-drxq9q10.js} +8 -2
  18. package/dist/chunks/{iframe-host-scpw01h8.js → iframe-host-psetcv20.js} +11 -11
  19. package/dist/chunks/{index-n4j7qxyr.js → index-9yjae3hz.js} +4 -4
  20. package/dist/chunks/{javascript-4abzjcy9.css → javascript-bc9z461d.css} +688 -54
  21. package/dist/chunks/{javascript-xvrfrpkb.js → javascript-hr5sg57n.js} +2 -2
  22. package/dist/chunks/{jsonMode-vvmpmk34.css → jsonMode-qqd9nm1t.css} +1120 -303
  23. package/dist/chunks/{jsonMode-tyx2kj6p.js → jsonMode-zs88v0wr.js} +4 -4
  24. package/dist/chunks/layers-panel-83a16ytx.js +41 -0
  25. package/dist/chunks/{layers-jnvdbqva.js → layers-s6mc01ry.js} +3 -3
  26. package/dist/chunks/{media-picker-f66nav16.js → media-picker-nhn6rv4w.js} +11 -11
  27. package/dist/chunks/{menu-1dfhry4s.js → menu-8j4qxjrp.js} +4 -4
  28. package/dist/chunks/{monaco-binding-sw6en4dw.js → monaco-binding-e8d9wzyk.js} +3 -3
  29. package/dist/chunks/{monaco-buffer-pykwbm92.js → monaco-buffer-jaq1t9zj.js} +2 -2
  30. package/dist/chunks/{monaco-setup-8vbyqnhr.css → monaco-setup-ey9cjcm3.css} +954 -137
  31. package/dist/chunks/{monaco-setup-km6abc6q.js → monaco-setup-gsjdysze.js} +6 -6
  32. package/dist/chunks/{platform-ts9cg1a4.js → platform-fnchmhy7.js} +5 -3
  33. package/dist/chunks/publish-panel-ak6hxfma.js +27 -0
  34. package/dist/chunks/quick-search-c63mkt3b.js +47 -0
  35. package/dist/chunks/{references-h69xp9zz.js → references-f7bdv3z5.js} +3 -3
  36. package/dist/chunks/right-panel-t5n8wttg.js +45 -0
  37. package/dist/chunks/{studio-ze46gzjh.js → studio-01269reb.js} +7 -7
  38. package/dist/chunks/{studio-rnyf3f8e.js → studio-0a4gncx0.js} +3 -3
  39. package/dist/chunks/{studio-e1f24eff.js → studio-0d4p4wxj.js} +6778 -2993
  40. package/dist/chunks/{studio-4wbb9ct0.js → studio-1tejxvba.js} +3006 -1855
  41. package/dist/chunks/{studio-d1n2bykn.js → studio-3nprwbd9.js} +117 -25
  42. package/dist/chunks/{studio-4c041r8y.js → studio-40z39dme.js} +3 -3
  43. package/dist/chunks/{studio-151w0xnh.js → studio-482eeazk.js} +20 -20
  44. package/dist/chunks/{studio-cgprcdxn.js → studio-4998spet.js} +10 -9
  45. package/dist/chunks/{studio-nq5yf5mp.js → studio-557bmn0x.js} +2 -2
  46. package/dist/chunks/{studio-rtskkm43.js → studio-5w26wza5.js} +3 -3
  47. package/dist/chunks/{studio-6nzaktvy.js → studio-6pwn9j8c.js} +6 -3
  48. package/dist/chunks/{studio-wnsyffg1.js → studio-6vg0x5fz.js} +3 -2
  49. package/dist/chunks/{studio-vn5hske5.js → studio-7d3c1m59.js} +12 -5
  50. package/dist/chunks/{studio-6gryj0sg.js → studio-9vsvz7w7.js} +6 -6
  51. package/dist/chunks/{studio-50wfwy44.js → studio-9wm0xzpf.js} +19 -19
  52. package/dist/chunks/{studio-0j7r7s9g.js → studio-ag3z6shb.js} +10 -4
  53. package/dist/chunks/studio-aj9drheq.js +177 -0
  54. package/dist/chunks/{studio-xajk70w0.js → studio-apv9x70c.js} +189 -130
  55. package/dist/chunks/{studio-c04nzbby.js → studio-b9q3znz8.js} +2 -2
  56. package/dist/chunks/{studio-nfx354t1.js → studio-bh47w0cy.js} +9 -10
  57. package/dist/chunks/{studio-gk2twyh4.js → studio-dgdm6vvt.js} +264 -52
  58. package/dist/chunks/{studio-gtfq1dkz.js → studio-dwdcr2e8.js} +4 -4
  59. package/dist/chunks/{studio-nqgawfks.js → studio-fbcyz234.js} +146 -139
  60. package/dist/chunks/{studio-27q131j3.js → studio-fqpkpq1t.js} +7 -4
  61. package/dist/chunks/{studio-c0qgc3tn.js → studio-fy320dfc.js} +62 -68
  62. package/dist/chunks/{studio-zjjde71a.js → studio-gjj4bbfx.js} +2 -2
  63. package/dist/chunks/{studio-g33v4fe9.js → studio-jfhxy8h3.js} +7 -7
  64. package/dist/chunks/{studio-ab87phj1.js → studio-kwewmhhq.js} +4 -4
  65. package/dist/chunks/{studio-7rrb1esn.js → studio-m58xn8at.js} +25 -24
  66. package/dist/chunks/{studio-fzjx96t2.js → studio-mfkh1q8d.js} +17 -17
  67. package/dist/chunks/{studio-drg8qj9k.js → studio-mrh0a92f.js} +17 -17
  68. package/dist/chunks/{studio-jt27ta6x.js → studio-mt79tn56.js} +3 -3
  69. package/dist/chunks/{studio-b66rsh78.js → studio-ne593z1j.js} +38 -31
  70. package/dist/chunks/{studio-h4nvnjvz.js → studio-ptfcxkz5.js} +418 -232
  71. package/dist/chunks/{studio-dd1qqkry.js → studio-qxye31h7.js} +7 -7
  72. package/dist/chunks/{studio-ye9drbk8.js → studio-rav5bpmp.js} +73 -52
  73. package/dist/chunks/{studio-6kvgrkrp.js → studio-rwmmbrth.js} +6 -6
  74. package/dist/chunks/{studio-b7xacrwe.js → studio-sceg8ws0.js} +8 -8
  75. package/dist/chunks/{studio-msc1ee1m.js → studio-sjas5b3a.js} +19 -13
  76. package/dist/chunks/{studio-a65w20ex.js → studio-vd67b66d.js} +3 -3
  77. package/dist/chunks/{studio-7144epdr.js → studio-w475cbf9.js} +10 -10
  78. package/dist/chunks/{studio-4f3psrk1.js → studio-w7gpcvfj.js} +9 -9
  79. package/dist/chunks/{studio-nsgw7dbk.js → studio-xrbfdxgk.js} +7 -7
  80. package/dist/chunks/{studio-ke09tn9k.js → studio-y49b6mjv.js} +35 -35
  81. package/dist/chunks/{studio-j0w60gft.js → studio-ygvr9e4q.js} +10 -10
  82. package/dist/chunks/{studio-z2smx5ce.js → studio-yxmmjy2a.js} +9 -6
  83. package/dist/chunks/{tsMode-jy4m86rv.js → tsMode-ay4c78ne.js} +4 -4
  84. package/dist/chunks/{tsMode-hnxxb73h.css → tsMode-c72wyz27.css} +954 -137
  85. package/dist/chunks/{workspace-np10mayv.js → workspace-b9k2frks.js} +5 -5
  86. package/dist/chunks/{ws-client-ny4zc51r.js → ws-client-erze4czt.js} +356 -20
  87. package/dist/codicon.ttf +0 -0
  88. package/dist/iframe-entry.js +18 -16
  89. package/dist/studio.css +956 -139
  90. package/dist/studio.js +1453 -830
  91. package/dist/workers/editor.worker.js +196 -107
  92. package/dist/workers/json.worker.js +196 -107
  93. package/dist/workers/ts.worker.js +196 -107
  94. package/package.json +15 -14
  95. package/src/about/about-modal.ts +4 -3
  96. package/src/browse/library-commands.ts +15 -13
  97. package/src/browse/library-pane.ts +2 -2
  98. package/src/canvas/canvas-render.ts +97 -83
  99. package/src/canvas/canvas-surface.ts +2 -2
  100. package/src/canvas/canvas-utils.ts +42 -32
  101. package/src/canvas/diff-toolbar.ts +21 -2
  102. package/src/canvas/diff-view.ts +30 -6
  103. package/src/canvas/iframe-entry.ts +2 -2
  104. package/src/canvas/iframe-host.ts +5 -5
  105. package/src/canvas/iframe-interaction.ts +7 -6
  106. package/src/canvas/iframe-overlay.ts +1 -1
  107. package/src/canvas/iframe-protocol.ts +6 -5
  108. package/src/canvas/iframe-render.ts +3 -3
  109. package/src/canvas/popover-state.ts +1 -1
  110. package/src/canvas/stage-scrollbar.ts +112 -0
  111. package/src/canvas/surface-registry.ts +9 -2
  112. package/src/collab/collab-commands.ts +8 -6
  113. package/src/collab/collab-session.ts +4 -4
  114. package/src/collab/collab-state.ts +4 -4
  115. package/src/collab/presence-chips.ts +3 -3
  116. package/src/commands/app-commands.ts +7 -7
  117. package/src/commands/budget.ts +17 -16
  118. package/src/commands/command-args.ts +10 -9
  119. package/src/commands/context.ts +20 -10
  120. package/src/commands/defaults.ts +30 -29
  121. package/src/commands/levels.ts +8 -6
  122. package/src/commands/live-context.ts +12 -10
  123. package/src/commands/reference.ts +5 -5
  124. package/src/commands/registry.ts +2 -2
  125. package/src/content/draft-state.ts +9 -8
  126. package/src/content/entry-commands.ts +16 -14
  127. package/src/content/entry-editor.ts +2 -2
  128. package/src/content/entry-fields.ts +1 -1
  129. package/src/editor/context-menu.ts +4 -4
  130. package/src/editor/convert-to-component.ts +6 -5
  131. package/src/editor/inline-edit.ts +3 -3
  132. package/src/editor/shortcuts.ts +88 -20
  133. package/src/editor/slash-menu.ts +11 -10
  134. package/src/files/elements.ts +4 -5
  135. package/src/files/file-ops.ts +1 -1
  136. package/src/files/files.ts +21 -17
  137. package/src/files/serialize-document.ts +1 -1
  138. package/src/format/convert-file.ts +5 -5
  139. package/src/github/github-auth-status.ts +107 -0
  140. package/src/github/github-auth.ts +18 -82
  141. package/src/github/github-publish.ts +7 -6
  142. package/src/grid/cell-editors.ts +8 -7
  143. package/src/grid/grid-layout.ts +1 -1
  144. package/src/grid/grid-open.ts +6 -5
  145. package/src/grid/grid-panel.ts +13 -12
  146. package/src/grid/redirects-grid.ts +14 -11
  147. package/src/grid/redirects.ts +10 -5
  148. package/src/grid/sources/content-source.ts +10 -9
  149. package/src/hosting/document.ts +28 -1
  150. package/src/hosting/stage.ts +15 -4
  151. package/src/i18n/i18n-commands.ts +9 -7
  152. package/src/new-project/location-fields.ts +16 -3
  153. package/src/new-project/new-project-modal.ts +23 -7
  154. package/src/page-params.ts +6 -6
  155. package/src/panels/activity-panel.ts +11 -10
  156. package/src/panels/ai-chat/chat-view.ts +27 -14
  157. package/src/panels/ai-chat/composer.ts +10 -3
  158. package/src/panels/ai-panel.ts +87 -29
  159. package/src/panels/block-action-bar.ts +59 -33
  160. package/src/panels/bottom-dock.ts +22 -22
  161. package/src/panels/data-explorer.ts +9 -9
  162. package/src/panels/data-grid.ts +1 -1
  163. package/src/panels/editors.ts +8 -8
  164. package/src/panels/elements-panel.ts +7 -8
  165. package/src/panels/empty-state.ts +1 -1
  166. package/src/panels/events-panel.ts +13 -12
  167. package/src/panels/formula-workspace.ts +8 -5
  168. package/src/panels/frontmatter-fields.ts +4 -1
  169. package/src/panels/frontmatter-panel.ts +18 -18
  170. package/src/panels/git-panel.ts +19 -13
  171. package/src/panels/head-panel.ts +9 -10
  172. package/src/panels/i18n-panel.ts +6 -4
  173. package/src/panels/imports-panel.ts +1 -1
  174. package/src/panels/jump-bar.ts +20 -18
  175. package/src/panels/layers-panel.ts +19 -17
  176. package/src/panels/left-panel.ts +3 -3
  177. package/src/panels/navigator-panels.ts +8 -8
  178. package/src/panels/overlays.ts +1 -1
  179. package/src/panels/pane-context.ts +56 -28
  180. package/src/panels/pane-grid.ts +9 -8
  181. package/src/panels/panel-registry.ts +47 -19
  182. package/src/panels/problems-panel.ts +11 -12
  183. package/src/panels/properties-panel.ts +21 -20
  184. package/src/panels/provenance.ts +3 -3
  185. package/src/panels/quick-search.ts +15 -11
  186. package/src/panels/right-panel.ts +4 -3
  187. package/src/panels/seo-modal.ts +5 -4
  188. package/src/panels/settings-menu.ts +9 -9
  189. package/src/panels/settings-pane.ts +3 -3
  190. package/src/panels/signals-panel.ts +16 -9
  191. package/src/panels/statement-editor.ts +12 -9
  192. package/src/panels/style-panel.ts +45 -41
  193. package/src/panels/stylebook-panel.ts +0 -1
  194. package/src/panels/tab-strip.ts +26 -23
  195. package/src/platform-errors.ts +2 -2
  196. package/src/platform.ts +44 -4
  197. package/src/platforms/cloud.ts +11 -1
  198. package/src/platforms/default-platform.ts +141 -4
  199. package/src/platforms/devserver.ts +23 -3
  200. package/src/publish/deploy-checklist.ts +11 -10
  201. package/src/publish/publish-commands.ts +9 -8
  202. package/src/services/a11y-report.ts +1 -1
  203. package/src/services/ai-ask.ts +39 -16
  204. package/src/services/ai-command-tools.ts +28 -14
  205. package/src/services/ai-import-tools.ts +43 -29
  206. package/src/services/ai-project-tools.ts +20 -38
  207. package/src/services/ai-settings.ts +55 -2
  208. package/src/services/ai-tools.ts +69 -58
  209. package/src/services/ai-write-report.ts +4 -4
  210. package/src/services/ai-writes.ts +74 -55
  211. package/src/services/automation.ts +12 -12
  212. package/src/services/clock.ts +2 -1
  213. package/src/services/connection.ts +2 -2
  214. package/src/services/context-manager.ts +69 -6
  215. package/src/services/directory-picker.ts +93 -27
  216. package/src/services/document-assistant.ts +86 -17
  217. package/src/services/gated-registry.ts +4 -3
  218. package/src/services/idle.ts +5 -4
  219. package/src/services/live-surfaces.ts +2 -1
  220. package/src/services/notify.ts +9 -7
  221. package/src/services/popover-report.ts +3 -3
  222. package/src/services/preview-eval.ts +1 -1
  223. package/src/services/project-adoption.ts +34 -1
  224. package/src/services/project-path.ts +53 -0
  225. package/src/services/settings/kernel.ts +13 -2
  226. package/src/services/tool-executor.ts +135 -30
  227. package/src/services/tool-outcomes.ts +143 -0
  228. package/src/settings/contexts-section.ts +8 -8
  229. package/src/settings/contributed-section.ts +6 -6
  230. package/src/settings/css-vars-editor.ts +6 -5
  231. package/src/settings/extension-commands.ts +19 -18
  232. package/src/settings/extension-sections.ts +7 -7
  233. package/src/settings/extensions-section.ts +3 -3
  234. package/src/settings/general-settings.ts +21 -18
  235. package/src/settings/preferences-accounts.ts +3 -3
  236. package/src/settings/preferences-dialog.ts +9 -8
  237. package/src/settings/preferences-sections.ts +1 -1
  238. package/src/settings/project-sections.ts +2 -2
  239. package/src/settings/section-registry.ts +7 -6
  240. package/src/settings/settings-document.ts +41 -43
  241. package/src/shell/tree.ts +29 -0
  242. package/src/shell.ts +63 -55
  243. package/src/site-context.ts +1 -1
  244. package/src/store.ts +2 -2
  245. package/src/studio.ts +46 -28
  246. package/src/style/live-preview.ts +8 -8
  247. package/src/style/project-styles.ts +8 -9
  248. package/src/style/token-ref.ts +2 -2
  249. package/src/surfaces/about.json +6 -2
  250. package/src/surfaces/add-repo.json +2 -2
  251. package/src/surfaces/add-repo.ts +2 -2
  252. package/src/surfaces/ai-chat.json +14 -6
  253. package/src/surfaces/ai-chat.ts +4 -2
  254. package/src/surfaces/ai-credentials-form.json +53 -49
  255. package/src/surfaces/ai-credentials-form.ts +18 -4
  256. package/src/surfaces/ai-managed-connect.json +4 -4
  257. package/src/surfaces/block-action-bar.json +4 -4
  258. package/src/surfaces/block-action-bar.ts +3 -3
  259. package/src/surfaces/boot-failure.json +228 -0
  260. package/src/surfaces/boot-failure.ts +156 -0
  261. package/src/surfaces/bottom-dock.json +1 -1
  262. package/src/surfaces/canvas-stage.json +9 -40
  263. package/src/surfaces/canvas-stage.ts +9 -9
  264. package/src/surfaces/cf-account-picker.json +11 -8
  265. package/src/surfaces/commandbar.ts +11 -10
  266. package/src/surfaces/convert-repeater.ts +3 -2
  267. package/src/surfaces/dialog.json +7 -1
  268. package/src/surfaces/dialog.ts +2 -2
  269. package/src/surfaces/doc-header.json +6 -13
  270. package/src/surfaces/doc-header.ts +4 -5
  271. package/src/surfaces/entry-editor.json +1 -1
  272. package/src/surfaces/entry-editor.ts +2 -1
  273. package/src/surfaces/expression-editor.json +5 -5
  274. package/src/surfaces/files-panel.json +4 -3
  275. package/src/surfaces/files-panel.ts +1 -1
  276. package/src/surfaces/formula-palette.json +2 -2
  277. package/src/surfaces/formula-palette.ts +1 -1
  278. package/src/surfaces/git-panel.json +167 -109
  279. package/src/surfaces/git-panel.ts +2 -2
  280. package/src/surfaces/github-auth.json +2 -1
  281. package/src/surfaces/github-publish.ts +3 -3
  282. package/src/surfaces/grid-open.json +1 -1
  283. package/src/surfaces/grid-panel.json +2 -2
  284. package/src/surfaces/grid-views.json +1 -1
  285. package/src/surfaces/inspector-dock.json +2 -2
  286. package/src/surfaces/jump-bar.json +1 -1
  287. package/src/surfaces/jump-bar.ts +1 -1
  288. package/src/surfaces/library-pane.ts +2 -1
  289. package/src/surfaces/logic-panel.json +7 -7
  290. package/src/surfaces/logic-panel.ts +6 -4
  291. package/src/surfaces/logic-workspace.json +2 -2
  292. package/src/surfaces/logic-workspace.ts +2 -2
  293. package/src/surfaces/media-browser.ts +3 -3
  294. package/src/surfaces/media-pane.ts +2 -1
  295. package/src/surfaces/menu.ts +5 -5
  296. package/src/surfaces/new-project.json +1 -1
  297. package/src/surfaces/pane-context.json +86 -57
  298. package/src/surfaces/pane-context.ts +2 -1
  299. package/src/surfaces/pane-grid.json +3 -3
  300. package/src/surfaces/panel-activity.json +2 -1
  301. package/src/surfaces/panel-deploy-checklist.json +1 -1
  302. package/src/surfaces/panel-elements.ts +2 -1
  303. package/src/surfaces/panel-i18n.ts +2 -1
  304. package/src/surfaces/panel-outline.json +1 -1
  305. package/src/surfaces/panel-outline.ts +4 -3
  306. package/src/surfaces/panel-page.json +2 -2
  307. package/src/surfaces/panel-page.ts +4 -1
  308. package/src/surfaces/panel-problems.json +4 -3
  309. package/src/surfaces/panel-problems.ts +2 -2
  310. package/src/surfaces/panel-signals.json +23 -8
  311. package/src/surfaces/panel-signals.ts +5 -1
  312. package/src/surfaces/panel-stylebook-layers.json +1 -1
  313. package/src/surfaces/panel-stylebook-layers.ts +2 -2
  314. package/src/surfaces/preferences.json +21 -8
  315. package/src/surfaces/preferences.ts +9 -1
  316. package/src/surfaces/properties-panel.json +4 -4
  317. package/src/surfaces/properties-panel.ts +2 -2
  318. package/src/surfaces/publish.json +1 -1
  319. package/src/surfaces/publish.ts +2 -1
  320. package/src/surfaces/push-plan.json +4 -3
  321. package/src/surfaces/rail.json +2 -2
  322. package/src/surfaces/rail.ts +10 -4
  323. package/src/surfaces/reference-field.json +1 -1
  324. package/src/surfaces/schema-form.json +2 -2
  325. package/src/surfaces/schema-form.ts +1 -1
  326. package/src/surfaces/seo.json +1 -1
  327. package/src/surfaces/seo.ts +2 -2
  328. package/src/surfaces/settings-contributed.ts +2 -1
  329. package/src/surfaces/settings-css-vars.json +4 -4
  330. package/src/surfaces/settings-deploy.json +4 -4
  331. package/src/surfaces/settings-deploy.ts +2 -1
  332. package/src/surfaces/settings-extensions.json +6 -6
  333. package/src/surfaces/settings-extensions.ts +6 -2
  334. package/src/surfaces/settings-locales.json +4 -4
  335. package/src/surfaces/settings-overview.ts +2 -1
  336. package/src/surfaces/settings-pane.ts +3 -2
  337. package/src/surfaces/settings-rawjson.ts +1 -1
  338. package/src/surfaces/slash-menu.ts +4 -4
  339. package/src/surfaces/statements.json +3 -3
  340. package/src/surfaces/statusbar.ts +23 -23
  341. package/src/surfaces/style-panel.json +9 -5
  342. package/src/surfaces/style-panel.ts +3 -3
  343. package/src/surfaces/tab-strip.json +2 -2
  344. package/src/surfaces/target-line.json +1 -1
  345. package/src/surfaces/target-line.ts +12 -10
  346. package/src/surfaces/welcome.json +7 -2
  347. package/src/tabs/doc-op-apply.ts +5 -5
  348. package/src/tabs/patch-ops.ts +3 -3
  349. package/src/tabs/project-config.ts +10 -10
  350. package/src/tabs/selection.ts +1 -1
  351. package/src/tabs/tab.ts +13 -14
  352. package/src/tabs/transact.ts +18 -24
  353. package/src/types.ts +27 -3
  354. package/src/ui/ai-credentials-form.ts +74 -16
  355. package/src/ui/ai-managed-connect.ts +68 -19
  356. package/src/ui/color-selector.ts +1 -1
  357. package/src/ui/expression-editor.ts +3 -3
  358. package/src/ui/form-controls.ts +6 -5
  359. package/src/ui/formula-catalog.ts +4 -4
  360. package/src/ui/formula-chips.ts +2 -2
  361. package/src/ui/layers.ts +20 -18
  362. package/src/ui/panel-resize.ts +5 -5
  363. package/src/ui/popover-surface.ts +2 -2
  364. package/src/ui/progress-modal.ts +3 -3
  365. package/src/ui/regions.ts +14 -9
  366. package/src/ui/schema-form.ts +10 -9
  367. package/src/ui/timing.ts +9 -7
  368. package/src/ui/value-source.ts +4 -4
  369. package/src/ui/virtual-window.ts +1 -1
  370. package/src/utils/base64.ts +20 -1
  371. package/src/utils/canvas-media.ts +1 -1
  372. package/src/utils/studio-utils.ts +0 -31
  373. package/src/view.ts +4 -3
  374. package/src/workspace/pane-derive.ts +14 -13
  375. package/src/workspace/session.ts +7 -6
  376. package/src/workspace/workspace.ts +49 -39
  377. package/styles/canvas.css +1 -27
  378. package/styles/inspector.css +4 -3
  379. package/styles/overlays.css +1 -1
  380. package/styles/tokens.css +17 -1
  381. package/styles/tokens.json +6 -1
  382. package/dist/chunks/entry-commands-1wnsqn5d.js +0 -42
  383. package/dist/chunks/layers-panel-73gfkcga.js +0 -41
  384. package/dist/chunks/publish-panel-z1zd2da1.js +0 -27
  385. package/dist/chunks/quick-search-zdv7h8ht.js +0 -47
  386. package/dist/chunks/right-panel-889vbnm5.js +0 -45
  387. package/dist/chunks/studio-727xh0e3.js +0 -76
  388. package/src/files/json-layout.ts +0 -474
  389. package/src/services/ai-turn-signal.ts +0 -70
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://jxsuite.com/schema/v1",
3
3
  "$id": "StudioBlockActionBar",
4
- "$description": "The floating action bar over the canvas selection (plan §3.2 region ⑩, studio-ui-guidelines.md §8.6), as a Jx document over the kit. ONE SHAPE is the whole rule this markup exists to keep: the parent selector, the element badge, the drag handle and every verb are drawn on every selection, and a control that cannot act is DISABLED rather than removed — a toolbar whose buttons move under the cursor is worse than one with a greyed button. Nothing here decides what a verb is called, whether it can act or what its chord reads: `panels/block-action-bar.ts` projects the command registry into `verbs` and `formats`, already resolved to a glyph, a name, a tooltip and a refusal, and this document draws them. The toolbar role, the roving caret and the arrow keys are `jx-action-group`'s, so no keyboard code rides along; Escape is the one key this document claims, because leaving the bar means going back to the canvas and only the host knows where that is. The drag handle is an ISLAND (§9.4): the document draws the node and `surfaces/block-action-bar.ts` attaches the pragmatic-dnd registration to it through `onNodeCreated`. Position is a DECISION measured against the selection rect, so it arrives as two numbers the flow projects — `barX` and `barY` — rather than as a layout this document could compute; the `style` object below binds them, because a style declaration may read state like any other value (spec §9.1).",
4
+ "$description": "The floating action bar over the canvas selection (studio.md §4.4, studio-ui-guidelines.md §8.6), as a Jx document over the kit. ONE SHAPE is the whole rule this markup exists to keep: the parent selector, the element badge, the drag handle and every verb are drawn on every selection, and a control that cannot act is DISABLED rather than removed — a toolbar whose buttons move under the cursor is worse than one with a greyed button. Nothing here decides what a verb is called, whether it can act or what its chord reads: `panels/block-action-bar.ts` projects the command registry into `verbs` and `formats`, already resolved to a glyph, a name, a tooltip and a refusal, and this document draws them. The toolbar role, the roving caret and the arrow keys are `jx-action-group`'s, so no keyboard code rides along; Escape is the one key this document claims, because leaving the bar means going back to the canvas and only the host knows where that is. The drag handle is an ISLAND (studio-ui-guidelines.md §9.4): the document draws the node and `surfaces/block-action-bar.ts` attaches the pragmatic-dnd registration to it through `onNodeCreated`. Position is a DECISION measured against the selection rect, so it arrives as two numbers the flow projects — `barX` and `barY` — rather than as a layout this document could compute; the `style` object below binds them, because a style declaration may read state like any other value (spec.md §9.1).",
5
5
  "tagName": "div",
6
6
  "attributes": {
7
7
  "part": "root",
8
8
  "role": "none"
9
9
  },
10
10
  "style": {
11
- "$description": "The `.block-action-bar` rules that used to live in `styles/canvas.css`, re-valued onto the kit's tokens. The bar is `position: fixed` because its anchor is a rect in viewport space that crossed the iframe bridge; the layer it sits in has no clipping, which is why the host clamps it rather than letting overflow do it.\n\nThe two placement properties are declared HERE, bound to the flow's measured numbers. They used to travel as a `style` ATTRIBUTE the flow assembled into one string, on the belief that a document cannot bind a style declaration to state. It can, and always could: a reactive value on a custom property in a rule targeting the element itself is written inline under the author's own name (spec §9.1), which is precisely the attribute that string was hand-writing. The bar reads them by name through the ordinary cascade — the root is `display: contents`, so a custom property set on it inherits down — and `panels/block-action-bar.ts` overrides `--jx-bar-x` on the bar itself when it clamps, because a value set on an element beats one it inherits — which is also why that clamp releases its own previous write before it measures, or the bar would be pinned at the right edge for the rest of the session.",
11
+ "$description": "The `.block-action-bar` rules that used to live in `styles/canvas.css`, re-valued onto the kit's tokens. The bar is `position: fixed` because its anchor is a rect in viewport space that crossed the iframe bridge; the layer it sits in has no clipping, which is why the host clamps it rather than letting overflow do it.\n\nThe two placement properties are declared HERE, bound to the flow's measured numbers. They used to travel as a `style` ATTRIBUTE the flow assembled into one string, on the belief that a document cannot bind a style declaration to state. It can, and always could: a reactive value on a custom property in a rule targeting the element itself is written inline under the author's own name (spec.md §9.1), which is precisely the attribute that string was hand-writing. The bar reads them by name through the ordinary cascade — the root is `display: contents`, so a custom property set on it inherits down — and `panels/block-action-bar.ts` overrides `--jx-bar-x` on the bar itself when it clamps, because a value set on an element beats one it inherits — which is also why that clamp releases its own previous write before it measures, or the bar would be pinned at the right edge for the rest of the session.",
12
12
  "display": "contents",
13
13
  "--jx-bar-x": "${state.barX}px",
14
14
  "--jx-bar-y": "${state.barY}px",
@@ -39,7 +39,7 @@
39
39
  "gap": "2px"
40
40
  },
41
41
  "& [part=\"tag\"] > [part=\"control\"]": {
42
- "$description": "The element badge. It is a button on every selection and disabled where the tag cannot be changed — a component instance, a repeater — which is §8.6's rule applied to the one control that used to change shape.",
42
+ "$description": "The element badge. It is a button on every selection and disabled where the tag cannot be changed — a component instance, a repeater — which is studio-ui-guidelines.md §8.6's rule applied to the one control that used to change shape.",
43
43
  "minWidth": "0",
44
44
  "minHeight": "0",
45
45
  "maxWidth": "140px",
@@ -84,7 +84,7 @@
84
84
  }
85
85
  },
86
86
  "& [part=\"drag-handle\"][aria-disabled=\"true\"]": {
87
- "$description": "ONE shape (§8.6): the handle is greyed on the document root, never removed — a toolbar whose controls move under the cursor is worse than one with a dead affordance.",
87
+ "$description": "ONE shape (studio-ui-guidelines.md §8.6): the handle is greyed on the document root, never removed — a toolbar whose controls move under the cursor is worse than one with a dead affordance.",
88
88
  "cursor": "default",
89
89
  "opacity": "0.3"
90
90
  },
@@ -19,7 +19,7 @@
19
19
  * takes its pragmatic-dnd registration as it is created — `canDrag` and the dragged path are the
20
20
  * flow's, so the registration outlives every selection change and the bar never carries two. The
21
21
  * link panel is the kit's `jx-popover`, and an element's own `showPopover()` is the one overlay
22
- * call §9.4 leaves on this side of the seam.
22
+ * call `studio-ui-guidelines.md` §9.4 leaves on this side of the seam.
23
23
  *
24
24
  * **Every control the flow has to reach again is announced, never queried.** `format.link`'s button
25
25
  * is the link panel's anchor and ⌥↑ needs the toolbar itself; both are recorded here as the runtime
@@ -332,8 +332,8 @@ export function mountBlockActionBar(host: HTMLElement, actions: BlockBarActions)
332
332
  }
333
333
  /*
334
334
  * Placing is by measured coordinate — the anchor's box, read here rather than bound in the
335
- * document, which is the one measurement §9.4 leaves on this side of the seam — and showing
336
- * is the element's own `showPopover`.
335
+ * document, which is the one measurement `studio-ui-guidelines.md` §9.4 leaves on this side
336
+ * of the seam — and showing is the element's own `showPopover`.
337
337
  *
338
338
  * A custom element connects asynchronously, so the panel may not yet carry the `popover`
339
339
  * attribute that makes it showable: `jx-ready` is the element saying it does. The same
@@ -0,0 +1,228 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "StudioBootFailure",
4
+ "$description": "What Studio draws INSTEAD of the application frame when a launcher was supposed to register a platform adapter and did not (`platforms/default-platform.ts`'s `bootRefusal`). It replaces a failure that drew everything: desktop 5.0.0 to 5.1.3 fell back to the dev-server adapter inside a `views://` window, so every panel rendered and the first click said \"Failed to fetch\". This says so up front instead: what failed, the error the launcher recorded, and the facts a support thread needs, with a Reload for a transient failure and a Copy for everything else. The adapter decides every sentence; the document only draws them. It is the whole page, so it carries a window drag strip of its own — the desktop window hides its title bar, and with no Command Bar mounted there is otherwise nothing to move the window by.",
5
+ "tagName": "div",
6
+ "attributes": {
7
+ "part": "screen",
8
+ "role": "alert"
9
+ },
10
+ "style": {
11
+ "$description": "Tokens throughout: the screen is mounted before anything but the kit's theme has run, so it can lean on nothing the frame's stylesheets declare. The top padding clears the macOS traffic lights, which sit over the page because the window's title bar is hidden.",
12
+ "position": "fixed",
13
+ "inset": "0",
14
+ "display": "flex",
15
+ "alignItems": "flex-start",
16
+ "justifyContent": "center",
17
+ "paddingTop": "max(10vh, calc(var(--jx-control-h) * 2))",
18
+ "overflowY": "auto",
19
+ "boxSizing": "border-box",
20
+ "background": "var(--jx-bg)",
21
+ "fontFamily": "var(--jx-font-sans)",
22
+ "color": "var(--jx-fg)",
23
+ "& > [part=\"drag-strip\"]": {
24
+ "$description": "The window's handle. Electrobun's preload recognises the class and supplies the drag behaviour itself, so the rule here only sizes the strip: as tall as the hidden title bar would have been.",
25
+ "position": "absolute",
26
+ "top": "0",
27
+ "left": "0",
28
+ "right": "0",
29
+ "height": "calc(var(--jx-control-h) + var(--jx-space-3))"
30
+ },
31
+ "& > [part=\"content\"]": {
32
+ "position": "relative",
33
+ "maxWidth": "40rem",
34
+ "width": "100%",
35
+ "padding": "0 var(--jx-space-6) var(--jx-space-7)",
36
+ "boxSizing": "border-box",
37
+ "display": "flex",
38
+ "flexDirection": "column",
39
+ "gap": "var(--jx-space-4)"
40
+ },
41
+ "& > [part=\"content\"] > [part=\"icon\"]": {
42
+ "$description": "The child, not any descendant: `jx-button` renders its own `<span part=\"icon\">` into light DOM unconditionally, so a bare `[part=\"icon\"]` reached the Reload and Copy buttons too. `--jx-icon-size` is a custom property and `color` inherits, so both passed through that span's `display: contents` and drew the Copy button's clipboard glyph at 32px in warning amber, stretching the actions row with it. This is the collision `[part=\"error\"]` taught: a part name is shared with the kit unless a selector says otherwise.",
43
+ "--jx-icon-size": "2rem",
44
+ "color": "var(--jx-warning)"
45
+ },
46
+ "& [part=\"title\"]": {
47
+ "margin": "0",
48
+ "fontSize": "1.5rem",
49
+ "fontWeight": "400",
50
+ "color": "var(--jx-fg)"
51
+ },
52
+ "& [part=\"lead\"]": {
53
+ "margin": "0",
54
+ "fontSize": "var(--jx-text-lg)",
55
+ "lineHeight": "1.5",
56
+ "color": "var(--jx-fg)"
57
+ },
58
+ "& [part=\"detail\"]": {
59
+ "$description": "The launcher's own error, verbatim. Selectable, because the point of printing it is that someone pastes it into an issue, and wrapped, because a stack line is wider than any window it is likely to be read in.",
60
+ "margin": "0",
61
+ "padding": "var(--jx-space-3) var(--jx-space-4)",
62
+ "maxHeight": "40vh",
63
+ "overflow": "auto",
64
+ "background": "var(--jx-bg-panel)",
65
+ "border": "1px solid var(--jx-border)",
66
+ "borderRadius": "var(--jx-radius-sm)",
67
+ "fontFamily": "var(--jx-font-mono)",
68
+ "fontSize": "var(--jx-text-sm)",
69
+ "whiteSpace": "pre-wrap",
70
+ "wordBreak": "break-word",
71
+ "userSelect": "text"
72
+ },
73
+ "& [part=\"facts\"]": {
74
+ "margin": "0",
75
+ "fontSize": "var(--jx-text-sm)",
76
+ "color": "var(--jx-fg-dim)",
77
+ "wordBreak": "break-all",
78
+ "userSelect": "text"
79
+ },
80
+ "& [part=\"actions\"]": {
81
+ "display": "flex",
82
+ "flexWrap": "wrap",
83
+ "gap": "var(--jx-space-3)"
84
+ }
85
+ },
86
+ "children": [
87
+ {
88
+ "tagName": "div",
89
+ "attributes": {
90
+ "part": "drag-strip",
91
+ "class": "electrobun-webkit-app-region-drag",
92
+ "aria-hidden": "true"
93
+ }
94
+ },
95
+ {
96
+ "tagName": "div",
97
+ "attributes": {
98
+ "part": "content"
99
+ },
100
+ "children": [
101
+ {
102
+ "tagName": "jx-icon",
103
+ "attributes": {
104
+ "part": "icon"
105
+ },
106
+ "$props": {
107
+ "name": "warning",
108
+ "weight": "fill"
109
+ }
110
+ },
111
+ {
112
+ "tagName": "h1",
113
+ "attributes": {
114
+ "part": "title"
115
+ },
116
+ "textContent": "${state.title}"
117
+ },
118
+ {
119
+ "tagName": "p",
120
+ "attributes": {
121
+ "part": "lead"
122
+ },
123
+ "textContent": "${state.lead}"
124
+ },
125
+ {
126
+ "tagName": "div",
127
+ "attributes": {
128
+ "part": "detail-slot",
129
+ "role": "none"
130
+ },
131
+ "style": {
132
+ "display": "contents"
133
+ },
134
+ "$switch": {
135
+ "$ref": "#/state/hasDetail"
136
+ },
137
+ "cases": {
138
+ "true": {
139
+ "tagName": "pre",
140
+ "attributes": {
141
+ "part": "detail"
142
+ },
143
+ "textContent": "${state.detail}"
144
+ }
145
+ }
146
+ },
147
+ {
148
+ "tagName": "p",
149
+ "attributes": {
150
+ "part": "facts"
151
+ },
152
+ "textContent": "${state.facts}"
153
+ },
154
+ {
155
+ "tagName": "div",
156
+ "attributes": {
157
+ "part": "actions"
158
+ },
159
+ "children": [
160
+ {
161
+ "tagName": "jx-button",
162
+ "attributes": {
163
+ "part": "reload"
164
+ },
165
+ "$props": {
166
+ "variant": "accent"
167
+ },
168
+ "onclick": {
169
+ "$prototype": "Function",
170
+ "body": [
171
+ {
172
+ "operator": "call",
173
+ "target": {
174
+ "$ref": "#/state/reload"
175
+ },
176
+ "value": []
177
+ }
178
+ ]
179
+ },
180
+ "children": [
181
+ {
182
+ "tagName": "span",
183
+ "textContent": "Reload"
184
+ }
185
+ ]
186
+ },
187
+ {
188
+ "tagName": "jx-button",
189
+ "attributes": {
190
+ "part": "copy"
191
+ },
192
+ "$props": {
193
+ "quiet": true
194
+ },
195
+ "onclick": {
196
+ "$prototype": "Function",
197
+ "body": [
198
+ {
199
+ "operator": "call",
200
+ "target": {
201
+ "$ref": "#/state/copy"
202
+ },
203
+ "value": []
204
+ }
205
+ ]
206
+ },
207
+ "children": [
208
+ {
209
+ "tagName": "jx-icon",
210
+ "attributes": {
211
+ "slot": "icon"
212
+ },
213
+ "$props": {
214
+ "name": "copy"
215
+ }
216
+ },
217
+ {
218
+ "tagName": "span",
219
+ "textContent": "${state.copied ? 'Copied' : 'Copy details'}"
220
+ }
221
+ ]
222
+ }
223
+ ]
224
+ }
225
+ ]
226
+ }
227
+ ]
228
+ }
@@ -0,0 +1,156 @@
1
+ /// <reference lib="dom" />
2
+ /**
3
+ * The boot-failure surface: what Studio draws instead of its frame when the platform adapter a
4
+ * launcher was supposed to register never arrived.
5
+ *
6
+ * `platforms/default-platform.ts` decides WHETHER to refuse the dev-server fallback; this decides
7
+ * what to SAY about it. The difference matters because the reader is a customer, not a developer
8
+ * with a console open: desktop 5.0.0 to 5.1.3 failed this way silently for months, and the only
9
+ * report that reached anyone was "Create Project says Failed to fetch". So the screen names the
10
+ * failure in one sentence, prints the error the launcher recorded, and carries the facts a support
11
+ * thread asks for first — which bundle, which launcher, which page — behind a Copy button, so the
12
+ * next report arrives with them attached.
13
+ *
14
+ * The error is read LAZILY, from `launcherSignal()` at the moment the view is built, and not from
15
+ * the refusal. The launcher's boot module records the first page error it sees; reading it late
16
+ * costs nothing and cannot miss one that landed after the refusal was decided.
17
+ *
18
+ * The page's query string is never printed. The Chromium launcher authenticates its window with a
19
+ * `?token=` in the URL, and "copy details" is an invitation to paste the result somewhere public.
20
+ *
21
+ * @docs studio/desktop
22
+ */
23
+
24
+ import { reactive } from "../reactivity";
25
+ import { launcherSignal } from "../platform";
26
+ import { mountSurface, registerSurface } from "../ui/surface";
27
+ import { APP_NAME, GIT_COMMIT, VERSION } from "../version";
28
+ import bootFailureDoc from "./boot-failure.json";
29
+ import type { BootRefusal } from "../platforms/default-platform";
30
+ import type { SurfaceHandle } from "../ui/surface";
31
+ import type { JxDocument } from "@jxsuite/schema/types";
32
+
33
+ registerSurface("boot-failure", bootFailureDoc as unknown as JxDocument);
34
+
35
+ /** The page the failure happened on — `location`, or a stand-in with the one field read. */
36
+ export interface BootFailurePage {
37
+ href: string;
38
+ }
39
+
40
+ /** What the document draws, with every sentence already decided. */
41
+ export interface BootFailureView {
42
+ title: string;
43
+ lead: string;
44
+ /** The launcher's recorded error: its message, then its stack when it has one. */
45
+ detail: string;
46
+ hasDetail: boolean;
47
+ /** One line of support facts: bundle version and commit, launcher, page (no query string). */
48
+ facts: string;
49
+ }
50
+
51
+ /** The scope `boot-failure.json` reads. */
52
+ interface BootFailureScope extends Record<string, unknown>, BootFailureView {
53
+ /** The last Copy landed on the clipboard; the button says so. */
54
+ copied: boolean;
55
+ reload: () => void;
56
+ copy: () => Promise<void>;
57
+ }
58
+
59
+ /** One sentence per refusal: what failed, in the words of someone who only saw the window. */
60
+ function leadFor(refusal: BootRefusal): string {
61
+ if (refusal.kind === "launcher") {
62
+ return "The desktop app's bridge to its backend failed to start, so nothing can be opened, saved or created; reinstalling the latest release from the download page fixes this.";
63
+ }
64
+ if (refusal.kind === "declared") {
65
+ return "This page's startup script never ran, so Studio has no backend to open, save or create projects with.";
66
+ }
67
+ return `This page was opened from a ${refusal.protocol} URL, which has no Studio backend behind it; open Studio through the desktop app or a Jx dev server instead.`;
68
+ }
69
+
70
+ /**
71
+ * The error text, message first.
72
+ *
73
+ * A V8 stack already begins with the message, so printing both would say it twice; a stack that
74
+ * does not contain it (a non-Error throw, a WebKit stack of bare frames) gets the message above
75
+ * it.
76
+ */
77
+ function detailFor(): string {
78
+ const error = launcherSignal()?.error;
79
+ if (!error) {
80
+ return "";
81
+ }
82
+ const { message, stack } = error;
83
+ if (!stack) {
84
+ return message;
85
+ }
86
+ return stack.includes(message) ? stack : `${message}\n${stack}`;
87
+ }
88
+
89
+ /**
90
+ * Everything the screen says, decided from the refusal and the live launcher signal.
91
+ *
92
+ * Pure apart from reading that signal, which is the point: see the header on why it is read here.
93
+ *
94
+ * @param refusal Why the dev-server fallback was refused.
95
+ * @param page The page to name in the facts line. Only its path survives; see the header.
96
+ */
97
+ export function bootFailureView(
98
+ refusal: BootRefusal,
99
+ page: BootFailurePage = location,
100
+ ): BootFailureView {
101
+ const detail = detailFor();
102
+ const launcher =
103
+ (refusal.kind === "launcher" ? refusal.launcher : undefined) ??
104
+ launcherSignal()?.launcher ??
105
+ "none";
106
+ // Cut at the first `?` or `#`: the query is where the Chromium launcher's token lives.
107
+ const [where] = page.href.split(/[?#]/u);
108
+ return {
109
+ detail,
110
+ // Labelled as the STUDIO bundle's version, not the app's: the desktop app wraps a Studio bundle
111
+ // Whose version moves on its own schedule, and a support thread that reads "5.3.0" as the
112
+ // Desktop release is chasing a build that does not exist.
113
+ facts: `${APP_NAME} bundle ${VERSION} (${GIT_COMMIT}) · launcher ${launcher} · ${where}`,
114
+ hasDetail: detail !== "",
115
+ lead: leadFor(refusal),
116
+ title: "Jx Studio couldn't connect to its backend",
117
+ };
118
+ }
119
+
120
+ /** The plain-text report Copy puts on the clipboard: everything the screen says, in order. */
121
+ export function bootFailureReport(view: BootFailureView): string {
122
+ return [view.title, view.lead, view.detail, view.facts].filter(Boolean).join("\n\n");
123
+ }
124
+
125
+ /**
126
+ * Mount the boot-failure screen into `host`.
127
+ *
128
+ * @param host The container it owns — `#shell-root`, via `shell/tree.ts`'s `mountBootFailureTree`.
129
+ * @param refusal Why the dev-server fallback was refused.
130
+ * @param page The page to name in the facts line; `location` by default.
131
+ */
132
+ export function mountBootFailureSurface(
133
+ host: HTMLElement,
134
+ refusal: BootRefusal,
135
+ page: BootFailurePage = location,
136
+ ): Promise<SurfaceHandle> {
137
+ const view = bootFailureView(refusal, page);
138
+ const scope = reactive<BootFailureScope>({
139
+ ...view,
140
+ copied: false,
141
+ async copy() {
142
+ try {
143
+ await navigator.clipboard.writeText(bootFailureReport(view));
144
+ scope.copied = true;
145
+ } catch {
146
+ /* No clipboard: an insecure context, a denied permission, or a webview without the API.
147
+ The button stays "Copy details", and the text it would have copied is on the screen,
148
+ selectable, directly above it — so the failure costs one drag rather than the report. */
149
+ }
150
+ },
151
+ reload() {
152
+ location.reload();
153
+ },
154
+ }) as BootFailureScope;
155
+ return mountSurface("boot-failure", scope, host);
156
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://jxsuite.com/schema/v1",
3
3
  "$id": "StudioBottomDock",
4
- "$description": "⑪ The Bottom dock's chrome as a Jx document over the kit: a real `tablist` of the dock's tabs, the button that shuts it, and ONE `tabpanel` for whichever tab is showing. Every tab names that one panel — the dock draws the selected tab's body and no other, so there is exactly one panel element and its `aria-labelledby` follows the selection, which is the same shape `surfaces/git-panel.json` uses for its two sub-tabs. It draws no tab BODY: `panels/bottom-dock.ts` keeps the panel registry, the `when` filter, the badge in each tab's label, the Logic reveal and every tab's `afterRender`, and renders the active record into the one empty `[part=\"dock-body\"]` island this document leaves for it (studio-ui-guidelines.md §9.4).",
4
+ "$description": "The Bottom dock's chrome (studio.md §16.3) as a Jx document over the kit: a real `tablist` of the dock's tabs, the button that shuts it, and ONE `tabpanel` for whichever tab is showing. Every tab names that one panel — the dock draws the selected tab's body and no other, so there is exactly one panel element and its `aria-labelledby` follows the selection, which is the same shape `surfaces/git-panel.json` uses for its two sub-tabs. It draws no tab BODY: `panels/bottom-dock.ts` keeps the panel registry, the `when` filter, the badge in each tab's label, the Logic reveal and every tab's `afterRender`, and renders the active record into the one empty `[part=\"dock-body\"]` island this document leaves for it (studio-ui-guidelines.md §9.4).",
5
5
  "tagName": "div",
6
6
  "attributes": {
7
7
  "part": "bottom-dock"
@@ -7,7 +7,7 @@
7
7
  "part": "stage"
8
8
  },
9
9
  "style": {
10
- "$description": "`styles/canvas.css`'s `.panzoom-wrap`, `.canvas-panel*`, `.source-*`, `.doc-header-host`, `.content-edit-*`, `.edit-width-handle`, `.preview-stage` and `.diff-code-*` rules, keyed on `part`. Two selectors reach FOREIGN DOM and say so where they stand: `.doc-header` is the card's own root inside its host, and `.is-resizing` is written by `canvas/edit-width-drag.ts` onto the column this document draws — the same shape `grid-panel.json` uses for Tabulator's theme. The width handles are `jx-split` elements, which paint their own hover, drag and focus states; this sheet says only where they stand and how wide they are.",
10
+ "$description": "`styles/canvas.css`'s `.panzoom-wrap`, `.canvas-panel*`, `.source-*`, `.content-edit-*`, `.edit-width-handle`, `.preview-stage` and `.diff-code-*` rules, keyed on `part`, plus the Document Header card's host. One selector reaches FOREIGN DOM and says so where it stands: `.is-resizing` is written by `canvas/edit-width-drag.ts` onto the column this document draws — the same shape `grid-panel.json` uses for Tabulator's theme. The width handles are `jx-split` elements, which paint their own hover, drag and focus states; this sheet says only where they stand and how wide they are.",
11
11
  "display": "contents",
12
12
  "& [part=\"panzoom\"]": {
13
13
  "$description": "The transformed surface. `applyTransform` writes `transform` on it imperatively, so only the origin is declared here. `--boards-inset` is the Project Styles bar's clearance: that bar floats over the stage, so the boards start below it.",
@@ -97,21 +97,12 @@
97
97
  "left": "50%",
98
98
  "transform": "translateX(-50%)"
99
99
  },
100
- "& [part=\"doc-header\"][data-placement=\"in-column\"]": {
101
- "$description": "Edit: the card is a block of the artefact's own column and scrolls with it, so it is part of the document rather than a strip above it.",
102
- "display": "block",
103
- "paddingBottom": "16px"
104
- },
105
- "& [part=\"doc-header\"][data-placement=\"pinned\"]": {
106
- "$description": "Design: the artboards are drawn under a pan/zoom transform, and a form drawn at 40% is a picture of a form — so the card sits above the surface at 1:1 and keeps its own scroll. This is the one placement that still needs a cap.",
100
+ "& [part=\"doc-header\"]": {
101
+ "$description": "Edit only: the card is docked above the page's scroller as a band across the pane at 1:1, so its width is the pane's rather than the breakpoint's, and the page scrolls under it rather than taking it along. It used to be a block of Edit's column, which made it exactly as wide as the column's breakpoint or dragged width and scrolled it off with the first screen of the page. `canvas-render.ts` stacks the stage cell when it draws one — and closes its gap, so the band's own bottom border is where the scroller clips; `flex-shrink: 0` keeps the band whole while the scroller below takes the squeeze. THE CAP IS TWO CAPS, because the band has two ways to eat the page: `40vh` is the tall-pane answer, and `50%` is the short-pane one — a percentage `max-height` resolves against this flex container, the stage cell, whose height is definite (row 2 of the pane's `auto minmax(0, 1fr)` grid), so the page always keeps half the pane however little of it the dock and the bars have left. `40vh` alone is a share of the WINDOW: with the bottom dock open in a 650px window it is most of a 280px stage, and the page was a sliver. No `z-index`: the one it had was for Design, where the band's sibling was a pan/zoom surface whose boards could paint over it. Edit's sibling is the scroller, which clips its own content, and Design draws no card at all. The shadow is the same one-edge idiom as `panel-outline.json`'s verb cluster — it reaches over the scroller's top padding, so the page reads as passing under a docked band rather than ending at a rule. No `display`, so `hidden` on the host still hides it.",
107
102
  "flexShrink": "0",
108
- "maxHeight": "40vh",
109
- "overflowY": "auto"
110
- },
111
- "& [part=\"doc-header\"][data-placement=\"pinned\"] .doc-header": {
112
- "$description": "FOREIGN DOM: `.doc-header` is the frontmatter card's own root, mounted into this host by `panels/frontmatter-panel.ts`. Pinned, the card is a band across the stage rather than a card on it, so it loses its own rounding and keeps only the edge that separates it from the boards.",
113
- "borderWidth": "0 0 1px",
114
- "borderRadius": "0"
103
+ "maxHeight": "min(40vh, 50%)",
104
+ "overflowY": "auto",
105
+ "boxShadow": "0 8px 8px -8px rgb(0 0 0 / 0.35)"
115
106
  },
116
107
  "& [part=\"edit-canvas\"]": {
117
108
  "$description": "The side gutter is LOAD-BEARING, not breathing room: the resize handles hang outside the column's own box — flex siblings with a negative margin, so they take no width from it — and this container clips horizontally, so without it the handles would be unreachable at exactly the width where dragging inward matters most. It must stay at least as wide as `EDIT_CANVAS_GUTTER` in `canvas/edit-width.ts`, which is what the drag's own ceiling subtracts. This box is also the TRACK the two `jx-split`s measure: the first ancestor of a handle that generates a box, which is why the handles are drawn here beside the column rather than inside it — inside, the column would have been the track, and the track cannot be the thing being resized.",
@@ -198,7 +189,7 @@
198
189
  },
199
190
  "children": [
200
191
  {
201
- "$description": "What stands over the frame, and only ever one of the three: the Document Header card above a pan/zoom surface, the Compare bar over a comparison, or the Project Styles bar over the catalogue. Each is an empty host — the surface that fills it is mounted by the module that owns it.",
192
+ "$description": "What stands over the frame, and only ever one of the three: the Document Header card docked above Edit's scrolling column, the Compare bar over a comparison, or the Project Styles bar over the catalogue. Each is an empty host — the surface that fills it is mounted by the module that owns it.",
202
193
  "tagName": "div",
203
194
  "attributes": {
204
195
  "part": "lead-slot"
@@ -211,10 +202,10 @@
211
202
  },
212
203
  "cases": {
213
204
  "header": {
205
+ "$description": "The card has ONE place, so the host says nothing about where it is. It used to carry `data-placement`, one of two, and the card read it back as the host was announced — which is before the runtime writes a node's attributes, so the card read no attribute at all and drew `in-column` even where the host said `pinned`.",
214
206
  "tagName": "div",
215
207
  "attributes": {
216
- "part": "doc-header",
217
- "data-placement": "pinned"
208
+ "part": "doc-header"
218
209
  }
219
210
  },
220
211
  "toolbar": {
@@ -295,28 +286,6 @@
295
286
  }
296
287
  },
297
288
  "children": [
298
- {
299
- "$description": "Edit draws the Document Header card INSIDE the document's column, as its first block — the column's first child by contract. The width handles are not in the column at all (they stand beside it, see the frame), so nothing here can get in front of it.",
300
- "tagName": "div",
301
- "attributes": {
302
- "part": "column-header-slot"
303
- },
304
- "style": {
305
- "display": "contents"
306
- },
307
- "$switch": {
308
- "$ref": "#/state/columnHeader"
309
- },
310
- "cases": {
311
- "shown": {
312
- "tagName": "div",
313
- "attributes": {
314
- "part": "doc-header",
315
- "data-placement": "in-column"
316
- }
317
- }
318
- }
319
- },
320
289
  {
321
290
  "$prototype": "Array",
322
291
  "items": { "$ref": "#/state/panels" },
@@ -64,10 +64,12 @@ export interface CanvasStageView {
64
64
  frameVars: string;
65
65
  /** Whether Edit's column hugs its content — a component definition rather than a page. */
66
66
  hug: boolean;
67
- /** What stands over the frame, and only ever one of the three. */
67
+ /**
68
+ * What stands over the frame, and only ever one of the three: the Document Header card docked
69
+ * above Edit's scrolling column, the Compare bar over a comparison, or the Project Styles bar
70
+ * over the catalogue.
71
+ */
68
72
  lead: "none" | "header" | "toolbar" | "chrome";
69
- /** Whether Edit draws the Document Header card inside its column. */
70
- columnHeader: "hidden" | "shown";
71
73
  /** Whether the column has its two width handles. */
72
74
  handles: "hidden" | "shown";
73
75
  panels: CanvasStagePanelItem[];
@@ -81,8 +83,8 @@ export interface CanvasStageActions {
81
83
  * A host the document drew, announced as it is BUILT — one reconcile step before it is in the
82
84
  * page, which is what lets an editor be handed a node before the frame paints.
83
85
  *
84
- * `detail` is the handle's side for `edit-handle` and the card's placement for `doc-header`; the
85
- * artboard's own three parts are not announced here at all, because a record is filled from
86
+ * `detail` is the handle's side for `edit-handle` and "" for every other part; the artboard's own
87
+ * three parts are not announced here at all, because a record is filled from
86
88
  * {@link CanvasStageHandle.panelNode} once the reconcile has settled.
87
89
  */
88
90
  host: (part: string, element: HTMLElement, detail: string) => void;
@@ -112,7 +114,7 @@ interface CanvasStageScope extends Record<string, unknown>, CanvasStageView {
112
114
  * Static is the whole point. A node is announced as it is BUILT, one reconcile step before its
113
115
  * attributes are settled, so nothing here may read the element: `part` is what the node is,
114
116
  * `data-slot` says which of the two bound parts it is (see {@link CanvasStageView.framePart}), and
115
- * `data-side` / `data-placement` tell two nodes of one part apart.
117
+ * `data-side` tells the two width handles apart — the one part the document draws twice.
116
118
  */
117
119
  function attrOf(def: JxElement | string, name: string): string {
118
120
  const value = typeof def === "string" ? undefined : def.attributes?.[name];
@@ -153,7 +155,6 @@ function project(scope: CanvasStageScope, view: CanvasStageView): void {
153
155
  scope.frameVars = view.frameVars;
154
156
  scope.hug = view.hug;
155
157
  scope.lead = view.lead;
156
- scope.columnHeader = view.columnHeader;
157
158
  scope.handles = view.handles;
158
159
  scope.panels = view.panels;
159
160
  }
@@ -180,7 +181,6 @@ export function mountCanvasStage(
180
181
  than from a callback that will not fire again. */
181
182
  const boards = new Map<string, Map<string, HTMLElement>>();
182
183
  const scope = reactive<CanvasStageScope>({
183
- columnHeader: "hidden",
184
184
  frame: "boards",
185
185
  framePart: "panzoom",
186
186
  frameVars: "",
@@ -206,7 +206,7 @@ export function mountCanvasStage(
206
206
  const slot = attrOf(def, "data-slot");
207
207
  const named =
208
208
  slot === "frame" ? scope.framePart : slot === "inner" ? scope.innerPart : part;
209
- actions.host(named, element, attrOf(def, "data-side") || attrOf(def, "data-placement"));
209
+ actions.host(named, element, attrOf(def, "data-side"));
210
210
  }
211
211
  },
212
212
  }).then((surface) => {