@jxsuite/studio 5.2.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 (398) hide show
  1. package/data/css-meta.json +28 -27
  2. package/dist/chunks/{cf-account-picker-h4dab9bq.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-sgg1sv6n.js → content-source-jt7rbcbc.js} +22 -22
  6. package/dist/chunks/{convert-to-repeater-mf1cxgfn.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-c6zwzbre.js → extension-sections-r73an5s6.js} +31 -30
  10. package/dist/chunks/{file-ops-vrpq1jjk.js → file-ops-3xan8mnj.js} +21 -21
  11. package/dist/chunks/{files-msaf95y6.js → files-egsb0ry8.js} +30 -29
  12. package/dist/chunks/{format-host-f64fnesp.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-bv5e22j0.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-paj67nr5.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-dh5np8vk.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/{jx-validate-j0wxk72w.js → jx-validate-epp2z3s3.js} +2 -2
  25. package/dist/chunks/layers-panel-83a16ytx.js +41 -0
  26. package/dist/chunks/{layers-1vcfdbet.js → layers-s6mc01ry.js} +3 -3
  27. package/dist/chunks/{listbox-6v2ac08j.js → listbox-b7jxnhq1.js} +19 -3
  28. package/dist/chunks/{media-picker-p49nhqhs.js → media-picker-nhn6rv4w.js} +11 -11
  29. package/dist/chunks/{menu-qht48vnc.js → menu-8j4qxjrp.js} +4 -4
  30. package/dist/chunks/{monaco-binding-sw6en4dw.js → monaco-binding-e8d9wzyk.js} +3 -3
  31. package/dist/chunks/{monaco-buffer-pykwbm92.js → monaco-buffer-jaq1t9zj.js} +2 -2
  32. package/dist/chunks/{monaco-setup-8vbyqnhr.css → monaco-setup-ey9cjcm3.css} +954 -137
  33. package/dist/chunks/{monaco-setup-8r62fj6y.js → monaco-setup-gsjdysze.js} +7 -7
  34. package/dist/chunks/{platform-ts9cg1a4.js → platform-fnchmhy7.js} +5 -3
  35. package/dist/chunks/publish-panel-ak6hxfma.js +27 -0
  36. package/dist/chunks/quick-search-c63mkt3b.js +47 -0
  37. package/dist/chunks/{references-h69xp9zz.js → references-f7bdv3z5.js} +3 -3
  38. package/dist/chunks/right-panel-t5n8wttg.js +45 -0
  39. package/dist/chunks/{split-g7nm1rgb.js → split-4cz4b6ef.js} +14 -3
  40. package/dist/chunks/{studio-sar8g54p.js → studio-01269reb.js} +8 -8
  41. package/dist/chunks/{studio-rnyf3f8e.js → studio-0a4gncx0.js} +3 -3
  42. package/dist/chunks/{studio-e1f24eff.js → studio-0d4p4wxj.js} +6778 -2993
  43. package/dist/chunks/{studio-4wbb9ct0.js → studio-1tejxvba.js} +3006 -1855
  44. package/dist/chunks/{studio-p6pmwkvh.js → studio-3nprwbd9.js} +147 -28
  45. package/dist/chunks/{studio-4c041r8y.js → studio-40z39dme.js} +3 -3
  46. package/dist/chunks/{studio-68fydsrj.js → studio-482eeazk.js} +20 -20
  47. package/dist/chunks/{studio-y4f9fdge.js → studio-4998spet.js} +10 -9
  48. package/dist/chunks/{studio-nq5yf5mp.js → studio-557bmn0x.js} +2 -2
  49. package/dist/chunks/{studio-hdc2jt3z.js → studio-5w26wza5.js} +3 -3
  50. package/dist/chunks/{studio-6nzaktvy.js → studio-6pwn9j8c.js} +6 -3
  51. package/dist/chunks/{studio-wnsyffg1.js → studio-6vg0x5fz.js} +3 -2
  52. package/dist/chunks/{studio-vn5hske5.js → studio-7d3c1m59.js} +12 -5
  53. package/dist/chunks/{studio-28vs5k2y.js → studio-9vsvz7w7.js} +7 -7
  54. package/dist/chunks/{studio-t3adrr56.js → studio-9wm0xzpf.js} +19 -19
  55. package/dist/chunks/{studio-38emantv.js → studio-a5h5j33a.js} +19 -5
  56. package/dist/chunks/{studio-ympe0n7a.js → studio-ag3z6shb.js} +10 -4
  57. package/dist/chunks/studio-aj9drheq.js +177 -0
  58. package/dist/chunks/{studio-vt0tj32j.js → studio-apv9x70c.js} +189 -130
  59. package/dist/chunks/{studio-c04nzbby.js → studio-b9q3znz8.js} +2 -2
  60. package/dist/chunks/{studio-2mdbbc76.js → studio-bh47w0cy.js} +9 -10
  61. package/dist/chunks/{studio-ez11dmdh.js → studio-dgdm6vvt.js} +264 -52
  62. package/dist/chunks/{studio-5nz00bhh.js → studio-dwdcr2e8.js} +4 -4
  63. package/dist/chunks/{studio-nqgawfks.js → studio-fbcyz234.js} +146 -139
  64. package/dist/chunks/{studio-kcgff4r0.js → studio-fgmfksz8.js} +2 -2
  65. package/dist/chunks/{studio-x72j58vw.js → studio-fqpkpq1t.js} +7 -4
  66. package/dist/chunks/{studio-15f3kxqe.js → studio-fy320dfc.js} +62 -68
  67. package/dist/chunks/{studio-zjjde71a.js → studio-gjj4bbfx.js} +2 -2
  68. package/dist/chunks/{studio-66arbpc2.js → studio-jfhxy8h3.js} +16 -15
  69. package/dist/chunks/{studio-d0300636.js → studio-ks2zzth2.js} +17 -2
  70. package/dist/chunks/{studio-c07s5ckd.js → studio-kwewmhhq.js} +4 -4
  71. package/dist/chunks/{studio-01jeck2y.js → studio-m58xn8at.js} +26 -25
  72. package/dist/chunks/{studio-mpzwze9x.js → studio-mfkh1q8d.js} +17 -17
  73. package/dist/chunks/{studio-etvx9s2g.js → studio-mrh0a92f.js} +17 -17
  74. package/dist/chunks/{studio-qa7fzxan.js → studio-mt79tn56.js} +3 -3
  75. package/dist/chunks/{studio-hhskq2mr.js → studio-ne593z1j.js} +39 -32
  76. package/dist/chunks/{studio-h4nvnjvz.js → studio-ptfcxkz5.js} +418 -232
  77. package/dist/chunks/{studio-4xmjcrg3.js → studio-qxye31h7.js} +7 -7
  78. package/dist/chunks/{studio-a1pswps3.js → studio-rav5bpmp.js} +81 -59
  79. package/dist/chunks/{studio-ncn9e189.js → studio-rwmmbrth.js} +6 -6
  80. package/dist/chunks/{studio-en82c639.js → studio-sceg8ws0.js} +8 -8
  81. package/dist/chunks/{studio-wjpgxywa.js → studio-sjas5b3a.js} +19 -13
  82. package/dist/chunks/{studio-4r14yzyy.js → studio-vd67b66d.js} +3 -3
  83. package/dist/chunks/{studio-14d9tq4d.js → studio-w475cbf9.js} +10 -10
  84. package/dist/chunks/{studio-ctm7bhx5.js → studio-w7gpcvfj.js} +9 -9
  85. package/dist/chunks/{studio-9j6sfeba.js → studio-xrbfdxgk.js} +7 -7
  86. package/dist/chunks/{studio-x10fp4tp.js → studio-y49b6mjv.js} +35 -35
  87. package/dist/chunks/{studio-5t7ena5z.js → studio-ygvr9e4q.js} +10 -10
  88. package/dist/chunks/{studio-z2smx5ce.js → studio-yxmmjy2a.js} +9 -6
  89. package/dist/chunks/{tsMode-jy4m86rv.js → tsMode-ay4c78ne.js} +4 -4
  90. package/dist/chunks/{tsMode-hnxxb73h.css → tsMode-c72wyz27.css} +954 -137
  91. package/dist/chunks/{workspace-bnw54cha.js → workspace-b9k2frks.js} +5 -5
  92. package/dist/chunks/{ws-client-ny4zc51r.js → ws-client-erze4czt.js} +356 -20
  93. package/dist/codicon.ttf +0 -0
  94. package/dist/iframe-entry.js +20 -18
  95. package/dist/studio.css +956 -139
  96. package/dist/studio.js +1511 -851
  97. package/dist/workers/editor.worker.js +196 -107
  98. package/dist/workers/json.worker.js +196 -107
  99. package/dist/workers/ts.worker.js +196 -107
  100. package/package.json +18 -17
  101. package/src/about/about-modal.ts +4 -3
  102. package/src/browse/library-commands.ts +15 -13
  103. package/src/browse/library-pane.ts +2 -2
  104. package/src/canvas/canvas-render.ts +97 -83
  105. package/src/canvas/canvas-surface.ts +2 -2
  106. package/src/canvas/canvas-utils.ts +42 -32
  107. package/src/canvas/diff-toolbar.ts +21 -2
  108. package/src/canvas/diff-view.ts +30 -6
  109. package/src/canvas/iframe-entry.ts +2 -2
  110. package/src/canvas/iframe-host.ts +5 -5
  111. package/src/canvas/iframe-interaction.ts +7 -6
  112. package/src/canvas/iframe-overlay.ts +1 -1
  113. package/src/canvas/iframe-protocol.ts +6 -5
  114. package/src/canvas/iframe-render.ts +3 -3
  115. package/src/canvas/popover-state.ts +1 -1
  116. package/src/canvas/stage-scrollbar.ts +112 -0
  117. package/src/canvas/surface-registry.ts +9 -2
  118. package/src/collab/collab-commands.ts +8 -6
  119. package/src/collab/collab-session.ts +4 -4
  120. package/src/collab/collab-state.ts +4 -4
  121. package/src/collab/presence-chips.ts +3 -3
  122. package/src/commands/app-commands.ts +7 -7
  123. package/src/commands/budget.ts +17 -16
  124. package/src/commands/command-args.ts +10 -9
  125. package/src/commands/context.ts +20 -10
  126. package/src/commands/defaults.ts +30 -29
  127. package/src/commands/levels.ts +8 -6
  128. package/src/commands/live-context.ts +12 -10
  129. package/src/commands/reference.ts +5 -5
  130. package/src/commands/registry.ts +2 -2
  131. package/src/content/draft-state.ts +9 -8
  132. package/src/content/entry-commands.ts +16 -14
  133. package/src/content/entry-editor.ts +2 -2
  134. package/src/content/entry-fields.ts +1 -1
  135. package/src/editor/context-menu.ts +4 -4
  136. package/src/editor/convert-to-component.ts +6 -5
  137. package/src/editor/inline-edit.ts +3 -3
  138. package/src/editor/shortcuts.ts +88 -20
  139. package/src/editor/slash-menu.ts +11 -10
  140. package/src/files/elements.ts +4 -5
  141. package/src/files/file-ops.ts +1 -1
  142. package/src/files/files.ts +21 -17
  143. package/src/files/serialize-document.ts +1 -1
  144. package/src/format/convert-file.ts +5 -5
  145. package/src/github/github-auth-status.ts +107 -0
  146. package/src/github/github-auth.ts +18 -82
  147. package/src/github/github-publish.ts +7 -6
  148. package/src/grid/cell-editors.ts +8 -7
  149. package/src/grid/grid-layout.ts +1 -1
  150. package/src/grid/grid-open.ts +6 -5
  151. package/src/grid/grid-panel.ts +13 -12
  152. package/src/grid/redirects-grid.ts +14 -11
  153. package/src/grid/redirects.ts +10 -5
  154. package/src/grid/sources/content-source.ts +10 -9
  155. package/src/hosting/document.ts +28 -1
  156. package/src/hosting/stage.ts +15 -4
  157. package/src/i18n/i18n-commands.ts +9 -7
  158. package/src/new-project/location-fields.ts +16 -3
  159. package/src/new-project/new-project-modal.ts +23 -7
  160. package/src/page-params.ts +6 -6
  161. package/src/panels/activity-panel.ts +11 -10
  162. package/src/panels/ai-chat/chat-view.ts +27 -14
  163. package/src/panels/ai-chat/composer.ts +10 -3
  164. package/src/panels/ai-panel.ts +87 -29
  165. package/src/panels/block-action-bar.ts +59 -33
  166. package/src/panels/bottom-dock.ts +22 -22
  167. package/src/panels/chat-panel.ts +40 -5
  168. package/src/panels/data-explorer.ts +9 -9
  169. package/src/panels/data-grid.ts +1 -1
  170. package/src/panels/editors.ts +8 -8
  171. package/src/panels/elements-panel.ts +7 -8
  172. package/src/panels/empty-state.ts +1 -1
  173. package/src/panels/events-panel.ts +13 -12
  174. package/src/panels/formula-workspace.ts +8 -5
  175. package/src/panels/frontmatter-fields.ts +4 -1
  176. package/src/panels/frontmatter-panel.ts +18 -18
  177. package/src/panels/git-panel.ts +19 -13
  178. package/src/panels/head-panel.ts +9 -10
  179. package/src/panels/i18n-panel.ts +6 -4
  180. package/src/panels/imports-panel.ts +1 -1
  181. package/src/panels/jump-bar.ts +20 -18
  182. package/src/panels/layers-panel.ts +19 -17
  183. package/src/panels/left-panel.ts +3 -3
  184. package/src/panels/navigator-panels.ts +8 -8
  185. package/src/panels/overlays.ts +1 -1
  186. package/src/panels/pane-context.ts +56 -28
  187. package/src/panels/pane-grid.ts +9 -8
  188. package/src/panels/panel-registry.ts +47 -19
  189. package/src/panels/problems-panel.ts +11 -12
  190. package/src/panels/properties-panel.ts +21 -20
  191. package/src/panels/provenance.ts +3 -3
  192. package/src/panels/quick-search.ts +15 -11
  193. package/src/panels/right-panel.ts +4 -3
  194. package/src/panels/seo-modal.ts +5 -4
  195. package/src/panels/settings-menu.ts +9 -9
  196. package/src/panels/settings-pane.ts +3 -3
  197. package/src/panels/signals-panel.ts +16 -9
  198. package/src/panels/statement-editor.ts +12 -9
  199. package/src/panels/style-panel.ts +45 -41
  200. package/src/panels/stylebook-panel.ts +0 -1
  201. package/src/panels/tab-strip.ts +26 -23
  202. package/src/platform-errors.ts +2 -2
  203. package/src/platform.ts +44 -4
  204. package/src/platforms/cloud.ts +11 -1
  205. package/src/platforms/default-platform.ts +141 -4
  206. package/src/platforms/devserver.ts +23 -3
  207. package/src/publish/deploy-checklist.ts +11 -10
  208. package/src/publish/publish-commands.ts +9 -8
  209. package/src/services/a11y-report.ts +1 -1
  210. package/src/services/ai-ask.ts +39 -16
  211. package/src/services/ai-command-tools.ts +28 -14
  212. package/src/services/ai-import-tools.ts +43 -29
  213. package/src/services/ai-project-tools.ts +20 -38
  214. package/src/services/ai-settings.ts +55 -2
  215. package/src/services/ai-tools.ts +69 -58
  216. package/src/services/ai-write-report.ts +4 -4
  217. package/src/services/ai-writes.ts +74 -55
  218. package/src/services/automation.ts +12 -12
  219. package/src/services/clock.ts +2 -1
  220. package/src/services/connection.ts +2 -2
  221. package/src/services/context-manager.ts +69 -6
  222. package/src/services/directory-picker.ts +93 -27
  223. package/src/services/document-assistant.ts +86 -17
  224. package/src/services/gated-registry.ts +4 -3
  225. package/src/services/idle.ts +5 -4
  226. package/src/services/live-surfaces.ts +2 -1
  227. package/src/services/module-preloads.ts +67 -0
  228. package/src/services/notify.ts +9 -7
  229. package/src/services/popover-report.ts +3 -3
  230. package/src/services/preview-eval.ts +1 -1
  231. package/src/services/project-adoption.ts +34 -1
  232. package/src/services/project-path.ts +53 -0
  233. package/src/services/settings/kernel.ts +13 -2
  234. package/src/services/tool-executor.ts +135 -30
  235. package/src/services/tool-outcomes.ts +143 -0
  236. package/src/settings/contexts-section.ts +8 -8
  237. package/src/settings/contributed-section.ts +6 -6
  238. package/src/settings/css-vars-editor.ts +6 -5
  239. package/src/settings/extension-commands.ts +19 -18
  240. package/src/settings/extension-sections.ts +7 -7
  241. package/src/settings/extensions-section.ts +3 -3
  242. package/src/settings/general-settings.ts +21 -18
  243. package/src/settings/preferences-accounts.ts +3 -3
  244. package/src/settings/preferences-dialog.ts +9 -8
  245. package/src/settings/preferences-sections.ts +1 -1
  246. package/src/settings/project-sections.ts +2 -2
  247. package/src/settings/section-registry.ts +7 -6
  248. package/src/settings/settings-document.ts +41 -43
  249. package/src/shell/tree.ts +29 -0
  250. package/src/shell.ts +63 -55
  251. package/src/site-context.ts +1 -1
  252. package/src/store.ts +2 -2
  253. package/src/studio.ts +52 -28
  254. package/src/style/live-preview.ts +8 -8
  255. package/src/style/project-styles.ts +8 -9
  256. package/src/style/token-ref.ts +2 -2
  257. package/src/surfaces/about.json +6 -2
  258. package/src/surfaces/add-repo.json +2 -2
  259. package/src/surfaces/add-repo.ts +2 -2
  260. package/src/surfaces/ai-chat.json +14 -6
  261. package/src/surfaces/ai-chat.ts +4 -2
  262. package/src/surfaces/ai-credentials-form.json +53 -49
  263. package/src/surfaces/ai-credentials-form.ts +18 -4
  264. package/src/surfaces/ai-managed-connect.json +4 -4
  265. package/src/surfaces/block-action-bar.json +4 -4
  266. package/src/surfaces/block-action-bar.ts +3 -3
  267. package/src/surfaces/boot-failure.json +228 -0
  268. package/src/surfaces/boot-failure.ts +156 -0
  269. package/src/surfaces/bottom-dock.json +1 -1
  270. package/src/surfaces/canvas-stage.json +9 -40
  271. package/src/surfaces/canvas-stage.ts +9 -9
  272. package/src/surfaces/cf-account-picker.json +11 -8
  273. package/src/surfaces/commandbar.ts +11 -10
  274. package/src/surfaces/convert-repeater.ts +3 -2
  275. package/src/surfaces/dialog.json +7 -1
  276. package/src/surfaces/dialog.ts +2 -2
  277. package/src/surfaces/doc-header.json +6 -13
  278. package/src/surfaces/doc-header.ts +4 -5
  279. package/src/surfaces/entry-editor.json +1 -1
  280. package/src/surfaces/entry-editor.ts +2 -1
  281. package/src/surfaces/expression-editor.json +5 -5
  282. package/src/surfaces/files-panel.json +4 -3
  283. package/src/surfaces/files-panel.ts +1 -1
  284. package/src/surfaces/formula-palette.json +10 -9
  285. package/src/surfaces/formula-palette.ts +11 -7
  286. package/src/surfaces/git-panel.json +167 -109
  287. package/src/surfaces/git-panel.ts +2 -2
  288. package/src/surfaces/github-auth.json +2 -1
  289. package/src/surfaces/github-publish.ts +3 -3
  290. package/src/surfaces/grid-open.json +1 -1
  291. package/src/surfaces/grid-panel.json +2 -2
  292. package/src/surfaces/grid-views.json +1 -1
  293. package/src/surfaces/inspector-dock.json +2 -2
  294. package/src/surfaces/jump-bar.json +1 -1
  295. package/src/surfaces/jump-bar.ts +1 -1
  296. package/src/surfaces/library-pane.ts +2 -1
  297. package/src/surfaces/logic-panel.json +7 -7
  298. package/src/surfaces/logic-panel.ts +6 -4
  299. package/src/surfaces/logic-workspace.json +2 -2
  300. package/src/surfaces/logic-workspace.ts +2 -2
  301. package/src/surfaces/media-browser.ts +3 -3
  302. package/src/surfaces/media-pane.ts +2 -1
  303. package/src/surfaces/menu.ts +5 -5
  304. package/src/surfaces/new-project.json +1 -1
  305. package/src/surfaces/palette.json +8 -7
  306. package/src/surfaces/pane-context.json +86 -57
  307. package/src/surfaces/pane-context.ts +2 -1
  308. package/src/surfaces/pane-grid.json +3 -3
  309. package/src/surfaces/panel-activity.json +2 -1
  310. package/src/surfaces/panel-deploy-checklist.json +1 -1
  311. package/src/surfaces/panel-elements.ts +2 -1
  312. package/src/surfaces/panel-i18n.ts +2 -1
  313. package/src/surfaces/panel-outline.json +1 -1
  314. package/src/surfaces/panel-outline.ts +4 -3
  315. package/src/surfaces/panel-page.json +2 -2
  316. package/src/surfaces/panel-page.ts +4 -1
  317. package/src/surfaces/panel-problems.json +4 -3
  318. package/src/surfaces/panel-problems.ts +2 -2
  319. package/src/surfaces/panel-signals.json +23 -8
  320. package/src/surfaces/panel-signals.ts +5 -1
  321. package/src/surfaces/panel-stylebook-layers.json +1 -1
  322. package/src/surfaces/panel-stylebook-layers.ts +2 -2
  323. package/src/surfaces/preferences.json +21 -8
  324. package/src/surfaces/preferences.ts +9 -1
  325. package/src/surfaces/properties-panel.json +4 -4
  326. package/src/surfaces/properties-panel.ts +2 -2
  327. package/src/surfaces/publish.json +1 -1
  328. package/src/surfaces/publish.ts +2 -1
  329. package/src/surfaces/push-plan.json +4 -3
  330. package/src/surfaces/rail.json +2 -2
  331. package/src/surfaces/rail.ts +10 -4
  332. package/src/surfaces/reference-field.json +1 -1
  333. package/src/surfaces/schema-form.json +2 -2
  334. package/src/surfaces/schema-form.ts +1 -1
  335. package/src/surfaces/seo.json +1 -1
  336. package/src/surfaces/seo.ts +2 -2
  337. package/src/surfaces/settings-contributed.ts +2 -1
  338. package/src/surfaces/settings-css-vars.json +4 -4
  339. package/src/surfaces/settings-deploy.json +4 -4
  340. package/src/surfaces/settings-deploy.ts +2 -1
  341. package/src/surfaces/settings-extensions.json +6 -6
  342. package/src/surfaces/settings-extensions.ts +6 -2
  343. package/src/surfaces/settings-locales.json +4 -4
  344. package/src/surfaces/settings-overview.ts +2 -1
  345. package/src/surfaces/settings-pane.ts +3 -2
  346. package/src/surfaces/settings-rawjson.ts +1 -1
  347. package/src/surfaces/slash-menu.ts +4 -4
  348. package/src/surfaces/statements.json +3 -3
  349. package/src/surfaces/statusbar.ts +23 -23
  350. package/src/surfaces/style-panel.json +9 -5
  351. package/src/surfaces/style-panel.ts +3 -3
  352. package/src/surfaces/tab-strip.json +2 -2
  353. package/src/surfaces/target-line.json +1 -1
  354. package/src/surfaces/target-line.ts +12 -10
  355. package/src/surfaces/welcome.json +7 -2
  356. package/src/tabs/doc-op-apply.ts +5 -5
  357. package/src/tabs/patch-ops.ts +3 -3
  358. package/src/tabs/project-config.ts +10 -10
  359. package/src/tabs/selection.ts +1 -1
  360. package/src/tabs/tab.ts +13 -14
  361. package/src/tabs/transact.ts +18 -24
  362. package/src/types.ts +27 -3
  363. package/src/ui/ai-credentials-form.ts +74 -16
  364. package/src/ui/ai-managed-connect.ts +68 -19
  365. package/src/ui/color-selector.ts +1 -1
  366. package/src/ui/expression-editor.ts +3 -3
  367. package/src/ui/form-controls.ts +6 -5
  368. package/src/ui/formula-catalog.ts +4 -4
  369. package/src/ui/formula-chips.ts +2 -2
  370. package/src/ui/layers.ts +20 -18
  371. package/src/ui/panel-resize.ts +8 -28
  372. package/src/ui/popover-surface.ts +2 -2
  373. package/src/ui/progress-modal.ts +3 -3
  374. package/src/ui/regions.ts +14 -9
  375. package/src/ui/schema-form.ts +10 -9
  376. package/src/ui/timing.ts +9 -7
  377. package/src/ui/value-source.ts +4 -4
  378. package/src/ui/virtual-window.ts +58 -5
  379. package/src/utils/base64.ts +20 -1
  380. package/src/utils/canvas-media.ts +1 -1
  381. package/src/utils/studio-utils.ts +0 -31
  382. package/src/view.ts +4 -3
  383. package/src/workspace/pane-derive.ts +14 -13
  384. package/src/workspace/session.ts +7 -6
  385. package/src/workspace/workspace.ts +49 -39
  386. package/styles/canvas.css +1 -27
  387. package/styles/inspector.css +4 -3
  388. package/styles/overlays.css +1 -1
  389. package/styles/tokens.css +17 -1
  390. package/styles/tokens.json +6 -1
  391. package/dist/chunks/entry-commands-w9qsxa6q.js +0 -42
  392. package/dist/chunks/layers-panel-fksbdg4q.js +0 -40
  393. package/dist/chunks/publish-panel-vz23wwmg.js +0 -27
  394. package/dist/chunks/quick-search-e9rp74m8.js +0 -46
  395. package/dist/chunks/right-panel-j97t2yvy.js +0 -45
  396. package/dist/chunks/studio-727xh0e3.js +0 -76
  397. package/src/files/json-layout.ts +0 -474
  398. package/src/services/ai-turn-signal.ts +0 -70
@@ -163,7 +163,11 @@
163
163
  "fontSize": "var(--jx-text-xs)",
164
164
  "color": "var(--fg-dim)"
165
165
  },
166
- "& [part=\"bar-segments\"], & [part=\"bar-buttons\"]": {
166
+ "& [part=\"bar-segments\"]": {
167
+ "$description": "The Body switch is the kit's segmented control, which draws its own row, frame and selected segment; all the bar asks of it is not to shrink.",
168
+ "flex": "none"
169
+ },
170
+ "& [part=\"bar-buttons\"]": {
167
171
  "display": "flex",
168
172
  "flex": "none",
169
173
  "alignItems": "center"
@@ -1172,11 +1176,17 @@
1172
1176
  "textContent": "${$map.item.label}"
1173
1177
  },
1174
1178
  {
1175
- "tagName": "span",
1179
+ "$description": "The mode switch is the kit's radiogroup, as the Logic panel's Handler body is. It was a `span` with `role=group` over buttons that carried `selected` alone: the one Spectrum `compact` group the conversion never reached, so it drew as two loose words and announced neither which mode was on nor that the two exclude each other. `checked` makes each segment a radio, so the caret roves and `aria-checked` is the element's own.",
1180
+ "tagName": "jx-action-group",
1176
1181
  "attributes": {
1177
- "part": "bar-segments",
1178
- "role": "group",
1179
- "aria-label": "${$map.item.label}"
1182
+ "part": "bar-segments"
1183
+ },
1184
+ "$props": {
1185
+ "selects": "single",
1186
+ "compact": true,
1187
+ "label": {
1188
+ "$ref": "$map/item/label"
1189
+ }
1180
1190
  },
1181
1191
  "children": [
1182
1192
  {
@@ -1198,11 +1208,16 @@
1198
1208
  "label": {
1199
1209
  "$ref": "$map/item/label"
1200
1210
  },
1201
- "selected": {
1202
- "$ref": "$map/item/selected"
1211
+ "checked": {
1212
+ "$ref": "$map/item/checked"
1203
1213
  }
1204
1214
  },
1205
- "textContent": "${$map.item.label}",
1215
+ "children": [
1216
+ {
1217
+ "tagName": "span",
1218
+ "textContent": "${$map.item.label}"
1219
+ }
1220
+ ],
1206
1221
  "onclick": {
1207
1222
  "$prototype": "Function",
1208
1223
  "body": [
@@ -93,7 +93,11 @@ export interface SignalCellRowView {
93
93
  export interface SignalSegmentView {
94
94
  key: string;
95
95
  label: string;
96
- selected: boolean;
96
+ /**
97
+ * `"true"` / `"false"`: the switch is a radiogroup, and a segment is a radio only while `checked`
98
+ * is non-empty. It also draws the segment selected, so there is no separate `selected`.
99
+ */
100
+ checked: "true" | "false";
97
101
  signal: string;
98
102
  field: string;
99
103
  }
@@ -95,7 +95,7 @@
95
95
  "whiteSpace": "nowrap"
96
96
  },
97
97
  "& [part=\"empty\"]": {
98
- "$description": "Drawn here rather than borrowed from `panels/empty-state.ts`, which is a lit template a document cannot call. What is kept is the pattern's rules (§11): one sentence saying what the region is for, then where its content comes from.",
98
+ "$description": "Drawn here rather than borrowed from `panels/empty-state.ts`, which is a lit template a document cannot call. What is kept is the pattern's rules (studio-ui-guidelines.md §11): one sentence saying what the region is for, then where its content comes from.",
99
99
  "display": "flex",
100
100
  "flexDirection": "column",
101
101
  "alignItems": "center",
@@ -108,8 +108,8 @@ function project(scope: StylebookLayersScope, values: StylebookLayersValues): vo
108
108
  *
109
109
  * Nothing is called on the elements, so the mount is all this has to wait for: the DOCUMENT is what
110
110
  * this surface renders, and the kit elements inside it settle their own templates one
111
- * `connectedCallback` later without anybody here asking them to (guidelines §1.1, "await the
112
- * element").
111
+ * `connectedCallback` later without anybody here asking them to (studio-ui-guidelines.md §1.1,
112
+ * "await the element").
113
113
  */
114
114
  export function mountStylebookLayersSurface(
115
115
  container: HTMLElement,
@@ -85,7 +85,8 @@
85
85
  "maxHeight": "60vh",
86
86
  "overflowY": "auto"
87
87
  },
88
- "& [part=\"title\"]": {
88
+ "& [part=\"section\"] > [part=\"title\"]": {
89
+ "$description": "The sheet's own heading, and a CHILD selector because the Assistant section mounts other documents into this one's light DOM: the credentials form draws a `[part=\"title\"]` of its own (\"AI provider key\"), and as a bare descendant this rule set the section heading's size on it. A host styles the boxes it draws, never a name its guest also uses — `tests/surface-part-names.test.ts` holds the island hosts to that.",
89
90
  "margin": "0",
90
91
  "fontSize": "var(--jx-text-lg)",
91
92
  "color": "var(--fg)"
@@ -121,8 +122,10 @@
121
122
  "gap": "var(--jx-space-2)"
122
123
  },
123
124
  "& [part=\"account\"]": {
125
+ "$description": "A wrapping row (studio-ui-guidelines.md §4.6): the sentence and the actions share one line while the sentence keeps its basis, and the actions drop under it when they would not. A brokered Cloudflare row carries two actions (Reconnect or Choose account, beside Disconnect), and on one line they squeezed the sentence into a column about 114px wide at the default width. Every single-action row measures exactly what it did before the wrap existed. `align-items: flex-start`, not `center`, because the sentence's height is not the row's: the AI row's endpoint wraps to five lines, and centred that put Disconnect level with the fourth line of a URL while the heading it acts on sat at the top, so the card read as two unrelated things. Pinned to the start, the button is always beside its label.",
124
126
  "display": "flex",
125
- "alignItems": "center",
127
+ "flexWrap": "wrap",
128
+ "alignItems": "flex-start",
126
129
  "justifyContent": "space-between",
127
130
  "gap": "var(--jx-space-4)",
128
131
  "padding": "var(--jx-space-3)",
@@ -130,8 +133,9 @@
130
133
  "borderRadius": "var(--radius)"
131
134
  },
132
135
  "& [part=\"account-text\"]": {
133
- "$description": "`min-width: 0` so a long detail sentence ellipses inside the row rather than pushing the row's own buttons off the end of it.",
136
+ "$description": "The wrap threshold is this basis, not a width: 120px of sentence is the least a row keeps before its actions take a line of their own. Keep it well under 200px, or a single-action row at the default sheet width wraps at rest. `min-width: 0` lets the column shrink below its content, and what then fits the detail into it is the detail's own `overflow-wrap`. Nothing here ellipsizes: the detail is the only place the row names its endpoint or account, so a truncated one would hide exactly the part that tells two of them apart.",
134
137
  "display": "flex",
138
+ "flex": "1 1 120px",
135
139
  "flexDirection": "column",
136
140
  "gap": "var(--jx-space-1)",
137
141
  "minWidth": "0"
@@ -140,19 +144,25 @@
140
144
  "color": "var(--fg)"
141
145
  },
142
146
  "& [part=\"account-detail\"]": {
147
+ "$description": "`overflow-wrap: anywhere` because the detail carries author-supplied strings with no break opportunity in them: the AI row's endpoint URL (a Cloudflare AI Gateway URL is a 32-hex account id between slashes) and the local Cloudflare row's account id. Without it one of them measured 419px in a 223px column, ran under Disconnect, past the card's border, and scrolled the whole section sideways. `anywhere` rather than `break-word`, because only `anywhere` lowers the min-content the row is sized from; not `word-break: break-all`, which would split every ordinary word in the sentences around it. It sits here rather than on the column because the label is a fixed service name and only the detail is unbounded.",
143
148
  "fontSize": "var(--jx-text-sm)",
144
- "color": "var(--fg-dim)"
149
+ "color": "var(--fg-dim)",
150
+ "overflowWrap": "anywhere"
145
151
  },
146
152
  "& [part=\"account-actions\"]": {
153
+ "$description": "`margin-inline-start: auto` keeps the actions at the row's end when the wrap puts them on a line of their own; on a shared line `space-between` already puts them there, so the margin changes nothing.",
147
154
  "display": "flex",
148
155
  "alignItems": "center",
149
156
  "gap": "var(--jx-space-3)",
150
- "flexShrink": "0"
157
+ "flexShrink": "0",
158
+ "marginInlineStart": "auto"
151
159
  },
152
160
  "& [part=\"keys\"]": {
161
+ "$description": "The inline-end padding is for the scrollbar, not for rhythm. A row whose title wraps pushes its `Change` button to the very end of the line, and the sheet always scrolls (64 bindings), so that button's right edge landed exactly on the scroller's content edge and read as touching the scrollbar track.",
153
162
  "display": "flex",
154
163
  "flexDirection": "column",
155
- "gap": "var(--jx-space-1)"
164
+ "gap": "var(--jx-space-1)",
165
+ "paddingInlineEnd": "var(--jx-space-2)"
156
166
  },
157
167
  "& [part=\"refusal\"]": {
158
168
  "display": "flex",
@@ -177,9 +187,10 @@
177
187
  "textTransform": "uppercase",
178
188
  "color": "var(--fg-dim)"
179
189
  },
180
- "& [part=\"key\"]": {
190
+ "& [part=\"key\"][data-command]": {
191
+ "$description": "Qualified by `data-command`, the attribute a binding row carries, because `key` is also the credentials form's API-key FIELD and that form is mounted into this sheet's own light DOM: as a bare descendant this rule laid a 16px flex row over a `jx-textfield`, which drew it 24px tall beside the 20px endpoint field under it. `center`, not `baseline`: the `Change` and `Reset` buttons are small kit action buttons, and a small kit control is layout-contained so its outset hit area adds nothing to this sheet's scrollable overflow, which leaves it with no baseline to export. A baseline row synthesises one from the button's bottom edge instead, and every row grew from 24px to 29px with the chord and title dropped onto it. Centred, every single-line row measures exactly what the baseline layout did (24px, with the chord, the title and the button label on one baseline); a row whose title wraps centres its chord and buttons between the title's lines. surface-baseline-rows.test.ts holds the rule for every surface.",
181
192
  "display": "flex",
182
- "alignItems": "baseline",
193
+ "alignItems": "center",
183
194
  "gap": "var(--jx-space-4)",
184
195
  "padding": "var(--jx-space-1) 0"
185
196
  },
@@ -191,6 +202,8 @@
191
202
  "color": "var(--fg)"
192
203
  },
193
204
  "& [part=\"key-title\"]": {
205
+ "$description": "`flex: 1` for the same reason the chord beside it is a fixed 96px column: down 64 rows, an action that starts where the last title ended is not scannable. The title took its content's width, so `Change` landed at fourteen different offsets in the first twenty rows, and at the line's very end on a row whose title wrapped. Growing the title instead pins the actions to that end, where a reader finds them by scanning one edge. `minWidth: 0` is what still lets a long title wrap rather than widen the sheet.",
206
+ "flex": "1",
194
207
  "color": "var(--fg-dim)",
195
208
  "minWidth": "0"
196
209
  }
@@ -253,7 +253,8 @@ export function openPreferencesSurface(
253
253
  setKeyQuery: (value: string) => {
254
254
  /* What the control now holds, first and unconditionally. A binding only writes when the
255
255
  scope CHANGES, so a surface that decided a query without announcing the raw one would
256
- leave the field showing something the scope does not have (§9.3). */
256
+ leave the field showing something the scope does not have
257
+ (studio-ui-guidelines.md §9.3). */
257
258
  scope.keyQuery = value;
258
259
  options.onKeyQuery(value);
259
260
  },
@@ -303,6 +304,13 @@ export function openPreferencesSurface(
303
304
  const box = element.querySelector<HTMLElement>('dialog[part="dialog"]') ?? element;
304
305
  box.setAttribute(REGION_ATTR, overlayRegion("dialog", "preferences"));
305
306
  showModal(element);
307
+ /* The nav item the sheet OPENED on, not the first one the dialog finds. `showModal()` focuses
308
+ the first focusable descendant, which is always Appearance, so `app.preferences` with a
309
+ section put the ring on one row while `aria-current` and the selected fill were on another:
310
+ two rows looked active at once, and the keyboard was in the wrong place to move between
311
+ them. Read off `aria-current` rather than from the view, because that attribute is the one
312
+ record of which section is showing (`preferences.json` says so on the rule that draws it). */
313
+ element.querySelector<HTMLElement>('[part="nav-item"][aria-current="true"]')?.focus();
306
314
  return element;
307
315
  });
308
316
 
@@ -48,7 +48,7 @@
48
48
  "minWidth": "0"
49
49
  },
50
50
  "& [part=\"section-body\"] > [part=\"row\"], & [part=\"layout-class-slot\"] > [part=\"row\"]": {
51
- "$description": "§4.1's standard form row, stacked: the label sits above a control that takes the whole width. `min-width: 0` is what keeps it honest in a narrow dock — a field refuses to shrink below its own min-content without it. Scoped to the tab's OWN rows rather than to every `part=\"row\"` beneath it, which a colour row made load-bearing: the kit is light DOM and one cascade, so a bare descendant selector also matches `jx-color-field`'s internal row — and at equal specificity with the kit's own `& > [part=\"row\"]` the winner is whichever sheet was interned later, which is not a thing a stylesheet may depend on. `[part=\"chip\"]` moved under `[part=\"chip-slot\"]` for the same reason and a sharper one: its `background: transparent` and its border would otherwise have erased a swatch's colour and drawn a box round it. The `layout-class-slot` half of the pair is there because that slot is `display: contents`, so its row is a grandchild in the DOM even though it is a child in the box tree.",
51
+ "$description": "studio-ui-guidelines.md §4.1's standard form row, stacked: the label sits above a control that takes the whole width. `min-width: 0` is what keeps it honest in a narrow dock — a field refuses to shrink below its own min-content without it. Scoped to the tab's OWN rows rather than to every `part=\"row\"` beneath it, which a colour row made load-bearing: the kit is light DOM and one cascade, so a bare descendant selector also matches `jx-color-field`'s internal row — and at equal specificity with the kit's own `& > [part=\"row\"]` the winner is whichever sheet was interned later, which is not a thing a stylesheet may depend on. `[part=\"chip\"]` moved under `[part=\"chip-slot\"]` for the same reason and a sharper one: its `background: transparent` and its border would otherwise have erased a swatch's colour and drawn a box round it. The `layout-class-slot` half of the pair is there because that slot is `display: contents`, so its row is a grandchild in the DOM even though it is a child in the box tree.",
52
52
  "display": "flex",
53
53
  "flexDirection": "column",
54
54
  "alignItems": "stretch",
@@ -92,7 +92,7 @@
92
92
  "minInlineSize": "0"
93
93
  },
94
94
  "& [part=\"chip-slot\"] > [part=\"chip\"]": {
95
- "$description": "§6.2's provenance chip. `set` is the 6px accent dot it has always been — a circle is not a button, whatever element draws it — and the three states that carry a donor are bordered chips naming it. The fourth state, `default`, draws nothing at all: a ghost dot on every unset row says less than silence.",
95
+ "$description": "§6.7's provenance chip. `set` is the 6px accent dot it has always been — a circle is not a button, whatever element draws it — and the three states that carry a donor are bordered chips naming it. The fourth state, `default`, draws nothing at all: a ghost dot on every unset row says less than silence.",
96
96
  "flexShrink": "0",
97
97
  "display": "inline-flex",
98
98
  "alignItems": "center",
@@ -585,7 +585,7 @@
585
585
  },
586
586
  "children": [
587
587
  {
588
- "$description": "§6.2's collapsed-header tally. It is an indicator and not a control: the heading's own click already toggles the section, so a second meaning for the same click would be worse than the silence. It says how many values in the section are set, which is what a closed section otherwise cannot say.",
588
+ "$description": "§6.7's collapsed-header tally. It is an indicator and not a control: the heading's own click already toggles the section, so a second meaning for the same click would be worse than the silence. It says how many values in the section are set, which is what a closed section otherwise cannot say.",
589
589
  "tagName": "span",
590
590
  "attributes": {
591
591
  "slot": "heading",
@@ -744,7 +744,7 @@
744
744
  },
745
745
  "cases": {
746
746
  "true": {
747
- "$description": "§6.3's Value Source chip: the rung this value is produced at, in plain language, opening a picker of every rung the POSITION permits. The rungs are derived from the schema at that position and the picker is the kit menu every other list in the shell opens, so neither is decided here.",
747
+ "$description": "§6.6's Value Source chip: the rung this value is produced at, in plain language, opening a picker of every rung the POSITION permits. The rungs are derived from the schema at that position and the picker is the kit menu every other list in the shell opens, so neither is decided here.",
748
748
  "tagName": "jx-action-button",
749
749
  "attributes": {
750
750
  "part": "source",
@@ -104,7 +104,7 @@ export interface ContentRowView {
104
104
  tokens: ContentTokenView[];
105
105
  hasTokens: boolean;
106
106
  /**
107
- * The provenance chip's shape: `""` draws nothing (§6.2's `default` state, where absence IS the
107
+ * The provenance chip's shape: `""` draws nothing (§6.7's `default` state, where absence IS the
108
108
  * ghost), `dot` is the 6px accent dot that clears the value, `text` states a donor without
109
109
  * offering to go there, and `press` states one and opens it.
110
110
  */
@@ -145,7 +145,7 @@ export interface ContentSectionView {
145
145
  key: string;
146
146
  label: string;
147
147
  open: boolean;
148
- /** Whether anything in this section is set, so a closed section still says so (§6.2). */
148
+ /** Whether anything in this section is set, so a closed section still says so (§6.7). */
149
149
  hasDot: boolean;
150
150
  dotTitle: string;
151
151
  rows: ContentRowView[];
@@ -53,7 +53,7 @@
53
53
  "gap": "var(--jx-space-3)"
54
54
  },
55
55
  "& [part=\"actions\"]": {
56
- "$description": "Wraps rather than overflows (§4.6): two buttons whose labels are whole phrases — \"Verify & Connect\", \"Preferences › Accounts\" — are wider than a narrow dialog at the sizes a reader may have set.",
56
+ "$description": "Wraps rather than overflows (studio-ui-guidelines.md §4.6): two buttons whose labels are whole phrases — \"Verify & Connect\", \"Preferences › Accounts\" — are wider than a narrow dialog at the sizes a reader may have set.",
57
57
  "display": "flex",
58
58
  "flexWrap": "wrap",
59
59
  "gap": "var(--jx-space-2)"
@@ -309,7 +309,8 @@ export function openPublishSurface(options: PublishSurfaceOptions): PublishSurfa
309
309
  setAccount: (value: string) => {
310
310
  /* What the control now holds, first and unconditionally. A binding only writes when the
311
311
  scope CHANGES, so a surface that decided a value without announcing the raw one would
312
- leave the control showing something the scope does not have (§9.3). */
312
+ leave the control showing something the scope does not have
313
+ (studio-ui-guidelines.md §9.3). */
313
314
  scope.accountId = value;
314
315
  options.onField("accountId", value);
315
316
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://jxsuite.com/schema/v1",
3
3
  "$id": "StudioPushPlan",
4
- "$description": "What pushing the schema would do, or what it did. The dry run is the whole point of the surface: a push rewrites a live database's shape, so the plan is read before the apply, and the confirm dialog around this document is the one that gates it. The ISLAND of `ui/layers.ts`'s confirm dialog rather than a dialog of its own (§12.5).",
4
+ "$description": "What pushing the schema would do, or what it did. The dry run is the whole point of the surface: a push rewrites a live database's shape, so the plan is read before the apply, and the confirm dialog around this document is the one that gates it. The ISLAND of `ui/layers.ts`'s confirm dialog rather than a dialog of its own (studio-ui-guidelines.md §12.5).",
5
5
  "tagName": "div",
6
6
  "attributes": {
7
7
  "part": "plan"
@@ -41,7 +41,8 @@
41
41
  "fontSize": "var(--jx-text-sm)",
42
42
  "color": "var(--warning, var(--fg-dim))"
43
43
  },
44
- "& [part=\"error\"]": {
44
+ "& [part=\"failure\"]": {
45
+ "$description": "`failure` rather than `error`: every kit field draws a permanent, empty `[part=\"error\"]` of its own, and the kit is light DOM, so a rule on that name here would reach any field the plan ever holds.",
45
46
  "margin": "0",
46
47
  "fontSize": "var(--jx-text-sm)",
47
48
  "color": "var(--danger)"
@@ -100,7 +101,7 @@
100
101
  "map": {
101
102
  "tagName": "p",
102
103
  "attributes": {
103
- "part": "error",
104
+ "part": "failure",
104
105
  "role": "alert"
105
106
  },
106
107
  "textContent": "${$map.item.text}"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://jxsuite.com/schema/v1",
3
3
  "$id": "StudioRail",
4
- "$description": "The Navigator rail: a rendering of the panel registry. The adapter hands in `groups`, every rail-able panel grouped by level with its selected state and badge, and `settingsVisible`/`settingsOpen` for the foot's gear. Nothing here is a list of panels.",
4
+ "$description": "The Navigator rail: a rendering of the panel registry. The adapter hands in `groups`, every rail-able panel grouped by level with its selected state and badge, and `settingsVisible`/`settingsOpen` for the foot's gear. Nothing here is a list of panels. Each button prints its record's short `railLabel` under the glyph, falling back to `title`, and carries the full `title` as its accessible name and tooltip: the visible words lead the name a reader hears (WCAG 2.5.3), and the tooltip restores what a short label leaves out.",
5
5
  "tagName": "div",
6
6
  "attributes": {
7
7
  "part": "rail"
@@ -145,7 +145,7 @@
145
145
  "children": [
146
146
  {
147
147
  "tagName": "span",
148
- "textContent": "${$map.item.title}"
148
+ "textContent": "${$map.item.railLabel}"
149
149
  }
150
150
  ]
151
151
  }
@@ -7,10 +7,12 @@
7
7
  * call in the module that owns it, and it appears here; there is nothing to update in step.
8
8
  *
9
9
  * **Every rail button opens the Navigator, and the grouping is by LEVEL.** Every button is a
10
- * `jx-action-button` in its stacked form, so it carries an 11px text label under its icon — an icon
11
- * whose only name is a hover tooltip is the accessibility failure §2 principle 6 names — and
12
- * `aria-pressed` states the toggle-focus semantics honestly: re-picking the open panel collapses
13
- * its dock, which is a two-state control, not a one-way selection.
10
+ * `jx-action-button` in its stacked form, so it carries a 10px text label under its icon — an icon
11
+ * whose only name is a hover tooltip is the accessibility failure studio-ui-guidelines.md §12.3
12
+ * names — and `aria-pressed` states the toggle-focus semantics honestly: re-picking the open panel
13
+ * collapses its dock, which is a two-state control, not a one-way selection. The label is the
14
+ * record's `railLabel` when it declares one (Source Control's is "Source", because the full title
15
+ * ellipsed in the 48px label box), and the full `title` stays the accessible name and the tooltip.
14
16
  *
15
17
  * The foot is the ⚙ **Settings** menu, a menu button rendered from the `settings/menu` placement: a
16
18
  * record joins the gear by declaring the placement and there is nothing here to update in step.
@@ -48,7 +50,10 @@ registerSurface("rail", railDoc as unknown as JxDocument);
48
50
  /** One rail button, as the surface reads it. */
49
51
  interface RailButton {
50
52
  id: string;
53
+ /** The full name: the control's accessible name and its tooltip. */
51
54
  title: string;
55
+ /** The text under the glyph: the record's `railLabel`, else its title. */
56
+ railLabel: string;
52
57
  icon: string;
53
58
  selected: boolean;
54
59
  /** The badge text; empty for none. */
@@ -109,6 +114,7 @@ function project(): { groups: RailGroupProjection[]; settingsVisible: boolean }
109
114
  badge: String(panel.badge?.(ctx) ?? ""),
110
115
  icon: panel.icon,
111
116
  id: panel.id,
117
+ railLabel: panel.railLabel ?? panel.title,
112
118
  selected: isRailPanelShowing(panel),
113
119
  title: panel.title,
114
120
  })),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://jxsuite.com/schema/v1",
3
3
  "$id": "StudioReferenceField",
4
- "$description": "The `reference` form control — site-architecture.md §6.1's `{ \"$ref\": \"#/content/x\" }` and §7.4's entry picker. Registered once and dispatched to by `ui/schema-form.ts` for any property whose `$ref` names a collection, so the settings forms, the entry editor and an array-of-objects cell all draw the same control without any of them knowing it exists. `ui/form-controls.ts` decides which of the three states the field is in and what each gesture commits; nothing here reads a schema or lists a directory. The three states are drawn as three different controls on purpose: a picker while the entries are known, a TEXT field while they are not — a failed read leaves the value editable with the reason beside it, because swapping it for an empty dropdown would present \"no entries\" and \"could not find out\" as the same screen — and a disabled picker saying so while the read is in flight.",
4
+ "$description": "The `reference` form control — site-architecture.md §6.1's `{ \"$ref\": \"#/content/x\" }` and site-architecture.md §7.4's entry picker. Registered once and dispatched to by `ui/schema-form.ts` for any property whose `$ref` names a collection, so the settings forms, the entry editor and an array-of-objects cell all draw the same control without any of them knowing it exists. `ui/form-controls.ts` decides which of the three states the field is in and what each gesture commits; nothing here reads a schema or lists a directory. The three states are drawn as three different controls on purpose: a picker while the entries are known, a TEXT field while they are not — a failed read leaves the value editable with the reason beside it, because swapping it for an empty dropdown would present \"no entries\" and \"could not find out\" as the same screen — and a disabled picker saying so while the read is in flight.",
5
5
  "tagName": "div",
6
6
  "attributes": {
7
7
  "part": "reference",
@@ -151,7 +151,7 @@
151
151
  },
152
152
  "cases": {
153
153
  "true": {
154
- "$description": "The Value Source chip (§6.3): what produces this value, in the same four words every other bindable position in Studio uses. It opens the rung picker rather than cycling, so any rung the position permits is one action away. Drawn only where the host named somewhere a value could come from — a settings form that names none edits fixed values and shows no chip.",
154
+ "$description": "The Value Source chip (§6.6): what produces this value, in the same four words every other bindable position in Studio uses. It opens the rung picker rather than cycling, so any rung the position permits is one action away. Drawn only where the host named somewhere a value could come from — a settings form that names none edits fixed values and shows no chip.",
155
155
  "tagName": "jx-action-button",
156
156
  "attributes": {
157
157
  "part": "source",
@@ -966,7 +966,7 @@
966
966
  },
967
967
  "cases": {
968
968
  "true": {
969
- "$description": "§7.1's inline tier: why this value is refused, said AT the control that refuses it and for exactly as long as the value stays bad. `role=\"alert\"` so it is announced when it appears, and a repeat counter from two up — “it refused me again” is otherwise indistinguishable from “the field is still red from last time”.",
969
+ "$description": "§16.1's inline tier: why this value is refused, said AT the control that refuses it and for exactly as long as the value stays bad. `role=\"alert\"` so it is announced when it appears, and a repeat counter from two up — “it refused me again” is otherwise indistinguishable from “the field is still red from last time”.",
970
970
  "tagName": "p",
971
971
  "attributes": {
972
972
  "part": "field-error",
@@ -117,7 +117,7 @@ export interface SchemaFormFieldView {
117
117
  mono: boolean;
118
118
  /** Draw the text control as a text area. */
119
119
  multiline: boolean;
120
- /** Why this value is refused (§7.1's inline tier). Empty draws nothing. */
120
+ /** Why this value is refused (§16.1's inline tier). Empty draws nothing. */
121
121
  error: string;
122
122
  /** Whether there is a refusal to announce. A document branches on a flag, never on a length. */
123
123
  hasError: boolean;
@@ -194,7 +194,7 @@
194
194
  }
195
195
  },
196
196
  "& [part=\"chip\"]": {
197
- "$description": "The provenance vocabulary of `panels/provenance.ts` §6.2, drawn by this document rather than borrowed as a class: `set` keeps the accent dot it has always been, `inherited` is an amber pill naming its donor, and a field nothing supplies gets no chip at all — because a ghost dot on every unset row says less than silence. The two chips that can go somewhere are `<button>`s; the ones with nowhere to go are not, which is §6.2's rule that a control which looks pressable and does nothing is a defect.",
197
+ "$description": "The provenance vocabulary of `panels/provenance.ts` (§6.7), drawn by this document rather than borrowed as a class: `set` keeps the accent dot it has always been, `inherited` is an amber pill naming its donor, and a field nothing supplies gets no chip at all — because a ghost dot on every unset row says less than silence. The two chips that can go somewhere are `<button>`s; the ones with nowhere to go are not, which is §6.7's rule that a control which looks pressable and does nothing is a defect.",
198
198
  "flexShrink": "0"
199
199
  },
200
200
  "& jx-dot[part=\"chip\"][data-state=\"set\"]": {
@@ -41,7 +41,7 @@ import type { JxDocument } from "@jxsuite/schema/types";
41
41
 
42
42
  registerSurface("seo", seoDoc as unknown as JxDocument);
43
43
 
44
- /** How a field's provenance is drawn — §6.2's vocabulary, reduced to three shapes and an absence. */
44
+ /** How a field's provenance is drawn — §6.7's vocabulary, reduced to three shapes and an absence. */
45
45
  export type SeoChipKind = "none" | "dot" | "static" | "link";
46
46
 
47
47
  /** One row of the resolved-field list: what reaches the browser, how long it is, where it came from. */
@@ -55,7 +55,7 @@ export interface SeoFieldView {
55
55
  unsetLabel: string;
56
56
  /** Whether anybody counts this field at all; `og:image` is a URL and nobody does. */
57
57
  counted: boolean;
58
- /** The counter, already formatted: `61/60`. Never a total, and never a grade (§9.2, §14). */
58
+ /** The counter, already formatted: `61/60`. Never a total, and never a grade (§16.6). */
59
59
  count: string;
60
60
  /** Over its budget. Stated on the counter and named in the warning list — never summed. */
61
61
  over: boolean;
@@ -145,7 +145,8 @@ export function mountContributedSurface(
145
145
  let disposed = false;
146
146
  /* Nothing is called on an element here, so the mount is all there is to wait for: the islands
147
147
  announce themselves through `onNodeCreated` as they are created, which is one
148
- `connectedCallback` earlier than awaiting the element would be (§1.1, "await the element"). */
148
+ `connectedCallback` earlier than awaiting the element would be (studio-ui-guidelines.md §1.1,
149
+ "await the element"). */
149
150
  const ready = mountSurface("settings-contributed", scope, host, {
150
151
  onNodeCreated: (element, _path, def) => {
151
152
  if (!(element instanceof HTMLElement)) {
@@ -15,8 +15,8 @@
15
15
  "fontWeight": "600",
16
16
  "color": "var(--fg)"
17
17
  },
18
- "& [part=\"error\"]": {
19
- "$description": "A write that failed, said under the section title rather than pinned to a control. This section saves on change and the predecessor dropped every rejection on the floor, so a read-only file made each edit look as though it had been taken and then quietly forgotten.",
18
+ "& [part=\"section-error\"]": {
19
+ "$description": "A write that failed, said under the section title rather than pinned to a control. This section saves on change and the predecessor dropped every rejection on the floor, so a read-only file made each edit look as though it had been taken and then quietly forgotten. It is `section-error` rather than `error` because every text field and select in the section draws a permanent `[part=\"error\"]` of its own in this same light-DOM tree, and a rule on that name would give their refusal sentences this margin and size too.",
20
20
  "margin": "0 0 12px",
21
21
  "fontSize": "var(--jx-text-md)",
22
22
  "color": "var(--danger)"
@@ -172,7 +172,7 @@
172
172
  {
173
173
  "tagName": "div",
174
174
  "attributes": {
175
- "part": "error-slot",
175
+ "part": "section-error-slot",
176
176
  "role": "none"
177
177
  },
178
178
  "$switch": {
@@ -182,7 +182,7 @@
182
182
  "true": {
183
183
  "tagName": "p",
184
184
  "attributes": {
185
- "part": "error",
185
+ "part": "section-error",
186
186
  "role": "alert"
187
187
  },
188
188
  "textContent": "${state.error}"
@@ -17,8 +17,8 @@
17
17
  "fontWeight": "600",
18
18
  "color": "var(--fg)"
19
19
  },
20
- "& [part=\"error\"]": {
21
- "$description": "A write that failed, said under the section title rather than pinned to the picker: settings save on change, so a silent rejection would read as \"my edit just vanished\", and what failed was the whole file rather than the value. Its size read `--spectrum-font-size-75` with a 12px fallback, which resolved only inside `<sp-theme>` — a document is mounted in the settings pane, where that name is not in scope and the fallback is all it would ever have taken — so the size is the kit's scale and the colour is the studio layer's.",
20
+ "& [part=\"section-error\"]": {
21
+ "$description": "A write that failed, said under the section title rather than pinned to the picker: settings save on change, so a silent rejection would read as \"my edit just vanished\", and what failed was the whole file rather than the value. Its size read `--spectrum-font-size-75` with a 12px fallback, which resolved only inside `<sp-theme>` — a document is mounted in the settings pane, where that name is not in scope and the fallback is all it would ever have taken — so the size is the kit's scale and the colour is the studio layer's. It is `section-error` rather than `error` because the adapter picker is a `jx-select`, which draws a permanent `[part=\"error\"]` of its own in this same light-DOM tree: a rule on that name would give the picker's own refusal sentence this 16px margin too.",
22
22
  "margin": "0 0 16px",
23
23
  "fontSize": "var(--jx-text-md)",
24
24
  "color": "var(--danger)"
@@ -39,7 +39,7 @@
39
39
  {
40
40
  "tagName": "div",
41
41
  "attributes": {
42
- "part": "error-slot",
42
+ "part": "section-error-slot",
43
43
  "role": "none"
44
44
  },
45
45
  "style": {
@@ -52,7 +52,7 @@
52
52
  "true": {
53
53
  "tagName": "p",
54
54
  "attributes": {
55
- "part": "error",
55
+ "part": "section-error",
56
56
  "role": "alert"
57
57
  },
58
58
  "textContent": "${state.error}"
@@ -105,7 +105,8 @@ export function mountDeploySurface(
105
105
  let disposed = false;
106
106
  /* Nothing is called on the element, so the mount is all this has to wait for: the DOCUMENT is
107
107
  what this surface renders, and `jx-field` and `jx-select` settle their own templates one
108
- `connectedCallback` later without anybody here asking them to (§1.1, "await the element"). */
108
+ `connectedCallback` later without anybody here asking them to (studio-ui-guidelines.md §1.1,
109
+ "await the element"). */
109
110
  void mountSurface("settings-deploy", scope, container).then((surface) => {
110
111
  if (disposed) {
111
112
  surface.dispose();
@@ -21,8 +21,8 @@
21
21
  "fontSize": "var(--jx-text-md)",
22
22
  "color": "var(--fg-dim)"
23
23
  },
24
- "& [part=\"error\"]": {
25
- "$description": "The last operation that failed, said under the section title. Not a second announcement: `updateSiteConfig` already files a Problem for a rejected write and `activity.fail` files one for a rejected install. §13.1 makes INLINE the tier for \"the value is on screen, and nothing else is the right place\" — the Problem is about the file, and this line is about the switch the reader is looking at.",
24
+ "& [part=\"section-error\"]": {
25
+ "$description": "The last operation that failed, said under the section title. Not a second announcement: `updateSiteConfig` already files a Problem for a rejected write and `activity.fail` files one for a rejected install. studio-ui-guidelines.md §13.1 makes INLINE the tier for \"the value is on screen, and nothing else is the right place\" — the Problem is about the file, and this line is about the switch the reader is looking at. It is `section-error` rather than `error`, the name every settings section uses, because every kit field draws a permanent `[part=\"error\"]` of its own and the kit is light DOM: a rule on that name here would reach any field the section ever holds.",
26
26
  "margin": "6px 0 0",
27
27
  "fontSize": "var(--jx-text-md)",
28
28
  "color": "var(--danger)"
@@ -39,7 +39,7 @@
39
39
  "color": "var(--fg)"
40
40
  },
41
41
  "& [part=\"row\"]": {
42
- "$description": "A wrapping row, never an overflowing one (guidelines §4.6): the package name is author-supplied and unbounded, and Project Settings renders at two very different widths.",
42
+ "$description": "A wrapping row, never an overflowing one (studio-ui-guidelines.md §4.6): the package name is author-supplied and unbounded, and Project Settings renders at two very different widths.",
43
43
  "display": "flex",
44
44
  "flexWrap": "wrap",
45
45
  "alignItems": "flex-start",
@@ -115,7 +115,7 @@
115
115
  "flexShrink": "0"
116
116
  },
117
117
  "& [part=\"empty\"]": {
118
- "$description": "The teaching empty state, drawn here rather than borrowed from `panels/empty-state.ts`: that helper is a lit template, and a document cannot call one. What is kept is the pattern's rules (§11) — one sentence saying what the region is FOR, never \"no extensions\", then where its content comes from — in the compact shape, which reads as a note inside an otherwise populated pane rather than as a whole empty region. It offers no action because there is nothing here to act on: a backend that lists no catalogue is not a project waiting to be filled in.",
118
+ "$description": "The teaching empty state, drawn here rather than borrowed from `panels/empty-state.ts`: that helper is a lit template, and a document cannot call one. What is kept is the pattern's rules (studio-ui-guidelines.md §11) — one sentence saying what the region is FOR, never \"no extensions\", then where its content comes from — in the compact shape, which reads as a note inside an otherwise populated pane rather than as a whole empty region. It offers no action because there is nothing here to act on: a backend that lists no catalogue is not a project waiting to be filled in.",
119
119
  "display": "flex",
120
120
  "flexDirection": "column",
121
121
  "alignItems": "flex-start",
@@ -152,7 +152,7 @@
152
152
  {
153
153
  "tagName": "div",
154
154
  "attributes": {
155
- "part": "error-slot",
155
+ "part": "section-error-slot",
156
156
  "role": "none"
157
157
  },
158
158
  "style": {
@@ -165,7 +165,7 @@
165
165
  "true": {
166
166
  "tagName": "p",
167
167
  "attributes": {
168
- "part": "error",
168
+ "part": "section-error",
169
169
  "role": "alert"
170
170
  },
171
171
  "textContent": "${state.error}"
@@ -63,7 +63,10 @@ export interface ExtensionRowView {
63
63
  note: string;
64
64
  /** Whether Remove is offered at all — it is not for a package the project never installed. */
65
65
  canRemove: boolean;
66
- /** Offered but refused, which is how §10 wants a control that cannot act right now. */
66
+ /**
67
+ * Offered but refused, which is how studio-ui-guidelines.md §10 wants a control that cannot act
68
+ * right now.
69
+ */
67
70
  removeDisabled: boolean;
68
71
  removeLabel: string;
69
72
  removeHint: string;
@@ -159,7 +162,8 @@ export function mountExtensionsSurface(
159
162
  let disposed = false;
160
163
  /* Nothing is called on an element here, so the mount is all this has to wait for: the DOCUMENT is
161
164
  what this surface renders, and the kit elements inside it settle their own templates one
162
- `connectedCallback` later without anybody asking them to (§1.1, "await the element"). */
165
+ `connectedCallback` later without anybody asking them to (studio-ui-guidelines.md §1.1,
166
+ "await the element"). */
163
167
  void mountSurface("settings-extensions", scope, container).then((surface) => {
164
168
  if (disposed) {
165
169
  surface.dispose();