@jxsuite/studio 6.1.0 → 6.1.2

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 (645) hide show
  1. package/dist/chunks/2020-f2gkpy8d.js +4 -0
  2. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  3. package/dist/chunks/adapter-4912g339.js +4 -0
  4. package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
  5. package/dist/chunks/cf-settings-br6105tr.js +4 -0
  6. package/dist/chunks/color-28ksk2qm.js +4 -0
  7. package/dist/chunks/color-area-0fj8a4ga.js +4 -0
  8. package/dist/chunks/color-field-xch8kx2g.js +4 -0
  9. package/dist/chunks/color-slider-jxd8v350.js +4 -0
  10. package/dist/chunks/combobox-p0efwjke.js +4 -0
  11. package/dist/chunks/components-db68vsn7.js +4 -0
  12. package/dist/chunks/content-source-1449qesq.js +4 -0
  13. package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
  14. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  15. package/dist/chunks/editor-x9jn86a7.js +4 -0
  16. package/dist/chunks/entry-commands-may24cpt.js +4 -0
  17. package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
  18. package/dist/chunks/file-ops-x9v54pcj.js +4 -0
  19. package/dist/chunks/files-j3knqf0s.js +4 -0
  20. package/dist/chunks/format-host-tyre2trb.js +4 -0
  21. package/dist/chunks/fs-events-64ma9htc.js +4 -0
  22. package/dist/chunks/git-panel-84ps5dex.js +4 -0
  23. package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
  24. package/dist/chunks/icons-pnfz478q.js +4 -0
  25. package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
  26. package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
  27. package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
  28. package/dist/chunks/iframe-entry-zap785cw.js +5 -0
  29. package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
  30. package/dist/chunks/index-b8xw3vy9.js +4 -0
  31. package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
  34. package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
  35. package/dist/chunks/layers-h4xp1pss.js +4 -0
  36. package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
  37. package/dist/chunks/listbox-e74qjyq6.js +4 -0
  38. package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
  39. package/dist/chunks/media-picker-2cweexc5.js +4 -0
  40. package/dist/chunks/menu-n6yzswmy.js +4 -0
  41. package/dist/chunks/menu-ynw13y0s.js +4 -0
  42. package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
  43. package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
  44. package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
  45. package/dist/chunks/notify-cj5zbrs2.js +4 -0
  46. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  47. package/dist/chunks/parse-b7ddhr8m.js +4 -0
  48. package/dist/chunks/platform-3dfws9js.js +4 -0
  49. package/dist/chunks/popover-jt2gxmzs.js +4 -0
  50. package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
  51. package/dist/chunks/quick-search-0dajrwqg.js +4 -0
  52. package/dist/chunks/references-49qgt404.js +4 -0
  53. package/dist/chunks/right-panel-jm1bwe53.js +4 -0
  54. package/dist/chunks/section-registry-6kwc4fky.js +4 -0
  55. package/dist/chunks/select-rzds841e.js +4 -0
  56. package/dist/chunks/split-n2gfpm5m.js +4 -0
  57. package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
  58. package/dist/chunks/studio-0rt52vpq.js +5 -0
  59. package/dist/chunks/studio-18vgbhs5.js +5 -0
  60. package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
  61. package/dist/chunks/studio-24mccdrj.js +5 -0
  62. package/dist/chunks/studio-2eh507zk.js +9 -0
  63. package/dist/chunks/studio-2hcbccfv.js +5 -0
  64. package/dist/chunks/studio-2j1cb95x.js +5 -0
  65. package/dist/chunks/studio-2jbs3rxv.js +5 -0
  66. package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
  67. package/dist/chunks/studio-4h8k4dw9.js +5 -0
  68. package/dist/chunks/studio-5f6n18kx.js +5 -0
  69. package/dist/chunks/studio-5gthpky6.js +5 -0
  70. package/dist/chunks/studio-5ve6bbep.js +5 -0
  71. package/dist/chunks/studio-6ep3js6b.js +9 -0
  72. package/dist/chunks/studio-6wkmf3wz.js +9 -0
  73. package/dist/chunks/studio-841rf3cg.js +5 -0
  74. package/dist/chunks/studio-8gmwgheg.js +5 -0
  75. package/dist/chunks/studio-8qm0ep50.js +5 -0
  76. package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
  79. package/dist/chunks/studio-a3shpz9y.js +5 -0
  80. package/dist/chunks/studio-amsbaaar.js +6 -0
  81. package/dist/chunks/studio-at5spjbc.js +7 -0
  82. package/dist/chunks/studio-b2xv945e.js +5 -0
  83. package/dist/chunks/studio-bn5nkafw.js +5 -0
  84. package/dist/chunks/studio-bw6q5xjf.js +9 -0
  85. package/dist/chunks/studio-c7q0t9x1.js +5 -0
  86. package/dist/chunks/studio-camnhc96.js +6 -0
  87. package/dist/chunks/studio-cffqvnzd.js +5 -0
  88. package/dist/chunks/studio-d81xfh1g.js +5 -0
  89. package/dist/chunks/studio-dgz8d0c1.js +5 -0
  90. package/dist/chunks/studio-efvfrsf8.js +5 -0
  91. package/dist/chunks/studio-er30bpcx.js +5 -0
  92. package/dist/chunks/studio-ezscgr64.js +5 -0
  93. package/dist/chunks/studio-ffrrncvz.js +5 -0
  94. package/dist/chunks/studio-fpphgn8y.js +10 -0
  95. package/dist/chunks/studio-j1kvhdjk.js +4 -0
  96. package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
  97. package/dist/chunks/studio-jjkg84nj.js +5 -0
  98. package/dist/chunks/studio-m0q32ars.js +4 -0
  99. package/dist/chunks/studio-m6bdst11.js +5 -0
  100. package/dist/chunks/studio-nv2cptd4.js +64 -0
  101. package/dist/chunks/studio-nwfrc98n.js +5 -0
  102. package/dist/chunks/studio-p1wgvp7r.js +5 -0
  103. package/dist/chunks/studio-pag2wncm.js +5 -0
  104. package/dist/chunks/studio-qvanvzfd.js +5 -0
  105. package/dist/chunks/studio-qwa64kt7.js +5 -0
  106. package/dist/chunks/studio-rk1zc4x3.js +928 -0
  107. package/dist/chunks/studio-se2r3ptc.js +5 -0
  108. package/dist/chunks/studio-sg2a0dh0.js +5 -0
  109. package/dist/chunks/studio-tjzjhe68.js +5 -0
  110. package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
  112. package/dist/chunks/studio-v2w7q8r1.js +7 -0
  113. package/dist/chunks/studio-v5vjq1h0.js +4 -0
  114. package/dist/chunks/studio-v8aga3vp.js +14 -0
  115. package/dist/chunks/studio-vfcdrfmv.js +5 -0
  116. package/dist/chunks/studio-vmfkgdjf.js +5 -0
  117. package/dist/chunks/studio-wt1816jj.js +5 -0
  118. package/dist/chunks/studio-wz73q5kq.js +4 -0
  119. package/dist/chunks/studio-y04qtxvp.js +7 -0
  120. package/dist/chunks/studio-y21g8zzg.js +5 -0
  121. package/dist/chunks/studio-y64hrt8p.js +12 -0
  122. package/dist/chunks/studio-ynn90f58.js +16 -0
  123. package/dist/chunks/studio-yxz682sx.js +5 -0
  124. package/dist/chunks/studio-zp7snvkq.js +5 -0
  125. package/dist/chunks/studio-zq4z6tm6.js +5 -0
  126. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  127. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  128. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  129. package/dist/chunks/toast-c9fn075p.js +4 -0
  130. package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
  131. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  132. package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
  133. package/dist/chunks/tree-mdq3v5cw.js +4 -0
  134. package/dist/chunks/tsMode-sf49ee9x.js +14 -0
  135. package/dist/chunks/workspace-jtfahpee.js +4 -0
  136. package/dist/chunks/ws-client-nze0k6mv.js +4 -0
  137. package/dist/iframe-entry.js +16 -16
  138. package/dist/manifest.json +63 -63
  139. package/dist/studio.js +98 -98
  140. package/dist/workers/ts.worker.js +3 -3
  141. package/package.json +11 -11
  142. package/src/about/about-modal.ts +4 -3
  143. package/src/account/action-flow.ts +45 -38
  144. package/src/account-status.ts +7 -2
  145. package/src/browse/library-layouts.ts +8 -5
  146. package/src/browse/library-model.ts +18 -6
  147. package/src/browse/library-pane.ts +37 -21
  148. package/src/browse/library-preview.ts +14 -9
  149. package/src/browse/library-source.ts +1 -1
  150. package/src/canvas/asset-refs.ts +24 -9
  151. package/src/canvas/asset-resolve.ts +19 -23
  152. package/src/canvas/canvas-helpers.ts +7 -6
  153. package/src/canvas/canvas-live-render.ts +44 -53
  154. package/src/canvas/canvas-patcher.ts +30 -30
  155. package/src/canvas/canvas-perf.ts +11 -5
  156. package/src/canvas/canvas-render.ts +66 -42
  157. package/src/canvas/canvas-surface.ts +5 -3
  158. package/src/canvas/canvas-utils.ts +163 -64
  159. package/src/canvas/dialog-path.ts +9 -4
  160. package/src/canvas/dialog-state.ts +1 -2
  161. package/src/canvas/diff-marks.ts +9 -16
  162. package/src/canvas/diff-toolbar.ts +8 -7
  163. package/src/canvas/edit-width-drag.ts +4 -1
  164. package/src/canvas/edit-width.ts +1 -3
  165. package/src/canvas/iframe-channel.ts +27 -13
  166. package/src/canvas/iframe-drop.ts +13 -12
  167. package/src/canvas/iframe-editable-root.ts +29 -16
  168. package/src/canvas/iframe-entry.ts +80 -63
  169. package/src/canvas/iframe-eval.ts +73 -49
  170. package/src/canvas/iframe-host.ts +203 -118
  171. package/src/canvas/iframe-inline-edit.ts +69 -32
  172. package/src/canvas/iframe-insert.ts +5 -4
  173. package/src/canvas/iframe-interaction.ts +37 -26
  174. package/src/canvas/iframe-overlay.ts +1 -1
  175. package/src/canvas/iframe-patch.ts +18 -15
  176. package/src/canvas/iframe-position.ts +12 -6
  177. package/src/canvas/iframe-protocol.ts +15 -16
  178. package/src/canvas/iframe-render.ts +41 -36
  179. package/src/canvas/iframe-slash.ts +24 -11
  180. package/src/canvas/iframe-subtree.ts +6 -2
  181. package/src/canvas/path-mapping.ts +19 -12
  182. package/src/canvas/popover-path.ts +7 -3
  183. package/src/canvas/popover-state.ts +1 -2
  184. package/src/canvas/serialize-scope.ts +13 -5
  185. package/src/canvas/stage-scrollbar.ts +2 -1
  186. package/src/canvas/surface-registry.ts +21 -3
  187. package/src/collab/collab-commands.ts +7 -2
  188. package/src/collab/collab-session.ts +84 -45
  189. package/src/collab/collab-state.ts +4 -3
  190. package/src/collab/monaco-binding.ts +16 -13
  191. package/src/collab/monaco-cursors.ts +5 -2
  192. package/src/commands/budget.ts +3 -3
  193. package/src/commands/command-args.ts +103 -71
  194. package/src/commands/context.ts +22 -20
  195. package/src/commands/defaults.ts +4 -1
  196. package/src/commands/keymap.ts +47 -43
  197. package/src/commands/levels.ts +3 -3
  198. package/src/commands/live-context.ts +10 -8
  199. package/src/commands/reference.ts +2 -1
  200. package/src/commands/registry.ts +12 -10
  201. package/src/commands/run-reported.ts +15 -10
  202. package/src/component-props.ts +46 -30
  203. package/src/content/collection-match.ts +5 -4
  204. package/src/content/draft-state.ts +4 -3
  205. package/src/content/entry-commands.ts +3 -2
  206. package/src/content/entry-editor.ts +29 -17
  207. package/src/content/entry-fields.ts +12 -7
  208. package/src/content/entry-model.ts +21 -12
  209. package/src/editor/canvas-context-menu.ts +1 -2
  210. package/src/editor/canvas-slash-bridge.ts +3 -6
  211. package/src/editor/content-slice.ts +16 -14
  212. package/src/editor/context-menu.ts +35 -22
  213. package/src/editor/convert-targets.ts +30 -35
  214. package/src/editor/convert-to-component.ts +11 -5
  215. package/src/editor/convert-to-repeater.ts +34 -22
  216. package/src/editor/editable-tags.ts +17 -2
  217. package/src/editor/file-drop-action.ts +21 -22
  218. package/src/editor/inline-edit-apply.ts +35 -17
  219. package/src/editor/inline-edit.ts +66 -50
  220. package/src/editor/inline-format.ts +59 -56
  221. package/src/editor/inline-link.ts +40 -15
  222. package/src/editor/insert-zone-action.ts +1 -1
  223. package/src/editor/merge-tags.ts +58 -19
  224. package/src/editor/repeater-scope.ts +39 -28
  225. package/src/editor/shortcuts.ts +87 -47
  226. package/src/editor/slash-menu.ts +1 -6
  227. package/src/files/asset-versions.ts +4 -4
  228. package/src/files/components.ts +15 -10
  229. package/src/files/elements.ts +5 -6
  230. package/src/files/file-ops.ts +77 -36
  231. package/src/files/files.ts +90 -95
  232. package/src/files/media-meta.ts +2 -1
  233. package/src/files/media-paths.ts +6 -1
  234. package/src/files/serialize-document.ts +2 -2
  235. package/src/format/constraints.ts +1 -1
  236. package/src/format/convert-file.ts +27 -13
  237. package/src/format/format-choices.ts +2 -1
  238. package/src/format/format-host.ts +76 -50
  239. package/src/github/github-auth-status.ts +27 -3
  240. package/src/github/github-auth.ts +19 -9
  241. package/src/github/github-publish.ts +24 -20
  242. package/src/grid/cell-editors.ts +46 -31
  243. package/src/grid/cell-popovers.ts +5 -3
  244. package/src/grid/edit-buffer.ts +10 -9
  245. package/src/grid/grid-controller.ts +20 -22
  246. package/src/grid/grid-layout.ts +21 -5
  247. package/src/grid/grid-open.ts +3 -6
  248. package/src/grid/grid-panel.ts +11 -4
  249. package/src/grid/grid-source.ts +8 -8
  250. package/src/grid/grid-view.ts +14 -17
  251. package/src/grid/redirects-grid.ts +14 -5
  252. package/src/grid/redirects.ts +16 -14
  253. package/src/grid/schema-columns.ts +25 -19
  254. package/src/grid/sources/connector-source.ts +47 -20
  255. package/src/grid/sources/content-source.ts +25 -24
  256. package/src/grid/sources/csv-file-source.ts +2 -2
  257. package/src/grid/tabulator-tables.d.ts +55 -34
  258. package/src/hosting/stage.ts +7 -7
  259. package/src/i18n/i18n-commands.ts +1 -2
  260. package/src/media/media-pane.ts +4 -1
  261. package/src/new-project/add-repo-modal.ts +20 -19
  262. package/src/new-project/import-tab.ts +10 -14
  263. package/src/new-project/location-fields.ts +2 -1
  264. package/src/new-project/new-project-modal.ts +12 -9
  265. package/src/packages/jxsuite-update.ts +4 -3
  266. package/src/packages/pull-package-sync.ts +26 -25
  267. package/src/page-params.ts +97 -68
  268. package/src/panels/activity-panel.ts +17 -9
  269. package/src/panels/ai-chat/attached-context.ts +13 -7
  270. package/src/panels/ai-chat/chat-view.ts +80 -73
  271. package/src/panels/ai-chat/composer.ts +30 -33
  272. package/src/panels/ai-chat/sessions-view.ts +1 -2
  273. package/src/panels/ai-panel.ts +23 -20
  274. package/src/panels/block-action-bar.ts +46 -35
  275. package/src/panels/bottom-dock.ts +5 -3
  276. package/src/panels/canvas-dnd-bridge.ts +31 -24
  277. package/src/panels/data-explorer.ts +62 -25
  278. package/src/panels/data-grid.ts +14 -11
  279. package/src/panels/dnd.ts +108 -118
  280. package/src/panels/editors.ts +55 -22
  281. package/src/panels/elements-panel.ts +10 -3
  282. package/src/panels/events-panel.ts +84 -69
  283. package/src/panels/formula-workspace.ts +76 -51
  284. package/src/panels/frontmatter-fields.ts +24 -19
  285. package/src/panels/frontmatter-panel.ts +44 -34
  286. package/src/panels/git-diff-open.ts +4 -4
  287. package/src/panels/git-panel.ts +49 -61
  288. package/src/panels/head-panel.ts +131 -111
  289. package/src/panels/i18n-panel.ts +10 -3
  290. package/src/panels/imports-panel.ts +23 -47
  291. package/src/panels/jump-bar.ts +48 -29
  292. package/src/panels/layers-panel.ts +97 -74
  293. package/src/panels/left-panel.ts +3 -3
  294. package/src/panels/pane-context.ts +31 -22
  295. package/src/panels/pane-grid.ts +49 -20
  296. package/src/panels/panel-registry.ts +22 -37
  297. package/src/panels/properties-panel.ts +175 -121
  298. package/src/panels/quick-search.ts +53 -31
  299. package/src/panels/right-panel.ts +3 -3
  300. package/src/panels/seo-modal.ts +13 -17
  301. package/src/panels/settings-menu.ts +15 -15
  302. package/src/panels/signals-panel.ts +153 -131
  303. package/src/panels/statement-editor.ts +230 -140
  304. package/src/panels/style-panel.ts +254 -216
  305. package/src/panels/style-utils.ts +114 -51
  306. package/src/panels/stylebook-doc.ts +57 -54
  307. package/src/panels/stylebook-layers-panel.ts +9 -9
  308. package/src/panels/stylebook-panel.ts +13 -17
  309. package/src/panels/tab-drop.ts +27 -11
  310. package/src/panels/tab-strip.ts +36 -26
  311. package/src/platform-errors.ts +57 -43
  312. package/src/platform.ts +58 -30
  313. package/src/platforms/cloud.ts +345 -175
  314. package/src/platforms/default-platform.ts +10 -4
  315. package/src/platforms/devserver.ts +174 -127
  316. package/src/platforms/read-batcher.ts +16 -8
  317. package/src/project-list.ts +2 -1
  318. package/src/publish/deploy-checklist.ts +8 -2
  319. package/src/publish/pages-service.ts +28 -13
  320. package/src/publish/publish-commands.ts +5 -4
  321. package/src/publish/publish-panel.ts +10 -6
  322. package/src/recent-projects.ts +15 -8
  323. package/src/resize-edges.ts +26 -36
  324. package/src/services/a11y-report.ts +26 -19
  325. package/src/services/agent-seed.ts +23 -11
  326. package/src/services/ai-ask.ts +9 -12
  327. package/src/services/ai-command-tools.ts +68 -62
  328. package/src/services/ai-import-tools.ts +80 -67
  329. package/src/services/ai-models.ts +17 -13
  330. package/src/services/ai-project-tools.ts +68 -32
  331. package/src/services/ai-session-store.ts +19 -10
  332. package/src/services/ai-system-prompt.ts +46 -20
  333. package/src/services/ai-tools.ts +71 -27
  334. package/src/services/ai-write-report.ts +20 -12
  335. package/src/services/ai-writes.ts +4 -4
  336. package/src/services/automation.ts +58 -31
  337. package/src/services/cem-export.ts +149 -58
  338. package/src/services/clock.ts +6 -1
  339. package/src/services/code-services.ts +37 -31
  340. package/src/services/context-manager.ts +14 -10
  341. package/src/services/context-resolver.ts +20 -8
  342. package/src/services/data-service.ts +19 -15
  343. package/src/services/directory-picker.ts +18 -12
  344. package/src/services/document-assistant.ts +39 -19
  345. package/src/services/gated-registry.ts +10 -6
  346. package/src/services/harness/chat-reducer.ts +23 -1
  347. package/src/services/import-client.ts +91 -38
  348. package/src/services/import-seed.ts +8 -2
  349. package/src/services/jx-validate.ts +28 -31
  350. package/src/services/live-preview.ts +0 -0
  351. package/src/services/live-surfaces.ts +6 -3
  352. package/src/services/model-uri.ts +10 -2
  353. package/src/services/module-preloads.ts +12 -8
  354. package/src/services/monaco-buffer.ts +43 -24
  355. package/src/services/monaco-lazy.ts +7 -8
  356. package/src/services/monaco-setup.ts +23 -16
  357. package/src/services/notify.ts +44 -17
  358. package/src/services/popover-report.ts +25 -10
  359. package/src/services/preview-eval.ts +20 -8
  360. package/src/services/profile.ts +13 -6
  361. package/src/services/project-path.ts +13 -10
  362. package/src/services/references.ts +0 -0
  363. package/src/services/render-critic.ts +8 -7
  364. package/src/services/settings/kernel.ts +13 -4
  365. package/src/services/settings/write-queue.ts +9 -9
  366. package/src/services/token-lint.ts +12 -10
  367. package/src/services/tool-executor.ts +17 -5
  368. package/src/services/tool-outcomes.ts +44 -24
  369. package/src/services/trusted-types.ts +24 -7
  370. package/src/settings/contexts-section.ts +11 -8
  371. package/src/settings/contributed-section.ts +79 -60
  372. package/src/settings/css-vars-editor.ts +37 -16
  373. package/src/settings/defs-editor.ts +38 -35
  374. package/src/settings/extension-rows.ts +16 -8
  375. package/src/settings/extension-sections.ts +23 -13
  376. package/src/settings/extensions-section.ts +4 -1
  377. package/src/settings/general-settings.ts +11 -8
  378. package/src/settings/locales-section.ts +20 -12
  379. package/src/settings/preferences-dialog.ts +9 -6
  380. package/src/settings/preferences-keymap.ts +7 -5
  381. package/src/settings/preferences-sections.ts +11 -5
  382. package/src/settings/project-sections.ts +1 -1
  383. package/src/settings/schema-field-ui.ts +9 -0
  384. package/src/settings/settings-document.ts +5 -5
  385. package/src/shell/tree.ts +6 -5
  386. package/src/shell.ts +104 -81
  387. package/src/site-context.ts +37 -22
  388. package/src/state.ts +41 -49
  389. package/src/store.ts +54 -34
  390. package/src/studio.ts +39 -77
  391. package/src/style/live-preview.ts +1 -1
  392. package/src/style/project-styles.ts +6 -7
  393. package/src/style/token-ref.ts +5 -4
  394. package/src/surfaces/about.ts +18 -19
  395. package/src/surfaces/add-repo.ts +17 -19
  396. package/src/surfaces/ai-chat.ts +31 -36
  397. package/src/surfaces/ai-credentials-form.ts +6 -16
  398. package/src/surfaces/ai-managed-connect.ts +3 -4
  399. package/src/surfaces/ai-model-picker.ts +3 -5
  400. package/src/surfaces/block-action-bar.ts +22 -11
  401. package/src/surfaces/boot-failure.ts +4 -5
  402. package/src/surfaces/bottom-dock.ts +9 -18
  403. package/src/surfaces/canvas-stage.ts +12 -11
  404. package/src/surfaces/cf-account-picker.ts +17 -18
  405. package/src/surfaces/commandbar.ts +14 -9
  406. package/src/surfaces/convert-repeater.ts +17 -19
  407. package/src/surfaces/data-actions.ts +9 -7
  408. package/src/surfaces/dialog.ts +26 -28
  409. package/src/surfaces/diff-toolbar.ts +9 -7
  410. package/src/surfaces/doc-header.ts +10 -19
  411. package/src/surfaces/empty-state.ts +7 -10
  412. package/src/surfaces/entry-editor.ts +14 -11
  413. package/src/surfaces/expression-editor.ts +11 -25
  414. package/src/surfaces/files-panel.ts +27 -14
  415. package/src/surfaces/formula-palette.ts +4 -5
  416. package/src/surfaces/git-panel.ts +7 -15
  417. package/src/surfaces/github-auth.ts +16 -20
  418. package/src/surfaces/github-publish.ts +17 -22
  419. package/src/surfaces/grid-cell.ts +30 -31
  420. package/src/surfaces/grid-open.ts +10 -14
  421. package/src/surfaces/grid-panel.ts +13 -9
  422. package/src/surfaces/grid-replace.ts +13 -13
  423. package/src/surfaces/grid-views.ts +15 -18
  424. package/src/surfaces/inspector-dock.ts +13 -12
  425. package/src/surfaces/jump-bar.ts +5 -6
  426. package/src/surfaces/jxsuite-update.ts +16 -22
  427. package/src/surfaces/library-pane.ts +25 -20
  428. package/src/surfaces/logic-panel.ts +17 -30
  429. package/src/surfaces/logic-workspace.ts +13 -15
  430. package/src/surfaces/media-browser.ts +11 -10
  431. package/src/surfaces/media-field.ts +4 -5
  432. package/src/surfaces/media-pane.ts +8 -7
  433. package/src/surfaces/menu.ts +29 -23
  434. package/src/surfaces/navigator-dock.ts +11 -12
  435. package/src/surfaces/new-project.ts +27 -26
  436. package/src/surfaces/pane-context.ts +20 -25
  437. package/src/surfaces/pane-grid.ts +15 -10
  438. package/src/surfaces/panel-activity.ts +5 -6
  439. package/src/surfaces/panel-data.ts +3 -4
  440. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  441. package/src/surfaces/panel-elements.ts +5 -7
  442. package/src/surfaces/panel-i18n.ts +5 -7
  443. package/src/surfaces/panel-imports.ts +6 -13
  444. package/src/surfaces/panel-outline.ts +25 -19
  445. package/src/surfaces/panel-page.ts +11 -18
  446. package/src/surfaces/panel-problems.ts +5 -7
  447. package/src/surfaces/panel-signals.ts +20 -34
  448. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  449. package/src/surfaces/preferences.ts +21 -11
  450. package/src/surfaces/progress-modal.ts +15 -9
  451. package/src/surfaces/properties-panel.json +1 -1
  452. package/src/surfaces/properties-panel.ts +20 -42
  453. package/src/surfaces/publish.ts +18 -18
  454. package/src/surfaces/push-plan.ts +7 -8
  455. package/src/surfaces/rail.json +126 -73
  456. package/src/surfaces/rail.ts +38 -12
  457. package/src/surfaces/reference-field.ts +11 -15
  458. package/src/surfaces/schema-builder.ts +16 -22
  459. package/src/surfaces/schema-form.ts +15 -25
  460. package/src/surfaces/secret-field.ts +9 -6
  461. package/src/surfaces/seo.ts +21 -15
  462. package/src/surfaces/settings-contexts.ts +9 -7
  463. package/src/surfaces/settings-contributed.ts +14 -10
  464. package/src/surfaces/settings-css-vars.ts +5 -12
  465. package/src/surfaces/settings-defs.json +2 -2
  466. package/src/surfaces/settings-defs.ts +17 -21
  467. package/src/surfaces/settings-deploy.ts +8 -15
  468. package/src/surfaces/settings-extensions.ts +5 -6
  469. package/src/surfaces/settings-head.ts +33 -39
  470. package/src/surfaces/settings-locales.ts +8 -20
  471. package/src/surfaces/settings-overview.ts +5 -6
  472. package/src/surfaces/settings-packages.ts +8 -7
  473. package/src/surfaces/settings-pane.ts +9 -18
  474. package/src/surfaces/settings-rawjson.ts +5 -6
  475. package/src/surfaces/shell.ts +1 -2
  476. package/src/surfaces/slash-menu.ts +19 -9
  477. package/src/surfaces/statements.ts +13 -18
  478. package/src/surfaces/statusbar.ts +17 -14
  479. package/src/surfaces/style-panel.ts +18 -31
  480. package/src/surfaces/stylebook-chrome.ts +3 -5
  481. package/src/surfaces/tab-strip.ts +14 -13
  482. package/src/surfaces/target-line.ts +6 -7
  483. package/src/surfaces/welcome.ts +5 -7
  484. package/src/tabs/patch-ops.ts +4 -3
  485. package/src/tabs/project-config.ts +32 -21
  486. package/src/tabs/selection.ts +36 -8
  487. package/src/tabs/tab.ts +52 -41
  488. package/src/tabs/transact.ts +98 -53
  489. package/src/tabs/typing.ts +31 -0
  490. package/src/types.ts +32 -17
  491. package/src/ui/ai-credentials-form.ts +10 -13
  492. package/src/ui/ai-model-picker.ts +3 -3
  493. package/src/ui/cf-account-picker.ts +7 -9
  494. package/src/ui/color-selector.ts +9 -5
  495. package/src/ui/dynamic-slot.ts +7 -8
  496. package/src/ui/expression-editor.ts +112 -105
  497. package/src/ui/form-controls.ts +57 -48
  498. package/src/ui/formula-catalog.ts +239 -230
  499. package/src/ui/formula-chips.ts +33 -18
  500. package/src/ui/layers.ts +44 -31
  501. package/src/ui/media-picker.ts +18 -9
  502. package/src/ui/popover-surface.ts +20 -12
  503. package/src/ui/progress-modal.ts +13 -8
  504. package/src/ui/regions.ts +7 -6
  505. package/src/ui/schema-form.ts +113 -70
  506. package/src/ui/surface.ts +71 -8
  507. package/src/ui/timing.ts +9 -0
  508. package/src/ui/value-source.ts +44 -31
  509. package/src/ui/virtual-window.ts +3 -2
  510. package/src/utils/base64.ts +3 -1
  511. package/src/utils/edit-display.ts +103 -74
  512. package/src/utils/element-selectors.ts +3 -2
  513. package/src/utils/google-fonts.ts +15 -14
  514. package/src/utils/inherited-style.ts +18 -20
  515. package/src/utils/link-target.ts +1 -1
  516. package/src/utils/preview-format.ts +25 -3
  517. package/src/utils/strip-events.ts +49 -22
  518. package/src/utils/studio-utils.ts +29 -14
  519. package/src/view.ts +2 -3
  520. package/src/workspace/pane-derive.ts +10 -12
  521. package/src/workspace/session.ts +53 -43
  522. package/src/workspace/workspace.ts +47 -36
  523. package/dist/chunks/2020-nkxms0ay.js +0 -4
  524. package/dist/chunks/adapter-m948ab5f.js +0 -4
  525. package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
  526. package/dist/chunks/cf-settings-356xdtne.js +0 -4
  527. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  528. package/dist/chunks/color-field-embq5ctg.js +0 -4
  529. package/dist/chunks/color-fpezvnkt.js +0 -4
  530. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  531. package/dist/chunks/combobox-773hdzyj.js +0 -4
  532. package/dist/chunks/components-yk3t844e.js +0 -4
  533. package/dist/chunks/content-source-bawmyc09.js +0 -4
  534. package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
  535. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  536. package/dist/chunks/editor-6sc8nacq.js +0 -4
  537. package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
  538. package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
  539. package/dist/chunks/file-ops-gye0qw56.js +0 -4
  540. package/dist/chunks/files-dmc2xvcq.js +0 -4
  541. package/dist/chunks/format-host-t76b53f8.js +0 -4
  542. package/dist/chunks/fs-events-cg4tpz06.js +0 -4
  543. package/dist/chunks/git-panel-yef7bshy.js +0 -4
  544. package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
  545. package/dist/chunks/icons-qbh8akb1.js +0 -4
  546. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  547. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  548. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  549. package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
  550. package/dist/chunks/index-nag78a9h.js +0 -4
  551. package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
  552. package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
  553. package/dist/chunks/layers-fvz99859.js +0 -4
  554. package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
  555. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  556. package/dist/chunks/lit-html-9agdspkt.js +0 -4
  557. package/dist/chunks/media-picker-rhjvyy00.js +0 -4
  558. package/dist/chunks/menu-2e4y9j7b.js +0 -4
  559. package/dist/chunks/menu-37d07z9m.js +0 -4
  560. package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
  561. package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
  562. package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
  563. package/dist/chunks/notify-h3www560.js +0 -4
  564. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  565. package/dist/chunks/parse-897fvqah.js +0 -4
  566. package/dist/chunks/platform-hz34wcd7.js +0 -4
  567. package/dist/chunks/popover-8htra4er.js +0 -4
  568. package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
  569. package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
  570. package/dist/chunks/references-2cgdxnb8.js +0 -4
  571. package/dist/chunks/right-panel-jf856w5w.js +0 -4
  572. package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
  573. package/dist/chunks/select-n3v7gwas.js +0 -4
  574. package/dist/chunks/split-pff8f3ze.js +0 -4
  575. package/dist/chunks/studio-0f55h9ye.js +0 -5
  576. package/dist/chunks/studio-0sqdhnew.js +0 -12
  577. package/dist/chunks/studio-19x1c75w.js +0 -5
  578. package/dist/chunks/studio-2sqcndak.js +0 -5
  579. package/dist/chunks/studio-3aey7dd3.js +0 -5
  580. package/dist/chunks/studio-3bpdkq2s.js +0 -5
  581. package/dist/chunks/studio-47y6fbpf.js +0 -5
  582. package/dist/chunks/studio-4m3826v2.js +0 -5
  583. package/dist/chunks/studio-4nx2dj1g.js +0 -4
  584. package/dist/chunks/studio-4xv5s47r.js +0 -9
  585. package/dist/chunks/studio-5g4t8v6w.js +0 -5
  586. package/dist/chunks/studio-5py436sf.js +0 -5
  587. package/dist/chunks/studio-77kt594t.js +0 -5
  588. package/dist/chunks/studio-8f87n763.js +0 -10
  589. package/dist/chunks/studio-8mb00b84.js +0 -5
  590. package/dist/chunks/studio-8p51gq2h.js +0 -6
  591. package/dist/chunks/studio-954ds834.js +0 -5
  592. package/dist/chunks/studio-9ft45c83.js +0 -9
  593. package/dist/chunks/studio-a2138x5k.js +0 -7
  594. package/dist/chunks/studio-a9yzstqj.js +0 -5
  595. package/dist/chunks/studio-acdksxx6.js +0 -5
  596. package/dist/chunks/studio-ar8jcf2y.js +0 -5
  597. package/dist/chunks/studio-bmn4mn9j.js +0 -7
  598. package/dist/chunks/studio-e7xxa0sj.js +0 -5
  599. package/dist/chunks/studio-ecaz25vk.js +0 -5
  600. package/dist/chunks/studio-ery42sqr.js +0 -4
  601. package/dist/chunks/studio-fzdywr6p.js +0 -9
  602. package/dist/chunks/studio-g5fmf0c1.js +0 -5
  603. package/dist/chunks/studio-g7nse7zb.js +0 -5
  604. package/dist/chunks/studio-geq1ea6k.js +0 -14
  605. package/dist/chunks/studio-ghkb32r8.js +0 -5
  606. package/dist/chunks/studio-ghrhy2y7.js +0 -5
  607. package/dist/chunks/studio-grawhey1.js +0 -5
  608. package/dist/chunks/studio-h0xgswew.js +0 -5
  609. package/dist/chunks/studio-h9c4p2tx.js +0 -5
  610. package/dist/chunks/studio-jyzj5cxs.js +0 -5
  611. package/dist/chunks/studio-mgx8yhnz.js +0 -64
  612. package/dist/chunks/studio-mpb04y1d.js +0 -6
  613. package/dist/chunks/studio-n17mty64.js +0 -5
  614. package/dist/chunks/studio-nwh2eqsk.js +0 -6
  615. package/dist/chunks/studio-q1h883bt.js +0 -16
  616. package/dist/chunks/studio-q4tv82h7.js +0 -9
  617. package/dist/chunks/studio-qpqa7vk3.js +0 -5
  618. package/dist/chunks/studio-qqz8e5gk.js +0 -5
  619. package/dist/chunks/studio-qvasen3f.js +0 -5
  620. package/dist/chunks/studio-rggdb3hm.js +0 -5
  621. package/dist/chunks/studio-sghy936h.js +0 -4
  622. package/dist/chunks/studio-skprc6ef.js +0 -5
  623. package/dist/chunks/studio-tt2nactf.js +0 -5
  624. package/dist/chunks/studio-tyasmc39.js +0 -5
  625. package/dist/chunks/studio-vk9ezads.js +0 -5
  626. package/dist/chunks/studio-vzacdfsc.js +0 -4
  627. package/dist/chunks/studio-w4c0xmrw.js +0 -5
  628. package/dist/chunks/studio-wfjqhhbk.js +0 -5
  629. package/dist/chunks/studio-wgh5kxpj.js +0 -5
  630. package/dist/chunks/studio-xasj0796.js +0 -5
  631. package/dist/chunks/studio-y78s8r2n.js +0 -5
  632. package/dist/chunks/studio-z8w183sh.js +0 -5
  633. package/dist/chunks/studio-zscd9ty4.js +0 -928
  634. package/dist/chunks/studio-zxp13sss.js +0 -7
  635. package/dist/chunks/studio-zygnmm01.js +0 -5
  636. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  637. package/dist/chunks/tabs-jwthg40w.js +0 -4
  638. package/dist/chunks/textfield-spy3hc77.js +0 -4
  639. package/dist/chunks/toast-4d35zd64.js +0 -4
  640. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  641. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  642. package/dist/chunks/tree-h19v1jfz.js +0 -4
  643. package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
  644. package/dist/chunks/workspace-m15qtcqp.js +0 -4
  645. package/dist/chunks/ws-client-nf61frr1.js +0 -4
package/src/shell.ts CHANGED
@@ -21,6 +21,7 @@
21
21
  * the branch. See specs/studio.md and the level × placement matrix.
22
22
  */
23
23
 
24
+ import { isBoolean, isJsonObject, isNumber, isString } from "@jxsuite/schema/guards";
24
25
  import { effect, effectScope, reactive } from "./reactivity";
25
26
  import { SETTINGS } from "./services/settings/definitions";
26
27
  import { readStoredSetting, setSetting } from "./services/settings/kernel";
@@ -39,18 +40,11 @@ import {
39
40
  stringProperty,
40
41
  } from "./commands/command-args";
41
42
  import type { EffectScope } from "@vue/reactivity";
43
+ import type { JsonObject, JsonValue } from "@jxsuite/schema/types";
42
44
  import type { LayoutHit } from "./canvas/iframe-protocol";
43
- import type { GitBranchesResult, GitDiffState, GitStatusResult } from "./types";
45
+ import type { GitBranchesResult, GitDiffState, GitLogEntry, GitStatusResult } from "./types";
44
46
  import type { AnyCommand, CommandRegistry } from "./commands/registry";
45
47
 
46
- /**
47
- * The canvas selection when the author clicked LAYOUT chrome rather than page content — a header, a
48
- * footer, anything contributed by the layout file. It is deliberately NOT a document selection: the
49
- * node is not in the open page at all, so the properties panel shows the read-only layout panel
50
- * (with "Open Layout →") instead of the element inspector. See {@link setLayoutSelection}.
51
- */
52
- export type LayoutSelection = LayoutHit;
53
-
54
48
  /**
55
49
  * The three resizable docks around the pane grid: two flanking it, one under it.
56
50
  *
@@ -115,23 +109,23 @@ export type NavigatorPanelId = (typeof NAVIGATOR_PANEL_IDS)[number];
115
109
  * value is the one place those old strings can still arrive from, so they are translated once, on
116
110
  * read, and then never again — there is no alias in the registry and no branch in the rail.
117
111
  */
118
- const RENAMED_PANEL_IDS: Readonly<Record<string, NavigatorPanelId>> = {
119
- blocks: "insert",
120
- head: "page",
121
- imports: "packages",
112
+ const RENAMED_PANEL_IDS = new Map<string, NavigatorPanelId>([
113
+ ["blocks", "insert"],
114
+ ["head", "page"],
115
+ ["imports", "packages"],
122
116
  /* Not a rename — a MERGE. The State editor is part of the Data panel now (§5.6), so a
123
117
  stored `leftTab: "state"` names a real place and lands on it, rather than returning `null` and
124
118
  booting into the default the way `problems` does. Defining a value and watching it resolve are
125
119
  one task; they were two panels. */
126
- state: "data",
127
- };
120
+ ["state", "data"],
121
+ ]);
128
122
 
129
123
  /** The panel the Navigator wakes up on when nothing usable is stored. */
130
124
  export const DEFAULT_PANEL_ID: NavigatorPanelId = "layers";
131
125
 
132
126
  /** Whether a string is a declared panel id. */
133
127
  export function isNavigatorPanelId(value: unknown): value is NavigatorPanelId {
134
- return typeof value === "string" && (NAVIGATOR_PANEL_IDS as readonly string[]).includes(value);
128
+ return typeof value === "string" && NAVIGATOR_PANEL_IDS.some((id) => id === value);
135
129
  }
136
130
 
137
131
  /**
@@ -147,10 +141,12 @@ export function isNavigatorPanelId(value: unknown): value is NavigatorPanelId {
147
141
  * drift was a control that silently did nothing.
148
142
  */
149
143
  export function requireNavigatorPanelId(value: string, source: string): NavigatorPanelId {
150
- if (!isNavigatorPanelId(value)) {
144
+ // `find` hands back the DECLARED id, typed as one, which is the same string the caller sent.
145
+ const id = NAVIGATOR_PANEL_IDS.find((candidate) => candidate === value);
146
+ if (id === undefined) {
151
147
  throw new Error(`${source}: "${value}" is not a declared Navigator panel id.`);
152
148
  }
153
- return value;
149
+ return id;
154
150
  }
155
151
 
156
152
  /**
@@ -166,15 +162,15 @@ export function requireNavigatorPanelId(value: string, source: string): Navigato
166
162
  * Bottom dock keeps its own `bottomTab`, which already defaults to Problems. This is exactly the
167
163
  * wedge this function exists to prevent.
168
164
  */
169
- export function migratePanelId(stored: unknown): NavigatorPanelId | null {
170
- if (typeof stored !== "string") {
165
+ export function migratePanelId(stored: JsonValue | undefined): NavigatorPanelId | null {
166
+ if (!isString(stored)) {
171
167
  return null;
172
168
  }
173
- const renamed = RENAMED_PANEL_IDS[stored];
169
+ const renamed = RENAMED_PANEL_IDS.get(stored);
174
170
  if (renamed) {
175
171
  return renamed;
176
172
  }
177
- return isNavigatorPanelId(stored) ? stored : null;
173
+ return NAVIGATOR_PANEL_IDS.find((id) => id === stored) ?? null;
178
174
  }
179
175
 
180
176
  /**
@@ -199,7 +195,7 @@ export const DEFAULT_INSPECTOR_TAB: InspectorTabId = "properties";
199
195
 
200
196
  /** Whether a string is a declared Inspector tab id. */
201
197
  export function isInspectorTabId(value: unknown): value is InspectorTabId {
202
- return typeof value === "string" && (INSPECTOR_TAB_IDS as readonly string[]).includes(value);
198
+ return typeof value === "string" && INSPECTOR_TAB_IDS.some((id) => id === value);
203
199
  }
204
200
 
205
201
  /**
@@ -225,7 +221,7 @@ export const DEFAULT_BOTTOM_TAB: BottomTabId = "problems";
225
221
 
226
222
  /** Whether a string is a declared Bottom dock tab id. */
227
223
  export function isBottomTabId(value: unknown): value is BottomTabId {
228
- return typeof value === "string" && (BOTTOM_TAB_IDS as readonly string[]).includes(value);
224
+ return typeof value === "string" && BOTTOM_TAB_IDS.some((id) => id === value);
229
225
  }
230
226
 
231
227
  /** The Studio chrome's themes — the `data-theme` stamp on `<html>` (studio-ui-guidelines.md §1.1). */
@@ -249,13 +245,9 @@ export interface DockState {
249
245
  size: number;
250
246
  }
251
247
 
252
- /** One row of `git log`, as the Source Control panel's History tab renders it. */
253
- export interface GitLogEntry {
254
- hash: string;
255
- message: string;
256
- author: string;
257
- date: string;
258
- }
248
+ /* One row of `git log`, as the Source Control panel's History tab renders it: the platform's own
249
+ `gitLog` row, re-exported so the panels reading shell state keep one import. */
250
+ export type { GitLogEntry } from "./types";
259
251
 
260
252
  /** Source control — project level, one copy, independent of which document is focused. */
261
253
  export interface ShellGit {
@@ -354,14 +346,20 @@ export interface ShellState {
354
346
  layout: string;
355
347
  /** Every layout this project has, built-ins included. Persisted per project root. */
356
348
  layouts: LayoutPreset[];
357
- layoutSelection: LayoutSelection | null;
349
+ /**
350
+ * Layout chrome the author clicked, or `null`: a header, a footer, anything contributed by the
351
+ * layout file. It is deliberately NOT a document selection: the node is not in the open page at
352
+ * all, so the properties panel shows the read-only layout panel (with "Open Layout →") instead of
353
+ * the element inspector. See {@link setLayoutSelection}.
354
+ */
355
+ layoutSelection: LayoutHit | null;
358
356
  /** Which section Project Settings opens on. */
359
357
  settingsTab: string;
360
358
  stylebook: ShellStylebook;
361
359
  git: ShellGit;
362
360
  }
363
361
 
364
- const DOCK_STORAGE_KEY = "jx-studio-panel-widths";
362
+ export const DOCK_STORAGE_KEY = "jx-studio-panel-widths";
365
363
 
366
364
  /**
367
365
  * The per-project record's key prefix — one namespaced record per project root (§14.8).
@@ -387,8 +385,8 @@ const PROJECT_STORAGE_PREFIX = "jx-studio-project::";
387
385
  const DEFAULT_THEME: ChromeTheme = "dark";
388
386
 
389
387
  /** Whether a string is one of the declared {@link CHROME_THEMES}. */
390
- function isChromeTheme(value: unknown): value is ChromeTheme {
391
- return typeof value === "string" && (CHROME_THEMES as readonly string[]).includes(value);
388
+ export function isChromeTheme(value: unknown): value is ChromeTheme {
389
+ return typeof value === "string" && CHROME_THEMES.some((theme) => theme === value);
392
390
  }
393
391
 
394
392
  /** Read the persisted theme, falling back to {@link DEFAULT_THEME} on an absent/unknown value. */
@@ -486,8 +484,8 @@ export const PANE_SPLIT_MAX = 0.8;
486
484
  * range, so the only way a bad value arrives is a corrupt or hand-edited record — and that is the
487
485
  * one caller that has to be defended.
488
486
  */
489
- function clampPaneSplit(value: unknown): number {
490
- return typeof value === "number" && value >= PANE_SPLIT_MIN && value <= PANE_SPLIT_MAX
487
+ function clampPaneSplit(value: JsonValue | undefined): number {
488
+ return isNumber(value) && value >= PANE_SPLIT_MIN && value <= PANE_SPLIT_MAX
491
489
  ? value
492
490
  : DEFAULT_PANE_SPLIT;
493
491
  }
@@ -497,15 +495,27 @@ export function setPaneSplit(value: number): void {
497
495
  shell.paneSplit = Math.min(PANE_SPLIT_MAX, Math.max(PANE_SPLIT_MIN, value));
498
496
  }
499
497
 
500
- /** Read the persisted dock record, tolerating absent/corrupt storage. */
501
- function readPersistedDocks(): PersistedDocks {
498
+ /**
499
+ * Read the persisted dock record, tolerating absent/corrupt storage.
500
+ *
501
+ * What comes back is the parsed JSON object rather than a {@link PersistedDocks}: that interface is
502
+ * what {@link persistDocks} WRITES, and a stored record is untrusted input, so every member is
503
+ * checked where it is read.
504
+ */
505
+ function readPersistedDocks(): JsonObject {
502
506
  try {
503
- return JSON.parse(localStorage.getItem(DOCK_STORAGE_KEY) || "{}") as PersistedDocks;
507
+ const parsed: unknown = JSON.parse(localStorage.getItem(DOCK_STORAGE_KEY) || "{}");
508
+ return isJsonObject(parsed) ? parsed : {};
504
509
  } catch {
505
510
  return {};
506
511
  }
507
512
  }
508
513
 
514
+ /** One state per dock, in {@link DOCK_IDS} order, each built by `make`. */
515
+ function perDock(make: (id: DockId) => DockState): Record<DockId, DockState> {
516
+ return { left: make("left"), right: make("right"), bottom: make("bottom") };
517
+ }
518
+
509
519
  function freshGit(): ShellGit {
510
520
  return {
511
521
  branches: null,
@@ -613,18 +623,17 @@ export const DEFAULT_LAYOUT_ID = "design";
613
623
  */
614
624
  function createShellState(): ShellState {
615
625
  const saved = readPersistedDocks();
616
- const docks = {} as Record<DockId, DockState>;
617
- for (const id of DOCK_IDS) {
626
+ const docks = perDock((id) => {
618
627
  const width = saved[id];
619
- const collapsed = saved[`${id}Collapsed` as const];
620
- docks[id] = {
628
+ const collapsed = saved[`${id}Collapsed`];
629
+ return {
621
630
  // A stored `false` has to REOPEN a dock, so this cannot be the usual
622
631
  // `if (saved.x) { collapse() }` shape — that silently pins a dock shut forever for
623
632
  // Everyone who ever closed it once.
624
- collapsed: typeof collapsed === "boolean" ? collapsed : DOCK_DEFAULTS[id].collapsed,
625
- size: typeof width === "number" && width > 0 ? width : DOCK_DEFAULTS[id].size,
633
+ collapsed: isBoolean(collapsed) ? collapsed : DOCK_DEFAULTS[id].collapsed,
634
+ size: isNumber(width) && width > 0 ? width : DOCK_DEFAULTS[id].size,
626
635
  };
627
- }
636
+ });
628
637
  return {
629
638
  bottomTab: isBottomTabId(saved.bottomTab) ? saved.bottomTab : DEFAULT_BOTTOM_TAB,
630
639
  docks,
@@ -652,14 +661,13 @@ function createShellState(): ShellState {
652
661
  applyStartupProfile();
653
662
 
654
663
  /*
655
- * The input is widened before `reactive()` sees it: `UnwrapNestedRefs<ShellState>` recurses through
656
- * `LayoutHit` and the git result shapes deeply enough for tsc to give up (TS2589). The proxy is
657
- * deep either way — only the type computation is short-circuited — and the declared annotation is
658
- * what every consumer sees. Same reason `tabs/tab.ts` casts its own reactive tree.
664
+ * SAFETY: `reactive()` returns a deep proxy carrying its target's own members, and ShellState holds
665
+ * no refs for `UnwrapNestedRefs` to unwrap, so the proxy IS a ShellState. The type argument is
666
+ * pinned to `object` because `UnwrapNestedRefs<ShellState>` recurses through `LayoutHit` and the
667
+ * git result shapes deeply enough for tsc to give up (TS2589). The proxy is deep either way — only
668
+ * the type computation is short-circuited. Same reason `tabs/tab.ts` casts its own reactive tree.
659
669
  */
660
- export const shell: ShellState = reactive(
661
- createShellState() as unknown as Record<string, unknown>,
662
- ) as unknown as ShellState;
670
+ export const shell = reactive<object>(createShellState()) as ShellState;
663
671
 
664
672
  /**
665
673
  * Write the whole dock record in one shot.
@@ -693,10 +701,13 @@ export function persistDocks(): void {
693
701
 
694
702
  /** What a project's namespaced record holds: its named layouts, and the session it was left in. */
695
703
  interface PersistedProject {
696
- layouts?: unknown;
697
- activeLayout?: unknown;
698
- /** §14.8's session — open documents per pane, the active one, and each one's view settings. */
699
- session?: unknown;
704
+ layouts?: LayoutPreset[];
705
+ activeLayout?: string;
706
+ /**
707
+ * §14.8's session — open documents per pane, the active one, and each one's view settings. A
708
+ * session this boot has not read yet is carried over as the stored JSON it was.
709
+ */
710
+ session?: PersistedSession | JsonValue | undefined;
700
711
  }
701
712
 
702
713
  /** The project whose layouts are loaded, or `undefined` before the first sync. */
@@ -704,51 +715,63 @@ let _layoutRoot: string | null | undefined;
704
715
 
705
716
  /** Whether a parsed value is a usable {@link LayoutPreset} — a stored record is untrusted input. */
706
717
  function isLayoutPreset(value: unknown): value is LayoutPreset {
707
- if (typeof value !== "object" || value === null) {
718
+ /* Arrays fail here where the old `typeof … === "object"` let them through, and the outcome is
719
+ the same: an array carries no string `id`, so it was refused one line later. */
720
+ if (!isJsonObject(value)) {
708
721
  return false;
709
722
  }
710
- const preset = value as Partial<LayoutPreset>;
723
+ const { docks } = value;
711
724
  return (
712
- typeof preset.id === "string" &&
713
- preset.id !== "" &&
714
- typeof preset.name === "string" &&
715
- isNavigatorPanelId(preset.navigatorPanel) &&
716
- isInspectorTabId(preset.inspectorTab) &&
717
- isBottomTabId(preset.bottomTab) &&
718
- DOCK_IDS.every((dock) => typeof preset.docks?.[dock]?.size === "number")
725
+ isString(value.id) &&
726
+ value.id !== "" &&
727
+ isString(value.name) &&
728
+ isNavigatorPanelId(value.navigatorPanel) &&
729
+ isInspectorTabId(value.inspectorTab) &&
730
+ isBottomTabId(value.bottomTab) &&
731
+ isJsonObject(docks) &&
732
+ DOCK_IDS.every((dock) => {
733
+ const entry = docks[dock];
734
+ return isJsonObject(entry) && isNumber(entry.size);
735
+ })
719
736
  );
720
737
  }
721
738
 
722
739
  /** The raw record for `root`, or `{}` for absent, corrupt or hand-edited storage. */
723
- function rawPersistedProject(root: string | null): PersistedProject {
740
+ function rawPersistedProject(root: string | null): JsonObject {
724
741
  if (!root) {
725
742
  return {};
726
743
  }
727
744
  try {
728
- return JSON.parse(
745
+ const parsed: unknown = JSON.parse(
729
746
  localStorage.getItem(`${PROJECT_STORAGE_PREFIX}${root}`) || "{}",
730
- ) as PersistedProject;
747
+ );
748
+ return isJsonObject(parsed) ? parsed : {};
731
749
  } catch {
732
750
  return {};
733
751
  }
734
752
  }
735
753
 
736
- /** Read a project's namespaced record, tolerating absent, corrupt and hand-edited storage. */
737
- function readPersistedProject(root: string | null): {
754
+ /** A project's layouts as {@link readPersistedProject} recovers them. */
755
+ interface ProjectLayouts {
738
756
  layouts: LayoutPreset[];
739
757
  activeLayout: string | null;
740
- } {
741
- const fresh = { activeLayout: null, layouts: builtInLayouts() };
758
+ }
759
+
760
+ /** Read a project's namespaced record, tolerating absent, corrupt and hand-edited storage. */
761
+ function readPersistedProject(root: string | null): ProjectLayouts {
762
+ const fresh: ProjectLayouts = { activeLayout: null, layouts: builtInLayouts() };
742
763
  if (!root) {
743
764
  return fresh;
744
765
  }
745
766
  const parsed = rawPersistedProject(root);
746
- const layouts = Array.isArray(parsed.layouts) ? parsed.layouts.filter(isLayoutPreset) : [];
767
+ const layouts = Array.isArray(parsed.layouts)
768
+ ? parsed.layouts.flatMap((entry) => (isLayoutPreset(entry) ? [entry] : []))
769
+ : [];
747
770
  if (layouts.length === 0) {
748
771
  return fresh;
749
772
  }
750
773
  return {
751
- activeLayout: typeof parsed.activeLayout === "string" ? parsed.activeLayout : null,
774
+ activeLayout: isString(parsed.activeLayout) ? parsed.activeLayout : null,
752
775
  layouts,
753
776
  };
754
777
  }
@@ -903,10 +926,10 @@ export function applyLayout(id: string, deps: LayoutDeps): void {
903
926
  export function saveLayout(name: string, deps: LayoutDeps): LayoutPreset {
904
927
  const trimmed = name.trim();
905
928
  const id = layoutIdFor(trimmed);
906
- const docks = {} as Record<DockId, DockState>;
907
- for (const dock of DOCK_IDS) {
908
- docks[dock] = { collapsed: shell.docks[dock].collapsed, size: shell.docks[dock].size };
909
- }
929
+ const docks = perDock((dock) => ({
930
+ collapsed: shell.docks[dock].collapsed,
931
+ size: shell.docks[dock].size,
932
+ }));
910
933
  const preset: LayoutPreset = {
911
934
  bottomTab: isBottomTabId(shell.bottomTab) ? shell.bottomTab : DEFAULT_BOTTOM_TAB,
912
935
  docks,
@@ -1219,7 +1242,7 @@ export function toggleActivityTab(tab: NavigatorPanelId): void {
1219
1242
  * a long release cycle with a reader (the properties panel's layout panel) and no writer at all,
1220
1243
  * which is why clicking a header did nothing.
1221
1244
  */
1222
- export function setLayoutSelection(selection: LayoutSelection | null): void {
1245
+ export function setLayoutSelection(selection: LayoutHit | null): void {
1223
1246
  shell.layoutSelection = selection;
1224
1247
  }
1225
1248
 
@@ -8,6 +8,7 @@
8
8
  * @docs framework/site/i18n
9
9
  */
10
10
 
11
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
11
12
  import { projectState } from "./store";
12
13
  import { getPlatform } from "./platform";
13
14
  import { commitProjectConfig } from "./tabs/project-config";
@@ -57,10 +58,8 @@ export function getEffectiveStyle(docStyle?: JxStyle) {
57
58
  }
58
59
  const merged = { ...siteStyle };
59
60
  for (const [k, v] of Object.entries(docStyle)) {
60
- merged[k] =
61
- typeof v === "object" && v !== null && typeof merged[k] === "object" && merged[k] !== null
62
- ? { ...(merged[k] as JxStyle), ...(v as JxStyle) }
63
- : v;
61
+ const base = merged[k];
62
+ merged[k] = isNonNullObject(v) && isNonNullObject(base) ? { ...base, ...v } : v;
64
63
  }
65
64
  return merged;
66
65
  }
@@ -101,7 +100,8 @@ export function getEffectiveElements(docElements?: (JxElement | string)[]) {
101
100
  const seen = new Set<string>();
102
101
  const merged: (JxElement | string)[] = [];
103
102
  for (const entry of [...siteElements, ...docElements]) {
104
- const key = typeof entry === "string" ? entry : entry?.$ref;
103
+ // A null entry in hand-edited JSON has no key, and is skipped rather than thrown on.
104
+ const key = isString(entry) ? entry : isNonNullObject(entry) ? entry.$ref : undefined;
105
105
  if (key && !seen.has(key)) {
106
106
  seen.add(key);
107
107
  merged.push(entry);
@@ -127,8 +127,9 @@ export function getEffectiveHead(docHead?: JxHeadEntry[]) {
127
127
  const seen = new Set<string>();
128
128
  const merged: JxHeadEntry[] = [];
129
129
  for (const entry of [...siteHead, ...docHead]) {
130
- const key =
131
- String(entry?.attributes?.href || entry?.attributes?.src || "") || JSON.stringify(entry);
130
+ // A null entry in hand-edited JSON is keyed by its serialisation, like any entry without a URL.
131
+ const attributes = isNonNullObject(entry) ? entry.attributes : undefined;
132
+ const key = String(attributes?.href || attributes?.src || "") || JSON.stringify(entry);
132
133
  if (!seen.has(key)) {
133
134
  seen.add(key);
134
135
  merged.push(entry);
@@ -189,13 +190,16 @@ export function getEffectiveLayoutPath(docLayout: string | false | undefined) {
189
190
  */
190
191
  export async function resolveLayoutDoc(layoutPath: string) {
191
192
  const normalized = layoutPath.replace(/^\.\//, "");
192
- if (layoutCache.has(normalized)) {
193
- return structuredClone(layoutCache.get(normalized) as JxMutableNode);
193
+ const cached = layoutCache.get(normalized);
194
+ if (cached !== undefined) {
195
+ return structuredClone(cached);
194
196
  }
195
197
 
196
198
  try {
197
199
  const platform = getPlatform();
198
200
  const content = await platform.readFile(normalized);
201
+ /* SAFETY: a `$layout` target is a Jx document file, which is a JSON element object; the slot
202
+ walk that consumes it checks `children` is an array before reading any of it. */
199
203
  const doc = JSON.parse(content) as JxMutableNode;
200
204
  layoutCache.set(normalized, doc);
201
205
  return structuredClone(doc);
@@ -220,8 +224,8 @@ export function distributePageIntoLayout(layoutDoc: JxMutableNode, pageDoc: JxMu
220
224
  const defaults: (JxMutableNode | string)[] = [];
221
225
 
222
226
  for (const child of children) {
223
- const slotName = typeof child === "object" ? child.attributes?.slot : undefined;
224
- if (typeof child === "object" && typeof slotName === "string" && slotName) {
227
+ const slotName = isString(child) ? undefined : child.attributes?.slot;
228
+ if (!isString(child) && isString(slotName) && slotName) {
225
229
  if (!named.has(slotName)) {
226
230
  named.set(slotName, []);
227
231
  }
@@ -254,18 +258,15 @@ function fillSlots(
254
258
  named: Map<string, JxMutableNode[]>,
255
259
  defaults: (JxMutableNode | string)[],
256
260
  ) {
257
- if (!node || typeof node !== "object") {
258
- return;
259
- }
260
261
  if (!Array.isArray(node.children)) {
261
262
  return;
262
263
  }
263
264
 
264
265
  const newChildren: (JxMutableNode | string)[] = [];
265
266
  for (const child of node.children) {
266
- if (child && typeof child === "object" && child.tagName === "slot") {
267
+ if (isNonNullObject(child) && child.tagName === "slot") {
267
268
  const slotName = child.attributes?.name;
268
- if (typeof slotName === "string" && slotName && named.has(slotName)) {
269
+ if (isString(slotName) && slotName && named.has(slotName)) {
269
270
  newChildren.push(...named.get(slotName)!);
270
271
  named.delete(slotName);
271
272
  } else if (!slotName && defaults.length > 0) {
@@ -274,15 +275,26 @@ function fillSlots(
274
275
  newChildren.push(...child.children);
275
276
  }
276
277
  } else {
277
- if (typeof child !== "string") {
278
+ /* Only an element has slots to fill. A null child (hand-edited JSON) used to reach the
279
+ `!node` guard this function opened with; it now stops here, with the same outcome. */
280
+ if (isNonNullObject(child)) {
278
281
  fillSlots(child, named, defaults);
279
282
  }
280
283
  newChildren.push(child);
281
284
  }
282
285
  }
283
- node.children = newChildren as JxMutableNode[];
286
+ node.children = newChildren;
284
287
  }
285
288
 
289
+ /**
290
+ * A `project.json` patch: each key's new value, or `undefined` to remove the key.
291
+ *
292
+ * `Partial<ProjectConfig>` cannot say the second half under `exactOptionalPropertyTypes` — its
293
+ * `url` is `string` when present, never `undefined` — so clearing a setting had to be spelled as a
294
+ * double cast at every call site that wanted to.
295
+ */
296
+ export type ProjectConfigPatch = { [K in keyof ProjectConfig]?: ProjectConfig[K] | undefined };
297
+
286
298
  /**
287
299
  * Merge a partial patch into the project's configuration and persist it.
288
300
  *
@@ -297,12 +309,15 @@ function fillSlots(
297
309
  * Problem, because the eight other sites reach this through `void updateSiteConfig(...)` and used
298
310
  * to drop it on the floor.
299
311
  *
300
- * @param {Partial<ProjectConfig>} patch - Fields to merge into the current projectConfig; a value
301
- * of `undefined` clears the key.
312
+ * @param {ProjectConfigPatch} patch - Fields to merge into the current projectConfig; a value of
313
+ * `undefined` clears the key.
302
314
  * @throws {unknown} The platform's rejection, when the write fails.
303
315
  */
304
- export async function updateSiteConfig(patch: Partial<ProjectConfig>) {
305
- const result = await commitProjectConfig(patch);
316
+ export async function updateSiteConfig(patch: ProjectConfigPatch) {
317
+ /* SAFETY: `commitProjectConfig` spreads the patch over the current config and serialises the
318
+ result with JSON.stringify, so an `undefined` member reaches disk as an absent key and the
319
+ written file is a ProjectConfig; every other member already has its ProjectConfig type. */
320
+ const result = await commitProjectConfig(patch as Partial<ProjectConfig>);
306
321
  if (!result.ok) {
307
322
  throw result.error;
308
323
  }