@jxsuite/studio 10.1.0 → 10.2.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 (239) hide show
  1. package/dist/chunks/{2020-mkb0qa6p.js → 2020-bx702wqa.js} +3 -3
  2. package/dist/chunks/adapter-pp011m5x.js +4 -0
  3. package/dist/chunks/add-new-flow-ecqmzz76.js +4 -0
  4. package/dist/chunks/cf-account-picker-c07znkqt.js +4 -0
  5. package/dist/chunks/cf-settings-0v2bmqy0.js +4 -0
  6. package/dist/chunks/components-yn0dn2pq.js +4 -0
  7. package/dist/chunks/content-source-g0j41yy6.js +4 -0
  8. package/dist/chunks/{convert-to-repeater-f92ey3kp.js → convert-to-repeater-sbjk7tgn.js} +3 -3
  9. package/dist/chunks/editor-xz02jeh1.js +4 -0
  10. package/dist/chunks/entry-commands-kmt02crp.js +4 -0
  11. package/dist/chunks/extension-sections-0rprf12d.js +4 -0
  12. package/dist/chunks/file-ops-mexj5qed.js +4 -0
  13. package/dist/chunks/files-b2tcppdd.js +4 -0
  14. package/dist/chunks/format-host-btsevv0c.js +4 -0
  15. package/dist/chunks/fs-events-r0apejva.js +4 -0
  16. package/dist/chunks/grid-open-n2a8xkht.js +4 -0
  17. package/dist/chunks/{grid-view-r22jsqht.js → grid-view-tghcwrrt.js} +12 -12
  18. package/dist/chunks/iframe-host-gx0ypyh3.js +4 -0
  19. package/dist/chunks/index-bs4k9tr6.js +4 -0
  20. package/dist/chunks/{index-pxwwf00y.js → index-vr006kbt.js} +3 -3
  21. package/dist/chunks/{javascript-pzqryby6.js → javascript-z1g3s9fd.js} +2 -2
  22. package/dist/chunks/{jsonMode-tcnyxyap.js → jsonMode-7szwg8c4.js} +5 -5
  23. package/dist/chunks/jx-validate-ymf10teh.js +4 -0
  24. package/dist/chunks/layers-p9nfya38.js +4 -0
  25. package/dist/chunks/layers-panel-tt1hzhhf.js +4 -0
  26. package/dist/chunks/lit-html-x18n2sfz.js +4 -0
  27. package/dist/chunks/media-library-0n45gv8r.js +4 -0
  28. package/dist/chunks/media-picker-s09at95z.js +4 -0
  29. package/dist/chunks/{monaco-binding-bqpge64f.js → monaco-binding-v42w9c1v.js} +3 -3
  30. package/dist/chunks/monaco-buffer-een2ea0v.js +4 -0
  31. package/dist/chunks/{monaco-setup-1mkab762.js → monaco-setup-7bffxd6v.js} +3 -3
  32. package/dist/chunks/notify-qwb8radt.js +4 -0
  33. package/dist/chunks/parse-v77xtwv7.js +4 -0
  34. package/dist/chunks/platform-8jnez0wr.js +4 -0
  35. package/dist/chunks/publish-panel-aysnj611.js +4 -0
  36. package/dist/chunks/{publish-quick-m9vkhahq.js → publish-quick-kpbqs9mz.js} +3 -3
  37. package/dist/chunks/publish-workspace-nd0a8q99.js +4 -0
  38. package/dist/chunks/quick-search-vg0jkhk2.js +4 -0
  39. package/dist/chunks/references-a7v6a0e2.js +4 -0
  40. package/dist/chunks/right-panel-cvk1vxx5.js +4 -0
  41. package/dist/chunks/source-control-fsqzc6he.js +4 -0
  42. package/dist/chunks/studio-05jfwbmf.js +5 -0
  43. package/dist/chunks/{studio-qyb5bebs.js → studio-0q5jwddh.js} +7 -7
  44. package/dist/chunks/{studio-cvz0e00f.js → studio-0w2dr0q8.js} +4 -4
  45. package/dist/chunks/{studio-eesyjg7h.js → studio-1tzpds97.js} +5 -5
  46. package/dist/chunks/{studio-a3s6frde.js → studio-216b27sv.js} +3 -3
  47. package/dist/chunks/studio-2ejhqns4.js +5 -0
  48. package/dist/chunks/studio-2r90cts3.js +16 -0
  49. package/dist/chunks/{studio-dy2xtt7a.js → studio-399a25za.js} +4 -4
  50. package/dist/chunks/studio-399xknkb.js +6 -0
  51. package/dist/chunks/{studio-jh6t5qz4.js → studio-43y04qck.js} +4 -4
  52. package/dist/chunks/{studio-skynbac3.js → studio-4g8yb6jn.js} +2 -2
  53. package/dist/chunks/{studio-jw0q5j6k.js → studio-4jhw38b2.js} +4 -4
  54. package/dist/chunks/{studio-4smcnv33.js → studio-4ncmwqw5.js} +4 -4
  55. package/dist/chunks/studio-5atwjgkj.js +7 -0
  56. package/dist/chunks/{studio-vcz63n42.js → studio-5frqk7c0.js} +4 -4
  57. package/dist/chunks/{studio-hsr3k06v.js → studio-646nn2ys.js} +5 -5
  58. package/dist/chunks/{studio-ch8gt8vt.js → studio-6cwj6xrx.js} +4 -4
  59. package/dist/chunks/studio-6hzdjfv0.js +5 -0
  60. package/dist/chunks/{studio-9cp96v90.js → studio-71m92v9s.js} +7 -7
  61. package/dist/chunks/{studio-brdp85q7.js → studio-75kcdbsk.js} +4 -4
  62. package/dist/chunks/{studio-6vwvshw8.js → studio-78pywnp2.js} +5 -5
  63. package/dist/chunks/{studio-ggm7zf70.js → studio-86r8hp7r.js} +5 -5
  64. package/dist/chunks/studio-886t6ztg.js +5 -0
  65. package/dist/chunks/{studio-5dmgmyw4.js → studio-8wnvtr4z.js} +4 -4
  66. package/dist/chunks/studio-8z66jk4z.js +5 -0
  67. package/dist/chunks/{studio-x2metr13.js → studio-9rbe2xpw.js} +3 -3
  68. package/dist/chunks/{studio-8qejv8yf.js → studio-awxwjawq.js} +4 -4
  69. package/dist/chunks/studio-b2qpt0xy.js +14 -0
  70. package/dist/chunks/{studio-9rcbvksg.js → studio-bvs9kpst.js} +7 -7
  71. package/dist/chunks/studio-c71806xz.js +7 -0
  72. package/dist/chunks/{studio-vjhej0w5.js → studio-cbwks69x.js} +140 -140
  73. package/dist/chunks/studio-cg1bfyhf.js +9 -0
  74. package/dist/chunks/studio-cg710sk9.js +5 -0
  75. package/dist/chunks/studio-cw0wb9qk.js +7 -0
  76. package/dist/chunks/studio-cyheys7k.js +5 -0
  77. package/dist/chunks/studio-ea5m9kg5.js +5 -0
  78. package/dist/chunks/{studio-4nkm4404.js → studio-ea74s8c1.js} +4 -4
  79. package/dist/chunks/{studio-37twdaf7.js → studio-efdxjwyp.js} +34 -34
  80. package/dist/chunks/{studio-pmzg17fj.js → studio-egmw2837.js} +4 -4
  81. package/dist/chunks/{studio-8jb31dcf.js → studio-er5f383a.js} +4 -4
  82. package/dist/chunks/studio-f746039f.js +5 -0
  83. package/dist/chunks/studio-fmdymd9v.js +5 -0
  84. package/dist/chunks/studio-gcm12z00.js +6 -0
  85. package/dist/chunks/{studio-t3j8htp7.js → studio-gj98m8gy.js} +5 -5
  86. package/dist/chunks/{studio-cgb97rwv.js → studio-hasbgjah.js} +4 -4
  87. package/dist/chunks/studio-hhp4x8xf.js +6 -0
  88. package/dist/chunks/{studio-848rk4p1.js → studio-hz5n7x27.js} +4 -4
  89. package/dist/chunks/{studio-0g2sm01j.js → studio-j3d2fjqz.js} +4 -4
  90. package/dist/chunks/studio-jeraxdgv.js +7 -0
  91. package/dist/chunks/studio-jvgek9xt.js +5 -0
  92. package/dist/chunks/studio-jws1a87n.js +5 -0
  93. package/dist/chunks/studio-k2sz13zg.js +5 -0
  94. package/dist/chunks/studio-k3m4jkdk.js +5 -0
  95. package/dist/chunks/{studio-7vb997ff.js → studio-kg1abnz0.js} +4 -4
  96. package/dist/chunks/{studio-s0fg2wav.js → studio-kg5ya5r2.js} +4 -4
  97. package/dist/chunks/studio-khwbgrtg.js +5 -0
  98. package/dist/chunks/studio-mx6wzh25.js +5 -0
  99. package/dist/chunks/studio-mxs3ar9t.js +5 -0
  100. package/dist/chunks/studio-nm4szey4.js +5 -0
  101. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  102. package/dist/chunks/{studio-07k0geap.js → studio-pjtntksy.js} +4 -4
  103. package/dist/chunks/studio-qh8berdz.js +5 -0
  104. package/dist/chunks/studio-qn7z4krm.js +5 -0
  105. package/dist/chunks/studio-qyed0ah6.js +5 -0
  106. package/dist/chunks/{studio-5e7p1vgd.js → studio-r4bcdwhq.js} +4 -4
  107. package/dist/chunks/{studio-mwnmzx7g.js → studio-r7pf0rkv.js} +6 -6
  108. package/dist/chunks/studio-rtfnhrdg.js +5 -0
  109. package/dist/chunks/{studio-zacvfm31.js → studio-rzqaz21g.js} +4 -4
  110. package/dist/chunks/studio-s5tzw84t.js +5 -0
  111. package/dist/chunks/{studio-nf0pqpbj.js → studio-sevbc3xv.js} +4 -4
  112. package/dist/chunks/{studio-va0e63sk.js → studio-sxdb9h3q.js} +6 -6
  113. package/dist/chunks/studio-t51y8v1d.js +5 -0
  114. package/dist/chunks/{studio-pd9dsqpq.js → studio-t98vq4r6.js} +4 -4
  115. package/dist/chunks/studio-th7z3fg7.js +5 -0
  116. package/dist/chunks/studio-tsxpqvh0.js +6 -0
  117. package/dist/chunks/{studio-7823f0g8.js → studio-v1yascv2.js} +4 -4
  118. package/dist/chunks/{studio-tpy3rdxn.js → studio-wc6za3zs.js} +4 -4
  119. package/dist/chunks/{studio-5m0w815d.js → studio-wxq6v5sv.js} +4 -4
  120. package/dist/chunks/{studio-ahf3cspq.js → studio-y60sts62.js} +3 -3
  121. package/dist/chunks/studio-ybnwymxw.js +5 -0
  122. package/dist/chunks/studio-zndrqawb.js +5 -0
  123. package/dist/chunks/studio-zwaxn5s2.js +5 -0
  124. package/dist/chunks/{tsMode-6vwhy6ty.js → tsMode-f54j66ym.js} +5 -5
  125. package/dist/chunks/workspace-home-x1787wpv.js +4 -0
  126. package/dist/chunks/workspace-zpe1np43.js +4 -0
  127. package/dist/chunks/{ws-client-zcxkfgmf.js → ws-client-e8kj684q.js} +3 -3
  128. package/dist/manifest.json +76 -75
  129. package/dist/studio.js +81 -82
  130. package/package.json +4 -4
  131. package/src/browse/library-model.ts +56 -23
  132. package/src/commands/context.ts +1 -0
  133. package/src/editor/shortcuts.ts +3 -0
  134. package/src/panels/data-grid.ts +0 -4
  135. package/src/panels/settings-menu.ts +3 -3
  136. package/src/panels/settings-pane.ts +42 -56
  137. package/src/services/ai-import-tools.ts +6 -3
  138. package/src/services/ai-models.ts +65 -11
  139. package/src/services/ai-settings.ts +45 -5
  140. package/src/services/document-assistant.ts +5 -2
  141. package/src/services/settings/definitions.ts +19 -0
  142. package/src/settings/contributed-section.ts +16 -7
  143. package/src/settings/css-vars-editor.ts +4 -4
  144. package/src/settings/general-settings.ts +1 -4
  145. package/src/settings/preferences-accounts.ts +2 -2
  146. package/src/settings/preferences-dialog.ts +4 -2
  147. package/src/settings/project-sections.ts +1 -1
  148. package/src/settings/section-registry.ts +5 -4
  149. package/src/settings/settings-document.ts +33 -24
  150. package/src/settings/settings-workspace.ts +205 -0
  151. package/src/shell.ts +31 -6
  152. package/src/surfaces/ai-credentials-form.json +59 -5
  153. package/src/surfaces/ai-credentials-form.ts +15 -2
  154. package/src/surfaces/commandbar.ts +7 -3
  155. package/src/surfaces/settings-contributed.json +4 -4
  156. package/src/surfaces/settings-contributed.ts +2 -2
  157. package/src/surfaces/settings-pane.json +262 -180
  158. package/src/surfaces/settings-pane.ts +63 -14
  159. package/src/ui/ai-credentials-form.ts +128 -11
  160. package/src/ui/regions.ts +5 -5
  161. package/src/workspace/tab-workspace.ts +3 -2
  162. package/src/workspace/workspace-home.ts +18 -4
  163. package/src/workspace/workspace-ids.ts +40 -7
  164. package/dist/chunks/adapter-xcpsmecx.js +0 -4
  165. package/dist/chunks/add-new-flow-ptmhmzr9.js +0 -4
  166. package/dist/chunks/cf-account-picker-z1sgwpwd.js +0 -4
  167. package/dist/chunks/cf-settings-xqvhxxe9.js +0 -4
  168. package/dist/chunks/components-whsc81a7.js +0 -4
  169. package/dist/chunks/content-source-jwtxg78w.js +0 -4
  170. package/dist/chunks/editor-zdqdpq1x.js +0 -4
  171. package/dist/chunks/entry-commands-w8p2fbpt.js +0 -4
  172. package/dist/chunks/extension-sections-y2p1te2r.js +0 -4
  173. package/dist/chunks/file-ops-13ab4swj.js +0 -4
  174. package/dist/chunks/files-zbc8p6v1.js +0 -4
  175. package/dist/chunks/format-host-zjsbktbx.js +0 -4
  176. package/dist/chunks/fs-events-t6x0hch6.js +0 -4
  177. package/dist/chunks/grid-open-fyzdwpkh.js +0 -4
  178. package/dist/chunks/iframe-host-kbyqc7pt.js +0 -4
  179. package/dist/chunks/index-6nvj89vb.js +0 -4
  180. package/dist/chunks/jx-validate-5sp8a4rm.js +0 -4
  181. package/dist/chunks/layers-panel-qrxj9vr2.js +0 -4
  182. package/dist/chunks/layers-tpzayggx.js +0 -4
  183. package/dist/chunks/lit-html-x6nrxsx3.js +0 -4
  184. package/dist/chunks/media-library-ywppnjrz.js +0 -4
  185. package/dist/chunks/media-picker-etxgc8qq.js +0 -4
  186. package/dist/chunks/monaco-buffer-qrnqhk0b.js +0 -4
  187. package/dist/chunks/notify-kcv38wwe.js +0 -4
  188. package/dist/chunks/parse-df2kkmhc.js +0 -4
  189. package/dist/chunks/platform-dtsysmyd.js +0 -4
  190. package/dist/chunks/publish-panel-evb1rcxt.js +0 -4
  191. package/dist/chunks/publish-workspace-ktk9h536.js +0 -4
  192. package/dist/chunks/quick-search-2f47fxcw.js +0 -4
  193. package/dist/chunks/references-5w6ajjv7.js +0 -4
  194. package/dist/chunks/right-panel-kz0a6byf.js +0 -4
  195. package/dist/chunks/source-control-1phx90zk.js +0 -4
  196. package/dist/chunks/studio-0hr000ba.js +0 -5
  197. package/dist/chunks/studio-1wyp7dt5.js +0 -5
  198. package/dist/chunks/studio-20ap8dds.js +0 -5
  199. package/dist/chunks/studio-291gqh98.js +0 -5
  200. package/dist/chunks/studio-4zqfw5ha.js +0 -5
  201. package/dist/chunks/studio-56egy6vf.js +0 -5
  202. package/dist/chunks/studio-695k95bw.js +0 -5
  203. package/dist/chunks/studio-732mw0g8.js +0 -5
  204. package/dist/chunks/studio-76t560kn.js +0 -6
  205. package/dist/chunks/studio-8486jn4r.js +0 -5
  206. package/dist/chunks/studio-8x8616xd.js +0 -5
  207. package/dist/chunks/studio-bkmv1h3e.js +0 -9
  208. package/dist/chunks/studio-cqf1k4qk.js +0 -5
  209. package/dist/chunks/studio-dbgv4fv9.js +0 -16
  210. package/dist/chunks/studio-et6t8g4m.js +0 -4
  211. package/dist/chunks/studio-f2j9et3h.js +0 -14
  212. package/dist/chunks/studio-fep7hr66.js +0 -7
  213. package/dist/chunks/studio-fyf7j57j.js +0 -5
  214. package/dist/chunks/studio-g5prntab.js +0 -5
  215. package/dist/chunks/studio-ga77mf07.js +0 -5
  216. package/dist/chunks/studio-h7gy12h2.js +0 -5
  217. package/dist/chunks/studio-j933k8nr.js +0 -5
  218. package/dist/chunks/studio-jgbvqcgh.js +0 -5
  219. package/dist/chunks/studio-k4xc5g6h.js +0 -5
  220. package/dist/chunks/studio-p0nf2e1f.js +0 -6
  221. package/dist/chunks/studio-pzfa2vmb.js +0 -5
  222. package/dist/chunks/studio-rf8d6p9f.js +0 -7
  223. package/dist/chunks/studio-rt498t2v.js +0 -5
  224. package/dist/chunks/studio-sd07xva5.js +0 -6
  225. package/dist/chunks/studio-thj81e98.js +0 -7
  226. package/dist/chunks/studio-tyw7tk0x.js +0 -5
  227. package/dist/chunks/studio-vffwe9k7.js +0 -5
  228. package/dist/chunks/studio-vxjap704.js +0 -5
  229. package/dist/chunks/studio-w67vfgy5.js +0 -5
  230. package/dist/chunks/studio-xebavr9s.js +0 -5
  231. package/dist/chunks/studio-yg5n49za.js +0 -5
  232. package/dist/chunks/studio-yhz5b313.js +0 -5
  233. package/dist/chunks/studio-zsjpsw08.js +0 -5
  234. package/dist/chunks/studio-zxm98z2m.js +0 -7
  235. package/dist/chunks/workspace-d65bz1qk.js +0 -4
  236. package/dist/chunks/workspace-home-vbg9b3jh.js +0 -4
  237. package/src/settings/settings-dialog.ts +0 -192
  238. package/src/surfaces/settings-dialog.json +0 -51
  239. package/src/surfaces/settings-dialog.ts +0 -169
package/src/shell.ts CHANGED
@@ -45,8 +45,8 @@ import type { AnyCommand, CommandRegistry } from "./commands/registry";
45
45
  import {
46
46
  DEFAULT_WORKSPACE,
47
47
  isWorkspaceId,
48
+ SWITCHER_WORKSPACES,
48
49
  WORKSPACE_IDS,
49
- WORKSPACES,
50
50
  } from "./workspace/workspace-ids";
51
51
  import type { WorkspaceId } from "./workspace/workspace-ids";
52
52
  import { DEFAULT_PUBLISH_DESTINATION, DEFAULT_PUBLISH_TAB } from "./publish/publish-ids";
@@ -416,7 +416,7 @@ export interface WorkspacePreset {
416
416
  }
417
417
 
418
418
  /**
419
- * The five presets.
419
+ * The six presets.
420
420
  *
421
421
  * - **Design** draws the rail and both side docks: the canvas, its outline and its inspector.
422
422
  * - **Content** opens the Navigator on the Collections panel and collapses the Inspector, drawing it
@@ -427,8 +427,10 @@ export interface WorkspacePreset {
427
427
  * schemes), and the Inspector on its Style tab only while the Elements view is on screen: that
428
428
  * view selects an element default on a canvas, and the Inspector is where it is styled. Variables
429
429
  * is edited in the view itself, and Code has no canvas, so both leave the pane its width.
430
+ * - **Settings** collapses both side docks, as Media and Publish do: its home is the settings editor,
431
+ * whose section list is its own navigator.
430
432
  *
431
- * Only Design and Content draw a tab strip; the other three draw their home surface alone.
433
+ * Only Design and Content draw a tab strip; the other four draw their home surface alone.
432
434
  */
433
435
  export const WORKSPACE_PRESETS: Readonly<Record<WorkspaceId, WorkspacePreset>> = {
434
436
  content: {
@@ -459,6 +461,13 @@ export const WORKSPACE_PRESETS: Readonly<Record<WorkspaceId, WorkspacePreset>> =
459
461
  rail: false,
460
462
  tabStrip: false,
461
463
  },
464
+ settings: {
465
+ id: "settings",
466
+ inspector: { open: false },
467
+ navigator: { open: false },
468
+ rail: false,
469
+ tabStrip: false,
470
+ },
462
471
  styles: {
463
472
  id: "styles",
464
473
  inspector: { open: false, tab: "style", whileWriting: true },
@@ -833,6 +842,19 @@ let _workspaceRoot: string | null | undefined;
833
842
  */
834
843
  let _panels: Partial<Record<WorkspaceId, string>> = {};
835
844
 
845
+ /**
846
+ * The workspace on screen before the one that is, in this window, or `null` before the first
847
+ * switch. Not persisted, for the reason {@link _panels} is not. Project Settings' **Close** returns
848
+ * here (`settings/settings-workspace.ts`), because Settings is visited from somewhere rather than
849
+ * worked in, and the top bar has no tab to say where that was.
850
+ */
851
+ let _previous: WorkspaceId | null = null;
852
+
853
+ /** The workspace entered before the one on screen, or `null` when there was none this session. */
854
+ export function previousWorkspace(): WorkspaceId | null {
855
+ return _previous;
856
+ }
857
+
836
858
  /** The raw record for `root`, or `{}` for absent, corrupt or hand-edited storage. */
837
859
  function rawPersistedProject(root: string | null): JsonObject {
838
860
  if (!root) {
@@ -949,6 +971,7 @@ export function syncProjectWorkspace(root: string | null): void {
949
971
  }
950
972
  _workspaceRoot = root;
951
973
  _panels = {};
974
+ _previous = null;
952
975
  shell.workspace = persistedWorkspace(root);
953
976
  if (root === null) {
954
977
  /* No frame to apply, but the Navigator is still on screen beside the rail: a panel only the
@@ -1020,6 +1043,7 @@ export function enterWorkspace(id: WorkspaceId, deps?: WorkspaceDeps): boolean {
1020
1043
  if (!WORKSPACE_PRESETS[shell.workspace].navigator.panel) {
1021
1044
  _panels[shell.workspace] = shell.leftTab;
1022
1045
  }
1046
+ _previous = shell.workspace;
1023
1047
  shell.workspace = id;
1024
1048
  applyFrame(id, deps);
1025
1049
  persistDocks();
@@ -1580,8 +1604,9 @@ export function shellViewCommands(deps: ShellCommandDeps): AnyCommand[] {
1580
1604
  title: "Show Assistant",
1581
1605
  },
1582
1606
  // ── Workspaces ───────────────────────────────────────────────────────────
1583
- // One SETTER, and one chord record per workspace. A chord cannot carry an argument, so ⌘1–5
1584
- // Are five records that each run the setter's own path rather than five implementations of it.
1607
+ /* One SETTER, and one chord record per switcher workspace. A chord cannot carry an argument, so
1608
+ ⌘1–5 are five records that each run the setter's own path rather than five implementations
1609
+ of it. Settings has none: `settings.open` is its record, with its own chord (⌘⇧,). */
1585
1610
  {
1586
1611
  args: argsSchema({
1587
1612
  workspace: enumProperty(WORKSPACE_IDS, "Which workspace to show."),
@@ -1603,7 +1628,7 @@ export function shellViewCommands(deps: ShellCommandDeps): AnyCommand[] {
1603
1628
  },
1604
1629
  title: "Switch Workspace",
1605
1630
  },
1606
- ...WORKSPACES.map((entry, index): AnyCommand => ({
1631
+ ...SWITCHER_WORKSPACES.map((entry, index): AnyCommand => ({
1607
1632
  category: "View",
1608
1633
  id: `workspace.focus.${entry.id}`,
1609
1634
  keybinding: `mod+${index + 1}`,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://jxsuite.com/schema/v1",
3
3
  "$id": "StudioAiCredentialsForm",
4
- "$description": "The AI provider credentials form every gate embeds below the keyless offer: a key, a model, an endpoint, and the two buttons that keep or abandon them. Everything here is a projection — `ui/ai-credentials-form.ts` keeps the drafts, decides what a fetch is sent with, what Save actually persists and whether there is anything to Save or Cancel at all. This document never reads a setting and never calls the proxy.",
4
+ "$description": "The AI provider credentials form every gate embeds below the keyless offer: a provider family (only where the backend reaches more than one), a key, a model, an endpoint, and the two buttons that keep or abandon them. Everything here is a projection — `ui/ai-credentials-form.ts` keeps the drafts, decides what a fetch is sent with, what Save actually persists and whether there is anything to Save or Cancel at all. This document never reads a setting and never calls the proxy.",
5
5
  "tagName": "div",
6
6
  "attributes": {
7
7
  "part": "ai-creds-form",
@@ -32,7 +32,7 @@
32
32
  "fontWeight": "500",
33
33
  "fontSize": "var(--jx-text-sm)"
34
34
  },
35
- "& [part=\"key\"], & [part=\"model\"], & [part=\"endpoint\"]": {
35
+ "& [part=\"provider\"], & [part=\"key\"], & [part=\"model\"], & [part=\"endpoint\"]": {
36
36
  "$description": "Every control takes the column's width; the kit's fields are inline-flex by default.",
37
37
  "width": "100%"
38
38
  },
@@ -73,6 +73,54 @@
73
73
  },
74
74
  "textContent": "${state.intro}"
75
75
  },
76
+ {
77
+ "$description": "The family the key belongs to (specs/ai.md §2.6), drawn only where it is a choice: the backend's models route lists more than the OpenAI-compatible family, or the stored or drafted family is already another one, so a reader can always switch back. A backend that lists nothing reaches the OpenAI-compatible family alone and forwards every key there, so offering Claude to it would send a Claude key to OpenAI. Above the key because it decides what the key is.",
78
+ "tagName": "div",
79
+ "attributes": {
80
+ "part": "provider-slot",
81
+ "role": "none"
82
+ },
83
+ "style": {
84
+ "display": "contents"
85
+ },
86
+ "$switch": {
87
+ "$ref": "#/state/showProvider"
88
+ },
89
+ "cases": {
90
+ "true": {
91
+ "tagName": "jx-select",
92
+ "attributes": {
93
+ "part": "provider"
94
+ },
95
+ "$props": {
96
+ "label": "Provider",
97
+ "size": "sm",
98
+ "options": {
99
+ "$ref": "#/state/providerOptions"
100
+ },
101
+ "value": {
102
+ "$ref": "#/state/providerDraft"
103
+ }
104
+ },
105
+ "onchange": {
106
+ "$prototype": "Function",
107
+ "body": [
108
+ {
109
+ "operator": "call",
110
+ "target": {
111
+ "$ref": "#/state/setProvider"
112
+ },
113
+ "value": [
114
+ {
115
+ "$ref": "event#/target/value"
116
+ }
117
+ ]
118
+ }
119
+ ]
120
+ }
121
+ }
122
+ }
123
+ },
76
124
  {
77
125
  "tagName": "jx-textfield",
78
126
  "attributes": {
@@ -82,7 +130,9 @@
82
130
  "label": "AI provider key",
83
131
  "type": "password",
84
132
  "size": "sm",
85
- "placeholder": "sk-… or any compatible key",
133
+ "placeholder": {
134
+ "$ref": "#/state/keyPlaceholder"
135
+ },
86
136
  "value": {
87
137
  "$ref": "#/state/keyDraft"
88
138
  }
@@ -120,7 +170,9 @@
120
170
  "$props": {
121
171
  "label": "Model ID",
122
172
  "size": "sm",
123
- "placeholder": "Model ID (e.g. gpt-4o, claude-sonnet-4-20250514, etc.)",
173
+ "placeholder": {
174
+ "$ref": "#/state/modelPlaceholder"
175
+ },
124
176
  "allowsCustomValue": true,
125
177
  "value": {
126
178
  "$ref": "#/state/modelDraft"
@@ -231,7 +283,9 @@
231
283
  "$props": {
232
284
  "label": "Endpoint",
233
285
  "size": "sm",
234
- "placeholder": "Endpoint (optional, e.g. http://localhost:11434/v1)",
286
+ "placeholder": {
287
+ "$ref": "#/state/endpointPlaceholder"
288
+ },
235
289
  "value": {
236
290
  "$ref": "#/state/baseUrlDraft"
237
291
  }
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * The AI provider credentials form as a mounted document.
4
4
  *
5
- * `ui/ai-credentials-form.ts` is the flow — it holds the three drafts, decides which credentials a
5
+ * `ui/ai-credentials-form.ts` is the flow — it holds the drafts, decides which credentials a
6
6
  * listing is made with, what Save persists and re-reads, and whether there is anything to commit —
7
7
  * and this is the surface it draws into.
8
8
  *
@@ -37,10 +37,22 @@ registerSurface("ai-credentials-form", credentialsDoc);
37
37
  export interface AiCredentialsView {
38
38
  /** The line under the title: where the key goes, and where it does not. */
39
39
  intro: string;
40
- /** The three drafts, exactly as the flow holds them. */
40
+ /** The drafts, exactly as the flow holds them. */
41
+ providerDraft: string;
41
42
  keyDraft: string;
42
43
  modelDraft: string;
43
44
  baseUrlDraft: string;
45
+ /**
46
+ * Whether the provider picker is drawn: the backend reaches another family, or the drafted or
47
+ * stored family already is one (specs/ai.md §2.6).
48
+ */
49
+ showProvider: boolean;
50
+ /** The families the picker offers. */
51
+ providerOptions: SurfaceOption[];
52
+ /** What each field says while it is empty; they follow the drafted family. */
53
+ keyPlaceholder: string;
54
+ modelPlaceholder: string;
55
+ endpointPlaceholder: string;
44
56
  /** The catalogue the last successful listing returned; empty draws no chevron on the field. */
45
57
  models: SurfaceOption[];
46
58
  /** A listing is in flight: the button says so and refuses a second one. */
@@ -59,6 +71,7 @@ export interface AiCredentialsView {
59
71
 
60
72
  /** Everything the reader can do here. */
61
73
  export interface AiCredentialsActions {
74
+ setProvider: (value: string) => void;
62
75
  setKey: (value: string) => void;
63
76
  setModel: (value: string) => void;
64
77
  setBaseUrl: (value: string) => void;
@@ -57,7 +57,7 @@ import {
57
57
  openSettingsMenu,
58
58
  SETTINGS_MENU_PLACEMENT,
59
59
  } from "../panels/settings-menu";
60
- import { WORKSPACES } from "../workspace/workspace-ids";
60
+ import { SWITCHER_WORKSPACES } from "../workspace/workspace-ids";
61
61
  import type { WorkspaceId } from "../workspace/workspace-ids";
62
62
  import commandbarDoc from "./commandbar.json";
63
63
  import type { PresenceProjection } from "../collab/presence-chips";
@@ -584,7 +584,11 @@ function projectSegments(tab: Tab | null): SegmentProjection[] {
584
584
  }
585
585
 
586
586
  /**
587
- * `Design · Content · Media · Styles · Publish`: the five workspaces, as a tablist.
587
+ * `Design · Content · Media · Styles · Publish`: the five switcher workspaces, as a tablist.
588
+ *
589
+ * Project Settings is a workspace too, and is not here: it is reached from its links (the gear
590
+ * menu's row, ⌘⇧, and every `settings.open` deep link), so while it is on screen no tab is selected
591
+ * and any of these five leaves it (studio.md §22.2).
588
592
  *
589
593
  * Each tab RUNS `view.setWorkspace`, so the click, ⌘1–5, the palette row and a script all take the
590
594
  * same path, and the selected tab is `shell.workspace` rather than a second record of it. Publish
@@ -598,7 +602,7 @@ function projectWorkspaces(registry: CommandRegistry | null): WorkspaceTabProjec
598
602
  return [];
599
603
  }
600
604
  const dirty = shell.git.status?.files.length ?? 0;
601
- return WORKSPACES.map((entry) => {
605
+ return SWITCHER_WORKSPACES.map((entry) => {
602
606
  const badge = entry.id === "publish" && dirty > 0 ? String(dirty) : "";
603
607
  const chord = registry.keymap.formatBinding(`workspace.focus.${entry.id}`);
604
608
  const named = chord ? `${entry.title} (${chord})` : entry.title;
@@ -24,7 +24,7 @@
24
24
  "marginBottom": "12px"
25
25
  },
26
26
  "& [part=\"columns\"]": {
27
- "$description": "The 1px gap over the border colour is the divider between the two columns: two panels on `--bg-panel` with `--border` showing through the gap, so nothing draws a rule of its own.",
27
+ "$description": "The 1px gap over the border colour is the divider between the two columns: two panels on the page's own `--bg` with `--border` showing through the gap, so nothing draws a rule of its own. The panels are `--bg`, not `--bg-panel`, because the section is drawn on the Settings home, whose background is `--bg`: a second shade under one section of the form reads as a box nobody asked for.",
28
28
  "display": "flex",
29
29
  "height": "100%",
30
30
  "gap": "1px",
@@ -37,7 +37,7 @@
37
37
  "padding": "12px",
38
38
  "width": "200px",
39
39
  "minWidth": "200px",
40
- "background": "var(--bg-panel)",
40
+ "background": "var(--bg)",
41
41
  "overflowY": "auto"
42
42
  },
43
43
  "& [part=\"entry\"], & [part=\"new-open\"]": {
@@ -62,7 +62,7 @@
62
62
  "display": "flex",
63
63
  "alignItems": "center",
64
64
  "justifyContent": "center",
65
- "background": "var(--bg-panel)",
65
+ "background": "var(--bg)",
66
66
  "color": "var(--fg-dim)",
67
67
  "fontSize": "13px"
68
68
  },
@@ -70,7 +70,7 @@
70
70
  "$description": "`min-width: 0` is the one line `.settings-editor-panel` did not have and needed: a flex child's floor is its content, and the schema form inside this one is a whole form rather than the short cards Data Shapes puts here — so a long pointer or a wide row pushed the column past the right edge of the pane instead of scrolling inside it.",
71
71
  "flex": "1",
72
72
  "padding": "16px",
73
- "background": "var(--bg-panel)",
73
+ "background": "var(--bg)",
74
74
  "overflowY": "auto",
75
75
  "minWidth": "0"
76
76
  },
@@ -41,7 +41,7 @@ export interface ContributedEntryView {
41
41
  /** The key in the section's map on disk — the row's identity and its `data-entry`. */
42
42
  key: string;
43
43
  selected: boolean;
44
- /** `overlay.dialog:settings/entry:<key>`, so a shot can name the row without a selector. */
44
+ /** `pane.<id>/settings/entry:<key>`, so a shot can name the row without a selector. */
45
45
  region: string;
46
46
  }
47
47
 
@@ -61,7 +61,7 @@ export interface ContributedView {
61
61
  editorState: "empty" | "editing";
62
62
  /** What the rename field holds — the key on disk, or what the reader has just typed. */
63
63
  entryName: string;
64
- /** `overlay.dialog:settings/editor`. */
64
+ /** `pane.<id>/settings/editor`. */
65
65
  editorRegion: string;
66
66
  /** The new-entry button: "New content type", or "New entry" when the section names none. */
67
67
  newLabel: string;