@jxsuite/studio 6.1.1 → 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 (637) hide show
  1. package/dist/chunks/{2020-va2wwra4.js → 2020-f2gkpy8d.js} +3 -3
  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-2veqmnhr.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-8nbvs12s.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/{jsonMode-s8kt9dsj.js → jsonMode-w15cmrcm.js} +8 -8
  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-1q1sh2ax.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-h46vtzk8.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-rv11kfwa.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-8grwxtqk.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-pre0skq6.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-vrmcjf9g.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-wszjyh0j.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-kggey1jt.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-zey7zsdw.js → studio-y64hrt8p.js} +7 -7
  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-2frah6h1.js → tsMode-sf49ee9x.js} +7 -7
  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 +97 -97
  140. package/package.json +6 -6
  141. package/src/about/about-modal.ts +4 -3
  142. package/src/account/action-flow.ts +45 -38
  143. package/src/account-status.ts +7 -2
  144. package/src/browse/library-layouts.ts +8 -5
  145. package/src/browse/library-model.ts +18 -6
  146. package/src/browse/library-pane.ts +37 -21
  147. package/src/browse/library-preview.ts +14 -9
  148. package/src/browse/library-source.ts +1 -1
  149. package/src/canvas/asset-refs.ts +24 -9
  150. package/src/canvas/asset-resolve.ts +19 -23
  151. package/src/canvas/canvas-helpers.ts +7 -6
  152. package/src/canvas/canvas-live-render.ts +44 -53
  153. package/src/canvas/canvas-patcher.ts +30 -30
  154. package/src/canvas/canvas-perf.ts +11 -5
  155. package/src/canvas/canvas-render.ts +62 -41
  156. package/src/canvas/canvas-surface.ts +5 -3
  157. package/src/canvas/canvas-utils.ts +90 -49
  158. package/src/canvas/dialog-path.ts +9 -4
  159. package/src/canvas/dialog-state.ts +1 -2
  160. package/src/canvas/diff-marks.ts +9 -16
  161. package/src/canvas/diff-toolbar.ts +8 -7
  162. package/src/canvas/edit-width-drag.ts +4 -1
  163. package/src/canvas/edit-width.ts +1 -3
  164. package/src/canvas/iframe-channel.ts +27 -13
  165. package/src/canvas/iframe-drop.ts +13 -12
  166. package/src/canvas/iframe-editable-root.ts +29 -16
  167. package/src/canvas/iframe-entry.ts +80 -63
  168. package/src/canvas/iframe-eval.ts +73 -49
  169. package/src/canvas/iframe-host.ts +135 -96
  170. package/src/canvas/iframe-inline-edit.ts +49 -30
  171. package/src/canvas/iframe-insert.ts +5 -4
  172. package/src/canvas/iframe-interaction.ts +30 -25
  173. package/src/canvas/iframe-overlay.ts +1 -1
  174. package/src/canvas/iframe-patch.ts +18 -15
  175. package/src/canvas/iframe-position.ts +12 -6
  176. package/src/canvas/iframe-protocol.ts +12 -16
  177. package/src/canvas/iframe-render.ts +36 -34
  178. package/src/canvas/iframe-slash.ts +24 -11
  179. package/src/canvas/iframe-subtree.ts +6 -2
  180. package/src/canvas/path-mapping.ts +19 -12
  181. package/src/canvas/popover-path.ts +7 -3
  182. package/src/canvas/popover-state.ts +1 -2
  183. package/src/canvas/serialize-scope.ts +13 -5
  184. package/src/canvas/stage-scrollbar.ts +2 -1
  185. package/src/canvas/surface-registry.ts +21 -3
  186. package/src/collab/collab-commands.ts +7 -2
  187. package/src/collab/collab-session.ts +84 -45
  188. package/src/collab/collab-state.ts +4 -3
  189. package/src/collab/monaco-binding.ts +16 -13
  190. package/src/collab/monaco-cursors.ts +5 -2
  191. package/src/commands/budget.ts +3 -3
  192. package/src/commands/command-args.ts +103 -71
  193. package/src/commands/context.ts +22 -20
  194. package/src/commands/keymap.ts +47 -43
  195. package/src/commands/levels.ts +3 -3
  196. package/src/commands/live-context.ts +7 -7
  197. package/src/commands/reference.ts +2 -1
  198. package/src/commands/registry.ts +12 -10
  199. package/src/commands/run-reported.ts +15 -10
  200. package/src/component-props.ts +46 -30
  201. package/src/content/collection-match.ts +5 -4
  202. package/src/content/draft-state.ts +4 -3
  203. package/src/content/entry-commands.ts +3 -2
  204. package/src/content/entry-editor.ts +29 -17
  205. package/src/content/entry-fields.ts +12 -7
  206. package/src/content/entry-model.ts +21 -12
  207. package/src/editor/canvas-context-menu.ts +1 -2
  208. package/src/editor/canvas-slash-bridge.ts +3 -6
  209. package/src/editor/content-slice.ts +16 -14
  210. package/src/editor/context-menu.ts +35 -22
  211. package/src/editor/convert-targets.ts +30 -35
  212. package/src/editor/convert-to-component.ts +11 -5
  213. package/src/editor/convert-to-repeater.ts +34 -22
  214. package/src/editor/editable-tags.ts +17 -2
  215. package/src/editor/file-drop-action.ts +21 -22
  216. package/src/editor/inline-edit-apply.ts +35 -17
  217. package/src/editor/inline-edit.ts +66 -50
  218. package/src/editor/inline-format.ts +59 -56
  219. package/src/editor/inline-link.ts +40 -15
  220. package/src/editor/insert-zone-action.ts +1 -1
  221. package/src/editor/merge-tags.ts +58 -19
  222. package/src/editor/repeater-scope.ts +39 -28
  223. package/src/editor/shortcuts.ts +32 -20
  224. package/src/editor/slash-menu.ts +1 -6
  225. package/src/files/asset-versions.ts +4 -4
  226. package/src/files/components.ts +15 -10
  227. package/src/files/elements.ts +5 -6
  228. package/src/files/file-ops.ts +77 -36
  229. package/src/files/files.ts +90 -95
  230. package/src/files/media-meta.ts +2 -1
  231. package/src/files/media-paths.ts +3 -0
  232. package/src/files/serialize-document.ts +2 -2
  233. package/src/format/constraints.ts +1 -1
  234. package/src/format/convert-file.ts +27 -13
  235. package/src/format/format-choices.ts +2 -1
  236. package/src/format/format-host.ts +76 -50
  237. package/src/github/github-auth-status.ts +27 -3
  238. package/src/github/github-auth.ts +19 -9
  239. package/src/github/github-publish.ts +24 -20
  240. package/src/grid/cell-editors.ts +46 -31
  241. package/src/grid/cell-popovers.ts +5 -3
  242. package/src/grid/edit-buffer.ts +10 -9
  243. package/src/grid/grid-controller.ts +20 -22
  244. package/src/grid/grid-layout.ts +21 -5
  245. package/src/grid/grid-open.ts +3 -6
  246. package/src/grid/grid-panel.ts +11 -4
  247. package/src/grid/grid-source.ts +8 -8
  248. package/src/grid/grid-view.ts +14 -17
  249. package/src/grid/redirects-grid.ts +14 -5
  250. package/src/grid/redirects.ts +16 -14
  251. package/src/grid/schema-columns.ts +25 -19
  252. package/src/grid/sources/connector-source.ts +47 -20
  253. package/src/grid/sources/content-source.ts +25 -24
  254. package/src/grid/sources/csv-file-source.ts +2 -2
  255. package/src/grid/tabulator-tables.d.ts +55 -34
  256. package/src/hosting/stage.ts +7 -7
  257. package/src/i18n/i18n-commands.ts +1 -2
  258. package/src/media/media-pane.ts +4 -1
  259. package/src/new-project/add-repo-modal.ts +20 -19
  260. package/src/new-project/import-tab.ts +10 -14
  261. package/src/new-project/location-fields.ts +2 -1
  262. package/src/new-project/new-project-modal.ts +12 -9
  263. package/src/packages/jxsuite-update.ts +4 -3
  264. package/src/packages/pull-package-sync.ts +26 -25
  265. package/src/page-params.ts +97 -68
  266. package/src/panels/activity-panel.ts +17 -9
  267. package/src/panels/ai-chat/attached-context.ts +13 -7
  268. package/src/panels/ai-chat/chat-view.ts +80 -73
  269. package/src/panels/ai-chat/composer.ts +30 -33
  270. package/src/panels/ai-chat/sessions-view.ts +1 -2
  271. package/src/panels/ai-panel.ts +23 -20
  272. package/src/panels/block-action-bar.ts +46 -35
  273. package/src/panels/bottom-dock.ts +5 -3
  274. package/src/panels/canvas-dnd-bridge.ts +31 -24
  275. package/src/panels/data-explorer.ts +62 -25
  276. package/src/panels/data-grid.ts +14 -11
  277. package/src/panels/dnd.ts +108 -118
  278. package/src/panels/editors.ts +52 -21
  279. package/src/panels/elements-panel.ts +10 -3
  280. package/src/panels/events-panel.ts +84 -69
  281. package/src/panels/formula-workspace.ts +76 -51
  282. package/src/panels/frontmatter-fields.ts +24 -19
  283. package/src/panels/frontmatter-panel.ts +44 -34
  284. package/src/panels/git-diff-open.ts +4 -4
  285. package/src/panels/git-panel.ts +49 -61
  286. package/src/panels/head-panel.ts +131 -111
  287. package/src/panels/i18n-panel.ts +10 -3
  288. package/src/panels/imports-panel.ts +23 -47
  289. package/src/panels/jump-bar.ts +48 -29
  290. package/src/panels/layers-panel.ts +97 -74
  291. package/src/panels/left-panel.ts +3 -3
  292. package/src/panels/pane-context.ts +31 -22
  293. package/src/panels/pane-grid.ts +49 -20
  294. package/src/panels/panel-registry.ts +22 -37
  295. package/src/panels/properties-panel.ts +175 -121
  296. package/src/panels/quick-search.ts +53 -31
  297. package/src/panels/right-panel.ts +3 -3
  298. package/src/panels/seo-modal.ts +13 -17
  299. package/src/panels/settings-menu.ts +15 -15
  300. package/src/panels/signals-panel.ts +153 -131
  301. package/src/panels/statement-editor.ts +230 -140
  302. package/src/panels/style-panel.ts +218 -205
  303. package/src/panels/style-utils.ts +114 -51
  304. package/src/panels/stylebook-doc.ts +57 -54
  305. package/src/panels/stylebook-layers-panel.ts +9 -9
  306. package/src/panels/stylebook-panel.ts +13 -17
  307. package/src/panels/tab-drop.ts +27 -11
  308. package/src/panels/tab-strip.ts +36 -26
  309. package/src/platform-errors.ts +57 -43
  310. package/src/platform.ts +58 -30
  311. package/src/platforms/cloud.ts +345 -175
  312. package/src/platforms/default-platform.ts +10 -4
  313. package/src/platforms/devserver.ts +129 -117
  314. package/src/platforms/read-batcher.ts +16 -8
  315. package/src/project-list.ts +2 -1
  316. package/src/publish/deploy-checklist.ts +8 -2
  317. package/src/publish/pages-service.ts +28 -13
  318. package/src/publish/publish-commands.ts +5 -4
  319. package/src/publish/publish-panel.ts +10 -6
  320. package/src/recent-projects.ts +15 -8
  321. package/src/resize-edges.ts +26 -36
  322. package/src/services/a11y-report.ts +26 -19
  323. package/src/services/agent-seed.ts +23 -11
  324. package/src/services/ai-ask.ts +9 -12
  325. package/src/services/ai-command-tools.ts +68 -62
  326. package/src/services/ai-import-tools.ts +80 -67
  327. package/src/services/ai-models.ts +17 -13
  328. package/src/services/ai-project-tools.ts +68 -32
  329. package/src/services/ai-session-store.ts +19 -10
  330. package/src/services/ai-system-prompt.ts +46 -20
  331. package/src/services/ai-tools.ts +71 -27
  332. package/src/services/ai-write-report.ts +20 -12
  333. package/src/services/ai-writes.ts +4 -4
  334. package/src/services/automation.ts +58 -31
  335. package/src/services/cem-export.ts +149 -58
  336. package/src/services/clock.ts +6 -1
  337. package/src/services/code-services.ts +37 -31
  338. package/src/services/context-manager.ts +14 -10
  339. package/src/services/context-resolver.ts +20 -8
  340. package/src/services/data-service.ts +19 -15
  341. package/src/services/directory-picker.ts +18 -12
  342. package/src/services/document-assistant.ts +39 -19
  343. package/src/services/gated-registry.ts +10 -6
  344. package/src/services/harness/chat-reducer.ts +23 -1
  345. package/src/services/import-client.ts +91 -38
  346. package/src/services/import-seed.ts +8 -2
  347. package/src/services/jx-validate.ts +28 -31
  348. package/src/services/live-preview.ts +0 -0
  349. package/src/services/live-surfaces.ts +6 -3
  350. package/src/services/model-uri.ts +10 -2
  351. package/src/services/module-preloads.ts +12 -8
  352. package/src/services/monaco-buffer.ts +43 -24
  353. package/src/services/monaco-lazy.ts +7 -8
  354. package/src/services/monaco-setup.ts +23 -16
  355. package/src/services/notify.ts +44 -17
  356. package/src/services/popover-report.ts +25 -10
  357. package/src/services/preview-eval.ts +20 -8
  358. package/src/services/profile.ts +13 -6
  359. package/src/services/project-path.ts +13 -10
  360. package/src/services/references.ts +0 -0
  361. package/src/services/render-critic.ts +8 -7
  362. package/src/services/settings/kernel.ts +13 -4
  363. package/src/services/settings/write-queue.ts +9 -9
  364. package/src/services/token-lint.ts +12 -10
  365. package/src/services/tool-executor.ts +17 -5
  366. package/src/services/tool-outcomes.ts +44 -24
  367. package/src/services/trusted-types.ts +24 -7
  368. package/src/settings/contexts-section.ts +11 -8
  369. package/src/settings/contributed-section.ts +79 -60
  370. package/src/settings/css-vars-editor.ts +37 -16
  371. package/src/settings/defs-editor.ts +38 -35
  372. package/src/settings/extension-rows.ts +16 -8
  373. package/src/settings/extension-sections.ts +23 -13
  374. package/src/settings/extensions-section.ts +4 -1
  375. package/src/settings/general-settings.ts +11 -8
  376. package/src/settings/locales-section.ts +20 -12
  377. package/src/settings/preferences-dialog.ts +9 -6
  378. package/src/settings/preferences-keymap.ts +7 -5
  379. package/src/settings/preferences-sections.ts +11 -5
  380. package/src/settings/project-sections.ts +1 -1
  381. package/src/settings/schema-field-ui.ts +9 -0
  382. package/src/settings/settings-document.ts +5 -5
  383. package/src/shell/tree.ts +6 -5
  384. package/src/shell.ts +104 -81
  385. package/src/site-context.ts +37 -22
  386. package/src/state.ts +41 -49
  387. package/src/store.ts +54 -34
  388. package/src/studio.ts +25 -75
  389. package/src/style/live-preview.ts +1 -1
  390. package/src/style/project-styles.ts +6 -7
  391. package/src/style/token-ref.ts +5 -4
  392. package/src/surfaces/about.ts +18 -19
  393. package/src/surfaces/add-repo.ts +17 -19
  394. package/src/surfaces/ai-chat.ts +31 -36
  395. package/src/surfaces/ai-credentials-form.ts +6 -16
  396. package/src/surfaces/ai-managed-connect.ts +3 -4
  397. package/src/surfaces/ai-model-picker.ts +3 -5
  398. package/src/surfaces/block-action-bar.ts +22 -11
  399. package/src/surfaces/boot-failure.ts +4 -5
  400. package/src/surfaces/bottom-dock.ts +9 -18
  401. package/src/surfaces/canvas-stage.ts +12 -11
  402. package/src/surfaces/cf-account-picker.ts +17 -18
  403. package/src/surfaces/commandbar.ts +14 -9
  404. package/src/surfaces/convert-repeater.ts +17 -19
  405. package/src/surfaces/data-actions.ts +9 -7
  406. package/src/surfaces/dialog.ts +26 -28
  407. package/src/surfaces/diff-toolbar.ts +9 -7
  408. package/src/surfaces/doc-header.ts +10 -19
  409. package/src/surfaces/empty-state.ts +7 -10
  410. package/src/surfaces/entry-editor.ts +14 -11
  411. package/src/surfaces/expression-editor.ts +11 -25
  412. package/src/surfaces/files-panel.ts +27 -14
  413. package/src/surfaces/formula-palette.ts +4 -5
  414. package/src/surfaces/git-panel.ts +7 -15
  415. package/src/surfaces/github-auth.ts +16 -20
  416. package/src/surfaces/github-publish.ts +17 -22
  417. package/src/surfaces/grid-cell.ts +30 -31
  418. package/src/surfaces/grid-open.ts +10 -14
  419. package/src/surfaces/grid-panel.ts +13 -9
  420. package/src/surfaces/grid-replace.ts +13 -13
  421. package/src/surfaces/grid-views.ts +15 -18
  422. package/src/surfaces/inspector-dock.ts +13 -12
  423. package/src/surfaces/jump-bar.ts +5 -6
  424. package/src/surfaces/jxsuite-update.ts +16 -22
  425. package/src/surfaces/library-pane.ts +19 -20
  426. package/src/surfaces/logic-panel.ts +17 -30
  427. package/src/surfaces/logic-workspace.ts +13 -15
  428. package/src/surfaces/media-browser.ts +11 -10
  429. package/src/surfaces/media-field.ts +4 -5
  430. package/src/surfaces/media-pane.ts +8 -7
  431. package/src/surfaces/menu.ts +29 -23
  432. package/src/surfaces/navigator-dock.ts +11 -12
  433. package/src/surfaces/new-project.ts +27 -26
  434. package/src/surfaces/pane-context.ts +20 -25
  435. package/src/surfaces/pane-grid.ts +15 -10
  436. package/src/surfaces/panel-activity.ts +5 -6
  437. package/src/surfaces/panel-data.ts +3 -4
  438. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  439. package/src/surfaces/panel-elements.ts +5 -7
  440. package/src/surfaces/panel-i18n.ts +5 -7
  441. package/src/surfaces/panel-imports.ts +6 -13
  442. package/src/surfaces/panel-outline.ts +25 -19
  443. package/src/surfaces/panel-page.ts +11 -18
  444. package/src/surfaces/panel-problems.ts +5 -7
  445. package/src/surfaces/panel-signals.ts +20 -34
  446. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  447. package/src/surfaces/preferences.ts +21 -11
  448. package/src/surfaces/progress-modal.ts +15 -9
  449. package/src/surfaces/properties-panel.json +1 -1
  450. package/src/surfaces/properties-panel.ts +20 -42
  451. package/src/surfaces/publish.ts +18 -18
  452. package/src/surfaces/push-plan.ts +7 -8
  453. package/src/surfaces/rail.ts +13 -13
  454. package/src/surfaces/reference-field.ts +11 -15
  455. package/src/surfaces/schema-builder.ts +16 -22
  456. package/src/surfaces/schema-form.ts +15 -25
  457. package/src/surfaces/secret-field.ts +9 -6
  458. package/src/surfaces/seo.ts +21 -15
  459. package/src/surfaces/settings-contexts.ts +9 -7
  460. package/src/surfaces/settings-contributed.ts +14 -10
  461. package/src/surfaces/settings-css-vars.ts +5 -12
  462. package/src/surfaces/settings-defs.json +2 -2
  463. package/src/surfaces/settings-defs.ts +17 -21
  464. package/src/surfaces/settings-deploy.ts +8 -15
  465. package/src/surfaces/settings-extensions.ts +5 -6
  466. package/src/surfaces/settings-head.ts +33 -39
  467. package/src/surfaces/settings-locales.ts +8 -20
  468. package/src/surfaces/settings-overview.ts +5 -6
  469. package/src/surfaces/settings-packages.ts +8 -7
  470. package/src/surfaces/settings-pane.ts +9 -18
  471. package/src/surfaces/settings-rawjson.ts +5 -6
  472. package/src/surfaces/shell.ts +1 -2
  473. package/src/surfaces/slash-menu.ts +19 -9
  474. package/src/surfaces/statements.ts +13 -18
  475. package/src/surfaces/statusbar.ts +17 -14
  476. package/src/surfaces/style-panel.ts +18 -31
  477. package/src/surfaces/stylebook-chrome.ts +3 -5
  478. package/src/surfaces/tab-strip.ts +14 -13
  479. package/src/surfaces/target-line.ts +6 -7
  480. package/src/surfaces/welcome.ts +5 -7
  481. package/src/tabs/patch-ops.ts +4 -3
  482. package/src/tabs/project-config.ts +32 -21
  483. package/src/tabs/selection.ts +36 -8
  484. package/src/tabs/tab.ts +52 -41
  485. package/src/tabs/transact.ts +98 -53
  486. package/src/types.ts +32 -17
  487. package/src/ui/ai-credentials-form.ts +10 -13
  488. package/src/ui/ai-model-picker.ts +3 -3
  489. package/src/ui/cf-account-picker.ts +7 -9
  490. package/src/ui/color-selector.ts +9 -5
  491. package/src/ui/dynamic-slot.ts +7 -8
  492. package/src/ui/expression-editor.ts +112 -105
  493. package/src/ui/form-controls.ts +57 -48
  494. package/src/ui/formula-catalog.ts +239 -230
  495. package/src/ui/formula-chips.ts +33 -18
  496. package/src/ui/layers.ts +44 -31
  497. package/src/ui/media-picker.ts +18 -9
  498. package/src/ui/popover-surface.ts +20 -12
  499. package/src/ui/progress-modal.ts +13 -8
  500. package/src/ui/regions.ts +7 -6
  501. package/src/ui/schema-form.ts +113 -70
  502. package/src/ui/surface.ts +71 -8
  503. package/src/ui/timing.ts +9 -0
  504. package/src/ui/value-source.ts +44 -31
  505. package/src/ui/virtual-window.ts +3 -2
  506. package/src/utils/base64.ts +3 -1
  507. package/src/utils/edit-display.ts +73 -73
  508. package/src/utils/element-selectors.ts +3 -2
  509. package/src/utils/google-fonts.ts +15 -14
  510. package/src/utils/inherited-style.ts +18 -20
  511. package/src/utils/link-target.ts +1 -1
  512. package/src/utils/preview-format.ts +25 -3
  513. package/src/utils/strip-events.ts +49 -22
  514. package/src/utils/studio-utils.ts +29 -14
  515. package/src/view.ts +2 -3
  516. package/src/workspace/pane-derive.ts +10 -12
  517. package/src/workspace/session.ts +53 -43
  518. package/src/workspace/workspace.ts +40 -36
  519. package/dist/chunks/adapter-f93pafd7.js +0 -4
  520. package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
  521. package/dist/chunks/cf-settings-125tdm0w.js +0 -4
  522. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  523. package/dist/chunks/color-field-embq5ctg.js +0 -4
  524. package/dist/chunks/color-fpezvnkt.js +0 -4
  525. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  526. package/dist/chunks/combobox-773hdzyj.js +0 -4
  527. package/dist/chunks/components-ax2f1fnn.js +0 -4
  528. package/dist/chunks/content-source-108aqtk1.js +0 -4
  529. package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
  530. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  531. package/dist/chunks/editor-pfgdmkb0.js +0 -4
  532. package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
  533. package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
  534. package/dist/chunks/file-ops-meej5mqf.js +0 -4
  535. package/dist/chunks/files-44vp8a2s.js +0 -4
  536. package/dist/chunks/format-host-7q1petb9.js +0 -4
  537. package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
  538. package/dist/chunks/git-panel-zngbymvd.js +0 -4
  539. package/dist/chunks/grid-view-sx9vynsp.js +0 -51
  540. package/dist/chunks/icons-p44xhjf0.js +0 -4
  541. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  542. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  543. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  544. package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
  545. package/dist/chunks/index-wkyfjeqz.js +0 -4
  546. package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
  547. package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
  548. package/dist/chunks/layers-xd92fg8d.js +0 -4
  549. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  550. package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
  551. package/dist/chunks/media-picker-0svzkdyb.js +0 -4
  552. package/dist/chunks/menu-37d07z9m.js +0 -4
  553. package/dist/chunks/menu-5c55ea3d.js +0 -4
  554. package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
  555. package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
  556. package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
  557. package/dist/chunks/notify-0xgtn8q1.js +0 -4
  558. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  559. package/dist/chunks/parse-897fvqah.js +0 -4
  560. package/dist/chunks/platform-v1qctbe6.js +0 -4
  561. package/dist/chunks/popover-8htra4er.js +0 -4
  562. package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
  563. package/dist/chunks/quick-search-a54e6t5n.js +0 -4
  564. package/dist/chunks/references-gmqp82fs.js +0 -4
  565. package/dist/chunks/right-panel-v7t9awbk.js +0 -4
  566. package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
  567. package/dist/chunks/select-n3v7gwas.js +0 -4
  568. package/dist/chunks/split-pff8f3ze.js +0 -4
  569. package/dist/chunks/studio-0bhx5hz6.js +0 -5
  570. package/dist/chunks/studio-0k1ddnyy.js +0 -6
  571. package/dist/chunks/studio-1b04pd0j.js +0 -64
  572. package/dist/chunks/studio-4dwbj6gb.js +0 -5
  573. package/dist/chunks/studio-4tanh828.js +0 -5
  574. package/dist/chunks/studio-55h4mstj.js +0 -4
  575. package/dist/chunks/studio-5tnvjkz4.js +0 -5
  576. package/dist/chunks/studio-60dqgb0c.js +0 -5
  577. package/dist/chunks/studio-61dp09qg.js +0 -9
  578. package/dist/chunks/studio-63epcrj2.js +0 -5
  579. package/dist/chunks/studio-74k29dy9.js +0 -5
  580. package/dist/chunks/studio-7vg6jcd3.js +0 -5
  581. package/dist/chunks/studio-7zx31knw.js +0 -9
  582. package/dist/chunks/studio-8bxk97km.js +0 -5
  583. package/dist/chunks/studio-933e30n4.js +0 -5
  584. package/dist/chunks/studio-98wnwhbg.js +0 -5
  585. package/dist/chunks/studio-9mccjwjh.js +0 -14
  586. package/dist/chunks/studio-a2ke1e4t.js +0 -5
  587. package/dist/chunks/studio-e3a2a6v3.js +0 -4
  588. package/dist/chunks/studio-e81q1vb9.js +0 -5
  589. package/dist/chunks/studio-epgrmqqm.js +0 -5
  590. package/dist/chunks/studio-ery42sqr.js +0 -4
  591. package/dist/chunks/studio-g1shz58g.js +0 -5
  592. package/dist/chunks/studio-gf0fz03c.js +0 -5
  593. package/dist/chunks/studio-gjtpe62q.js +0 -6
  594. package/dist/chunks/studio-gkskhg7m.js +0 -5
  595. package/dist/chunks/studio-gx4dnjzd.js +0 -5
  596. package/dist/chunks/studio-j03zga3y.js +0 -9
  597. package/dist/chunks/studio-jhpxeckz.js +0 -5
  598. package/dist/chunks/studio-k01r7ykp.js +0 -5
  599. package/dist/chunks/studio-kk7h30ne.js +0 -7
  600. package/dist/chunks/studio-kt1zqney.js +0 -5
  601. package/dist/chunks/studio-m3cwhvye.js +0 -5
  602. package/dist/chunks/studio-mcayt6hz.js +0 -5
  603. package/dist/chunks/studio-myjcghv3.js +0 -5
  604. package/dist/chunks/studio-n8bxwc3y.js +0 -4
  605. package/dist/chunks/studio-ngm8gvpb.js +0 -5
  606. package/dist/chunks/studio-nj5a01jy.js +0 -928
  607. package/dist/chunks/studio-pcgz8heb.js +0 -5
  608. package/dist/chunks/studio-qcsq0t15.js +0 -5
  609. package/dist/chunks/studio-qkstvve9.js +0 -5
  610. package/dist/chunks/studio-qv1pwd3c.js +0 -5
  611. package/dist/chunks/studio-rc6dvxjb.js +0 -7
  612. package/dist/chunks/studio-s8dmmz66.js +0 -5
  613. package/dist/chunks/studio-sp5xzbj4.js +0 -6
  614. package/dist/chunks/studio-szsjbj0g.js +0 -5
  615. package/dist/chunks/studio-t1xzawhr.js +0 -16
  616. package/dist/chunks/studio-t6b6qe31.js +0 -5
  617. package/dist/chunks/studio-tdcprbqb.js +0 -5
  618. package/dist/chunks/studio-vyc0b4he.js +0 -10
  619. package/dist/chunks/studio-w0cgf6jg.js +0 -5
  620. package/dist/chunks/studio-w3hskzqk.js +0 -5
  621. package/dist/chunks/studio-xgrgcdyh.js +0 -9
  622. package/dist/chunks/studio-xz2yxfcb.js +0 -5
  623. package/dist/chunks/studio-y6n42tgs.js +0 -5
  624. package/dist/chunks/studio-yb560vxr.js +0 -5
  625. package/dist/chunks/studio-yn9f8vtx.js +0 -5
  626. package/dist/chunks/studio-yw05w8f0.js +0 -7
  627. package/dist/chunks/studio-z16sgavc.js +0 -5
  628. package/dist/chunks/studio-zyqn40w4.js +0 -5
  629. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  630. package/dist/chunks/tabs-jwthg40w.js +0 -4
  631. package/dist/chunks/textfield-spy3hc77.js +0 -4
  632. package/dist/chunks/toast-4d35zd64.js +0 -4
  633. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  634. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  635. package/dist/chunks/tree-h19v1jfz.js +0 -4
  636. package/dist/chunks/workspace-zt81g1ms.js +0 -4
  637. package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
@@ -4,13 +4,17 @@
4
4
  * dispatches to manage/settings/source/edit/design/preview rendering paths.
5
5
  */
6
6
 
7
- import { render as litRender, nothing } from "lit-html";
7
+ import { render, nothing } from "lit-html";
8
8
  import type * as monaco from "monaco-editor";
9
9
  import type { WireDiffMarks } from "./iframe-protocol";
10
10
  import type * as Y from "yjs";
11
11
  import { loadedMonaco, loadMonaco, mountStillWanted } from "../services/monaco-lazy";
12
12
 
13
- import { getNodeAtPath, updateCanvas } from "../store";
13
+ import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
14
+ import { isString } from "@jxsuite/schema/guards";
15
+ import { errorMessage } from "@jxsuite/schema/parse";
16
+ import { stageOf } from "./surface-registry";
17
+ import { updateCanvas } from "../store";
14
18
  import { activeTab, tabIsLive, workspace } from "../workspace/workspace";
15
19
  import {
16
20
  activeMediaOfPane,
@@ -40,8 +44,6 @@ import { canRenderComparison } from "../panels/git-diff-open";
40
44
  import { releaseStageScrollbar, trackStageScrollbar } from "./stage-scrollbar";
41
45
  import { renderDiffToolbar, setDiffRepaint, setDiffToolbarHost } from "./diff-toolbar";
42
46
  import { attachCursorStyles } from "../collab/monaco-cursors";
43
- import type { AwarenessLike } from "../collab/monaco-cursors";
44
- import type { BindingAwareness } from "../collab/monaco-binding";
45
47
  import { monacoTheme, shell } from "../shell";
46
48
  import { parseSourceForPath } from "../files/file-ops";
47
49
  import { serializeDocument } from "../files/serialize-document";
@@ -412,13 +414,15 @@ async function createSourceCollabBinding(
412
414
  ): Promise<() => void> {
413
415
  const { bindMonacoToYText } = await import("../collab/monaco-binding");
414
416
  const unbind = bindMonacoToYText({
415
- awareness: ctx.awareness as unknown as BindingAwareness,
417
+ awareness: ctx.awareness,
416
418
  editors: [editor],
417
419
  model,
418
420
  origin: ctx.localOrigin,
421
+ /* SAFETY: collabSourceContext's `text` is `collab.sourceText(handle.doc)`, the session's shared
422
+ source Y.Text, attached to the handle's Y.Doc as the binding requires. */
419
423
  text: ctx.text as Y.Text,
420
424
  });
421
- const detachStyles = attachCursorStyles(ctx.awareness as unknown as AwarenessLike, document);
425
+ const detachStyles = attachCursorStyles(ctx.awareness, document);
422
426
  return () => {
423
427
  detachStyles();
424
428
  unbind();
@@ -558,7 +562,7 @@ function sideMarks(
558
562
  */
559
563
  async function mountDiffEditor(
560
564
  surface: CanvasSurface,
561
- container: Element,
565
+ container: HTMLElement,
562
566
  state: GitDiffState,
563
567
  ): Promise<void> {
564
568
  const { paneId } = surface;
@@ -589,17 +593,20 @@ async function mountDiffEditor(
589
593
  lang,
590
594
  monaco.Uri.parse(uris.work),
591
595
  );
592
- const editor = monaco.editor.createDiffEditor(container as HTMLElement, {
593
- automaticLayout: true,
594
- fontFamily: "'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', monospace",
595
- fontSize: 12,
596
- minimap: { enabled: false },
597
- originalEditable: false,
598
- readOnly: true,
599
- renderSideBySide: true,
600
- scrollBeyondLastLine: false,
601
- theme: monacoTheme(),
602
- }) as NonNullable<CanvasSurface["monacoDiffEditor"]>;
596
+ const editor: NonNullable<CanvasSurface["monacoDiffEditor"]> = monaco.editor.createDiffEditor(
597
+ container,
598
+ {
599
+ automaticLayout: true,
600
+ fontFamily: "'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', monospace",
601
+ fontSize: 12,
602
+ minimap: { enabled: false },
603
+ originalEditable: false,
604
+ readOnly: true,
605
+ renderSideBySide: true,
606
+ scrollBeyondLastLine: false,
607
+ theme: monacoTheme(),
608
+ },
609
+ );
603
610
  editor.setModel({ modified, original });
604
611
  editor._diffKey = key;
605
612
  surface.monacoDiffEditor = editor;
@@ -663,7 +670,7 @@ function resetCanvasView(surface: CanvasSurface) {
663
670
  async function mountSourceEditor(
664
671
  tab: Tab,
665
672
  surface: CanvasSurface,
666
- editorContainer: Element,
673
+ editorContainer: HTMLElement,
667
674
  filePath: string,
668
675
  lang: string,
669
676
  ): Promise<void> {
@@ -757,7 +764,7 @@ async function mountSourceEditor(
757
764
  // Typed as the surface `view` declares (the editor plus `_ignoreNextChange` / `_writes`), because
758
765
  // The instance is HELD here now rather than re-read off `view.monacoEditor` in every callback.
759
766
  const sourceEditor: NonNullable<typeof surface.monacoEditor> = monaco.editor.create(
760
- editorContainer as unknown as HTMLElement,
767
+ editorContainer,
761
768
  {
762
769
  automaticLayout: true,
763
770
  fontFamily: "'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', monospace",
@@ -832,7 +839,7 @@ async function mountSourceEditor(
832
839
  if (!tabIsLive(tab)) {
833
840
  return;
834
841
  }
835
- tab.doc.document = document as JxMutableNode;
842
+ tab.doc.document = document;
836
843
  tab.doc.content.frontmatter = frontmatter;
837
844
  tab.doc.dirty = true;
838
845
  writes.markSettled();
@@ -845,6 +852,8 @@ async function mountSourceEditor(
845
852
  // The buffer's text is the author's own layout now — the objects they opened up or
846
853
  // Closed, the blank lines they left — so it is what the next save preserves.
847
854
  const parsed = parseJsonDocument(sourceEditor.getValue());
855
+ /* SAFETY: a JSON source tab holds a Jx document, whose schema makes the top-level object
856
+ parseJsonDocument returns a node; text that does not parse throws into the catch. */
848
857
  tab.doc.document = parsed.document as JxMutableNode;
849
858
  tab.doc.layout = parsed.layout;
850
859
  tab.doc.dirty = true;
@@ -930,7 +939,7 @@ function renderDerivationNotice(
930
939
  surface.wrap.style.display = "block";
931
940
  const registry = activeRegistry();
932
941
  const pin = registry?.get("pane.pin");
933
- litRender(
942
+ render(
934
943
  emptyState(surface.wrap, {
935
944
  message,
936
945
  ...(held && { detail: `${tabLabel(held)} is still open here.` }),
@@ -954,7 +963,7 @@ function renderCanvasImpl(surface: CanvasSurface) {
954
963
  /* Every read below is scoped to ONE pane. The stage, the panels it mounted and the mode it draws
955
964
  are the surface's; the document is whatever tab that pane is showing, which is `activeTab` only
956
965
  when the pane is the focused one. */
957
- const canvasWrap = surface.wrap;
966
+ const canvasWrap = stageOf(surface);
958
967
  /* A pane with no stage renders nothing — it is not an error and it is not a fallback to some
959
968
  other pane's stage. Two schedulers can name a stage-less pane: a frame queued for a pane that
960
969
  lost the shell's single stage between the schedule and the rAF, and `escalateToFullRender` on
@@ -1012,6 +1021,8 @@ function renderCanvasImpl(surface: CanvasSurface) {
1012
1021
  );
1013
1022
  return;
1014
1023
  }
1024
+ /* SAFETY: `initCanvasRender` runs at studio boot (studio.ts), before the shell schedules the first
1025
+ pane render, and nothing resets `_ctx` afterwards. */
1015
1026
  const ctx = _ctx as CanvasRenderCtx;
1016
1027
  const S = {
1017
1028
  document: tab.doc.document,
@@ -1193,8 +1204,8 @@ function renderCanvasImpl(surface: CanvasSurface) {
1193
1204
  curFilter !== surface.prevStylebookFilter ||
1194
1205
  curCustomized !== surface.prevStylebookCustomizedOnly;
1195
1206
  if (!filterChanged) {
1196
- const style = transposeStylebookStyle(getEffectiveStyle(tab.doc.document?.style));
1197
- if (postStyleUpdateToStylebookHosts(style as Record<string, unknown>) > 0) {
1207
+ const style = transposeStylebookStyle(getEffectiveStyle(tab.doc.document.style));
1208
+ if (postStyleUpdateToStylebookHosts(style) > 0) {
1198
1209
  return;
1199
1210
  }
1200
1211
  }
@@ -1261,7 +1272,7 @@ function renderCanvasImpl(surface: CanvasSurface) {
1261
1272
  leaving, and lit's part, which the empty-state and welcome paths own. */
1262
1273
  releaseCanvasHosts(canvasWrap);
1263
1274
  detachCanvasStage(surface);
1264
- litRender(nothing, canvasWrap);
1275
+ render(nothing, canvasWrap);
1265
1276
  surface.panzoomWrap = null;
1266
1277
  // Reset inline style overrides from other modes
1267
1278
  canvasWrap.style.padding = "";
@@ -1465,7 +1476,7 @@ function renderCanvasImpl(surface: CanvasSurface) {
1465
1476
  decided rather than the opener: a comparison reaches this branch from three doors (the panel,
1466
1477
  a Diff lens, the Editor axis) and only this one sees every arrival. Forcing it here also
1467
1478
  leaves `diffView` alone, so a document opened after a `.css` still comes up Visual. */
1468
- const renderable = canRenderComparison(gitDiffState.filePath ?? "");
1479
+ const renderable = canRenderComparison(gitDiffState.filePath);
1469
1480
  if (diffShowsCode(surface.paneId, renderable)) {
1470
1481
  /* A null map is how the toolbar learns there is no visual half to offer: it draws Code as a
1471
1482
  static label rather than as half of a choice, and reports the line marks instead of a node
@@ -1518,12 +1529,15 @@ function renderCanvasImpl(surface: CanvasSurface) {
1518
1529
 
1519
1530
  /** @param {string} content */
1520
1531
  const parseContent = (content: string): Promise<JxMutableNode> => {
1521
- const fmtPath = gitDiffState.filePath ?? "";
1532
+ const fmtPath = gitDiffState.filePath;
1522
1533
  if (formatForPath(fmtPath)) {
1523
1534
  return parseSourceForPath(fmtPath, content).then((r) => r.document);
1524
1535
  }
1525
1536
  return Promise.resolve().then(() => {
1526
1537
  try {
1538
+ /* SAFETY: a side of a VISUAL comparison is a revision of a document the canvas renders
1539
+ (canRenderComparison chose this half), a JSON Jx document; unparseable text throws into
1540
+ the catch, which draws the failure instead. */
1527
1541
  return JSON.parse(content) as JxMutableNode;
1528
1542
  } catch {
1529
1543
  return {
@@ -1636,8 +1650,8 @@ function renderCanvasImpl(surface: CanvasSurface) {
1636
1650
  const entry = canvasPanelEntry(null, null, true);
1637
1651
  // A component-definition doc (root tag is a custom element) is a fragment, not a page: it should
1638
1652
  // Hug its content rather than have the column fill+stretch to the viewport (dead scroll space).
1639
- const rootTag = (S.document as { tagName?: unknown }).tagName;
1640
- const isComponentDoc = typeof rootTag === "string" && rootTag.includes("-");
1653
+ const rootTag = S.document.tagName;
1654
+ const isComponentDoc = isString(rootTag) && rootTag.includes("-");
1641
1655
  const { featureToggles: editToggles } = S.ui;
1642
1656
  /* The stage stacks when it carries the card: the band first, the page's scroller below it.
1643
1657
  Set on every render rather than on the transition, because whether a document HAS a header
@@ -1680,6 +1694,8 @@ function renderCanvasImpl(surface: CanvasSurface) {
1680
1694
  }
1681
1695
  const editColumn = stageHost(surface, "edit-column");
1682
1696
  const scroller = stageHost(surface, "edit-canvas");
1697
+ /* SAFETY: the edit stage view always draws its `edit-canvas` part, and this runs only once
1698
+ drawStage settled with that stage (the `!stage` return above). */
1683
1699
  entry.panel.scrollContainer = scroller as HTMLElement;
1684
1700
  /* The one mode whose stage SCROLLS under the zoom pod, so the one that tells the pane how
1685
1701
  wide its scrollbar is. The pod floats in the pane's chrome layer, which spans the gutter
@@ -1733,7 +1749,7 @@ function renderCanvasImpl(surface: CanvasSurface) {
1733
1749
  if (!hasMedia) {
1734
1750
  // Single panel — use baseWidth if a custom one is defined, otherwise full-width
1735
1751
  const effectiveMedia = getEffectiveMedia(S.document.$media);
1736
- const hasBaseWidth = effectiveMedia && effectiveMedia["--"];
1752
+ const hasBaseWidth = effectiveMedia["--"];
1737
1753
  const label = hasBaseWidth ? `${mediaDisplayName("--")} (${baseWidth}px)` : null;
1738
1754
  const entry = canvasPanelEntry(
1739
1755
  hasBaseWidth ? "base" : null,
@@ -1900,8 +1916,11 @@ function renderCanvasIntoPanel(
1900
1916
  ) {
1901
1917
  const gen = passGen ?? surface.renderGeneration;
1902
1918
  const tab = tabOfPane(surface.paneId);
1919
+ /* SAFETY: every caller is a renderCanvasImpl pass, which returns before drawing any panel when its
1920
+ pane has no tab, so without an override `tab` was non-null when this pass began; the git-diff
1921
+ callers always pass their override. */
1903
1922
  const docToRender = docOverride || (tab?.doc.document as JxMutableNode);
1904
- const canvas = panel.canvas as HTMLElement;
1923
+ const { canvas } = panel;
1905
1924
 
1906
1925
  canvasPerf.panelRenders += 1;
1907
1926
  panel.ready = false;
@@ -1947,14 +1966,16 @@ function renderCanvasIntoPanel(
1947
1966
  // The canvas you are looking at; it says so itself.
1948
1967
  }
1949
1968
  })
1950
- .catch((error: unknown) => {
1951
- const detail = error instanceof Error ? error.message : String(error);
1952
- notify.error("The canvas could not be mounted.", {
1953
- detail,
1954
- key: "canvas.mount",
1955
- source: "Canvas",
1956
- });
1957
- });
1969
+ .catch(reportMountFailure);
1970
+ }
1971
+
1972
+ /** A canvas mount that rejected, reported as a Problem with the failure's own message. */
1973
+ function reportMountFailure(cause: unknown): void {
1974
+ notify.error("The canvas could not be mounted.", {
1975
+ detail: errorMessage(cause),
1976
+ key: "canvas.mount",
1977
+ source: "Canvas",
1978
+ });
1958
1979
  }
1959
1980
 
1960
1981
  /*
@@ -2012,7 +2033,7 @@ function refuseUnresolvableToken(token: string): void {
2012
2033
  throw new RangeError(`command "insert.data" needs an open document; no tab is active`);
2013
2034
  }
2014
2035
  const root = tokenRoot(token);
2015
- const state = (tab.doc.document.state ?? {}) as Record<string, unknown>;
2036
+ const state = tab.doc.document.state ?? {};
2016
2037
  if (root === "state") {
2017
2038
  const name = token.split(".")[1] ?? "";
2018
2039
  if (!(name in state)) {
@@ -17,6 +17,7 @@ import { allCanvasSurfaces, stageContaining, surfaceForPane } from "./surface-re
17
17
  import type { CanvasSurface } from "./surface-registry";
18
18
  import type { PaneDerivation } from "../workspace/workspace";
19
19
  import type { CanvasPanel } from "../types";
20
+ import type { UnboundCanvasPanel } from "./canvas-utils";
20
21
  import type { Tab } from "../tabs/tab";
21
22
 
22
23
  export {
@@ -149,11 +150,12 @@ export function panelHostingCanvas(
149
150
  * answers with the FOCUSED pane's tab, which is a different document the moment the click is in a
150
151
  * pane the keyboard is not in.
151
152
  *
152
- * @param {CanvasPanel} panel
153
+ * @param {UnboundCanvasPanel} panel
153
154
  * @returns {Tab | null}
154
155
  */
155
- export function tabOfMountedPanel(panel: CanvasPanel): Tab | null {
156
- const canvasEl = panel.canvas as HTMLElement | null;
156
+ export function tabOfMountedPanel(panel: UnboundCanvasPanel): Tab | null {
157
+ // An unbound board (no canvas node yet) has no pane mounting it.
158
+ const canvasEl = panel.canvas;
157
159
  const mounted = canvasEl ? panelHostingCanvas(canvasEl) : null;
158
160
  return mounted ? tabOfPane(mounted.surface.paneId) : null;
159
161
  }
@@ -4,7 +4,7 @@
4
4
  * template creation, centering, transform application, zoom indicator, and fit-to-screen.
5
5
  */
6
6
 
7
- import type { CanvasPanel, JsonValue } from "../types";
7
+ import type { CanvasPanel } from "../types";
8
8
 
9
9
  import { renderOnly } from "../store";
10
10
  import {
@@ -39,6 +39,7 @@ import {
39
39
  import type { CanvasStageHandle, CanvasStagePanelItem } from "../surfaces/canvas-stage";
40
40
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
41
41
  import type { CommandArgValues } from "../commands/command-args";
42
+ import { isNumber, isString } from "@jxsuite/schema/guards";
42
43
  import type { Tab } from "../tabs/tab";
43
44
 
44
45
  /*
@@ -106,6 +107,22 @@ function setZoomOf(surface: CanvasSurface, zoom: number): void {
106
107
  }
107
108
  }
108
109
 
110
+ /** The {@link CanvasPanel} fields that hold the board's drawn nodes. */
111
+ type CanvasPanelNodeKey = "canvas" | "element" | "scrollContainer" | "viewport";
112
+
113
+ /**
114
+ * A panel record as it may be before {@link bindCanvasPanels} has run: its DOM fields can still be
115
+ * null, because {@link canvasPanelEntry} builds them that way. A bound {@link CanvasPanel} is
116
+ * assignable to it, so a reader that must tolerate an unbound board takes this type.
117
+ */
118
+ export type UnboundCanvasPanel = Omit<CanvasPanel, CanvasPanelNodeKey> &
119
+ Record<CanvasPanelNodeKey, HTMLElement | null>;
120
+
121
+ /** Whether the stage has wired a board's canvas and viewport nodes into its record yet. */
122
+ export function isPanelBound(panel: UnboundCanvasPanel): boolean {
123
+ return Boolean(panel.canvas && panel.viewport);
124
+ }
125
+
109
126
  /**
110
127
  * One artboard: the record the geometry reads, and the item the stage document draws.
111
128
  *
@@ -139,7 +156,7 @@ export function canvasPanelEntry(
139
156
  fullWidth: boolean,
140
157
  width: number | null = null,
141
158
  ): CanvasPanelEntry {
142
- const panel = {
159
+ const unbound: UnboundCanvasPanel = {
143
160
  _width: width || null,
144
161
  canvas: null,
145
162
  element: null,
@@ -148,7 +165,11 @@ export function canvasPanelEntry(
148
165
  renderScope: null,
149
166
  scrollContainer: null,
150
167
  viewport: null,
151
- } as unknown as CanvasPanel;
168
+ };
169
+ /* SAFETY: the record is handed out unbound and filled in place by `bindCanvasPanels` once the
170
+ stage has drawn it; every reader that can run before that (`tabOfMountedPanel`, `applyEditZoom`,
171
+ `updateActivePanelHeaders`) reads it as an UnboundCanvasPanel and checks the nodes first. */
172
+ const panel = unbound as CanvasPanel;
152
173
  /* The viewport takes the declared width, the canvas takes it too — but a FULL-WIDTH board's
153
174
  viewport does not, because "full width" means "as wide as the box you are in". Carried as two
154
175
  custom properties rather than as `width:` so `applyEditZoom`'s inline write on the canvas still
@@ -186,9 +207,13 @@ export function canvasPanelEntry(
186
207
  */
187
208
  export function bindCanvasPanels(entries: CanvasPanelEntry[], stage: CanvasStageHandle): void {
188
209
  for (const { item, panel } of entries) {
189
- panel.element = stage.panelNode(item.key, "panel") as HTMLElement;
190
- panel.viewport = stage.panelNode(item.key, "panel-viewport") as HTMLElement;
191
- panel.canvas = stage.panelNode(item.key, "panel-canvas") as HTMLElement;
210
+ /* SAFETY: callers bind only after `drawStage` has settled, and the stage document draws the
211
+ `panel`, `panel-viewport` and `panel-canvas` parts for every item it was given, keyed by
212
+ `item.key`, so each lookup finds its node. */
213
+ const node = (part: string) => stage.panelNode(item.key, part) as HTMLElement;
214
+ panel.element = node("panel");
215
+ panel.viewport = node("panel-viewport");
216
+ panel.canvas = node("panel-canvas");
192
217
  }
193
218
  }
194
219
 
@@ -349,7 +374,7 @@ export function applyEditZoom(
349
374
  return;
350
375
  }
351
376
  const [panel] = surface.panels;
352
- if (!panel?.canvas || !panel.viewport) {
377
+ if (!panel || !isPanelBound(panel)) {
353
378
  return;
354
379
  }
355
380
  const canvasEl = panel.canvas;
@@ -571,12 +596,12 @@ export const FIT_WORDS: readonly string[] = ["width", "page", "none"];
571
596
  * assistant sees. It stays as the typed read the body needs (`args.fit` is `unknown`) and as the
572
597
  * refusal for a caller that reaches the body directly.
573
598
  */
574
- function fitArg(commandId: string, args: Record<string, unknown>, key: string): FitMode {
599
+ function fitArg(commandId: string, args: CommandArgValues, key: string): FitMode {
575
600
  const value = args[key];
576
- if (typeof value === "string" && FIT_WORDS.includes(value)) {
577
- return value as FitMode;
601
+ if (isFitWord(value)) {
602
+ return value;
578
603
  }
579
- if (typeof value === "number" && value >= PAN_ZOOM_MIN && value <= PAN_ZOOM_MAX) {
604
+ if (isNumber(value) && value >= PAN_ZOOM_MIN && value <= PAN_ZOOM_MAX) {
580
605
  return value;
581
606
  }
582
607
  throw new RangeError(
@@ -585,6 +610,11 @@ function fitArg(commandId: string, args: Record<string, unknown>, key: string):
585
610
  );
586
611
  }
587
612
 
613
+ /** Whether a value is one of {@link FIT_WORDS}, the named (non-scale) fits. */
614
+ function isFitWord(value: unknown): value is Exclude<FitMode, number> {
615
+ return isString(value) && FIT_WORDS.includes(value);
616
+ }
617
+
588
618
  /** Declared fits, keyed per tab + document. */
589
619
  const _fits = new Map<string, FitMode>();
590
620
 
@@ -641,7 +671,7 @@ export function applyFit(fit?: FitMode, surface: CanvasSurface = activeCanvasSur
641
671
  applyTransform(surface);
642
672
  return;
643
673
  }
644
- if (typeof chosen === "number") {
674
+ if (isNumber(chosen)) {
645
675
  setZoomOf(surface, clampPanZoom(chosen));
646
676
  applyTransform(surface);
647
677
  return;
@@ -853,6 +883,11 @@ export type CanvasMode = (typeof CANVAS_MODES)[number];
853
883
  /** The base modes the preview flag composes with — the two the Canvas view axis shows it beside. */
854
884
  const PREVIEWABLE_BASE_MODES = new Set(["edit", "design"]);
855
885
 
886
+ /** Whether a base mode is one the preview flag composes with: a member of PREVIEWABLE_BASE_MODES. */
887
+ function isPreviewableBase(mode: string): mode is "edit" | "design" {
888
+ return PREVIEWABLE_BASE_MODES.has(mode);
889
+ }
890
+
856
891
  // ─── The Canvas view (§4.2) ──────────────────────────────────────────────────
857
892
  // `Edit │ Design` is a radio and `Preview` is a TOGGLE beside it, because that is what the storage
858
893
  // Has always been: `preview` is not a base mode, it is a flag that composes with one.
@@ -913,7 +948,13 @@ export function canvasBaseViewsFor(tab: ViewableTab): CanvasView[] {
913
948
  /** The base view the tab returns to — what the radio marks while preview is on. */
914
949
  export function canvasBaseViewOf(tab: ViewableTab): CanvasView | null {
915
950
  const base = tab.session.ui.canvasMode;
916
- return PREVIEWABLE_BASE_MODES.has(base) ? (base as CanvasView) : null;
951
+ return isPreviewableBase(base) ? base : null;
952
+ }
953
+
954
+ /** A tab's Preview toggle: whether it is offered, and whether it is pressed. */
955
+ export interface PreviewState {
956
+ available: boolean;
957
+ on: boolean;
917
958
  }
918
959
 
919
960
  /**
@@ -922,7 +963,7 @@ export function canvasBaseViewOf(tab: ViewableTab): CanvasView | null {
922
963
  * `available` is a fact about the DOCUMENT (its declared modes) and about the base it is currently
923
964
  * in — `source` composes with no preview, so the toggle is not offered there.
924
965
  */
925
- export function previewStateOf(tab: ViewableTab): { available: boolean; on: boolean } {
966
+ export function previewStateOf(tab: ViewableTab): PreviewState {
926
967
  return {
927
968
  available:
928
969
  tab.capabilities.modes.includes("preview") &&
@@ -1041,7 +1082,7 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1041
1082
  * than the control it replaced, which is the opposite of the point.
1042
1083
  */
1043
1084
  function contextTab(commandId: string, args: CommandArgValues) {
1044
- const { pane } = args as { pane?: unknown };
1085
+ const { pane } = args;
1045
1086
  if (pane === undefined) {
1046
1087
  return requireTab(commandId);
1047
1088
  }
@@ -1073,8 +1114,8 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1073
1114
 
1074
1115
  /** The pane a rendering-context verb addresses, named or focused. {@link repaint}'s own rule. */
1075
1116
  function paneOfArgs(args: CommandArgValues): string {
1076
- const { pane } = args as { pane?: unknown };
1077
- return typeof pane === "string" ? pane : workspace.activePaneId;
1117
+ const { pane } = args;
1118
+ return isString(pane) ? pane : workspace.activePaneId;
1078
1119
  }
1079
1120
 
1080
1121
  return [
@@ -1258,9 +1299,9 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1258
1299
  * so it simply renders at the pane's width — which is the same clamp the drag applies, arrived
1259
1300
  * at by CSS instead of by arithmetic. Refusing would make the verb depend on the window size.
1260
1301
  */
1261
- run: (_commandCtx, args) => {
1302
+ run: (_commandCtx, args: CommandArgValues) => {
1262
1303
  const tab = contextTab("canvas.setEditWidth", args);
1263
- const { width } = args as { width?: unknown };
1304
+ const { width } = args;
1264
1305
  if (width === null) {
1265
1306
  clearEditWidth(paneOfArgs(args));
1266
1307
  repaint(args);
@@ -1311,10 +1352,10 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1311
1352
  group: "3_canvas",
1312
1353
  requires: "an open document",
1313
1354
  when: documentOpen,
1314
- run: (_commandCtx, args) => {
1355
+ run: (_commandCtx, args: CommandArgValues) => {
1315
1356
  const tab = contextTab("canvas.setBreakpoint", args);
1316
- const { media } = args as { media?: unknown };
1317
- if (media !== null && typeof media !== "string") {
1357
+ const { media } = args;
1358
+ if (media !== null && !isString(media)) {
1318
1359
  throw new RangeError(
1319
1360
  `command "canvas.setBreakpoint" argument "media": expected a breakpoint key or null`,
1320
1361
  );
@@ -1323,9 +1364,7 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1323
1364
  that does not exist — the rule `data.expandRow` applies to a state entry's name.
1324
1365
  `getEffectiveMedia` and not `document.$media`: the popover offers the SITE's breakpoints
1325
1366
  too, and a command that refused what the control offers would be worse than no command. */
1326
- const declared = Object.keys(
1327
- getEffectiveMedia(tab.doc.document?.$media as Record<string, string> | undefined),
1328
- );
1367
+ const declared = Object.keys(getEffectiveMedia(tab.doc.document.$media));
1329
1368
  if (media !== null && !declared.includes(media)) {
1330
1369
  throw new RangeError(
1331
1370
  `command "canvas.setBreakpoint" argument "media": "${media}" is not a breakpoint this ` +
@@ -1359,7 +1398,7 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1359
1398
  args,
1360
1399
  "scheme",
1361
1400
  COLOR_SCHEMES,
1362
- ) as "auto" | "dark" | "light";
1401
+ );
1363
1402
  repaint(args);
1364
1403
  },
1365
1404
  title: "Set Color Scheme",
@@ -1475,16 +1514,18 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1475
1514
  level: "document",
1476
1515
  menus: ["palette"],
1477
1516
  requires: "a popover in the open document",
1478
- run: (_commandCtx, args) => {
1517
+ run: (_commandCtx, args: CommandArgValues) => {
1479
1518
  const tab = contextTab("canvas.setPopoverOpen", args);
1480
- const raw = (args ?? {}) as { open?: unknown; path?: JxPath };
1519
+ /* SAFETY: `registry.run` coerces args against this record's schema before `run`, and the
1520
+ schema declares `path` an array of strings and numbers, which is what a JxPath is. */
1521
+ const explicitPath = args["path"] as JxPath | undefined;
1481
1522
  const open =
1482
- raw.open === undefined ? true : booleanArg("canvas.setPopoverOpen", args, "open");
1483
- if (!open && raw.path === undefined) {
1523
+ args["open"] === undefined ? true : booleanArg("canvas.setPopoverOpen", args, "open");
1524
+ if (!open && explicitPath === undefined) {
1484
1525
  deps.setOpenPopover(tab, null);
1485
1526
  return;
1486
1527
  }
1487
- const path = popoverPathFor(tab, raw.path);
1528
+ const path = popoverPathFor(tab, explicitPath);
1488
1529
  /* REFUSES a path that is not a popover rather than opening nothing — the rule
1489
1530
  `canvas.setBreakpoint` applies to a breakpoint key. A <dialog> is refused with it: its UA
1490
1531
  rules key off `open`, not `popover`, so de-popovering one falls back to a different rule
@@ -1535,16 +1576,18 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1535
1576
  level: "document",
1536
1577
  menus: ["palette"],
1537
1578
  requires: "a dialog in the open document",
1538
- run: (_commandCtx, args) => {
1579
+ run: (_commandCtx, args: CommandArgValues) => {
1539
1580
  const tab = contextTab("canvas.setDialogOpen", args);
1540
- const raw = (args ?? {}) as { open?: unknown; path?: JxPath };
1581
+ /* SAFETY: `registry.run` coerces args against this record's schema before `run`, and the
1582
+ schema declares `path` an array of strings and numbers, which is what a JxPath is. */
1583
+ const explicitPath = args["path"] as JxPath | undefined;
1541
1584
  const open =
1542
- raw.open === undefined ? true : booleanArg("canvas.setDialogOpen", args, "open");
1543
- if (!open && raw.path === undefined) {
1585
+ args["open"] === undefined ? true : booleanArg("canvas.setDialogOpen", args, "open");
1586
+ if (!open && explicitPath === undefined) {
1544
1587
  deps.setOpenDialog(tab, null);
1545
1588
  return;
1546
1589
  }
1547
- const path = dialogPathFor(tab, raw.path);
1590
+ const path = dialogPathFor(tab, explicitPath);
1548
1591
  /* REFUSES a path that is not a dialog, for the same reason its twin refuses a non-popover:
1549
1592
  the canvas would draw it under the wrong rule and with the wrong name. */
1550
1593
  if (path === null) {
@@ -1586,14 +1629,14 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1586
1629
  * (`scripts/screenshots/README.md`) forbids outright. The pointer and the camera use the same
1587
1630
  * door.
1588
1631
  */
1589
- run: (_commandCtx, args) => {
1632
+ run: (_commandCtx, args: CommandArgValues) => {
1590
1633
  // Resolve the tab first, so a pane with no document refuses before anything opens.
1591
1634
  contextTab("canvas.setResolvingOpen", args);
1592
- const { open, pane } = args as { open?: unknown; pane?: unknown };
1635
+ const { open, pane } = args;
1593
1636
  // `open` defaults to true and is never COERCED: `{ open: "no" }` would otherwise read as a
1594
1637
  // Close, the class of silent wrong answer this setter family exists to stop.
1595
1638
  deps.setResolvingOpen(
1596
- typeof pane === "string" ? pane : workspace.activePaneId,
1639
+ isString(pane) ? pane : workspace.activePaneId,
1597
1640
  open === undefined || booleanArg("canvas.setResolvingOpen", args, "open"),
1598
1641
  );
1599
1642
  },
@@ -1636,26 +1679,24 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
1636
1679
  group: "3_canvas",
1637
1680
  requires: "an open component document",
1638
1681
  when: documentOpen,
1639
- run: (_commandCtx, args) => {
1682
+ run: (_commandCtx, args: CommandArgValues) => {
1640
1683
  const tab = contextTab("canvas.setTestProp", args);
1641
1684
  const name = stringArg("canvas.setTestProp", args, "name");
1642
1685
  // REFUSES a prop the component does not declare, rather than seeding a value nothing reads
1643
1686
  // — the rule `data.expandRow` and `canvas.setBreakpoint` both apply to their own names.
1644
- const declared = Object.keys(
1645
- (tab.doc.document?.state as Record<string, unknown> | undefined) ?? {},
1646
- );
1687
+ const declared = Object.keys(tab.doc.document.state ?? {});
1647
1688
  if (!declared.includes(name)) {
1648
1689
  throw new RangeError(
1649
1690
  `command "canvas.setTestProp" argument "name": "${name}" is not a prop this component ` +
1650
1691
  `declares — it declares: ${declared.length > 0 ? declared.join(", ") : "nothing"}`,
1651
1692
  );
1652
1693
  }
1653
- const { value } = args as { value?: unknown };
1694
+ const { value } = args;
1654
1695
  const next = { ...tab.session.ui.previewProps };
1655
1696
  if (value === null || value === undefined) {
1656
1697
  delete next[name];
1657
1698
  } else {
1658
- next[name] = value as JsonValue;
1699
+ next[name] = value;
1659
1700
  }
1660
1701
  tab.session.ui.previewProps = Object.keys(next).length > 0 ? next : null;
1661
1702
  repaint(args);
@@ -1723,13 +1764,13 @@ export function registerCanvasViewCommands(
1723
1764
  */
1724
1765
  export function updateActivePanelHeaders(surface: CanvasSurface = activeCanvasSurface()) {
1725
1766
  const activeMedia = activeMediaOfPane(surface.paneId);
1726
- for (const p of surface.panels) {
1767
+ // A board the stage has not bound yet has no header to mark.
1768
+ const panels: readonly UnboundCanvasPanel[] = surface.panels;
1769
+ for (const p of panels) {
1727
1770
  const header = p.element?.querySelector('[part="panel-header"]');
1728
1771
  if (header) {
1729
1772
  const isActive =
1730
- (activeMedia === null && p.mediaName === "base") ||
1731
- (activeMedia === null && p.mediaName === null) ||
1732
- activeMedia === p.mediaName;
1773
+ (activeMedia === null && p.mediaName === "base") || activeMedia === p.mediaName;
1733
1774
  /* An ATTRIBUTE the document does not bind, written from outside it. Which board is current is
1734
1775
  a fact about the pane's session that changes without the stage being rebuilt — the same
1735
1776
  reason the pan transform is written rather than bound — so a reconcile can never disagree