@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,16 +1,16 @@
1
1
  /// <reference lib="dom" />
2
2
  /**
3
- * ⑥ The jump bar — the pane's address, and every place you can go from it.
3
+ * The jump bar — the pane's address, and every place you can go from it.
4
4
  *
5
5
  * **The two half-breadcrumbs this replaces.** Studio grew two trails, neither of which could say
6
6
  * where you were:
7
7
  *
8
- * 1. `panels/pane-context.ts`'s `navTpl()` (the old `#tab-bar` breadcrumb, plan §3.2 ⑥ names it as
9
- * `tab-bar.ts:129-185`) — a `Back` button plus one span per `session.documentStack` frame. It
10
- * appeared ONLY while you were inside a sub-document, printed the frame's file basename (which
11
- * is the SAME basename for a `$map` template, so it read `index.json › index.json`), and knew
12
- * nothing about the project above it or the selection below it. It is deleted, and so is the
13
- * stack it walked: nothing ever pushed a frame, so it could only ever draw its empty branch.
8
+ * 1. `panels/pane-context.ts`'s `navTpl()` (the old `#tab-bar` breadcrumb, `tab-bar.ts:129-185`) — a
9
+ * `Back` button plus one span per `session.documentStack` frame. It appeared ONLY while you were
10
+ * inside a sub-document, printed the frame's file basename (which is the SAME basename for a
11
+ * `$map` template, so it read `index.json › index.json`), and knew nothing about the project
12
+ * above it or the selection below it. It is deleted, and so is the stack it walked: nothing ever
13
+ * pushed a frame, so it could only ever draw its empty branch.
14
14
  * 2. `surfaces/statusbar.ts`'s selection field — a clickable ancestor trail, `selection.set` per
15
15
  * crumb. It appeared ONLY while something was selected, and knew nothing about the document it
16
16
  * was inside.
@@ -23,12 +23,12 @@
23
23
  * project file selection ancestors
24
24
  * ```
25
25
  *
26
- * **The status bar keeps only what an address cannot say.** Plan §3.2 ⑫ and `studio.md` §16.2 give
27
- * the bar AMBIENT STATE, and an ancestor trail in a second place is exactly the duplication the
28
- * shell redesign exists to remove — three breadcrumbs would be worse than the two we started with.
29
- * So the trail moves here whole, and `statusbar/selection` keeps the two facts this bar cannot
30
- * state: HOW MANY things are selected (a count is not a path) and which Stylebook rule the Style
31
- * panel is editing (a selector is not a node).
26
+ * **The status bar keeps only what an address cannot say.** `studio.md` §16.2 gives the bar AMBIENT
27
+ * STATE, and an ancestor trail in a second place is exactly the duplication the shell redesign
28
+ * exists to remove — three breadcrumbs would be worse than the two we started with. So the trail
29
+ * moves here whole, and `statusbar/selection` keeps the two facts this bar cannot state: HOW MANY
30
+ * things are selected (a count is not a path) and which Stylebook rule the Style panel is editing
31
+ * (a selector is not a node).
32
32
  *
33
33
  * **Every interactive item is a command, resolved from the registry.** There is no click handler in
34
34
  * this file that names behaviour: a segment names a command id and its args, and the registry
@@ -47,7 +47,7 @@
47
47
  * (studio-ui-guidelines.md §6, §9.3). What stays here is the part that is a decision: which pane
48
48
  * this bar is about, what its address is, which of its steps the registry can run, and what a
49
49
  * chevron opens — and the chevron opens the KIT MENU, `surfaces/menu.ts`, because a list of
50
- * commands is what that surface already is (§12.5).
50
+ * commands is what that surface already is (studio-ui-guidelines.md §12.5).
51
51
  */
52
52
 
53
53
  import { displayTagName } from "@jxsuite/schema/guards";
@@ -81,7 +81,8 @@ const JUMP_BAR_HEIGHT = 24;
81
81
 
82
82
  /**
83
83
  * What a segment addresses. The kind is stamped on the element so a test — and a shot — can name a
84
- * step of the address without matching its rendered text, which is derived (§13 R1).
84
+ * step of the address without matching its rendered text, which is derived (the shot contract's R1,
85
+ * `scripts/screenshots/README.md`).
85
86
  */
86
87
  export type JumpSegmentKind = "project" | "file" | "editor" | "node";
87
88
 
@@ -301,7 +302,7 @@ export function jumpSegments(
301
302
  function editorSegment(sigil: string, def: FunctionEditDef | FormulaEditDef): JumpSegment {
302
303
  return {
303
304
  choices: [],
304
- // No command, and none is missing: the Logic tab's own header carries the Close (P8.5), which
305
+ // No command, and none is missing: the Logic tab's own header carries the Close (§16.3), which
305
306
  // Is where a reader looking at the editor already is. A second exit up here would be a button
306
307
  // Beside the address that means "stop being at this address" — and the pane context bar drew
307
308
  // Exactly that, a Back of its own, until this excision removed it.
@@ -350,7 +351,7 @@ function segmentTitle(registry: CommandRegistry, segment: JumpSegment, id: strin
350
351
  *
351
352
  * An unregistered or invisible command makes the step a READOUT rather than removing it, and more
352
353
  * than one alternative is what earns a chevron: one is not a choice, and a control that cannot move
353
- * is chrome (§2 principle 9).
354
+ * is chrome (studio-ui-guidelines.md §12.2).
354
355
  */
355
356
  function projectStep(
356
357
  registry: CommandRegistry | null,
@@ -411,7 +412,8 @@ export function dismissJumpMenu(): void {
411
412
  * The rows are built from the segment's choices, and every row runs a command — the same command
412
413
  * the segment itself names, with a different path. Nothing here decides what selecting means, and
413
414
  * nothing here draws a panel: `surfaces/menu.ts` owns the roving caret, typeahead, Escape and light
414
- * dismissal, because a list of commands is what that surface already is (§12.5).
415
+ * dismissal, because a list of commands is what that surface already is: a second one is the defect
416
+ * studio-ui-guidelines.md §12.5 names.
415
417
  */
416
418
  function openChoices(segment: JumpSegment, anchor: HTMLElement | null): void {
417
419
  const registry = activeRegistry();
@@ -16,13 +16,13 @@
16
16
  *
17
17
  * **Rows are `registry.forPlacement("outline/row")`.** Every row used to carry five hand-built
18
18
  * action buttons, always visible, on every row. They collapse to the selected row plus the hovered
19
- * one, which is Gutenberg's rule and the one plan §3.2 ⑩ codifies: the floating bar owns
20
- * selection-scoped verbs, the inspector owns values. The verbs, their names, their chords and their
21
- * disabled reasons all come from the records in `block-action-bar.ts` — the surface renders, it
22
- * does not decide. A row that is neither selected nor hovered is projected with an EMPTY command
23
- * list, so the cluster costs nothing rather than being hidden by a rule: a `display: none` kit
24
- * element is still an upgraded custom element, which is the whole cost the collapse exists to
25
- * remove.
19
+ * one, which is Gutenberg's rule and the one studio-ui-guidelines.md §12.1 codifies: the floating
20
+ * bar owns selection-scoped verbs, the inspector owns values. The verbs, their names, their chords
21
+ * and their disabled reasons all come from the records in `block-action-bar.ts` — the surface
22
+ * renders, it does not decide. A row that is neither selected nor hovered is projected with an
23
+ * EMPTY command list, so the cluster costs nothing rather than being hidden by a rule: a `display:
24
+ * none` kit element is still an upgraded custom element, which is the whole cost the collapse
25
+ * exists to remove.
26
26
  *
27
27
  * **A row says something.** On a real page the tree was a wall of rows all reading "div": only
28
28
  * text-bearing nodes got a preview and containers got the tag they already wear as a coloured
@@ -504,7 +504,8 @@ function selectModelRow(index: number, gesture: { range?: boolean } = {}): void
504
504
  }
505
505
 
506
506
  /**
507
- * Apply one row activation to the selection, honouring the two accumulate gestures (§6.5).
507
+ * Apply one row activation to the selection, honouring the two accumulate gestures
508
+ * (studio-ui-guidelines.md §8.1).
508
509
  *
509
510
  * - Plain: replace the selection with this path. **This is the only branch a keyboard walk or an
510
511
  * unmodified click can reach, and it is byte-identical to what the Outline always did.**
@@ -1254,9 +1255,10 @@ export function mountOutlinePanel(
1254
1255
  editInput,
1255
1256
  editReady: (element) => {
1256
1257
  /* On a microtask, because `onNodeCreated` fires as the node is BUILT and one tick before
1257
- it is in the document — which is exactly why it is the seam (guidelines §9.4): it
1258
- hands over the element earlier than awaiting the mount would, and the host decides
1259
- when it is worth anything. An unconnected input cannot take focus. */
1258
+ it is in the document — which is exactly why it is the seam
1259
+ (studio-ui-guidelines.md §9.4): it hands over the element earlier than awaiting the
1260
+ mount would, and the host decides when it is worth anything. An unconnected input
1261
+ cannot take focus. */
1260
1262
  queueMicrotask(() => {
1261
1263
  const input = element as HTMLInputElement;
1262
1264
  if (input.isConnected) {
@@ -1267,10 +1269,10 @@ export function mountOutlinePanel(
1267
1269
  },
1268
1270
  expand: expandOutlineRow,
1269
1271
  emptyAction: () => {
1270
- /* `"insert"`, not `"blocks"`. The panel was renamed in P3.1 and this call kept the old id
1271
- for three phases, so the one action an empty page offers landed the Navigator on "No
1272
- Navigator panel is registered as blocks". `setActivityTab` takes a `NavigatorPanelId`
1273
- now, so this cannot recur. */
1272
+ /* `"insert"`, not `"blocks"`. The panel was renamed with the registry-driven rail (§5.1),
1273
+ and this call kept the old id for three phases, so the one action an empty page offers
1274
+ landed the Navigator on "No Navigator panel is registered as blocks". `setActivityTab`
1275
+ takes a `NavigatorPanelId` now, so this cannot recur. */
1274
1276
  setActivityTab("insert");
1275
1277
  },
1276
1278
  hover: hoverRow,
@@ -1350,8 +1352,8 @@ export function detachOutline(): void {
1350
1352
  * Contribute the Outline panel.
1351
1353
  *
1352
1354
  * `level: "document"` — it writes the open document's tree (reorder, rename, delete, duplicate).
1353
- * "Outline" rather than "Layers" is §3.2 ③'s name for it; the id stays `layers` because that is
1354
- * what `view.setActivity` and 26 screenshot steps address it by, and an id is not a label.
1355
+ * "Outline" rather than "Layers" is §5.1's name for it; the id stays `layers` because that is what
1356
+ * `view.setActivity` and 26 screenshot steps address it by, and an id is not a label.
1355
1357
  */
1356
1358
  export function registerLayersPanel(): void {
1357
1359
  registerPanel({
@@ -6,8 +6,8 @@
6
6
  * no-document copy table and the two post-render special cases are gone: this file resolves ONE
7
7
  * record from the panel registry, hands the document its name and its level, renders its `render`
8
8
  * into the content island, and calls its `afterRender`. Everything a panel is — its name, its
9
- * level, its empty state, its drag registrations — is declared beside the state it writes (plan §2
10
- * principle 1).
9
+ * level, its empty state, its drag registrations — is declared beside the state it writes (one
10
+ * definition site per action, studio.md §13).
11
11
  *
12
12
  * **The box is `surfaces/navigator-dock.json` now, and the body is still lit.** A `PanelRecord`'s
13
13
  * `render` returns a lit template, so the panel body cannot be a document; the dock draws the
@@ -108,7 +108,7 @@ export function mount(deps: NavigatorPanelDeps) {
108
108
  void tab.doc.document;
109
109
  void tab.doc.mode;
110
110
  // The whole SET, joined — a bare property read would not re-trigger when the selection
111
- // Changes WITHIN the array, and §6.5's helpers always replace it but nothing enforces that.
111
+ // Changes WITHIN the array, and §6.7's helpers always replace it but nothing enforces that.
112
112
  void tab.session.selection.map((path) => path.join("/")).join("|");
113
113
  }
114
114
  render();
@@ -16,11 +16,11 @@
16
16
  * advertisement, in the shell's own furniture, for a place to find things wrong with the product.
17
17
  * The count reaches the user from the status bar the moment there is one.
18
18
  *
19
- * **Search is declared and hidden.** It is a surface a later phase builds (P3.3's palette index),
20
- * and it holds a rail slot §3.2 has already spent. A `when: () => false` record is the honest way
21
- * to say "this exists in the design and not yet in the app": the id is reserved, the budget already
22
- * counts it, and the day it ships the only edit is deleting one predicate — as opposed to a stub
23
- * button that lies to whoever clicks it.
19
+ * **Search is declared and hidden.** It is a surface a later phase builds (the palette's project
20
+ * index), and it holds a slot in the rail's four-tab budget (`studio-ui-guidelines.md` §12.2). A
21
+ * `when: () => false` record is the honest way to say "this exists in the design and not yet in the
22
+ * app": the id is reserved, the budget already counts it, and the day it ships the only edit is
23
+ * deleting one predicate — as opposed to a stub button that lies to whoever clicks it.
24
24
  */
25
25
 
26
26
  import { registerFilesPanel } from "../files/files";
@@ -79,11 +79,11 @@ export function registerNavigatorPanels(): void {
79
79
  // ── Off-rail: reachable by command and palette, no rail button ──────────────
80
80
  registerInsertPanel();
81
81
 
82
- // ── The Bottom dock's tabs (§3.2 ⑪): Problems · Logic · Activity ────────────
82
+ // ── The Bottom dock's tabs (§16.3): Problems · Logic · Activity ──────────────
83
83
  // Composed here, in the one place panel records are gathered, so the shell has ONE composition
84
84
  // Site rather than one per dock. Importing the module is also what attaches the dock to the
85
- // Shell's mount lifecycle — see its `registerShellSurface` call. Problems arrives with them and
86
- // Still takes the rail's fourth PROJECT slot, because the rail groups by level, not by dock.
85
+ // Shell's mount lifecycle — see its `registerShellSurface` call. Problems arrives with them and,
86
+ // Like every Bottom-dock tab, has no rail button (§16.3).
87
87
  registerBottomPanels();
88
88
  }
89
89
 
@@ -42,7 +42,7 @@ export function mount(ctx: OverlaysCtx) {
42
42
  // Track selection, hover, mode, and the active panel (a hit in another breakpoint panel — or
43
43
  // A header click — re-anchors the block action bar even when the selection path is unchanged).
44
44
  // The whole SET, joined — a bare property read would not re-trigger when the selection
45
- // Changes WITHIN the array, and §6.5's helpers always replace it but nothing enforces that.
45
+ // Changes WITHIN the array, and §6.7's helpers always replace it but nothing enforces that.
46
46
  void tab.session.selection.map((path) => path.join("/")).join("|");
47
47
  void tab.session.hover;
48
48
  void tab.doc.mode;
@@ -1,12 +1,12 @@
1
1
  /// <reference lib="dom" />
2
2
  /**
3
- * The pane's own chrome — region ⑦ (context bar) and region ⑩ (the floating zoom pod).
3
+ * The pane's own chrome — the pane context bar and the floating zoom pod.
4
4
  *
5
5
  * This replaces `#tab-bar`, which was a 28px band styled identically to the tab strip above it,
6
6
  * holding **five unrelated axes** with no labels on any of them: a document-stack breadcrumb
7
7
  * (navigation), a zoom widget (viewport), route params and component test props (document data), a
8
- * colour-scheme switch and feature toggles (rendering state), and Export (a mode action). Plan §3.2
9
- * ⑦ replaces them with three axes that each say what they are:
8
+ * colour-scheme switch and feature toggles (rendering state), and Export (a mode action). The pane
9
+ * context bar replaces them with three axes that each say what they are:
10
10
  *
11
11
  * - **Editor kind** — `Canvas ⌄`, offering only the kinds this document declares. A document with one
12
12
  * kind renders the name as text rather than as a dropdown that cannot go anywhere.
@@ -15,10 +15,10 @@
15
15
  * Canvas. The two are drawn apart because they are two axes: preview is a flag over an edit or
16
16
  * design base, so the radio marks the base throughout and the toggle says whether it is on.
17
17
  * - **Rendering context** — `md ⌄ Light ⌄`, folding the size breakpoint, the colour scheme, the
18
- * feature queries and the layout show/hide switch into one popover. Per §2 principle 5 this
19
- * control **only selects**; its footer is "Manage contexts…", which routes to the definition site
20
- * — Project Settings › Contexts (`settings/contexts-section.ts`), the one place a breakpoint, a
21
- * colour scheme or a feature query is defined.
18
+ * feature queries and the layout show/hide switch into one popover. Per §6.2 ("The breakpoint and
19
+ * scheme axes") this control **only selects**; its footer is "Manage contexts…", which routes to
20
+ * the definition site — Project Settings › Contexts (`settings/contexts-section.ts`), the one
21
+ * place a breakpoint, a colour scheme or a feature query is defined.
22
22
  * - **Resolving with** — the document DATA a render resolves against: a page's route params, a
23
23
  * component's test props. Its own popover beside the context one, headed "resolving with", with
24
24
  * the fields in a vertical stack. A SECOND popover rather than a fourth group in the first,
@@ -34,12 +34,13 @@
34
34
  * **The bar is not a grid row.** It renders inside the pane's own cell (`#pane-chrome`, stacked
35
35
  * over `#canvas-wrap`), because a per-pane surface cannot be a row of the application grid — the
36
36
  * second pane would have no way to have one. The stage is offset by {@link PANE_CONTEXT_VAR} rather
37
- * than by a track, and the zoom pod floats bottom-right over the canvas exactly as §3.2 ⑩ asks.
37
+ * than by a track, and the zoom pod floats bottom-right over the canvas, as
38
+ * `docs/studio/interface/tabs.md` ("The pane context bar") describes it.
38
39
  *
39
40
  * **The read-only banner rides with the bar.** `collab/collab-state.ts` says whether a guest may
40
- * write (§7.4); the surface that owes them the sentence is this one, because it is the per-pane,
41
- * per-document chrome that sits directly above the editing surface. It is stacked under the bar
42
- * inside the document's `[part="band"]` and the offset is MEASURED from that band
41
+ * write (`collab.md` §4); the surface that owes them the sentence is this one, because it is the
42
+ * per-pane, per-document chrome that sits directly above the editing surface. It is stacked under
43
+ * the bar inside the document's `[part="band"]` and the offset is MEASURED from that band
43
44
  * ({@link applyPaneContextOffset}), so a two-line banner pushes the stage down instead of covering
44
45
  * the document it is warning you about.
45
46
  */
@@ -66,6 +67,9 @@ import {
66
67
  import { openMenu } from "../surfaces/menu";
67
68
  import { emptyPaneContextView, mountPaneContextSurface } from "../surfaces/pane-context";
68
69
  import { PANE_SELECTOR } from "../surfaces/pane-grid";
70
+ import { diffShowsCode } from "../canvas/diff-view";
71
+ import { canRenderComparison } from "./git-diff-open";
72
+ import { shell } from "../shell";
69
73
  import { paneRegion } from "../ui/regions";
70
74
  import {
71
75
  fitToScreen,
@@ -268,9 +272,9 @@ export function mount(host: HTMLElement, ctx: PaneContextCtx) {
268
272
  void tab.session.ui.previewProps;
269
273
  void tab.session.ui.showLayout;
270
274
  void tab.session.ui.zoom;
271
- // The read-only banner (§7.4) is part of this chrome, so its two facts are tracked here
272
- // Too: a peer downgrading you mid-session must make the sentence appear, not wait for the
273
- // Next zoom.
275
+ // The read-only banner (`collab.md` §4) is part of this chrome, so its two facts are
276
+ // Tracked here too: a peer downgrading you mid-session must make the sentence appear, not
277
+ // Wait for the next zoom.
274
278
  void collabState(tab).active;
275
279
  void collabState(tab).readOnly;
276
280
  }
@@ -322,7 +326,7 @@ export function applyPaneContextOffset(height: number, host?: HTMLElement | null
322
326
  *
323
327
  * The band is the DOCUMENT's, handed back by the mount rather than found by selector — a surface
324
328
  * that re-queries its own markup is holding a node that the next render may already have replaced
325
- * (guidelines §9.4).
329
+ * (`studio-ui-guidelines.md` §9.4).
326
330
  */
327
331
  function topBandHeight(surface: PaneContextSurfaceHandle): number {
328
332
  return Math.max(surface.band()?.offsetHeight ?? 0, PANE_CONTEXT_HEIGHT);
@@ -416,7 +420,7 @@ export function dismissPresetMenu(): void {
416
420
  *
417
421
  * **It is the kit menu, not a second one.** `surfaces/menu.ts` already owns roving focus,
418
422
  * typeahead, light dismissal, the disabled row's `requires` sentence and the Escape that closes it
419
- * (guidelines §12.5); this hands it rows.
423
+ * (`studio-ui-guidelines.md` §12.5); this hands it rows.
420
424
  */
421
425
  function openPresetMenu(paneId: string, anchor: HTMLElement): void {
422
426
  dismissPresetMenu();
@@ -617,13 +621,13 @@ export function presetRows(paneId: string): PresetRow[] {
617
621
  * Everything one pane's chrome draws, as words and keyed rows.
618
622
  *
619
623
  * There is no takeover branch. Opening a function body or a formula reveals the dock's Logic tab
620
- * (P8) and leaves the canvas standing underneath it, so the axes still describe the document on the
621
- * stage and the zoom pod still has something to zoom. Suppressing them while the dock was open
624
+ * (§16.3) and leaves the canvas standing underneath it, so the axes still describe the document on
625
+ * the stage and the zoom pod still has something to zoom. Suppressing them while the dock was open
622
626
  * removed the controls for the very document the reader could still see.
623
627
  *
624
- * **There is no breadcrumb either.** The address is ⑥'s job — `panels/jump-bar.ts`, one row above —
625
- * and the Logic tab's own header carries the Close. This bar drew a second Back and a second trail
626
- * beside both of them.
628
+ * **There is no breadcrumb either.** The address is the jump bar's job — `panels/jump-bar.ts`, one
629
+ * row above — and the Logic tab's own header carries the Close. This bar drew a second Back and a
630
+ * second trail beside both of them.
627
631
  */
628
632
  function viewFor(tab: Tab, paneId: string, ctx: PaneContextCtx): PaneContextView {
629
633
  /* A LENS suppresses the two axes that WRITE. Editor kind and Canvas view both land in
@@ -802,9 +806,9 @@ interface PaneLocale {
802
806
  * and "groups a document declares nothing for are absent" is the rule the whole popover follows.
803
807
  *
804
808
  * The fallback chain is what makes the control honest about a file it has not been told about:
805
- * `previewLocale` is the author's explicit choice, the path is the file's own language (§13.3 puts
806
- * a translation in its own directory), and the default locale is what an unprefixed page renders
807
- * as.
809
+ * `previewLocale` is the author's explicit choice, the path is the file's own language
810
+ * (`site-architecture.md` §13.3 puts a translation in its own directory), and the default locale is
811
+ * what an unprefixed page renders as.
808
812
  */
809
813
  function localeOf(tab: Tab | null): PaneLocale | null {
810
814
  const i18n = getEffectiveLocales();
@@ -949,7 +953,7 @@ function localeGroup(locale: PaneLocale | null): Partial<PaneContextView> {
949
953
  };
950
954
  }
951
955
 
952
- // ─── ⑩ The floating zoom pod ─────────────────────────────────────────────────
956
+ // ─── The floating zoom pod ───────────────────────────────────────────────────
953
957
 
954
958
  /** The fit entries the pod offers, in menu order. `1` is "actual size", a numeric fit. */
955
959
  const FIT_CHOICES: readonly { value: string; fit: FitMode; label: string }[] = [
@@ -970,13 +974,28 @@ function fitChoiceValue(fit: FitMode): string {
970
974
  /** The modes whose stage is the panzoom surface — the only ones with a fit to state. */
971
975
  const STAGE_ZOOM_MODES = new Set(["design", "stylebook", "git-diff"]);
972
976
 
977
+ /**
978
+ * The path this pane is comparing, or "" before it has a comparison.
979
+ *
980
+ * Resolved exactly as `canvas-render.ts`'s git-diff branch resolves the comparison it draws: a Diff
981
+ * lens carries its own, and every other pane draws the Source Control panel's one app-level slot.
982
+ * Both halves are reactive, so the pod repaints when either one lands or retargets.
983
+ */
984
+ function comparisonPathOf(paneId: string): string {
985
+ const derived = derivationOfPane(paneId);
986
+ const state =
987
+ derived?.kind === "lens" && derived.preset === "diff" ? derived.diff : shell.git.diffState;
988
+ return state?.filePath ?? "";
989
+ }
990
+
973
991
  /**
974
992
  * Zoom and fit, floating over the canvas bottom-right.
975
993
  *
976
994
  * Two surfaces, one control: `edit` drives the content-reflow `editZoom`, while design / Stylebook
977
995
  * / git-diff render on the panzoom surface and drive `ui.zoom` — and only the panzoom surface has a
978
996
  * fit, because a fit is a statement about an artboard. Preview is deliberately absent: its frame is
979
- * a real viewport that scrolls its own document, so there is nothing to zoom.
997
+ * a real viewport that scrolls its own document, so there is nothing to zoom. So is a comparison's
998
+ * CODE half, for the same reason: see below.
980
999
  */
981
1000
  function podFor(tab: Tab, paneId: string): Partial<PaneContextView> {
982
1001
  /* THIS pane's mode. `ctx.getCanvasMode()` answers for the focused pane, so the unfocused pod
@@ -993,6 +1012,15 @@ function podFor(tab: Tab, paneId: string): Partial<PaneContextView> {
993
1012
  if (!STAGE_ZOOM_MODES.has(mode)) {
994
1013
  return { podState: "hidden" };
995
1014
  }
1015
+ /* NO POD OVER A COMPARISON'S CODE HALF. That half is one Monaco diff editor filling the stage,
1016
+ with no panzoom surface under it, so `applyTransform` and `resetZoom` return early and + / − /
1017
+ 100% / Fit moved nothing but their own label. And it sat on Monaco's own scrollbar and diff
1018
+ overview ruler at the stage's right edge, which no native measurement can see. The predicate is
1019
+ the one the renderer chose the half with, so the two cannot disagree; `diff-view.ts` is not
1020
+ reactive, so the Visual/Code switch repaints this chrome itself (`diff-toolbar.ts`). */
1021
+ if (mode === "git-diff" && diffShowsCode(paneId, canRenderComparison(comparisonPathOf(paneId)))) {
1022
+ return { podState: "hidden" };
1023
+ }
996
1024
  const zoom = stageZoom(surface);
997
1025
  return {
998
1026
  fitOptions: FIT_CHOICES.map(({ label, value }) => ({ label, value })),
@@ -1011,7 +1039,7 @@ function podFor(tab: Tab, paneId: string): Partial<PaneContextView> {
1011
1039
  * These four controls wrote `session.ui` directly through `updateUi`, which is why none of the
1012
1040
  * three axes was a command: the popover WAS the capability, and the palette, the assistant and
1013
1041
  * `__jxAutomation` had no name for it. Going through the registry makes the control and the verb
1014
- * one thing (§2, principle 1) and gets the breakpoint refusal for free.
1042
+ * one thing (one definition site per action, §13) and gets the breakpoint refusal for free.
1015
1043
  */
1016
1044
  function runContextCommand(paneId: string, id: string, args: Record<string, unknown>): void {
1017
1045
  // THIS pane, named. The bar is drawn once per pane and the side bar's controls write the side
@@ -1161,7 +1189,7 @@ export function isResolvingOpen(paneId: string): boolean {
1161
1189
  * Open or close it.
1162
1190
  *
1163
1191
  * A named end state rather than a toggle, so `canvas.setResolvingOpen { open: false }` means the
1164
- * same thing twice and a screenshot can photograph it (§13's R1).
1192
+ * same thing twice and a screenshot can photograph it (R1, `scripts/screenshots/README.md`).
1165
1193
  *
1166
1194
  * It writes the panel and does NOT re-project the bar. A popover moves into the top layer while it
1167
1195
  * is open; nothing about the bar changes when it does, and the only thing the bar redraws for is
@@ -2,13 +2,14 @@
2
2
  /**
3
3
  * The pane grid — `workspace.panes`, given a visual counterpart.
4
4
  *
5
- * `workspace.panes` has been a real data model since P3: an ordered list, a focused id, a split, an
6
- * unsplit. Nothing drew it. `index.html` declared ONE each of `#tab-strip`, `#jump-bar`,
7
- * `#pane-chrome` and `#canvas-wrap` as flat siblings in `#app`'s grid — four surfaces that belong
8
- * to a PANE, laid out as rows and columns of the APPLICATION — so the shell could model two panes
9
- * and had somewhere to put exactly one. §18.3's stage handover was the workaround: one stage, taken
10
- * by whichever pane had focus, releasing the loser's artboards on the way past. This module is what
11
- * that scaffolding was standing in for, and the handover is deleted with it.
5
+ * `workspace.panes` has been a real data model since the shell redesign's chrome phase: an ordered
6
+ * list, a focused id, a split, an unsplit. Nothing drew it. `index.html` declared ONE each of
7
+ * `#tab-strip`, `#jump-bar`, `#pane-chrome` and `#canvas-wrap` as flat siblings in `#app`'s grid —
8
+ * four surfaces that belong to a PANE, laid out as rows and columns of the APPLICATION — so the
9
+ * shell could model two panes and had somewhere to put exactly one. §18.3's stage handover was the
10
+ * workaround: one stage, taken by whichever pane had focus, releasing the loser's artboards on the
11
+ * way past. This module is what that scaffolding was standing in for, and the handover is deleted
12
+ * with it.
12
13
  *
13
14
  * **The document owns the frame; this module owns the decisions.** `surfaces/pane-grid.json` is the
14
15
  * cells, the five boxes inside each one, the splitter between two of them and every rule that lays
@@ -50,7 +51,7 @@
50
51
  * `scale`, `min` and `max` closures that read `clientWidth` on every `pointermove` are gone, along
51
52
  * with the window-resize staleness they were paying for.
52
53
  *
53
- * The fourth rule of §18.1 — _a pane with nothing in it is a hole in the grid_ — is enforced in
54
+ * The third rule of §18.1 — _a pane with nothing in it is a hole in the grid_ — is enforced in
54
55
  * `workspace/workspace.ts`, where the tabs are. This module never repairs: repairing inside a
55
56
  * reactive effect that writes `workspace.panes` is an effect that triggers itself.
56
57
  */
@@ -5,17 +5,18 @@
5
5
  * A {@link PanelRecord} is to a surface what a `Command` is to an action: its name, the containment
6
6
  * level of the state it WRITES, the dock that hosts it, the predicate that decides whether it
7
7
  * exists at all, and the function that draws it. The rail, the panel header and the dock budget
8
- * become RENDERINGS of these records — plan §2 principle 1, applied to regions rather than verbs.
8
+ * become RENDERINGS of these records — one definition site per action (§13), applied to regions
9
+ * rather than verbs.
9
10
  *
10
11
  * It mirrors the shipped `settings/settings-modal.ts` contribution point
11
12
  * (`registerSettingsSection`) deliberately: a module-level `Map`, keyed by id, written by the
12
13
  * module that OWNS the surface. The one thing it adds is the field that makes the rail derivable —
13
14
  *
14
15
  * **`level` is required, and it is the level of the state the panel WRITES, not the state it
15
- * reads** (plan §2 principle 3). Insert reads the project's component registry and writes the
16
- * document tree, so it is `document`. Files reads documents and writes project files, so it is
17
- * `project`. That rule, and not intuition, is what settles every contested placement and what stops
18
- * the rail re-accreting: the two rail groups are two rows of
16
+ * reads** (§13.2). Insert reads the project's component registry and writes the document tree, so
17
+ * it is `document`. Files reads documents and writes project files, so it is `project`. That rule,
18
+ * and not intuition, is what settles every contested placement and what stops the rail
19
+ * re-accreting: the two rail groups are two rows of
19
20
  * {@link
20
21
  * import("../commands/levels").PANEL_PLACEMENT_MATRIX}, checked at registration exactly the
21
22
  * way a command's `menus` are.
@@ -99,15 +100,16 @@ export interface NavigatorPanelDeps {
99
100
  /**
100
101
  * The focused document, as a document-level panel reads it. `null` when no tab is open.
101
102
  *
102
- * A `level: "project"` panel must not read this — that is principle 3's corollary, and the reason
103
- * the Source Control badge used to vanish when the last tab closed. {@link registerPanel} cannot
104
- * enforce it (a closure's imports are not inspectable), so the contract is stated here and asserted
105
- * by `tests/panel-registry.test.ts`, which renders every project-level panel with `doc: null`.
103
+ * A `level: "project"` panel must not read this — that is `studio-ui-guidelines.md` §12.1's closing
104
+ * rule, and the reason the Source Control badge used to vanish when the last tab closed.
105
+ * {@link registerPanel} cannot enforce it (a closure's imports are not inspectable), so the contract
106
+ * is stated here and asserted by `tests/panel-registry.test.ts`, which renders every project-level
107
+ * panel with `doc: null`.
106
108
  */
107
109
  export interface NavigatorDocument {
108
110
  document: JxMutableNode;
109
111
  mode: string;
110
- /** The whole selection SET the navigator/inspector panels render against (§6.5). */
112
+ /** The whole selection SET the navigator/inspector panels render against (§6.7). */
111
113
  selection: JxPath[];
112
114
  canvas: Record<string, unknown> | null;
113
115
  content?: { frontmatter?: Record<string, unknown> } | undefined;
@@ -131,8 +133,23 @@ export type PanelBody = TemplateResult | typeof nothing;
131
133
  export interface PanelRecord {
132
134
  /** Lowercase, stable, and the value `view.setActivity` accepts — renaming one is a shot break. */
133
135
  id: string;
134
- /** The human name. The rail label AND the panel header, so there is one place it is spelled. */
136
+ /**
137
+ * The human name, spelled once: the panel header, the rail button's accessible name and tooltip,
138
+ * the `Show …` command and the chrome-budget row. The rail prints it under the glyph too, unless
139
+ * {@link PanelRecord.railLabel} says otherwise.
140
+ */
135
141
  title: string;
142
+ /**
143
+ * The rail button's visible text, for a title too long to sit under the glyph.
144
+ *
145
+ * The stacked label box is 48px at `--jx-text-xs` (10px), and "Source Control" is 71px, so the
146
+ * kit's ellipsis drew it as "Source …". Absent: the rail prints `title`. It must be a LEADING
147
+ * part of `title`, because the button's accessible name stays the title and the words on screen
148
+ * must be inside it (WCAG 2.5.3 Label in Name; best practice is that they lead it).
149
+ * {@link registerPanel} throws otherwise. Not derived from the title's first word, which would
150
+ * turn "Project Styles" into "Project": a record that needs a short name says which one.
151
+ */
152
+ railLabel?: string;
136
153
  /** REQUIRED. The level of the state this panel WRITES. Checked against the panel matrix. */
137
154
  level: Level;
138
155
  dock: PanelDock;
@@ -146,9 +163,9 @@ export interface PanelRecord {
146
163
  *
147
164
  * Not a hiding mechanism — a rail-less panel is still reachable by `view.setActivity`, by the
148
165
  * palette and by another surface linking to it. It is how a record survives the interval between
149
- * losing its rail slot and gaining its real home (Insert becomes an overlay in P3.5; State folds
150
- * into Data). Declaring it `false` also removes the panel's `rail/<level>` placement, which is
151
- * what keeps the rail inside its four-per-group budget.
166
+ * losing its rail slot and gaining its real home (Insert, reachable from the canvas and palette;
167
+ * State, folded into Data — §5.1). Declaring it `false` also removes the panel's `rail/<level>`
168
+ * placement, which is what keeps the rail inside its four-per-group budget.
152
169
  */
153
170
  rail?: boolean;
154
171
  /**
@@ -209,7 +226,8 @@ const PANEL_ID_PATTERN = /^[a-z][\w-]*$/;
209
226
  const panelRegistry = new Map<string, PanelRecord>();
210
227
 
211
228
  /**
212
- * Define a panel. Throws on a duplicate id, a malformed id, or a matrix violation.
229
+ * Define a panel. Throws on a duplicate id, a malformed id, a matrix violation, or a `railLabel`
230
+ * that is not a leading part of the title.
213
231
  *
214
232
  * Failing at registration is the same bet `createCommandRegistry.register` makes: a misplaced
215
233
  * surface is a design error, and a design error that only shows up as a wrong-looking rail is a
@@ -240,6 +258,16 @@ export function registerPanel(panel: PanelRecord): void {
240
258
  const detail = violations.map((violation) => ` ✗ ${panel.id} ${violation.message}`).join("\n");
241
259
  throw new Error(`Panel "${panel.id}" violates the level × placement matrix:\n${detail}`);
242
260
  }
261
+ if (
262
+ panel.railLabel !== undefined &&
263
+ (panel.railLabel.trim() === "" || !panel.title.startsWith(panel.railLabel))
264
+ ) {
265
+ throw new Error(
266
+ `Panel "${panel.id}" declares railLabel "${panel.railLabel}", which is not a leading part ` +
267
+ `of its title "${panel.title}": the rail button's accessible name is the title, and the ` +
268
+ `words on screen must be inside it (WCAG 2.5.3, Label in Name).`,
269
+ );
270
+ }
243
271
  panelRegistry.set(panel.id, panel);
244
272
  }
245
273
 
@@ -287,10 +315,10 @@ const RAIL_GROUP_LEVELS: readonly { level: Level; label: string }[] = [
287
315
  * Every panel that has a rail button, whatever dock draws its body.
288
316
  *
289
317
  * The rail is NOT the Navigator's tab strip. `panelPlacements()` has always awarded `rail/<level>`
290
- * on `rail !== false` alone — the dock is a separate placement — and Problems is the panel that
291
- * proves it: its body is the Bottom dock's first tab (plan §7.2), and it still owns a rail slot and
292
- * a badge, because "how many things need fixing" is a question you ask without opening anything.
293
- * Filtering this by `dock === "navigator"` is what would put the same list in two hosts at once.
318
+ * on `rail !== false` alone — the dock is a separate placement. Problems proved it for a release:
319
+ * its body is the Bottom dock's first tab, and it owned a rail slot and a badge until §16.3 took
320
+ * every Bottom-dock tab off the rail and put its count in the status bar. Filtering this by `dock
321
+ * === "navigator"` is what would put the same list in two hosts at once.
294
322
  */
295
323
  function railablePanels(): readonly PanelRecord[] {
296
324
  return listPanels().filter((panel) => panel.rail !== false);
@@ -1,8 +1,8 @@
1
1
  /// <reference lib="dom" />
2
2
  /**
3
- * Problems — everything that must be fixed, listed until it is (plan §7.1, §7.2).
3
+ * Problems — everything that must be fixed, listed until it is (§16.1, §16.3).
4
4
  *
5
- * `services/notify.ts` landed the RECORD in P4 wave A: a failure is a `Notification` with `tier:
5
+ * `services/notify.ts` landed the RECORD first: a failure is a `Notification` with `tier:
6
6
  * "problem"`, which means the app promises to keep it until somebody fixes it. This is the surface
7
7
  * that keeps the promise. Until it existed, `problems` was a reactive array with a count (the rail
8
8
  * badge, the status bar) and no way to read what was in it.
@@ -41,11 +41,10 @@
41
41
  * it mounts, so it answers with the call the dock already made: `render` runs for the active tab
42
42
  * only, and `afterRender` consumes what it left.
43
43
  *
44
- * **One record, one host.** Problems lives in the BOTTOM DOCK — plan §7.2's table says so outright
45
- * ("Problems | Bottom dock ⑪, badge on the rail") and §3.2 ⑪ makes it the dock's first tab. §3.2 ③
46
- * also lists it among the Navigator's panels; that line loses, because a list open in two docks at
47
- * once is two hosts for one record, and hosting it in the Navigator spends left-dock width on
48
- * something that belongs under the pane grid.
44
+ * **One record, one host.** Problems lives in the BOTTOM DOCK, as its first tab (§16.3). The shell
45
+ * redesign also listed it among the Navigator's panels; that line lost, because a list open in two
46
+ * docks at once is two hosts for one record, and hosting it in the Navigator spends left-dock width
47
+ * on something that belongs under the pane grid.
49
48
  *
50
49
  * **And no rail button.** It had one, in the PROJECT group, which meant a control on the far left
51
50
  * that opened a dock along the bottom — the rail carried a per-dock branch in three places to keep
@@ -272,12 +271,12 @@ export function syncProblemsSurface(host: HTMLElement): void {
272
271
  }
273
272
 
274
273
  /**
275
- * Define the Problems panel — the P3 placeholder, built.
274
+ * Define the Problems panel — the chrome phase's placeholder, built.
276
275
  *
277
- * P3 registered this id with `when: () => false` and a `render` that threw: "declared in the design
278
- * and not yet in the app", holding the rail slot §3.2 ② had already spent so the budget counted it
279
- * from the day it was named. This is the edit that phase described — the predicate is gone, the
280
- * body is real, and the badge is live.
276
+ * The shell redesign's chrome phase registered this id with `when: () => false` and a `render` that
277
+ * threw: "declared in the design and not yet in the app", holding a Navigator rail slot so the
278
+ * budget counted it from the day it was named. This is the edit that phase described — the
279
+ * predicate is gone, the body is real, and the badge is live.
281
280
  *
282
281
  * One caller: `panels/bottom-dock.ts`'s {@link import("./bottom-dock").registerBottomPanels}, which
283
282
  * is the module that owns the dock this record is drawn in. `registerPanel` throws on a duplicate