@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
@@ -42,10 +42,11 @@
42
42
  */
43
43
 
44
44
  import { nothing } from "lit-html";
45
- import { getEventBinding, isExpressionDef, isJsonObject } from "@jxsuite/schema/guards";
45
+ import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
46
+ import { getEventBinding, isExpressionDef, isJsonObject, isString } from "@jxsuite/schema/guards";
46
47
 
47
48
  import { effect, effectScope, shallowRef } from "../reactivity";
48
- import { getNodeAtPath, updateUi } from "../store";
49
+ import { updateUi } from "../store";
49
50
  import { activeTab } from "../workspace/workspace";
50
51
  import { mutateAddDef, mutateUpdateDef, mutateUpdateProperty, transactDoc } from "../tabs/transact";
51
52
  import { setBottomTab } from "../shell";
@@ -69,14 +70,19 @@ import {
69
70
  stringProperty,
70
71
  } from "../commands/command-args";
71
72
 
72
- import type { JxNodeValue } from "../tabs/transact";
73
73
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
74
74
  import type { PanelBody } from "./panel-registry";
75
75
  import type { ExpressionPreview } from "../services/preview-eval";
76
- import type { FormulaEditDef, FunctionEditDef, JsonValue } from "../types";
76
+ import type { FormulaEditDef, FunctionEditDef } from "../types";
77
77
  import type { Tab } from "../tabs/tab";
78
- import type { JxStateDefinition } from "@jxsuite/schema/types";
78
+ import type {
79
+ JsonObject,
80
+ JsonValue,
81
+ JxEventBinding,
82
+ JxStateDefinition,
83
+ } from "@jxsuite/schema/types";
79
84
  import type { EffectScope } from "@vue/reactivity";
85
+ import type { ScopeValue } from "../editor/merge-tags";
80
86
  import type {
81
87
  LogicChipView,
82
88
  LogicScopeEntryView,
@@ -125,10 +131,10 @@ export function logicTarget(tab: Tab | null = activeTab.value): LogicTarget | nu
125
131
  return null;
126
132
  }
127
133
  if (ui.editingFunction) {
128
- return { editing: ui.editingFunction as FunctionEditDef, surface: "function" };
134
+ return { editing: ui.editingFunction, surface: "function" };
129
135
  }
130
136
  if (ui.editingFormula) {
131
- return { editing: ui.editingFormula as FormulaEditDef, surface: "formula" };
137
+ return { editing: ui.editingFormula, surface: "formula" };
132
138
  }
133
139
  return null;
134
140
  }
@@ -176,25 +182,35 @@ export function openLogicTarget(target: LogicTarget): void {
176
182
  revealLogicPanel();
177
183
  }
178
184
 
179
- function isExprNode(value: unknown): value is Record<string, unknown> {
180
- return isJsonObject(value) && typeof value.operator === "string";
185
+ /** An expression node: a plain object naming its `operator`. */
186
+ function isExprNode(value: JsonValue | undefined): value is JsonObject {
187
+ return isJsonObject(value) && isString(value.operator);
181
188
  }
182
189
 
183
190
  // ─── Document access ─────────────────────────────────────────────────────────
184
191
 
192
+ /**
193
+ * The `$expression` of an expression entry or binding, as the JSON object it is; null for anything
194
+ * else. `isExpressionDef` has already checked it is a plain object, and the guard carries that to
195
+ * the type.
196
+ */
197
+ function expressionOf(value: JxStateDefinition | JxEventBinding | undefined): JsonObject | null {
198
+ if (!isExpressionDef(value)) {
199
+ return null;
200
+ }
201
+ const { $expression } = value;
202
+ return isJsonObject($expression) ? $expression : null;
203
+ }
204
+
185
205
  /** Read the workspace target's current root expression node from the document. */
186
- export function formulaRoot(tab: Tab, editing: FormulaEditDef): Record<string, unknown> | null {
206
+ export function formulaRoot(tab: Tab, editing: FormulaEditDef): JsonObject | null {
187
207
  const { document } = tab.doc;
188
208
  if (editing.type === "def" && editing.defName) {
189
- const def = document?.state?.[editing.defName];
190
- return isExpressionDef(def) ? (def.$expression as unknown as Record<string, unknown>) : null;
209
+ return expressionOf(document.state?.[editing.defName]);
191
210
  }
192
211
  if (editing.type === "event" && editing.path && editing.eventKey) {
193
212
  const node = getNodeAtPath(document, editing.path);
194
- const binding = node ? getEventBinding(node, editing.eventKey) : undefined;
195
- return isExpressionDef(binding)
196
- ? (binding.$expression as unknown as Record<string, unknown>)
197
- : null;
213
+ return expressionOf(node ? getEventBinding(node, editing.eventKey) : undefined);
198
214
  }
199
215
  return null;
200
216
  }
@@ -203,18 +219,18 @@ export function formulaRoot(tab: Tab, editing: FormulaEditDef): Record<string, u
203
219
  * Resolve a chip selection to its editable node: the deepest expression-node prefix of `path` (head
204
220
  * chips target ref/literal operands; stale paths fall back toward the root).
205
221
  */
206
- function resolveSelection(
207
- root: Record<string, unknown>,
208
- path: NodePath,
209
- ): { node: Record<string, unknown>; path: NodePath } {
210
- let current: unknown = root;
211
- let node: Record<string, unknown> = root;
222
+ function resolveSelection(root: JsonObject, path: NodePath) {
223
+ let current: JsonValue | undefined = root;
224
+ let node = root;
212
225
  let nodePath: NodePath = [];
213
226
  for (const [i, seg] of path.entries()) {
214
- if (!current || typeof current !== "object") {
227
+ if (Array.isArray(current)) {
228
+ current = current[Number(seg)];
229
+ } else if (isJsonObject(current)) {
230
+ current = current[String(seg)];
231
+ } else {
215
232
  break;
216
233
  }
217
- current = (current as Record<string, unknown>)[seg as keyof typeof current];
218
234
  if (isExprNode(current)) {
219
235
  node = current;
220
236
  nodePath = path.slice(0, i + 1);
@@ -224,30 +240,28 @@ function resolveSelection(
224
240
  }
225
241
 
226
242
  /** Immutably replace the value at `path` within `node` (object keys / array indexes). */
227
- function replaceAtPath(node: unknown, path: NodePath, value: unknown): unknown {
228
- if (path.length === 0) {
243
+ function replaceAtPath(node: JsonValue | undefined, path: NodePath, value: JsonValue): JsonValue {
244
+ const [head, ...rest] = path;
245
+ if (head === undefined) {
229
246
  return value;
230
247
  }
231
- const [head, ...rest] = path as [string | number, ...NodePath];
232
248
  if (Array.isArray(node)) {
233
- const copy = [...(node as unknown[])];
249
+ const copy = [...node];
234
250
  copy[Number(head)] = replaceAtPath(copy[Number(head)], rest, value);
235
251
  return copy;
236
252
  }
237
- const base: Record<string, unknown> = isJsonObject(node) ? node : {};
238
- return { ...base, [head]: replaceAtPath(base[head as string], rest, value) };
253
+ const base: JsonObject = isJsonObject(node) ? node : {};
254
+ return { ...base, [head]: replaceAtPath(base[head], rest, value) };
239
255
  }
240
256
 
241
257
  /** Write the whole updated root node back to the document position (one undo step). */
242
- function writeRoot(tab: Tab, editing: FormulaEditDef, newRoot: unknown) {
258
+ function writeRoot(tab: Tab, editing: FormulaEditDef, newRoot: JsonValue) {
243
259
  if (editing.type === "def" && editing.defName) {
244
260
  const { defName } = editing;
245
- transactDoc(tab, (t) => mutateUpdateDef(t, defName, { $expression: newRoot as JsonValue }));
261
+ transactDoc(tab, (t) => mutateUpdateDef(t, defName, { $expression: newRoot }));
246
262
  } else if (editing.type === "event" && editing.path && editing.eventKey) {
247
263
  const { eventKey, path } = editing;
248
- transactDoc(tab, (t) =>
249
- mutateUpdateProperty(t, path, eventKey, { $expression: newRoot } as JxNodeValue),
250
- );
264
+ transactDoc(tab, (t) => mutateUpdateProperty(t, path, eventKey, { $expression: newRoot }));
251
265
  }
252
266
  }
253
267
 
@@ -295,8 +309,8 @@ function selectionKey(editing: FormulaEditDef): string {
295
309
  interface Resolved {
296
310
  tab: Tab;
297
311
  editing: FormulaEditDef;
298
- root: Record<string, unknown>;
299
- selected: Record<string, unknown>;
312
+ root: JsonObject;
313
+ selected: JsonObject;
300
314
  selectedPath: NodePath;
301
315
  stateEntries: Record<string, JxStateDefinition>;
302
316
  preview: ExpressionPreview | null;
@@ -304,19 +318,27 @@ interface Resolved {
304
318
  /** Chip key → node path, so a chip click needs no path parsing (a `switch` case may hold "/"). */
305
319
  chipPaths: Map<string, NodePath>;
306
320
  /** Rail entry name → the value its tree draws. */
307
- scopeValues: Map<string, unknown>;
321
+ scopeValues: Map<string, ScopeValue>;
308
322
  }
309
323
 
310
324
  let _resolved: Resolved | null = null;
311
325
 
312
- /** Replace the selected sub-node inside the root and write the whole root back. */
313
- function writeSelected(next: unknown): void {
326
+ /**
327
+ * Replace the selected sub-node inside the root and write the whole root back.
328
+ *
329
+ * Typed as the expression editor's own change callback, which is one of its two callers; the other
330
+ * is a catalog pick's `onChange`.
331
+ */
332
+ const writeSelected: Parameters<typeof mountExpressionEditor>[2] = (next) => {
314
333
  const held = _resolved;
315
334
  if (!held) {
316
335
  return;
317
336
  }
318
- writeRoot(held.tab, held.editing, replaceAtPath(held.root, held.selectedPath, next));
319
- }
337
+ /* SAFETY: both callers hand back an expression node built of JSON operator/operand values: the
338
+ expression editor's edited tree, and the node a catalog pick inserts (a JxExpressionNode). */
339
+ const node = next as JsonValue;
340
+ writeRoot(held.tab, held.editing, replaceAtPath(held.root, held.selectedPath, node));
341
+ };
320
342
 
321
343
  // ─── The projection ──────────────────────────────────────────────────────────
322
344
 
@@ -354,13 +376,13 @@ function resultOf(
354
376
  }
355
377
 
356
378
  /** The live data context — a SECOND opinion now that the page itself is on screen, not the only one. */
357
- function railOf(scope: Record<string, unknown> | null | undefined): {
358
- entries: LogicScopeEntryView[];
359
- values: Map<string, unknown>;
360
- } {
379
+ function railOf(scope: Tab["session"]["canvas"]["scope"] | undefined) {
361
380
  const entries: LogicScopeEntryView[] = [];
362
- const values = new Map<string, unknown>();
363
- for (const [name, value] of Object.entries(scope ?? {})) {
381
+ const values = new Map<string, ScopeValue>();
382
+ /* SAFETY: the canvas scope's one writer (iframe-host.ts, on a `dataScope` message) stores that
383
+ message's `scope`, a JsonObject of deep-cloned values (serialize-scope.ts). */
384
+ const snapshot = (scope ?? {}) as JsonObject;
385
+ for (const [name, value] of Object.entries(snapshot)) {
364
386
  entries.push({ key: name, name, type: dataTypeLabel(value) });
365
387
  values.set(name, unwrapSignal(value));
366
388
  }
@@ -422,7 +444,7 @@ export function workspaceView(): LogicWorkspaceView {
422
444
  };
423
445
  }
424
446
 
425
- const stateEntries = (tab.doc.document?.state ?? {}) as Record<string, JxStateDefinition>;
447
+ const stateEntries = tab.doc.document.state ?? {};
426
448
  /* Live-context evaluation in the canvas iframe with snapshot fallback (M6). The canvas is no
427
449
  longer unmounted while this surface is open — that is the entire point of the move — so the
428
450
  live path is the ORDINARY case now rather than the one that never happened. An event target's
@@ -595,7 +617,10 @@ const ACTIONS: LogicWorkspaceActions = {
595
617
  };
596
618
 
597
619
  /** Vendor a packaged formula's state entry into the document, as one undo step. */
598
- function insertDef(defName: string, def: unknown): void {
620
+ function insertDef(defName: string, def: JxStateDefinition): void {
621
+ /* SAFETY: the only def the editor and the catalog insert is a packaged formula's vendored entry
622
+ (formula-catalog.ts `ensure`): `$description`, `$expression` and `parameters`, all JSON from
623
+ @jxsuite/formulas. */
599
624
  transactDoc(activeTab.value, (t) => mutateAddDef(t, defName, def as Record<string, JsonValue>));
600
625
  }
601
626
 
@@ -750,7 +775,7 @@ export function formulaEditorCommands(): AnyCommand[] {
750
775
  if (!tab) {
751
776
  throw new RangeError(`command "formula.editDef" needs an open document`);
752
777
  }
753
- const defs = tab.doc.document?.state ?? {};
778
+ const defs = tab.doc.document.state ?? {};
754
779
  if (!(defName in defs)) {
755
780
  const defined = Object.keys(defs);
756
781
  throw new RangeError(
@@ -20,6 +20,7 @@
20
20
  * the two hosts. The Page panel was the last one, and the renderer went with it.
21
21
  */
22
22
 
23
+ import { isBoolean, isString } from "@jxsuite/schema/guards";
23
24
  import { previewAssetSrc } from "../canvas/asset-refs";
24
25
  import { IMAGE_EXTENSIONS, extensionOf } from "../files/media-upload";
25
26
  import { referenceEntryState } from "../ui/form-controls";
@@ -29,12 +30,14 @@ import { referenceTarget } from "../ui/schema-form";
29
30
  import type { JsonValue } from "../types";
30
31
  import type { Tab } from "../tabs/tab";
31
32
  import type { ProjectConfig } from "@jxsuite/schema/types";
33
+ import type { SurfaceOption } from "../ui/surface";
32
34
 
33
35
  export interface FmSchemaEntry {
34
36
  type?: string;
35
37
  enum?: string[];
36
38
  format?: string;
37
- properties?: Record<string, unknown>;
39
+ /** A nested object field's own field schemas. */
40
+ properties?: Record<string, FmSchemaEntry>;
38
41
  /** `#/content/<type>` — a relationship to another collection (site-architecture.md §6.1). */
39
42
  $ref?: string;
40
43
  }
@@ -42,7 +45,8 @@ export interface FmSchemaEntry {
42
45
  export interface FmField {
43
46
  field: string;
44
47
  entry: FmSchemaEntry;
45
- value: JsonValue;
48
+ /** What the document holds under the key; `undefined` for a schema field it does not set. */
49
+ value: JsonValue | undefined;
46
50
  }
47
51
 
48
52
  export interface FmFieldSet {
@@ -70,8 +74,15 @@ export function collectFmFields(
70
74
  projectConfig: ProjectConfig | null | undefined,
71
75
  reserved: Set<string>,
72
76
  ): FmFieldSet {
73
- const fm = tab.doc.content?.frontmatter || {};
77
+ /* SAFETY: `FormatFrontmatter` holds `JxDocumentValue`, which is the JSON value space seen through
78
+ the typed interfaces a document's declared keys use (JxRef, JxStatement, CemEvent, ...). Every
79
+ frontmatter value is parsed from the file by a format class's split or JSON-cloned from one, so
80
+ each is plain JSON data, and viewing it as JsonValue reads the same data without those views. */
81
+ const fm = tab.doc.content.frontmatter as Record<string, JsonValue | undefined>;
74
82
  const collection = findContentTypeSchema(tab.documentPath, projectConfig);
83
+ /* SAFETY: a collection schema is JSON Schema, and the only keywords an FmSchemaEntry reads —
84
+ `type`, `format`, `$ref` (strings) and `enum` (a list of choices) — carry those shapes there;
85
+ `required` is already typed `string[]` on ContentTypeSchema. */
75
86
  const schema = collection?.schema as
76
87
  | { properties?: Record<string, FmSchemaEntry>; required?: string[] }
77
88
  | undefined;
@@ -84,16 +95,16 @@ export function collectFmFields(
84
95
  if (reserved.has(field)) {
85
96
  continue;
86
97
  }
87
- fields.push({ entry: fieldSchema, field, value: fm[field] as JsonValue });
98
+ fields.push({ entry: fieldSchema, field, value: fm[field] });
88
99
  }
89
100
  for (const [field, value] of Object.entries(fm)) {
90
101
  if (schemaProps[field] || field.startsWith("$") || reserved.has(field)) {
91
102
  continue;
92
103
  }
93
104
  fields.push({
94
- entry: { type: typeof value === "boolean" ? "boolean" : "string" },
105
+ entry: { type: isBoolean(value) ? "boolean" : "string" },
95
106
  field,
96
- value: value as JsonValue,
107
+ value,
97
108
  });
98
109
  }
99
110
  } else {
@@ -102,9 +113,9 @@ export function collectFmFields(
102
113
  continue;
103
114
  }
104
115
  fields.push({
105
- entry: { type: typeof value === "boolean" ? "boolean" : "string" },
116
+ entry: { type: isBoolean(value) ? "boolean" : "string" },
106
117
  field,
107
- value: value as JsonValue,
118
+ value,
108
119
  });
109
120
  }
110
121
  }
@@ -112,12 +123,6 @@ export function collectFmFields(
112
123
  return { collection, fields, hasSchema: Boolean(schemaProps), requiredFields };
113
124
  }
114
125
 
115
- /** One choice in a row's picker — the shape `jx-select` reads. */
116
- export interface FmChoice {
117
- value: string;
118
- label: string;
119
- }
120
-
121
126
  /**
122
127
  * One frontmatter field as a surface draws it. Every field is present whatever the `kind`, because
123
128
  * a document's binding renders a value and its `$switch` chooses on one: a row that omitted
@@ -140,7 +145,7 @@ export interface FmRowView {
140
145
  /** A text row's placeholder. Empty draws none. */
141
146
  placeholder: string;
142
147
  /** A picker's rows, in the order they are offered. Empty on every other kind. */
143
- options: FmChoice[];
148
+ options: SurfaceOption[];
144
149
  /** A sentence under the control — an empty collection, or a listing that failed. */
145
150
  note: string;
146
151
  /** Whether {@link FmRowView.note} has anything in it; `$switch` is a document's conditional. */
@@ -162,8 +167,8 @@ export interface FmRowProjection {
162
167
  }
163
168
 
164
169
  /** A frontmatter value as the text a field shows. An object is not a string and never pretends. */
165
- function text(value: unknown): string {
166
- return typeof value === "string" ? value : "";
170
+ function text(value: JsonValue | undefined): string {
171
+ return isString(value) ? value : "";
167
172
  }
168
173
 
169
174
  /** A blank row, so every kind carries every field a surface's bindings read. */
@@ -188,7 +193,7 @@ function blankRow(label: string): FmRowView {
188
193
  *
189
194
  * @param {string} field The frontmatter key.
190
195
  * @param {FmSchemaEntry} entry Its schema, or the type inferred from the value it already holds.
191
- * @param {unknown} value What the document says today.
196
+ * @param {JsonValue | undefined} value What the document says today.
192
197
  * @param {Set<string>} requiredFields The collection's required keys, for the label's marker.
193
198
  * @param {{ rerender: () => void }} opts How a surface is repainted when a referenced collection's
194
199
  * entry ids land — the one asynchronous read a row can start.
@@ -197,7 +202,7 @@ function blankRow(label: string): FmRowView {
197
202
  export function projectFmField(
198
203
  field: string,
199
204
  entry: FmSchemaEntry,
200
- value: unknown,
205
+ value: JsonValue | undefined,
201
206
  requiredFields: Set<string>,
202
207
  opts: { rerender: () => void },
203
208
  ): FmRowProjection {
@@ -66,6 +66,7 @@
66
66
  * @docs studio/editing/frontmatter
67
67
  */
68
68
 
69
+ import { isString } from "@jxsuite/schema/guards";
69
70
  import { projectState } from "../store";
70
71
  import { workspace } from "../workspace/workspace";
71
72
  import { tabOfPane } from "../canvas/canvas-surface";
@@ -90,18 +91,18 @@ import { activeRegistry } from "../commands/active-registry";
90
91
  import { invalidateLayoutCache } from "../site-context";
91
92
  import { mountDocHeaderSurface } from "../surfaces/doc-header";
92
93
 
93
- import type { JxHeadEntry, JxMutableNode } from "@jxsuite/schema/types";
94
+ import type { JsonValue, JxHeadEntry, JxMutableNode } from "@jxsuite/schema/types";
94
95
  import type { Tab } from "../tabs/tab";
95
96
  import type { FmSchemaEntry } from "./frontmatter-fields";
96
97
  import type * as MediaPickerModule from "../ui/media-picker";
97
98
  import type {
98
99
  DocHeaderActions,
99
- DocHeaderChoice,
100
100
  DocHeaderRawEntry,
101
101
  DocHeaderRow,
102
102
  DocHeaderSurface,
103
103
  DocHeaderView,
104
104
  } from "../surfaces/doc-header";
105
+ import type { SurfaceOption } from "../ui/surface";
105
106
 
106
107
  /** What one row of the card writes. The document knows the control; this knows the document. */
107
108
  interface RowCommit {
@@ -120,7 +121,13 @@ interface RowCommit {
120
121
  * drawing a header the second `ref` to fire silently took the card away from the first, leaving one
121
122
  * pane's Document Header frozen on the frontmatter of the moment it lost the handle.
122
123
  */
123
- interface HeaderCard {
124
+ interface HeaderCard extends HeaderCardState {
125
+ /** Handed to the surface once, when it is mounted; every one of them reads `commits`. */
126
+ actions: DocHeaderActions;
127
+ }
128
+
129
+ /** Everything a card holds except its actions, which are built over this and read it lazily. */
130
+ interface HeaderCardState {
124
131
  /** The pane this card is drawn for. Held rather than looked up: an action has to answer it. */
125
132
  paneId: string;
126
133
  el: HTMLElement;
@@ -128,8 +135,6 @@ interface HeaderCard {
128
135
  surface: DocHeaderSurface | null;
129
136
  /** This pane's rows, by key. Rebuilt with each projection. */
130
137
  commits: Map<string, RowCommit>;
131
- /** Handed to the surface once, when it is mounted; every one of them reads `commits`. */
132
- actions: DocHeaderActions;
133
138
  /** Text edits waiting out {@link LIVE_PREVIEW}, one per row key. */
134
139
  pending: Map<string, { commit: () => void; timer: ReturnType<typeof setTimeout> }>;
135
140
  }
@@ -194,15 +199,20 @@ export function attachDocumentHeaderHost(paneId: string, el: HTMLElement | null)
194
199
  if (!el) {
195
200
  return;
196
201
  }
197
- const card: HeaderCard = {
198
- actions: {} as DocHeaderActions,
202
+ const state: HeaderCardState = {
199
203
  commits: new Map(),
200
204
  el,
201
205
  paneId,
202
206
  pending: new Map(),
203
207
  surface: null,
204
208
  };
205
- card.actions = makeActions(card);
209
+ /* The same object, not a copy: the actions read `state.commits`, which a projection reassigns.
210
+ `settle` runs only on a reader's toggle, long after `card` is bound. */
211
+ const card: HeaderCard = Object.assign(state, {
212
+ actions: makeActions(state, () => {
213
+ settle(card);
214
+ }),
215
+ });
206
216
  _hosts.set(paneId, card);
207
217
  paint(paneId, card);
208
218
  }
@@ -236,14 +246,12 @@ export function mount() {
236
246
  void tab.doc.mode;
237
247
  void tab.documentPath;
238
248
  void tab.doc.document;
239
- void tab.doc.document?.title;
240
- void tab.doc.document?.$head;
241
- void tab.doc.document?.$layout;
242
- const fm = tab.doc.content?.frontmatter;
243
- if (fm) {
244
- for (const key of Object.keys(fm)) {
245
- void fm[key];
246
- }
249
+ void tab.doc.document.title;
250
+ void tab.doc.document.$head;
251
+ void tab.doc.document.$layout;
252
+ const fm = tab.doc.content.frontmatter;
253
+ for (const key of Object.keys(fm)) {
254
+ void fm[key];
247
255
  }
248
256
  }
249
257
  render();
@@ -309,12 +317,13 @@ export function render() {
309
317
  * @returns {boolean}
310
318
  */
311
319
  export function hasDocumentHeader(tab: Tab): boolean {
312
- const fm = tab.doc.content?.frontmatter ?? {};
320
+ const fm = tab.doc.content.frontmatter;
313
321
  const doc = tab.doc.document;
314
322
  if (Object.keys(fm).length > 0) {
315
323
  return true;
316
324
  }
317
- if (typeof doc?.title === "string" || (doc?.$head?.length ?? 0) > 0) {
325
+ // `title` is typed a string, but a document read off disk may carry any JSON there.
326
+ if (isString(doc.title) || (doc.$head?.length ?? 0) > 0) {
318
327
  return true;
319
328
  }
320
329
  // A page always has one, even an empty one: Title and Route are the two facts it must state.
@@ -368,7 +377,7 @@ function paint(paneId: string, card: HeaderCard): void {
368
377
  */
369
378
  function viewFor(tab: Tab, paneId: string, card: HeaderCard): DocHeaderView {
370
379
  const isContent = tab.doc.mode === "content";
371
- const fm = (tab.doc.content?.frontmatter ?? {}) as Record<string, unknown>;
380
+ const fm = tab.doc.content.frontmatter;
372
381
  // ONE view of the document's head material, whichever realm it lives in: frontmatter keys for a
373
382
  // Markdown page, root properties for a JSON one.
374
383
  const headDoc = isContent ? buildHeadDoc(tab.doc.document, fm) : tab.doc.document;
@@ -437,7 +446,7 @@ function titleRow(
437
446
  applyMutation: (fn: (doc: JxMutableNode) => void) => void,
438
447
  commits: Map<string, RowCommit>,
439
448
  ): DocHeaderRow {
440
- const title = typeof headDoc.title === "string" ? headDoc.title : "";
449
+ const title = isString(headDoc.title) ? headDoc.title : "";
441
450
  commits.set("title", {
442
451
  clear: () =>
443
452
  applyMutation((d) => {
@@ -485,7 +494,7 @@ function layoutRow(
485
494
  const current = headDoc.$layout;
486
495
  const defaultPath = projectState?.projectConfig?.defaults?.layout;
487
496
  const defaultLabel = defaultPath ? layoutName(defaultPath) : "";
488
- const options: DocHeaderChoice[] = [
497
+ const options: SurfaceOption[] = [
489
498
  { label: defaultLabel ? `Default (${defaultLabel})` : "Default", value: "__default__" },
490
499
  { label: "None", value: "__none__" },
491
500
  ...entries.map((l) => ({ label: l.name, value: l.path })),
@@ -544,7 +553,7 @@ function fieldRow(
544
553
  tab: Tab,
545
554
  field: string,
546
555
  entry: FmSchemaEntry,
547
- value: unknown,
556
+ value: JsonValue | undefined,
548
557
  requiredFields: Set<string>,
549
558
  commits: Map<string, RowCommit>,
550
559
  ): DocHeaderRow {
@@ -564,15 +573,15 @@ function fieldRow(
564
573
  * they cannot see, and the Page panel remains the surface that adds and removes them.
565
574
  */
566
575
  function rawEntries(head: JxHeadEntry[]): DocHeaderRawEntry[] {
567
- return head
568
- .filter(
569
- (e: JxHeadEntry) => !isManagedEntry(e) && !isGoogleFontEntry(e) && !isGoogleFontPreconnect(e),
570
- )
571
- .map((entry, index) => ({
572
- key: `raw:${index}`,
573
- label: entryLabel(entry),
574
- value: entryValue(entry),
575
- }));
576
+ const rows: DocHeaderRawEntry[] = [];
577
+ for (const entry of head) {
578
+ if (isManagedEntry(entry) || isGoogleFontEntry(entry) || isGoogleFontPreconnect(entry)) {
579
+ continue;
580
+ }
581
+ // The key counts the LISTED entries, as the index of the filtered list it replaces did.
582
+ rows.push({ key: `raw:${rows.length}`, label: entryLabel(entry), value: entryValue(entry) });
583
+ }
584
+ return rows;
576
585
  }
577
586
 
578
587
  // ─── The actions ─────────────────────────────────────────────────────────────
@@ -582,8 +591,9 @@ function rawEntries(head: JxHeadEntry[]): DocHeaderRawEntry[] {
582
591
  *
583
592
  * Made once per host and handed to the surface at mount, so every one of them reads the CURRENT
584
593
  * commit table rather than closing over the projection that was standing when the card was drawn.
594
+ * `settleCard` repaints the whole card, which needs these actions, so it is handed in.
585
595
  */
586
- function makeActions(card: HeaderCard): DocHeaderActions {
596
+ function makeActions(card: HeaderCardState, settleCard: () => void): DocHeaderActions {
587
597
  const flush = (key: string): void => {
588
598
  const waiting = card.pending.get(key);
589
599
  if (waiting) {
@@ -645,7 +655,7 @@ function makeActions(card: HeaderCard): DocHeaderActions {
645
655
  } catch {
646
656
  // Storage full or unavailable — this card still folds, the next one just opens.
647
657
  }
648
- settle(card);
658
+ settleCard();
649
659
  },
650
660
  setNumber: (key, value) => now(key, value),
651
661
  setRawOpen: (open) => {
@@ -660,7 +670,7 @@ function makeActions(card: HeaderCard): DocHeaderActions {
660
670
  } else {
661
671
  _rawOpen.delete(tab.id);
662
672
  }
663
- settle(card);
673
+ settleCard();
664
674
  },
665
675
  upload: (key) => {
666
676
  flush(key);
@@ -132,8 +132,8 @@ export function openDiffTab(path: string): Tab {
132
132
  *
133
133
  * `files/files.ts` is imported dynamically because it imports `cleanupGitPanel` from
134
134
  * `panels/git-panel.ts`, which imports this module: a static edge back would close that cycle.
135
- * `openFileInTab` answers `void` when it reveals a tab that was already open, so the tab is
136
- * resolved from the workspace either way.
135
+ * `openFileInTab` answers `void` whether it opens a new tab or reveals one that was already open,
136
+ * so the tab is resolved from the workspace by its path.
137
137
  *
138
138
  * Answers null when the file could not be opened at all, which the caller states rather than
139
139
  * silently leaving the stage on someone else's document.
@@ -143,6 +143,6 @@ export async function openComparisonTab(path: string): Promise<Tab | null> {
143
143
  return openDiffTab(path);
144
144
  }
145
145
  const files = await import("../files/files");
146
- const opened = await files.openFileInTab(path, {});
147
- return opened ?? [...workspace.tabs.values()].find((tab) => tab.documentPath === path) ?? null;
146
+ await files.openFileInTab(path, {});
147
+ return [...workspace.tabs.values()].find((tab) => tab.documentPath === path) ?? null;
148
148
  }