@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
package/src/state.ts CHANGED
@@ -12,7 +12,15 @@
12
12
  */
13
13
 
14
14
  import type { ProjectState } from "./types";
15
- import { displayTagName, isRef } from "@jxsuite/schema/guards";
15
+ import {
16
+ displayTagName,
17
+ isBoolean,
18
+ isMappedArray,
19
+ isNonNullObject,
20
+ isNumber,
21
+ isRef,
22
+ isString,
23
+ } from "@jxsuite/schema/guards";
16
24
  import type { JxMutableNode } from "@jxsuite/schema/types";
17
25
 
18
26
  export type JxPath = (string | number)[];
@@ -20,23 +28,10 @@ export type JxPath = (string | number)[];
20
28
  // ─── Path utilities ───────────────────────────────────────────────────────────
21
29
 
22
30
  /**
23
- * Walk the document tree and return the node at the given path.
24
- *
25
- * @param {JxMutableNode} doc
26
- * @param {JxPath} path
27
- * @returns {JxMutableNode}
31
+ * Walk the document tree and return the node at the given path, or `undefined` when a step falls
32
+ * off the tree (a path gone stale since it was taken). One walk, shared with the document ops.
28
33
  */
29
- export function getNodeAtPath(doc: JxMutableNode, path: JxPath) {
30
- let node = doc;
31
- for (const key of path) {
32
- if (node == null) {
33
- return undefined as unknown as JxMutableNode;
34
- }
35
- // Paths address nodes by construction; non-node leaves surface as undefined above.
36
- node = node[key] as JxMutableNode;
37
- }
38
- return node;
39
- }
34
+ export { getNodeAtPath } from "@jxsuite/schema/doc-ops";
40
35
 
41
36
  /**
42
37
  * The node's children when they are a static array (the edit-mode invariant); an empty array for
@@ -56,11 +51,11 @@ export function childList(node: JxMutableNode | null | undefined): (JxMutableNod
56
51
  * `$switch` cases. Runs once when a document is loaded into a tab so every in-studio doc — and its
57
52
  * history checkpoints — uses the member form before any mutation.
58
53
  *
59
- * @param {unknown} node
60
- * @returns {unknown} The same node (mutated)
54
+ * @param {T} node
55
+ * @returns {T} The same node (mutated)
61
56
  */
62
- export function normalizeArrayChildren(node: unknown): unknown {
63
- if (!node || typeof node !== "object") {
57
+ export function normalizeArrayChildren<T>(node: T): T {
58
+ if (!isNonNullObject(node)) {
64
59
  return node;
65
60
  }
66
61
  if (Array.isArray(node)) {
@@ -69,14 +64,12 @@ export function normalizeArrayChildren(node: unknown): unknown {
69
64
  }
70
65
  return node;
71
66
  }
67
+ /* SAFETY: A non-array object reached from a document root, a children array, a repeater `map` or
68
+ a `$switch` case is a node definition, and JxMutableNode is the editor's open node shape. */
72
69
  const n = node as JxMutableNode;
73
70
  const { children } = n;
74
- if (
75
- children &&
76
- typeof children === "object" &&
77
- !Array.isArray(children) &&
78
- (children as JxMutableNode).$prototype === "Array"
79
- ) {
71
+ if (isMappedArray(children)) {
72
+ // SAFETY: A legacy whole-children repeater is the same repeater node that becomes the member.
80
73
  n.children = [children as JxMutableNode];
81
74
  }
82
75
  if (Array.isArray(n.children)) {
@@ -84,10 +77,10 @@ export function normalizeArrayChildren(node: unknown): unknown {
84
77
  normalizeArrayChildren(child);
85
78
  }
86
79
  }
87
- if (n.$prototype === "Array" && n.map && typeof n.map === "object") {
80
+ if (n.$prototype === "Array" && isNonNullObject(n.map)) {
88
81
  normalizeArrayChildren(n.map);
89
82
  }
90
- if (n.cases && typeof n.cases === "object") {
83
+ if (isNonNullObject(n.cases)) {
91
84
  for (const caseDef of Object.values(n.cases)) {
92
85
  normalizeArrayChildren(caseDef);
93
86
  }
@@ -209,7 +202,7 @@ function collectRows(
209
202
  skipSelf: boolean,
210
203
  ): void {
211
204
  // Text node children: bare primitives get a "text" row
212
- if (typeof doc === "string" || typeof doc === "number" || typeof doc === "boolean") {
205
+ if (isString(doc) || isNumber(doc) || isBoolean(doc)) {
213
206
  if (!skipSelf) {
214
207
  out.push({ depth, node: doc, nodeType: "text", path });
215
208
  }
@@ -220,13 +213,13 @@ function collectRows(
220
213
  // Recurse into its single template at `[...path, "map"]`. This is reached both when the array is
221
214
  // A member of a children array (path `[…, "children", i]`) and the legacy whole-children form
222
215
  // (path `[…, "children"]`).
223
- if ((doc as JxMutableNode).$prototype === "Array") {
216
+ if (doc.$prototype === "Array") {
224
217
  if (!skipSelf) {
225
218
  out.push({ depth, node: doc, nodeType: "map", path });
226
219
  }
227
- const mapDef = (doc as JxMutableNode).map;
228
- if (mapDef && typeof mapDef === "object") {
229
- collectRows(mapDef as JxMutableNode, [...path, "map"], depth + 1, out, false);
220
+ const mapDef = doc.map;
221
+ if (isNonNullObject(mapDef)) {
222
+ collectRows(mapDef, [...path, "map"], depth + 1, out, false);
230
223
  }
231
224
  return;
232
225
  }
@@ -247,36 +240,33 @@ function collectRows(
247
240
  const childPath = [...path, "children", i];
248
241
  collectRows(children[i]!, childPath, depth + 1, out, false);
249
242
  }
250
- } else if (
251
- children &&
252
- typeof children === "object" &&
253
- (children as JxMutableNode).$prototype === "Array"
254
- ) {
243
+ } else if (isMappedArray(children)) {
255
244
  // Legacy whole-children repeater: the array occupies the children slot itself.
245
+ // SAFETY: The repeater in the children slot is the same repeater node a children member is.
256
246
  collectRows(children as JxMutableNode, [...path, "children"], depth + 1, out, false);
257
247
  }
258
248
 
259
249
  // $switch — emit each case as a virtual child
260
- if (doc.$switch && doc.cases && typeof doc.cases === "object") {
250
+ if (doc.$switch && isNonNullObject(doc.cases)) {
261
251
  for (const [caseName, caseDef] of Object.entries(doc.cases)) {
262
252
  const casePath = [...path, "cases", caseName];
263
- if (caseDef && typeof caseDef === "object" && (caseDef as JxMutableNode).$ref) {
253
+ if (isNonNullObject(caseDef) && caseDef.$ref) {
264
254
  out.push({
265
255
  depth: depth + 1,
266
- node: caseDef as JxMutableNode,
256
+ node: caseDef,
267
257
  nodeType: "case-ref",
268
258
  path: casePath,
269
259
  });
270
- } else if (caseDef && typeof caseDef === "object") {
260
+ } else if (isNonNullObject(caseDef)) {
271
261
  out.push({
272
262
  depth: depth + 1,
273
- node: caseDef as JxMutableNode,
263
+ node: caseDef,
274
264
  nodeType: "case",
275
265
  path: casePath,
276
266
  });
277
267
  // Recurse into case children — skipSelf, because the "case" row above already stands in for
278
268
  // The case node itself (with its own nodeType).
279
- collectRows(caseDef as JxMutableNode, casePath, depth + 2, out, true);
269
+ collectRows(caseDef, casePath, depth + 2, out, true);
280
270
  }
281
271
  }
282
272
  }
@@ -285,10 +275,10 @@ function collectRows(
285
275
  /**
286
276
  * Get a display label for a node (for layers + overlays).
287
277
  *
288
- * @param {JxMutableNode | null} node
278
+ * @param {JxMutableNode | null | undefined} node
289
279
  * @returns {string}
290
280
  */
291
- export function nodeLabel(node: JxMutableNode | null) {
281
+ export function nodeLabel(node: JxMutableNode | null | undefined) {
292
282
  if (!node) {
293
283
  return "?";
294
284
  }
@@ -306,14 +296,14 @@ export function nodeLabel(node: JxMutableNode | null) {
306
296
  }
307
297
  if (node.tagName === "slot") {
308
298
  const name = node.attributes?.name;
309
- return typeof name === "string" && name.trim() ? `slot: ${name.trim()}` : "slot";
299
+ return isString(name) && name.trim() ? `slot: ${name.trim()}` : "slot";
310
300
  }
311
301
  /* `displayTagName`, because a tag may be CHOSEN rather than written: this label reached the
312
302
  Outline row, the Inspector's header and the jump bar, and a raw read rendered `[object Object]`
313
303
  in all three. `a|div` is the honest answer — one element, tag decided at creation. */
314
304
  const tag = displayTagName(node.tagName) || "div";
315
305
  const suffix = node.$switch ? " ⇆" : "";
316
- if (typeof node.textContent === "string" && node.textContent.length > 0) {
306
+ if (isString(node.textContent) && node.textContent.length > 0) {
317
307
  return `${tag} — ${node.textContent.slice(0, 24)}${suffix}`;
318
308
  }
319
309
  return tag + suffix;
@@ -340,5 +330,7 @@ export function setProjectState(ps: ProjectState | null) {
340
330
  * @returns {ProjectState}
341
331
  */
342
332
  export function requireProjectState() {
333
+ /* SAFETY: The contract above restricts callers to paths reached after `setProjectState` installed
334
+ a project (a project command, a panel that only mounts with one open); nothing here checks it. */
343
335
  return projectState as ProjectState;
344
336
  }
package/src/store.ts CHANGED
@@ -9,9 +9,10 @@
9
9
 
10
10
  // ─── Re-exports from state.js ────────────────────────────────────────────────
11
11
 
12
+ import { isFunction, isNonNullObject } from "@jxsuite/schema/guards";
12
13
  import { INPUT_DEBOUNCE } from "./ui/timing";
13
14
  import type { JxPath } from "./state";
14
- import type { Tab } from "./tabs/tab";
15
+ import type { Tab, TabUi } from "./tabs/tab";
15
16
  import type { JxMutableNode } from "@jxsuite/schema/types";
16
17
 
17
18
  export {
@@ -36,18 +37,38 @@ export {
36
37
  each of which meant "the pane I am acting on" and got "the pane that happens to be focused". A
37
38
  stage belongs to a pane (`canvas/canvas-surface.ts`), a pane's cell is built by
38
39
  `panels/pane-grid.ts`, and every one of those readers now takes its surface. */
39
- export let activityBar = null as unknown as HTMLElement;
40
- export let leftPanel = null as unknown as HTMLElement;
41
- export let rightPanel = null as unknown as HTMLElement;
42
- export let toolbarEl = null as unknown as HTMLElement;
43
- export let statusbarEl = null as unknown as HTMLElement;
40
+
41
+ /* Null until `initShellRefs()`, which `studio.ts` calls at boot right after mounting the shell
42
+ document; a render asked for before that (a test, or a command run ahead of the shell) reads null. */
43
+ export let activityBar: HTMLElement | null = null;
44
+ export let leftPanel: HTMLElement | null = null;
45
+ export let rightPanel: HTMLElement | null = null;
46
+ export let toolbarEl: HTMLElement | null = null;
47
+ export let statusbarEl: HTMLElement | null = null;
48
+
49
+ /** The shell region whose `id` is given, or null when the mounted shell has none. */
50
+ function shellRef(id: string): HTMLElement | null {
51
+ const element = document.querySelector(`#${id}`);
52
+ return element instanceof HTMLElement ? element : null;
53
+ }
44
54
 
45
55
  export function initShellRefs() {
46
- activityBar = document.querySelector("#activity-bar") as HTMLElement;
47
- leftPanel = document.querySelector("#left-panel") as HTMLElement;
48
- rightPanel = document.querySelector("#right-panel") as HTMLElement;
49
- toolbarEl = document.querySelector("#toolbar") as HTMLElement;
50
- statusbarEl = document.querySelector("#statusbar") as HTMLElement;
56
+ activityBar = shellRef("activity-bar");
57
+ leftPanel = shellRef("left-panel");
58
+ rightPanel = shellRef("right-panel");
59
+ toolbarEl = shellRef("toolbar");
60
+ statusbarEl = shellRef("statusbar");
61
+ }
62
+
63
+ /**
64
+ * A shell region for a caller that cannot work without it. Reading one before `initShellRefs()` has
65
+ * found it is a boot-order bug, so it throws a TypeError that names the region.
66
+ */
67
+ export function requireShellRef(ref: HTMLElement | null, id: string): HTMLElement {
68
+ if (!ref) {
69
+ throw new TypeError(`#${id} is not in the shell yet; initShellRefs() has not found it`);
70
+ }
71
+ return ref;
51
72
  }
52
73
 
53
74
  // ─── Shared constants ────────────────────────────────────────────────────────
@@ -130,6 +151,11 @@ export { stripEventHandlers } from "./utils/strip-events";
130
151
 
131
152
  const _renderers = new Map<string, () => void>();
132
153
 
154
+ /** Whether a renderer's return value is a thenable — an `async` renderer that is still painting. */
155
+ function isThenable(value: unknown): value is PromiseLike<unknown> {
156
+ return (isNonNullObject(value) || isFunction(value)) && "then" in value && isFunction(value.then);
157
+ }
158
+
133
159
  /**
134
160
  * How many registered renderers are mid-paint right now.
135
161
  *
@@ -154,9 +180,9 @@ function runRenderer(name: string, fn: () => void) {
154
180
  };
155
181
  let pending: PromiseLike<unknown> | null = null;
156
182
  try {
157
- const result = fn() as unknown;
158
- if (typeof (result as PromiseLike<unknown> | null)?.then === "function") {
159
- pending = result as PromiseLike<unknown>;
183
+ const result = fn();
184
+ if (isThenable(result)) {
185
+ pending = result;
160
186
  }
161
187
  } catch (error) {
162
188
  console.error(`Renderer "${name}" failed:`, error);
@@ -165,7 +191,7 @@ function runRenderer(name: string, fn: () => void) {
165
191
  done();
166
192
  return;
167
193
  }
168
- pending.then(done, (error: unknown) => {
194
+ pending.then(done, (error) => {
169
195
  console.error(`Renderer "${name}" failed:`, error);
170
196
  done();
171
197
  });
@@ -232,8 +258,8 @@ export function updateSession(
232
258
  selection?: JxPath[];
233
259
  hover?: JxPath | null;
234
260
  clipboard?: JxMutableNode | null;
235
- ui?: Record<string, unknown>;
236
- canvas?: Record<string, unknown>;
261
+ ui?: Partial<TabUi>;
262
+ canvas?: Partial<Tab["session"]["canvas"]>;
237
263
  },
238
264
  ) {
239
265
  if (tab) {
@@ -241,20 +267,16 @@ export function updateSession(
241
267
  tab.session.selection = patch.selection;
242
268
  }
243
269
  if (patch.hover !== undefined) {
244
- tab.session.hover = patch.hover as JxPath | null;
270
+ tab.session.hover = patch.hover;
245
271
  }
246
272
  if (patch.clipboard !== undefined) {
247
- tab.session.clipboard = patch.clipboard!;
273
+ tab.session.clipboard = patch.clipboard;
248
274
  }
249
275
  if (patch.ui) {
250
- for (const [k, v] of Object.entries(patch.ui)) {
251
- (tab.session.ui as unknown as Record<string, unknown>)[k] = v;
252
- }
276
+ Object.assign(tab.session.ui, patch.ui);
253
277
  }
254
278
  if (patch.canvas) {
255
- for (const [k, v] of Object.entries(patch.canvas)) {
256
- (tab.session.canvas as unknown as Record<string, unknown>)[k] = v;
257
- }
279
+ Object.assign(tab.session.canvas, patch.canvas);
258
280
  }
259
281
  }
260
282
  }
@@ -263,12 +285,12 @@ export function updateSession(
263
285
  * Update a single UI field on `tab`.
264
286
  *
265
287
  * @param {Tab | null} tab — the tab this field belongs to. `null` is a no-op.
266
- * @param {string} field
267
- * @param {unknown} value
288
+ * @param {K} field
289
+ * @param {TabUi[K]} value
268
290
  */
269
- export function updateUi(tab: Tab | null, field: string, value: unknown) {
291
+ export function updateUi<K extends keyof TabUi>(tab: Tab | null, field: K, value: TabUi[K]) {
270
292
  if (tab) {
271
- (tab.session.ui as unknown as Record<string, unknown>)[field] = value;
293
+ tab.session.ui[field] = value;
272
294
  }
273
295
  }
274
296
 
@@ -276,12 +298,10 @@ export function updateUi(tab: Tab | null, field: string, value: unknown) {
276
298
  * Update `tab`'s canvas async state (status, scope, error).
277
299
  *
278
300
  * @param {Tab | null} tab — the tab whose stage produced this state. `null` is a no-op.
279
- * @param {object} patch
301
+ * @param {Partial<Tab["session"]["canvas"]>} patch
280
302
  */
281
- export function updateCanvas(tab: Tab | null, patch: Record<string, unknown>) {
303
+ export function updateCanvas(tab: Tab | null, patch: Partial<Tab["session"]["canvas"]>) {
282
304
  if (tab) {
283
- for (const [k, v] of Object.entries(patch)) {
284
- (tab.session.canvas as Record<string, unknown>)[k] = v;
285
- }
305
+ Object.assign(tab.session.canvas, patch);
286
306
  }
287
307
  }
package/src/studio.ts CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  registerRenderer,
22
22
  render,
23
23
  requireProjectState,
24
+ requireShellRef,
24
25
  setProjectState,
25
26
  toolbarEl,
26
27
  updateSession,
@@ -117,13 +118,12 @@ import {
117
118
  import {
118
119
  loadProject as _loadProject,
119
120
  openProject as _openProject,
120
- renderFilesTemplate,
121
121
  findHomePage,
122
122
  loadDirectory,
123
+ loadProjectDirectories,
123
124
  openFileInPane,
124
125
  openFileInTab,
125
126
  openLastSessionOrHome,
126
- registerFileTreeDnD,
127
127
  reloadCleanTab,
128
128
  reloadTabsIfChanged,
129
129
  } from "./files/files";
@@ -136,9 +136,7 @@ import {
136
136
  configureCollabParser,
137
137
  configureCollabSerializer,
138
138
  } from "./collab/collab-session";
139
- import { renderImportsTemplate } from "./panels/imports-panel";
140
- import { invalidateLayoutPickerCache, renderHeadTemplate } from "./panels/head-panel";
141
- import { exportCemManifest as _exportCemManifest } from "./services/cem-export";
139
+ import { invalidateLayoutPickerCache } from "./panels/head-panel";
142
140
  import { installAutomationHook } from "./services/automation";
143
141
  import { invalidateLibrary } from "./browse/library-pane";
144
142
  import { invalidateMediaCache } from "./ui/media-picker";
@@ -175,7 +173,6 @@ import {
175
173
  cloneRepository,
176
174
  loadDiffForLens,
177
175
  registerSourceControlCommands,
178
- renderGitPanel,
179
176
  noteFileSaved,
180
177
  } from "./panels/git-panel";
181
178
 
@@ -191,7 +188,7 @@ import { chordsInScopes } from "./commands/keymap";
191
188
  import { FRAME_KEY_SCOPES } from "./canvas/iframe-keys";
192
189
  import { createLiveContext } from "./commands/live-context";
193
190
  import { hasAiCredentials } from "./services/ai-models";
194
- import { mount as mountActivityBar } from "./surfaces/rail";
191
+ import { mount } from "./surfaces/rail";
195
192
  import * as toolbarPanel from "./surfaces/commandbar";
196
193
  import * as overlaysPanel from "./panels/overlays";
197
194
  import * as frontmatterPanelMod from "./panels/frontmatter-panel";
@@ -268,7 +265,7 @@ import { registerI18nCommands } from "./i18n/i18n-commands";
268
265
  import { convertToComponent } from "./editor/convert-to-component";
269
266
  import type { GitDiffState } from "./types";
270
267
  import type { Tab } from "./tabs/tab";
271
- import type { JxDocument, JxMutableNode, ProjectConfig } from "@jxsuite/schema/types";
268
+ import type { JxDocument, ProjectConfig } from "@jxsuite/schema/types";
272
269
  import { setBundleBase } from "./services/bundle-base";
273
270
  import { mountBootFailureTree, mountShellTree } from "./shell/tree";
274
271
 
@@ -499,7 +496,7 @@ initShellRefs();
499
496
  mountShell();
500
497
 
501
498
  // Mount extracted panel modules
502
- toolbarPanel.mount(toolbarEl, {
499
+ toolbarPanel.mount(requireShellRef(toolbarEl, "toolbar"), {
503
500
  closeFunctionEditor: () => closeFunctionEditor(),
504
501
  getCanvasMode,
505
502
  openProject: () => openProject(),
@@ -641,9 +638,8 @@ window.addEventListener("beforeunload", (e: BeforeUnloadEvent) => {
641
638
  // Author may cancel the close, and the record is the same either way.
642
639
  flushSession();
643
640
  if (hasUnsavedTabs()) {
641
+ // The HTML standard's trigger for the leave-page prompt; the legacy `returnValue` is deprecated.
644
642
  e.preventDefault();
645
- // Legacy browsers require a truthy returnValue to trigger the native confirm prompt.
646
- e.returnValue = "";
647
643
  }
648
644
  });
649
645
 
@@ -743,11 +739,8 @@ function installPaneRenderEffects(paneId: string): void {
743
739
  installDerivationEffects(paneId, derivationDeps);
744
740
  effect(() => {
745
741
  const tab = tabOfPane(paneId);
746
- if (tab) {
747
- const doc = tab.doc.document;
748
- if (doc && consumePatchedDocument(doc, paneId)) {
749
- return;
750
- }
742
+ if (tab && consumePatchedDocument(tab.doc.document, paneId)) {
743
+ return;
751
744
  }
752
745
  scheduleCanvasRender(paneId);
753
746
  });
@@ -871,7 +864,6 @@ leftPanelMod.mount({
871
864
  navigateToComponent,
872
865
  registerComponentsDnD,
873
866
  registerElementsDnD,
874
- registerFileTreeDnD,
875
867
  registerLayersDnD,
876
868
  renderCanvas: () => renderCanvas(),
877
869
  // The Data panel's Refresh: a canvas re-render that ALSO lets automatic `Request` state entries
@@ -894,10 +886,6 @@ leftPanelMod.mount({
894
886
  }
895
887
  renderCanvas(paneId);
896
888
  },
897
- renderFilesTemplate,
898
- renderGitPanel,
899
- renderHeadTemplate,
900
- renderImportsTemplate,
901
889
  mountSignalsPanel,
902
890
  setCanvasMode,
903
891
  setGitDiffState: (state: GitDiffState | null) => {
@@ -919,7 +907,7 @@ renderStatusbar();
919
907
  // The status bar mounts the jump bar too: the focused pane's breadcrumb trail is its DOCUMENT
920
908
  // Field, and the only breadcrumb in the shell.
921
909
  mountStatusbar();
922
- mountActivityBar();
910
+ mount();
923
911
 
924
912
  /* The background-click deselect moved into `editor/shortcuts.ts`'s `installStageGestures`, beside
925
913
  the wheel and the middle-drag, because it is a STAGE gesture: it compared against the app's one
@@ -983,10 +971,10 @@ if (!_projectParam) {
983
971
  const _bootPlatform = getPlatform();
984
972
  // oxlint-disable-next-line unicorn/prefer-top-level-await -- fire-and-forget: must not block the initial render
985
973
  void _bootPlatform
986
- .activate?.()
974
+ .activate()
987
975
  // No project is bound yet, so this call only warms the canvasUrl; a backend that refuses it
988
976
  // Still gets the render below rather than an unhandled rejection.
989
- ?.catch((error: unknown) => {
977
+ .catch((error) => {
990
978
  // A refusal that offers an action is the action flow's to explain; it is not a fault.
991
979
  if (!isActionRequired(error)) {
992
980
  console.error("Boot activation failed:", error);
@@ -1018,18 +1006,14 @@ if (_projectParam) {
1018
1006
  // Report a bare `Error: <message>` because the only identifying fact was still block-scoped.
1019
1007
  let fileRelPath = _urlParams.get("file") || _projectParam;
1020
1008
  try {
1021
- const siteCtx = platform.resolveSiteContext
1022
- ? await platform.resolveSiteContext(_projectParam)
1023
- : { sitePath: null };
1009
+ const siteCtx = await platform.resolveSiteContext(_projectParam);
1024
1010
 
1025
1011
  if (siteCtx.sitePath) {
1026
1012
  // Set PAL project root to absolute path so file ops work
1027
1013
  if (siteCtx.sitePath) {
1028
1014
  platform.projectRoot = siteCtx.sitePath;
1029
1015
  // Await activation so the server resolves project-relative static files
1030
- if (platform.activate) {
1031
- await platform.activate();
1032
- }
1016
+ await platform.activate();
1033
1017
  }
1034
1018
 
1035
1019
  resetIgnoreCache();
@@ -1053,31 +1037,9 @@ if (_projectParam) {
1053
1037
  await ensureDependenciesInstalled();
1054
1038
  await loadComponentRegistry();
1055
1039
 
1056
- // Load directory tree and populate projectDirs from conventional dirs found
1057
- const conventionalDirs = new Set([
1058
- "pages",
1059
- "layouts",
1060
- "components",
1061
- "content",
1062
- "data",
1063
- "public",
1064
- "styles",
1065
- ]);
1066
- /* Through `loadDirectory`, not `platform.listDirectory`: this is the second copy of the
1067
- conventional-dir walk (the first is `openProject` in files/files.ts), and the loader is
1068
- what reads the `.gitignore` chain governing each directory. Listing around it left the
1069
- `?project=` boot as the one door into a project whose tree knew no ignore rules. */
1070
- await loadDirectory(".");
1071
- const dirEntries = requireProjectState().dirs.get(".") ?? [];
1072
- const foundDirs = [];
1073
- for (const e of dirEntries) {
1074
- if (e.type === "directory" && conventionalDirs.has(e.name)) {
1075
- foundDirs.push(e.name);
1076
- requireProjectState().expanded.add(e.path || e.name);
1077
- await loadDirectory(e.path || e.name);
1078
- }
1079
- }
1080
- requireProjectState().projectDirs = foundDirs;
1040
+ /* Through `loadDirectory` (inside `loadProjectDirectories`), not `platform.listDirectory`:
1041
+ the loader is what reads the `.gitignore` chain governing each directory. */
1042
+ await loadProjectDirectories();
1081
1043
  void maybePromptJxsuiteUpdate(siteCtx.sitePath);
1082
1044
  }
1083
1045
 
@@ -1144,7 +1106,7 @@ if (_projectParam) {
1144
1106
  openTab({
1145
1107
  id: fileRelPath,
1146
1108
  documentPath: fileRelPath,
1147
- document: parsedDoc as JxMutableNode,
1109
+ document: parsedDoc,
1148
1110
  ...(frontmatter != null && { frontmatter }),
1149
1111
  layout,
1150
1112
  sourceFormat: fileFormat?.name ?? null,
@@ -1365,6 +1327,9 @@ async function openRecentProject(root: string) {
1365
1327
  void loadFormats();
1366
1328
  refreshExtensionUi(platform);
1367
1329
  const content = await platform.readFile("project.json");
1330
+ /* SAFETY: This is `project.json` at the root the user chose to open, the project's own config
1331
+ file whose schema is ProjectConfig; Studio edits it in that shape and does not re-validate it
1332
+ on open, as the folder-picker path in `platforms/devserver.ts` does not either. */
1368
1333
  const config = JSON.parse(content) as ProjectConfig;
1369
1334
 
1370
1335
  closeAllTabs();
@@ -1389,26 +1354,9 @@ async function openRecentProject(root: string) {
1389
1354
  activity.step("Install dependencies");
1390
1355
  await ensureDependenciesInstalled();
1391
1356
  activity.step("Read the project");
1392
- await loadDirectory(".");
1357
+ await loadProjectDirectories();
1393
1358
  await loadComponentRegistry();
1394
1359
 
1395
- const conventionalDirs = new Set([
1396
- "pages",
1397
- "layouts",
1398
- "components",
1399
- "content",
1400
- "data",
1401
- "public",
1402
- "styles",
1403
- ]);
1404
- const entries = requireProjectState().dirs.get(".") || [];
1405
- for (const e of entries) {
1406
- if (e.type === "directory" && conventionalDirs.has(e.name)) {
1407
- requireProjectState().expanded.add(e.path || e.name);
1408
- await loadDirectory(e.path || e.name);
1409
- }
1410
- }
1411
-
1412
1360
  addRecentProject(requireProjectState().name, root);
1413
1361
  setActivityTab("files");
1414
1362
  renderLeftPanel();
@@ -1561,7 +1509,9 @@ const liveChrome = createLiveSurfaceSaver({
1561
1509
  registry reactively. */
1562
1510
  setDocumentSavedListener((path, doc) => {
1563
1511
  void noteFileSaved(path);
1564
- void liveChrome(path, doc as unknown as JxDocument);
1512
+ /* SAFETY: The listener fires for a tab's saved ROOT document, and a root document is a
1513
+ JxDocument held in the editor's mutable node form; `liveChrome` only acts on surface paths. */
1514
+ void liveChrome(path, doc as JxDocument);
1565
1515
  if (noteComponentSaved(path, doc)) {
1566
1516
  renderPropertiesPanel();
1567
1517
  renderLeftPanel();
@@ -32,5 +32,5 @@ import { activeTab } from "../workspace/workspace";
32
32
  export function pushProjectStylesToCanvas(): void {
33
33
  postSiteStyleToLiveHosts();
34
34
  const style = transposeStylebookStyle(getEffectiveStyle(activeTab.value?.doc.document?.style));
35
- postStyleUpdateToStylebookHosts(style as Record<string, unknown>);
35
+ postStyleUpdateToStylebookHosts(style);
36
36
  }
@@ -24,6 +24,7 @@
24
24
  * `style["--token"]` and `style["@--ctx"]["--token"]` shapes the compiler already consumes.
25
25
  */
26
26
 
27
+ import { ensureNestedStyle, getNestedStyle, isNumber, isString } from "@jxsuite/schema/guards";
27
28
  import { parseMediaEntries, schemeOfQuery } from "../utils/canvas-media";
28
29
  import { varDisplayName } from "../utils/studio-utils";
29
30
 
@@ -140,7 +141,7 @@ export function listTokens(style: JxStyle | null | undefined): ProjectToken[] {
140
141
  if (!name.startsWith("--")) {
141
142
  continue;
142
143
  }
143
- if (typeof value !== "string" && typeof value !== "number") {
144
+ if (!isString(value) && !isNumber(value)) {
144
145
  continue;
145
146
  }
146
147
  out.push({ group: groupIdOfToken(name), label: tokenLabel(name), name, value });
@@ -242,9 +243,8 @@ export interface TokenOverride {
242
243
  * @param {JxStyle} style
243
244
  * @param {TokenContext} context
244
245
  */
245
- function overrideBlock(style: JxStyle, context: TokenContext): Record<string, unknown> | undefined {
246
- const block = style[context.key];
247
- return block && typeof block === "object" ? (block as Record<string, unknown>) : undefined;
246
+ function overrideBlock(style: JxStyle, context: TokenContext): JxStyle | undefined {
247
+ return getNestedStyle(style, context.key);
248
248
  }
249
249
 
250
250
  /**
@@ -261,7 +261,7 @@ export function readTokenOverride(
261
261
  token: string,
262
262
  ): string | number | undefined {
263
263
  const value = overrideBlock(style, context)?.[token];
264
- return typeof value === "string" || typeof value === "number" ? value : undefined;
264
+ return isString(value) || isNumber(value) ? value : undefined;
265
265
  }
266
266
 
267
267
  /**
@@ -284,8 +284,7 @@ export function writeTokenOverride(
284
284
  value: string,
285
285
  ): void {
286
286
  if (value) {
287
- const block = (style[context.key] ??= {}) as Record<string, unknown>;
288
- block[token] = value;
287
+ ensureNestedStyle(style, context.key)[token] = value;
289
288
  return;
290
289
  }
291
290
  const block = overrideBlock(style, context);