@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
@@ -30,6 +30,7 @@
30
30
  * to the code that runs, so a chord and its behaviour cannot drift apart again.
31
31
  */
32
32
 
33
+ import { isFunction, isNonNullObject } from "@jxsuite/schema/guards";
33
34
  import { childIndex, childList, getNodeAtPath, parentElementPath, projectState } from "../store";
34
35
  import { activeTab, workspace } from "../workspace/workspace";
35
36
  import {
@@ -45,8 +46,8 @@ import {
45
46
  mutateDuplicateNodes,
46
47
  mutateInsertNode,
47
48
  mutateRemoveNodes,
48
- redo as tabRedo,
49
- undo as tabUndo,
49
+ redo,
50
+ undo,
50
51
  transactDoc,
51
52
  } from "../tabs/transact";
52
53
  import {
@@ -81,6 +82,7 @@ import { runReported } from "../commands/run-reported";
81
82
  import { pointerAnchor } from "../canvas/iframe-host";
82
83
  import type { PointerAnchor } from "../canvas/iframe-host";
83
84
  import type { CommandContext } from "../commands/context";
85
+ import type { CommandArgValues } from "../commands/command-args";
84
86
  import type { DockId as CommandDockId } from "../commands/defaults";
85
87
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
86
88
  import type { DockId, FocusRegion } from "../shell";
@@ -165,11 +167,14 @@ function navigateSelection(direction: -1 | 1): void {
165
167
  tab.session.selection = [[]];
166
168
  return;
167
169
  }
168
- if (selected.length < 2) {
170
+ // `parentElementPath` is null exactly when the path is the document element (length < 2).
171
+ const parentPath = parentElementPath(selected);
172
+ if (!parentPath) {
169
173
  return;
170
174
  }
171
- const parentPath = parentElementPath(selected) as JxPath;
172
175
  const parent = getNodeAtPath(tab.doc.document, parentPath);
176
+ // SAFETY: a selection path of length >= 2 addresses a child as `[..., "children", n]`, so its
177
+ // Last segment is the numeric index `n` (the same invariant `insertSiblingParagraph` relies on).
173
178
  const newIndex = (childIndex(selected) as number) + direction;
174
179
  if (newIndex >= 0 && newIndex < childList(parent).length) {
175
180
  tab.session.selection = [[...parentPath, "children", newIndex]];
@@ -190,14 +195,10 @@ function selectSiblings(): void {
190
195
  return;
191
196
  }
192
197
  const selected = primarySelection(tab.session.selection);
193
- const parentPath = (
194
- selected && selected.length >= 2 ? parentElementPath(selected) : []
195
- ) as JxPath;
198
+ const parentPath: JxPath = (selected ? parentElementPath(selected) : null) ?? [];
196
199
  const parent = getNodeAtPath(tab.doc.document, parentPath);
197
200
  const paths = childList(parent).flatMap((child, index) =>
198
- typeof child === "object" && child !== null
199
- ? [[...parentPath, "children", index] as JxPath]
200
- : [],
201
+ isNonNullObject(child) ? [[...parentPath, "children", index]] : [],
201
202
  );
202
203
  if (paths.length > 0) {
203
204
  tab.session.selection = paths;
@@ -242,10 +243,16 @@ function selectParent(): void {
242
243
  function insertSiblingParagraph(): void {
243
244
  const tab = activeTab.value;
244
245
  const selected = primarySelection(tab?.session.selection);
245
- if (!tab || !selected || selected.length < 2) {
246
+ if (!tab || !selected) {
247
+ return;
248
+ }
249
+ // Null exactly when the selection is the document element, which has no sibling slot.
250
+ const parentPath = parentElementPath(selected);
251
+ if (!parentPath) {
246
252
  return;
247
253
  }
248
- const parentPath = parentElementPath(selected) as JxPath;
254
+ // SAFETY: a selection path of length >= 2 addresses a child as `[..., "children", n]`, so its
255
+ // Last segment is the numeric child index `n`.
249
256
  const index = childIndex(selected) as number;
250
257
  const newPath = [...parentPath, "children", index + 1];
251
258
  transactDoc(tab, (t) => {
@@ -303,14 +310,14 @@ function closeDocument(): void {
303
310
  function undoDocument(): void {
304
311
  const tab = activeTab.value;
305
312
  if (tab) {
306
- tabUndo(tab);
313
+ undo(tab);
307
314
  }
308
315
  }
309
316
 
310
317
  function redoDocument(): void {
311
318
  const tab = activeTab.value;
312
319
  if (tab) {
313
- tabRedo(tab);
320
+ redo(tab);
314
321
  }
315
322
  }
316
323
 
@@ -349,7 +356,7 @@ function zoomBy(ctx: CommandContext, factor: number, redraw: () => void): void {
349
356
  return;
350
357
  }
351
358
  if (isContentZoom(ctx)) {
352
- setEditZoom((tab.session.ui.editZoom ?? 1) * factor);
359
+ setEditZoom(tab.session.ui.editZoom * factor);
353
360
  return;
354
361
  }
355
362
  // Around the stage's middle, like the zoom pod's buttons.
@@ -397,7 +404,7 @@ function toggleShellDock(registry: CommandRegistry, dock: CommandDockId): void {
397
404
  * a missing id must be inert rather than an exception thrown out of a keydown handler. A present
398
405
  * one that refuses its arguments is not inert: `commands/run-reported.ts` files it in Problems.
399
406
  */
400
- function runIfPresent(registry: CommandRegistry, id: string, args: Record<string, unknown>): void {
407
+ function runIfPresent(registry: CommandRegistry, id: string, args: CommandArgValues): void {
401
408
  if (registry.get(id) && registry.isEnabled(id)) {
402
409
  void runReported(registry, id, args, "Keyboard");
403
410
  }
@@ -647,8 +654,9 @@ function askWhereToOpen(openName: string): Promise<ProjectOpenTarget | "cancel">
647
654
  export async function openProjectFlow(hooks: StudioCommandHooks): Promise<void> {
648
655
  const platform = hasPlatform() ? getPlatform() : null;
649
656
  const canOpenElsewhere =
650
- typeof platform?.openProjectInNewWindow === "function" &&
651
- typeof platform?.pickProject === "function";
657
+ platform !== null &&
658
+ isFunction(platform.openProjectInNewWindow) &&
659
+ isFunction(platform.pickProject);
652
660
  if (!projectState || !canOpenElsewhere) {
653
661
  await hooks.openProject("thisWindow");
654
662
  return;
@@ -959,7 +967,11 @@ export function initShortcuts(registry: CommandRegistry, stageContext: StageCont
959
967
  document.addEventListener(
960
968
  "wheel",
961
969
  (e: WheelEvent) => {
962
- if ((e.ctrlKey || e.metaKey) && !(e.target as Element | null)?.closest(STAGE_SELECTOR)) {
970
+ const { target } = e;
971
+ if (
972
+ (e.ctrlKey || e.metaKey) &&
973
+ !(target instanceof Element && target.closest(STAGE_SELECTOR))
974
+ ) {
963
975
  e.preventDefault();
964
976
  }
965
977
  },
@@ -1022,7 +1034,7 @@ function wheelBelongsInside(
1022
1034
  ): boolean {
1023
1035
  const { target } = e;
1024
1036
  let el: Element | null =
1025
- target instanceof Element ? target : ((target as Node | null)?.parentElement ?? null);
1037
+ target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
1026
1038
  while (el && el !== stage) {
1027
1039
  if (el instanceof HTMLElement && el !== pageScroller && canScrollBy(el, e.deltaX, e.deltaY)) {
1028
1040
  return true;
@@ -29,12 +29,7 @@
29
29
  import { openSlashMenuSurface } from "../surfaces/slash-menu";
30
30
  import { rectOf } from "../utils/geometry";
31
31
  import type { SlashMenuRow, SlashMenuSurface, SlashMenuView } from "../surfaces/slash-menu";
32
-
33
- interface SlashCommand {
34
- label: string;
35
- tag: string;
36
- description: string;
37
- }
32
+ import type { SlashCommand } from "./inline-edit";
38
33
 
39
34
  // ─── Commands ─────────────────────────────────────────────────────────────────
40
35
 
@@ -30,13 +30,14 @@
30
30
  * paths only — a `.json` or `.md` file is never loaded by URL from the canvas, and leaving them out
31
31
  * keeps that message as small as the media set.
32
32
  *
33
- * Pure module state — it imports nothing but path normalization and the reactivity re-export — so
34
- * the canvas host can import it without dragging in the file layer.
33
+ * Pure module state — it imports nothing but path normalization, the primitive guards and the
34
+ * reactivity re-export — so the canvas host can import it without dragging in the file layer.
35
35
  *
36
36
  * @docs extending/embedding/platform-adapter
37
37
  */
38
38
 
39
39
  import { normalizeProjectPath } from "@jxsuite/schema/asset-paths";
40
+ import { isString } from "@jxsuite/schema/guards";
40
41
  import { shallowRef } from "../reactivity";
41
42
  import type { DirEntry } from "../types";
42
43
 
@@ -161,8 +162,7 @@ export function noteListing(entries: readonly DirEntry[], since: number): void {
161
162
  if (path === "" || dirtiedSince(path, since)) {
162
163
  continue;
163
164
  }
164
- const version =
165
- typeof entry.version === "string" && entry.version !== "" ? entry.version : null;
165
+ const version = isString(entry.version) && entry.version !== "" ? entry.version : null;
166
166
  const held = versions.get(path);
167
167
  if (version === null) {
168
168
  if (held === undefined) {
@@ -4,7 +4,8 @@ import { getPlatform } from "../platform";
4
4
  import { projectState } from "../store";
5
5
  import type { ComponentMeta } from "../types";
6
6
  import { componentMetaFrom } from "@jxsuite/schema/component-meta";
7
- import type { JxMutableNode } from "@jxsuite/schema/types";
7
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
8
+ import type { JsonValue, JxMutableNode } from "@jxsuite/schema/types";
8
9
 
9
10
  /** A discovered component: project components carry a file path; package components may not. */
10
11
  export interface ComponentEntry extends Omit<ComponentMeta, "path"> {
@@ -40,15 +41,17 @@ export async function loadComponentRegistry() {
40
41
  *
41
42
  * @param {string | null} path - The saved document's project-relative path; `null` for an unsaved
42
43
  * draft, which no scan would have seen either.
43
- * @param {unknown} doc - The saved document.
44
+ * @param {JxMutableNode} doc - The saved document.
44
45
  * @returns {boolean} Whether the registry changed, so a caller knows to repaint what reads it.
45
46
  */
46
- export function noteComponentSaved(path: string | null, doc: unknown): boolean {
47
+ export function noteComponentSaved(path: string | null, doc: JxMutableNode): boolean {
47
48
  if (!path) {
48
49
  return false;
49
50
  }
50
51
  const index = componentRegistry.findIndex((c) => c.path === path);
51
- const meta = componentMetaFrom(doc, path);
52
+ /* SAFETY: a saved tab's document was parsed from JSON and has just been written back as JSON
53
+ (`serializeDocument`), so every value it holds is a JSON value — the model the extractor reads. */
54
+ const meta = componentMetaFrom(doc as JsonValue, path);
52
55
  if (!meta) {
53
56
  if (index === -1) {
54
57
  return false;
@@ -56,6 +59,8 @@ export function noteComponentSaved(path: string | null, doc: unknown): boolean {
56
59
  componentRegistry.splice(index, 1);
57
60
  return true;
58
61
  }
62
+ /* SAFETY: `componentMetaFrom` is the extractor every backend's `discoverComponents` scan runs to
63
+ Produce the registry's entries, so its output has the shape the registry already holds. */
59
64
  const entry = meta as ComponentEntry;
60
65
  if (index === -1) {
61
66
  componentRegistry.push(entry);
@@ -84,7 +89,7 @@ export function buildComponentInstance(comp: ComponentEntry): JxMutableNode {
84
89
  for (const child of structuredClone(slot.fallback ?? [])) {
85
90
  if (!slot.name) {
86
91
  children.push(child);
87
- } else if (typeof child === "object" && child !== null && typeof child.tagName === "string") {
92
+ } else if (isNonNullObject(child) && isString(child.tagName)) {
88
93
  // Preserve an author-set slot attribute (slot forwarding inside fallback).
89
94
  child.attributes = { slot: slot.name, ...child.attributes };
90
95
  children.push(child);
@@ -94,11 +99,11 @@ export function buildComponentInstance(comp: ComponentEntry): JxMutableNode {
94
99
  }
95
100
  }
96
101
  }
97
- return {
98
- $props,
99
- tagName: comp.tagName,
100
- ...(children.length > 0 ? { children } : {}),
101
- };
102
+ const instance: JxMutableNode = { $props, tagName: comp.tagName };
103
+ if (children.length > 0) {
104
+ instance.children = children;
105
+ }
106
+ return instance;
102
107
  }
103
108
 
104
109
  /**
@@ -20,6 +20,7 @@
20
20
  * they must not differ on is WHICH entries the list should hold.
21
21
  */
22
22
 
23
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
23
24
  import { computeRelativePath } from "./components";
24
25
  import type { ComponentEntry } from "./components";
25
26
  import type { JxElement } from "@jxsuite/schema/types";
@@ -29,9 +30,7 @@ export type ElementsEntry = string | JxElement | { $ref: string };
29
30
 
30
31
  /** The `$ref` of an entry, when it has one. */
31
32
  function refOf(entry: ElementsEntry): string | null {
32
- return typeof entry === "object" && entry !== null && typeof entry.$ref === "string"
33
- ? entry.$ref
34
- : null;
33
+ return isNonNullObject(entry) && isString(entry.$ref) ? entry.$ref : null;
35
34
  }
36
35
 
37
36
  /**
@@ -81,7 +80,7 @@ export function hasElement(
81
80
  const specifier = npmSpecifier(comp);
82
81
  if (specifier) {
83
82
  return elements.some(
84
- (entry) => typeof entry === "string" && (entry === specifier || entry === comp.package),
83
+ (entry) => isString(entry) && (entry === specifier || entry === comp.package),
85
84
  );
86
85
  }
87
86
  if (!comp.path) {
@@ -132,7 +131,7 @@ export function disableElement(
132
131
  if (specifier) {
133
132
  // Both spellings: a component ticked off must not stay imported through the package entry.
134
133
  return elements.filter(
135
- (entry) => !(typeof entry === "string" && (entry === specifier || entry === comp.package)),
134
+ (entry) => !(isString(entry) && (entry === specifier || entry === comp.package)),
136
135
  );
137
136
  }
138
137
  if (!comp.path) {
@@ -151,7 +150,7 @@ export function removePackageElements(
151
150
  pkg: string,
152
151
  ): ElementsEntry[] {
153
152
  return elements.filter(
154
- (entry) => typeof entry !== "string" || !(entry === pkg || entry.startsWith(`${pkg}/`)),
153
+ (entry) => !isString(entry) || !(entry === pkg || entry.startsWith(`${pkg}/`)),
155
154
  );
156
155
  }
157
156
 
@@ -28,6 +28,8 @@ import { showConfirmDialog } from "../ui/layers";
28
28
  import { locateDocument } from "../services/code-services";
29
29
  import { errorMessage } from "@jxsuite/schema/parse";
30
30
  import { notify } from "../services/notify";
31
+ import type { NotifyOptions } from "../services/notify";
32
+ import { isString } from "@jxsuite/schema/guards";
31
33
  import { validateComponentSlots } from "../services/cem-export";
32
34
  import { reportPopoverProblems } from "../services/popover-report";
33
35
  import { getPlatform } from "../platform";
@@ -103,19 +105,66 @@ export async function parseSourceForPath(path: string, source: string) {
103
105
  export const parseCollabSource: CollabParser = async (tab, text) => {
104
106
  if (tab.documentPath && formatForPath(tab.documentPath)) {
105
107
  const parsed = await parseSourceForPath(tab.documentPath, text);
106
- return { document: parsed.document as JxMutableNode, frontmatter: parsed.frontmatter };
108
+ return { document: parsed.document, frontmatter: parsed.frontmatter };
107
109
  }
108
110
  const parsed = parseJsonDocument(text);
109
111
  tab.doc.layout = parsed.layout;
112
+ /* SAFETY: a co-edited path no format class claims is a `.json` Jx document (every other path
113
+ `ensureCollab` attaches to is a format file, handled above), and that file's schema makes its
114
+ Top-level object a node — the object `parseJsonDocument` already states it returns. */
110
115
  return { document: parsed.document as JxMutableNode };
111
116
  };
112
117
 
118
+ /** One `accept` group of a File System Access picker: media type → extensions, with a label. */
119
+ interface FilePickerAcceptType {
120
+ accept: Record<string, string[]>;
121
+ description: string;
122
+ }
123
+
124
+ /**
125
+ * The File System Access pickers (WICG), which TypeScript's DOM lib does not declare. Only what
126
+ * this module passes and reads is spelled out.
127
+ */
128
+ interface FilePickerWindow {
129
+ showOpenFilePicker: (options: {
130
+ types: FilePickerAcceptType[];
131
+ }) => Promise<FileSystemFileHandle[]>;
132
+ /* Export's single extension is `format.extensions[0]`, absent for a format that declares none —
133
+ So the save picker is typed with the value it is actually handed. */
134
+ showSaveFilePicker: (options: {
135
+ suggestedName?: string | undefined;
136
+ types: { accept: Record<string, (string | undefined)[]>; description: string }[];
137
+ }) => Promise<FileSystemFileHandle>;
138
+ }
139
+
140
+ /** Whether this browser offers `showOpenFilePicker` (Chromium does; Firefox and Safari do not). */
141
+ function hasOpenFilePicker(
142
+ win: Window,
143
+ ): win is Window & Pick<FilePickerWindow, "showOpenFilePicker"> {
144
+ return "showOpenFilePicker" in win;
145
+ }
146
+
147
+ /** Whether this browser offers `showSaveFilePicker` (Chromium does; Firefox and Safari do not). */
148
+ function hasSaveFilePicker(
149
+ win: Window,
150
+ ): win is Window & Pick<FilePickerWindow, "showSaveFilePicker"> {
151
+ return "showSaveFilePicker" in win;
152
+ }
153
+
154
+ /** Attach the tab's file to a notification's options, when it has one. */
155
+ function atTabPath(tab: Tab, options: NotifyOptions): NotifyOptions {
156
+ if (tab.documentPath !== null) {
157
+ options.path = tab.documentPath;
158
+ }
159
+ return options;
160
+ }
161
+
113
162
  /** Open a file via the File System Access API (or fallback input). */
114
163
  export async function openFile() {
115
164
  try {
116
165
  await loadFormats();
117
166
  const formats = getFormats();
118
- const pickerTypes = [
167
+ const pickerTypes: FilePickerAcceptType[] = [
119
168
  {
120
169
  accept: { "application/json": [".json"] },
121
170
  description: "Jx Component",
@@ -160,12 +209,8 @@ export async function openFile() {
160
209
  // Trail; it does not need a message that erases itself.
161
210
  };
162
211
 
163
- if ("showOpenFilePicker" in window) {
164
- const [handle] = await (
165
- window as unknown as {
166
- showOpenFilePicker: (options?: unknown) => Promise<FileSystemFileHandle[]>;
167
- }
168
- ).showOpenFilePicker({ types: pickerTypes });
212
+ if (hasOpenFilePicker(window)) {
213
+ const [handle] = await window.showOpenFilePicker({ types: pickerTypes });
169
214
  const file = await handle!.getFile();
170
215
  await handleSource(handle!.name, await file.text(), handle!);
171
216
  } else {
@@ -230,16 +275,16 @@ function reportSaved(tab: Tab) {
230
275
  const doc = tab.doc.document;
231
276
  _onDocumentSaved(tab.documentPath, doc);
232
277
  const warning =
233
- typeof doc.tagName === "string" && doc.tagName.includes("-")
234
- ? validateComponentSlots(doc)
235
- : null;
278
+ isString(doc.tagName) && doc.tagName.includes("-") ? validateComponentSlots(doc) : null;
236
279
  if (warning) {
237
- notify.warn(warning, {
238
- key: `slots:${tab.documentPath ?? tab.id}`,
239
- ...(tab.documentPath === null ? {} : { path: tab.documentPath }),
240
- source: "Components",
241
- tier: "problem",
242
- });
280
+ notify.warn(
281
+ warning,
282
+ atTabPath(tab, {
283
+ key: `slots:${tab.documentPath ?? tab.id}`,
284
+ source: "Components",
285
+ tier: "problem",
286
+ }),
287
+ );
243
288
  }
244
289
  /* Popover correctness, beside the slot check and for the same reason it is here: a successful
245
290
  save is the one chokepoint every edit passes through, whichever surface made it. A render-time
@@ -311,12 +356,11 @@ export async function saveFile(tab: Tab | null = activeTab.value): Promise<boole
311
356
  notify.warn(
312
357
  `You have read access to this session — changes to ${tab.documentPath ?? "this document"} ` +
313
358
  `stay in your browser and cannot be saved.`,
314
- {
359
+ atTabPath(tab, {
315
360
  action: "file.save",
316
361
  key: `save.readOnly:${tab.documentPath ?? tab.id}`,
317
- ...(tab.documentPath === null ? {} : { path: tab.documentPath }),
318
362
  source: "Collaboration",
319
- },
363
+ }),
320
364
  );
321
365
  return false;
322
366
  }
@@ -327,11 +371,10 @@ export async function saveFile(tab: Tab | null = activeTab.value): Promise<boole
327
371
  if (!hasSerializableDocument(tab)) {
328
372
  notify.warn(
329
373
  `${tab.documentPath ?? "This file"} is a media file, so there is no document for Save to write.`,
330
- {
374
+ atTabPath(tab, {
331
375
  key: `save.notADocument:${tab.documentPath ?? tab.id}`,
332
- ...(tab.documentPath === null ? {} : { path: tab.documentPath }),
333
376
  source: "Save",
334
- },
377
+ }),
335
378
  );
336
379
  return false;
337
380
  }
@@ -381,13 +424,15 @@ export async function saveFile(tab: Tab | null = activeTab.value): Promise<boole
381
424
  notify.warn("This document has no save target — use Export.", { key: "save.noTarget" });
382
425
  } catch (error) {
383
426
  if (!(error instanceof Error && error.name === "AbortError")) {
384
- notify.error(`Could not save ${tab.documentPath ?? tab.id}.`, {
385
- action: "file.save",
386
- detail: errorMessage(error),
387
- key: `save:${tab.documentPath ?? tab.id}`,
388
- ...(tab.documentPath === null ? {} : { path: tab.documentPath }),
389
- source: "Save",
390
- });
427
+ notify.error(
428
+ `Could not save ${tab.documentPath ?? tab.id}.`,
429
+ atTabPath(tab, {
430
+ action: "file.save",
431
+ detail: errorMessage(error),
432
+ key: `save:${tab.documentPath ?? tab.id}`,
433
+ source: "Save",
434
+ }),
435
+ );
391
436
  }
392
437
  }
393
438
  return false;
@@ -418,13 +463,9 @@ export async function exportFile() {
418
463
  const description = format ? format.name : "Jx Component";
419
464
  const fallbackName = format ? `content${ext}` : "component.json";
420
465
 
421
- if ("showSaveFilePicker" in window) {
466
+ if (hasSaveFilePicker(window)) {
422
467
  const suggestedName = tab.documentPath ? tab.documentPath.split("/").pop() : fallbackName;
423
- const handle = await (
424
- window as unknown as {
425
- showSaveFilePicker: (options?: unknown) => Promise<FileSystemFileHandle>;
426
- }
427
- ).showSaveFilePicker({
468
+ const handle = await window.showSaveFilePicker({
428
469
  suggestedName,
429
470
  types: [{ accept: { [mimeType]: [ext] }, description }],
430
471
  });