@jxsuite/studio 6.1.0 → 6.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (645) hide show
  1. package/dist/chunks/2020-f2gkpy8d.js +4 -0
  2. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  3. package/dist/chunks/adapter-4912g339.js +4 -0
  4. package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
  5. package/dist/chunks/cf-settings-br6105tr.js +4 -0
  6. package/dist/chunks/color-28ksk2qm.js +4 -0
  7. package/dist/chunks/color-area-0fj8a4ga.js +4 -0
  8. package/dist/chunks/color-field-xch8kx2g.js +4 -0
  9. package/dist/chunks/color-slider-jxd8v350.js +4 -0
  10. package/dist/chunks/combobox-p0efwjke.js +4 -0
  11. package/dist/chunks/components-db68vsn7.js +4 -0
  12. package/dist/chunks/content-source-1449qesq.js +4 -0
  13. package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
  14. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  15. package/dist/chunks/editor-x9jn86a7.js +4 -0
  16. package/dist/chunks/entry-commands-may24cpt.js +4 -0
  17. package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
  18. package/dist/chunks/file-ops-x9v54pcj.js +4 -0
  19. package/dist/chunks/files-j3knqf0s.js +4 -0
  20. package/dist/chunks/format-host-tyre2trb.js +4 -0
  21. package/dist/chunks/fs-events-64ma9htc.js +4 -0
  22. package/dist/chunks/git-panel-84ps5dex.js +4 -0
  23. package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
  24. package/dist/chunks/icons-pnfz478q.js +4 -0
  25. package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
  26. package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
  27. package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
  28. package/dist/chunks/iframe-entry-zap785cw.js +5 -0
  29. package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
  30. package/dist/chunks/index-b8xw3vy9.js +4 -0
  31. package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
  34. package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
  35. package/dist/chunks/layers-h4xp1pss.js +4 -0
  36. package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
  37. package/dist/chunks/listbox-e74qjyq6.js +4 -0
  38. package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
  39. package/dist/chunks/media-picker-2cweexc5.js +4 -0
  40. package/dist/chunks/menu-n6yzswmy.js +4 -0
  41. package/dist/chunks/menu-ynw13y0s.js +4 -0
  42. package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
  43. package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
  44. package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
  45. package/dist/chunks/notify-cj5zbrs2.js +4 -0
  46. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  47. package/dist/chunks/parse-b7ddhr8m.js +4 -0
  48. package/dist/chunks/platform-3dfws9js.js +4 -0
  49. package/dist/chunks/popover-jt2gxmzs.js +4 -0
  50. package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
  51. package/dist/chunks/quick-search-0dajrwqg.js +4 -0
  52. package/dist/chunks/references-49qgt404.js +4 -0
  53. package/dist/chunks/right-panel-jm1bwe53.js +4 -0
  54. package/dist/chunks/section-registry-6kwc4fky.js +4 -0
  55. package/dist/chunks/select-rzds841e.js +4 -0
  56. package/dist/chunks/split-n2gfpm5m.js +4 -0
  57. package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
  58. package/dist/chunks/studio-0rt52vpq.js +5 -0
  59. package/dist/chunks/studio-18vgbhs5.js +5 -0
  60. package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
  61. package/dist/chunks/studio-24mccdrj.js +5 -0
  62. package/dist/chunks/studio-2eh507zk.js +9 -0
  63. package/dist/chunks/studio-2hcbccfv.js +5 -0
  64. package/dist/chunks/studio-2j1cb95x.js +5 -0
  65. package/dist/chunks/studio-2jbs3rxv.js +5 -0
  66. package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
  67. package/dist/chunks/studio-4h8k4dw9.js +5 -0
  68. package/dist/chunks/studio-5f6n18kx.js +5 -0
  69. package/dist/chunks/studio-5gthpky6.js +5 -0
  70. package/dist/chunks/studio-5ve6bbep.js +5 -0
  71. package/dist/chunks/studio-6ep3js6b.js +9 -0
  72. package/dist/chunks/studio-6wkmf3wz.js +9 -0
  73. package/dist/chunks/studio-841rf3cg.js +5 -0
  74. package/dist/chunks/studio-8gmwgheg.js +5 -0
  75. package/dist/chunks/studio-8qm0ep50.js +5 -0
  76. package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
  79. package/dist/chunks/studio-a3shpz9y.js +5 -0
  80. package/dist/chunks/studio-amsbaaar.js +6 -0
  81. package/dist/chunks/studio-at5spjbc.js +7 -0
  82. package/dist/chunks/studio-b2xv945e.js +5 -0
  83. package/dist/chunks/studio-bn5nkafw.js +5 -0
  84. package/dist/chunks/studio-bw6q5xjf.js +9 -0
  85. package/dist/chunks/studio-c7q0t9x1.js +5 -0
  86. package/dist/chunks/studio-camnhc96.js +6 -0
  87. package/dist/chunks/studio-cffqvnzd.js +5 -0
  88. package/dist/chunks/studio-d81xfh1g.js +5 -0
  89. package/dist/chunks/studio-dgz8d0c1.js +5 -0
  90. package/dist/chunks/studio-efvfrsf8.js +5 -0
  91. package/dist/chunks/studio-er30bpcx.js +5 -0
  92. package/dist/chunks/studio-ezscgr64.js +5 -0
  93. package/dist/chunks/studio-ffrrncvz.js +5 -0
  94. package/dist/chunks/studio-fpphgn8y.js +10 -0
  95. package/dist/chunks/studio-j1kvhdjk.js +4 -0
  96. package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
  97. package/dist/chunks/studio-jjkg84nj.js +5 -0
  98. package/dist/chunks/studio-m0q32ars.js +4 -0
  99. package/dist/chunks/studio-m6bdst11.js +5 -0
  100. package/dist/chunks/studio-nv2cptd4.js +64 -0
  101. package/dist/chunks/studio-nwfrc98n.js +5 -0
  102. package/dist/chunks/studio-p1wgvp7r.js +5 -0
  103. package/dist/chunks/studio-pag2wncm.js +5 -0
  104. package/dist/chunks/studio-qvanvzfd.js +5 -0
  105. package/dist/chunks/studio-qwa64kt7.js +5 -0
  106. package/dist/chunks/studio-rk1zc4x3.js +928 -0
  107. package/dist/chunks/studio-se2r3ptc.js +5 -0
  108. package/dist/chunks/studio-sg2a0dh0.js +5 -0
  109. package/dist/chunks/studio-tjzjhe68.js +5 -0
  110. package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
  112. package/dist/chunks/studio-v2w7q8r1.js +7 -0
  113. package/dist/chunks/studio-v5vjq1h0.js +4 -0
  114. package/dist/chunks/studio-v8aga3vp.js +14 -0
  115. package/dist/chunks/studio-vfcdrfmv.js +5 -0
  116. package/dist/chunks/studio-vmfkgdjf.js +5 -0
  117. package/dist/chunks/studio-wt1816jj.js +5 -0
  118. package/dist/chunks/studio-wz73q5kq.js +4 -0
  119. package/dist/chunks/studio-y04qtxvp.js +7 -0
  120. package/dist/chunks/studio-y21g8zzg.js +5 -0
  121. package/dist/chunks/studio-y64hrt8p.js +12 -0
  122. package/dist/chunks/studio-ynn90f58.js +16 -0
  123. package/dist/chunks/studio-yxz682sx.js +5 -0
  124. package/dist/chunks/studio-zp7snvkq.js +5 -0
  125. package/dist/chunks/studio-zq4z6tm6.js +5 -0
  126. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  127. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  128. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  129. package/dist/chunks/toast-c9fn075p.js +4 -0
  130. package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
  131. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  132. package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
  133. package/dist/chunks/tree-mdq3v5cw.js +4 -0
  134. package/dist/chunks/tsMode-sf49ee9x.js +14 -0
  135. package/dist/chunks/workspace-jtfahpee.js +4 -0
  136. package/dist/chunks/ws-client-nze0k6mv.js +4 -0
  137. package/dist/iframe-entry.js +16 -16
  138. package/dist/manifest.json +63 -63
  139. package/dist/studio.js +98 -98
  140. package/dist/workers/ts.worker.js +3 -3
  141. package/package.json +11 -11
  142. package/src/about/about-modal.ts +4 -3
  143. package/src/account/action-flow.ts +45 -38
  144. package/src/account-status.ts +7 -2
  145. package/src/browse/library-layouts.ts +8 -5
  146. package/src/browse/library-model.ts +18 -6
  147. package/src/browse/library-pane.ts +37 -21
  148. package/src/browse/library-preview.ts +14 -9
  149. package/src/browse/library-source.ts +1 -1
  150. package/src/canvas/asset-refs.ts +24 -9
  151. package/src/canvas/asset-resolve.ts +19 -23
  152. package/src/canvas/canvas-helpers.ts +7 -6
  153. package/src/canvas/canvas-live-render.ts +44 -53
  154. package/src/canvas/canvas-patcher.ts +30 -30
  155. package/src/canvas/canvas-perf.ts +11 -5
  156. package/src/canvas/canvas-render.ts +66 -42
  157. package/src/canvas/canvas-surface.ts +5 -3
  158. package/src/canvas/canvas-utils.ts +163 -64
  159. package/src/canvas/dialog-path.ts +9 -4
  160. package/src/canvas/dialog-state.ts +1 -2
  161. package/src/canvas/diff-marks.ts +9 -16
  162. package/src/canvas/diff-toolbar.ts +8 -7
  163. package/src/canvas/edit-width-drag.ts +4 -1
  164. package/src/canvas/edit-width.ts +1 -3
  165. package/src/canvas/iframe-channel.ts +27 -13
  166. package/src/canvas/iframe-drop.ts +13 -12
  167. package/src/canvas/iframe-editable-root.ts +29 -16
  168. package/src/canvas/iframe-entry.ts +80 -63
  169. package/src/canvas/iframe-eval.ts +73 -49
  170. package/src/canvas/iframe-host.ts +203 -118
  171. package/src/canvas/iframe-inline-edit.ts +69 -32
  172. package/src/canvas/iframe-insert.ts +5 -4
  173. package/src/canvas/iframe-interaction.ts +37 -26
  174. package/src/canvas/iframe-overlay.ts +1 -1
  175. package/src/canvas/iframe-patch.ts +18 -15
  176. package/src/canvas/iframe-position.ts +12 -6
  177. package/src/canvas/iframe-protocol.ts +15 -16
  178. package/src/canvas/iframe-render.ts +41 -36
  179. package/src/canvas/iframe-slash.ts +24 -11
  180. package/src/canvas/iframe-subtree.ts +6 -2
  181. package/src/canvas/path-mapping.ts +19 -12
  182. package/src/canvas/popover-path.ts +7 -3
  183. package/src/canvas/popover-state.ts +1 -2
  184. package/src/canvas/serialize-scope.ts +13 -5
  185. package/src/canvas/stage-scrollbar.ts +2 -1
  186. package/src/canvas/surface-registry.ts +21 -3
  187. package/src/collab/collab-commands.ts +7 -2
  188. package/src/collab/collab-session.ts +84 -45
  189. package/src/collab/collab-state.ts +4 -3
  190. package/src/collab/monaco-binding.ts +16 -13
  191. package/src/collab/monaco-cursors.ts +5 -2
  192. package/src/commands/budget.ts +3 -3
  193. package/src/commands/command-args.ts +103 -71
  194. package/src/commands/context.ts +22 -20
  195. package/src/commands/defaults.ts +4 -1
  196. package/src/commands/keymap.ts +47 -43
  197. package/src/commands/levels.ts +3 -3
  198. package/src/commands/live-context.ts +10 -8
  199. package/src/commands/reference.ts +2 -1
  200. package/src/commands/registry.ts +12 -10
  201. package/src/commands/run-reported.ts +15 -10
  202. package/src/component-props.ts +46 -30
  203. package/src/content/collection-match.ts +5 -4
  204. package/src/content/draft-state.ts +4 -3
  205. package/src/content/entry-commands.ts +3 -2
  206. package/src/content/entry-editor.ts +29 -17
  207. package/src/content/entry-fields.ts +12 -7
  208. package/src/content/entry-model.ts +21 -12
  209. package/src/editor/canvas-context-menu.ts +1 -2
  210. package/src/editor/canvas-slash-bridge.ts +3 -6
  211. package/src/editor/content-slice.ts +16 -14
  212. package/src/editor/context-menu.ts +35 -22
  213. package/src/editor/convert-targets.ts +30 -35
  214. package/src/editor/convert-to-component.ts +11 -5
  215. package/src/editor/convert-to-repeater.ts +34 -22
  216. package/src/editor/editable-tags.ts +17 -2
  217. package/src/editor/file-drop-action.ts +21 -22
  218. package/src/editor/inline-edit-apply.ts +35 -17
  219. package/src/editor/inline-edit.ts +66 -50
  220. package/src/editor/inline-format.ts +59 -56
  221. package/src/editor/inline-link.ts +40 -15
  222. package/src/editor/insert-zone-action.ts +1 -1
  223. package/src/editor/merge-tags.ts +58 -19
  224. package/src/editor/repeater-scope.ts +39 -28
  225. package/src/editor/shortcuts.ts +87 -47
  226. package/src/editor/slash-menu.ts +1 -6
  227. package/src/files/asset-versions.ts +4 -4
  228. package/src/files/components.ts +15 -10
  229. package/src/files/elements.ts +5 -6
  230. package/src/files/file-ops.ts +77 -36
  231. package/src/files/files.ts +90 -95
  232. package/src/files/media-meta.ts +2 -1
  233. package/src/files/media-paths.ts +6 -1
  234. package/src/files/serialize-document.ts +2 -2
  235. package/src/format/constraints.ts +1 -1
  236. package/src/format/convert-file.ts +27 -13
  237. package/src/format/format-choices.ts +2 -1
  238. package/src/format/format-host.ts +76 -50
  239. package/src/github/github-auth-status.ts +27 -3
  240. package/src/github/github-auth.ts +19 -9
  241. package/src/github/github-publish.ts +24 -20
  242. package/src/grid/cell-editors.ts +46 -31
  243. package/src/grid/cell-popovers.ts +5 -3
  244. package/src/grid/edit-buffer.ts +10 -9
  245. package/src/grid/grid-controller.ts +20 -22
  246. package/src/grid/grid-layout.ts +21 -5
  247. package/src/grid/grid-open.ts +3 -6
  248. package/src/grid/grid-panel.ts +11 -4
  249. package/src/grid/grid-source.ts +8 -8
  250. package/src/grid/grid-view.ts +14 -17
  251. package/src/grid/redirects-grid.ts +14 -5
  252. package/src/grid/redirects.ts +16 -14
  253. package/src/grid/schema-columns.ts +25 -19
  254. package/src/grid/sources/connector-source.ts +47 -20
  255. package/src/grid/sources/content-source.ts +25 -24
  256. package/src/grid/sources/csv-file-source.ts +2 -2
  257. package/src/grid/tabulator-tables.d.ts +55 -34
  258. package/src/hosting/stage.ts +7 -7
  259. package/src/i18n/i18n-commands.ts +1 -2
  260. package/src/media/media-pane.ts +4 -1
  261. package/src/new-project/add-repo-modal.ts +20 -19
  262. package/src/new-project/import-tab.ts +10 -14
  263. package/src/new-project/location-fields.ts +2 -1
  264. package/src/new-project/new-project-modal.ts +12 -9
  265. package/src/packages/jxsuite-update.ts +4 -3
  266. package/src/packages/pull-package-sync.ts +26 -25
  267. package/src/page-params.ts +97 -68
  268. package/src/panels/activity-panel.ts +17 -9
  269. package/src/panels/ai-chat/attached-context.ts +13 -7
  270. package/src/panels/ai-chat/chat-view.ts +80 -73
  271. package/src/panels/ai-chat/composer.ts +30 -33
  272. package/src/panels/ai-chat/sessions-view.ts +1 -2
  273. package/src/panels/ai-panel.ts +23 -20
  274. package/src/panels/block-action-bar.ts +46 -35
  275. package/src/panels/bottom-dock.ts +5 -3
  276. package/src/panels/canvas-dnd-bridge.ts +31 -24
  277. package/src/panels/data-explorer.ts +62 -25
  278. package/src/panels/data-grid.ts +14 -11
  279. package/src/panels/dnd.ts +108 -118
  280. package/src/panels/editors.ts +55 -22
  281. package/src/panels/elements-panel.ts +10 -3
  282. package/src/panels/events-panel.ts +84 -69
  283. package/src/panels/formula-workspace.ts +76 -51
  284. package/src/panels/frontmatter-fields.ts +24 -19
  285. package/src/panels/frontmatter-panel.ts +44 -34
  286. package/src/panels/git-diff-open.ts +4 -4
  287. package/src/panels/git-panel.ts +49 -61
  288. package/src/panels/head-panel.ts +131 -111
  289. package/src/panels/i18n-panel.ts +10 -3
  290. package/src/panels/imports-panel.ts +23 -47
  291. package/src/panels/jump-bar.ts +48 -29
  292. package/src/panels/layers-panel.ts +97 -74
  293. package/src/panels/left-panel.ts +3 -3
  294. package/src/panels/pane-context.ts +31 -22
  295. package/src/panels/pane-grid.ts +49 -20
  296. package/src/panels/panel-registry.ts +22 -37
  297. package/src/panels/properties-panel.ts +175 -121
  298. package/src/panels/quick-search.ts +53 -31
  299. package/src/panels/right-panel.ts +3 -3
  300. package/src/panels/seo-modal.ts +13 -17
  301. package/src/panels/settings-menu.ts +15 -15
  302. package/src/panels/signals-panel.ts +153 -131
  303. package/src/panels/statement-editor.ts +230 -140
  304. package/src/panels/style-panel.ts +254 -216
  305. package/src/panels/style-utils.ts +114 -51
  306. package/src/panels/stylebook-doc.ts +57 -54
  307. package/src/panels/stylebook-layers-panel.ts +9 -9
  308. package/src/panels/stylebook-panel.ts +13 -17
  309. package/src/panels/tab-drop.ts +27 -11
  310. package/src/panels/tab-strip.ts +36 -26
  311. package/src/platform-errors.ts +57 -43
  312. package/src/platform.ts +58 -30
  313. package/src/platforms/cloud.ts +345 -175
  314. package/src/platforms/default-platform.ts +10 -4
  315. package/src/platforms/devserver.ts +174 -127
  316. package/src/platforms/read-batcher.ts +16 -8
  317. package/src/project-list.ts +2 -1
  318. package/src/publish/deploy-checklist.ts +8 -2
  319. package/src/publish/pages-service.ts +28 -13
  320. package/src/publish/publish-commands.ts +5 -4
  321. package/src/publish/publish-panel.ts +10 -6
  322. package/src/recent-projects.ts +15 -8
  323. package/src/resize-edges.ts +26 -36
  324. package/src/services/a11y-report.ts +26 -19
  325. package/src/services/agent-seed.ts +23 -11
  326. package/src/services/ai-ask.ts +9 -12
  327. package/src/services/ai-command-tools.ts +68 -62
  328. package/src/services/ai-import-tools.ts +80 -67
  329. package/src/services/ai-models.ts +17 -13
  330. package/src/services/ai-project-tools.ts +68 -32
  331. package/src/services/ai-session-store.ts +19 -10
  332. package/src/services/ai-system-prompt.ts +46 -20
  333. package/src/services/ai-tools.ts +71 -27
  334. package/src/services/ai-write-report.ts +20 -12
  335. package/src/services/ai-writes.ts +4 -4
  336. package/src/services/automation.ts +58 -31
  337. package/src/services/cem-export.ts +149 -58
  338. package/src/services/clock.ts +6 -1
  339. package/src/services/code-services.ts +37 -31
  340. package/src/services/context-manager.ts +14 -10
  341. package/src/services/context-resolver.ts +20 -8
  342. package/src/services/data-service.ts +19 -15
  343. package/src/services/directory-picker.ts +18 -12
  344. package/src/services/document-assistant.ts +39 -19
  345. package/src/services/gated-registry.ts +10 -6
  346. package/src/services/harness/chat-reducer.ts +23 -1
  347. package/src/services/import-client.ts +91 -38
  348. package/src/services/import-seed.ts +8 -2
  349. package/src/services/jx-validate.ts +28 -31
  350. package/src/services/live-preview.ts +0 -0
  351. package/src/services/live-surfaces.ts +6 -3
  352. package/src/services/model-uri.ts +10 -2
  353. package/src/services/module-preloads.ts +12 -8
  354. package/src/services/monaco-buffer.ts +43 -24
  355. package/src/services/monaco-lazy.ts +7 -8
  356. package/src/services/monaco-setup.ts +23 -16
  357. package/src/services/notify.ts +44 -17
  358. package/src/services/popover-report.ts +25 -10
  359. package/src/services/preview-eval.ts +20 -8
  360. package/src/services/profile.ts +13 -6
  361. package/src/services/project-path.ts +13 -10
  362. package/src/services/references.ts +0 -0
  363. package/src/services/render-critic.ts +8 -7
  364. package/src/services/settings/kernel.ts +13 -4
  365. package/src/services/settings/write-queue.ts +9 -9
  366. package/src/services/token-lint.ts +12 -10
  367. package/src/services/tool-executor.ts +17 -5
  368. package/src/services/tool-outcomes.ts +44 -24
  369. package/src/services/trusted-types.ts +24 -7
  370. package/src/settings/contexts-section.ts +11 -8
  371. package/src/settings/contributed-section.ts +79 -60
  372. package/src/settings/css-vars-editor.ts +37 -16
  373. package/src/settings/defs-editor.ts +38 -35
  374. package/src/settings/extension-rows.ts +16 -8
  375. package/src/settings/extension-sections.ts +23 -13
  376. package/src/settings/extensions-section.ts +4 -1
  377. package/src/settings/general-settings.ts +11 -8
  378. package/src/settings/locales-section.ts +20 -12
  379. package/src/settings/preferences-dialog.ts +9 -6
  380. package/src/settings/preferences-keymap.ts +7 -5
  381. package/src/settings/preferences-sections.ts +11 -5
  382. package/src/settings/project-sections.ts +1 -1
  383. package/src/settings/schema-field-ui.ts +9 -0
  384. package/src/settings/settings-document.ts +5 -5
  385. package/src/shell/tree.ts +6 -5
  386. package/src/shell.ts +104 -81
  387. package/src/site-context.ts +37 -22
  388. package/src/state.ts +41 -49
  389. package/src/store.ts +54 -34
  390. package/src/studio.ts +39 -77
  391. package/src/style/live-preview.ts +1 -1
  392. package/src/style/project-styles.ts +6 -7
  393. package/src/style/token-ref.ts +5 -4
  394. package/src/surfaces/about.ts +18 -19
  395. package/src/surfaces/add-repo.ts +17 -19
  396. package/src/surfaces/ai-chat.ts +31 -36
  397. package/src/surfaces/ai-credentials-form.ts +6 -16
  398. package/src/surfaces/ai-managed-connect.ts +3 -4
  399. package/src/surfaces/ai-model-picker.ts +3 -5
  400. package/src/surfaces/block-action-bar.ts +22 -11
  401. package/src/surfaces/boot-failure.ts +4 -5
  402. package/src/surfaces/bottom-dock.ts +9 -18
  403. package/src/surfaces/canvas-stage.ts +12 -11
  404. package/src/surfaces/cf-account-picker.ts +17 -18
  405. package/src/surfaces/commandbar.ts +14 -9
  406. package/src/surfaces/convert-repeater.ts +17 -19
  407. package/src/surfaces/data-actions.ts +9 -7
  408. package/src/surfaces/dialog.ts +26 -28
  409. package/src/surfaces/diff-toolbar.ts +9 -7
  410. package/src/surfaces/doc-header.ts +10 -19
  411. package/src/surfaces/empty-state.ts +7 -10
  412. package/src/surfaces/entry-editor.ts +14 -11
  413. package/src/surfaces/expression-editor.ts +11 -25
  414. package/src/surfaces/files-panel.ts +27 -14
  415. package/src/surfaces/formula-palette.ts +4 -5
  416. package/src/surfaces/git-panel.ts +7 -15
  417. package/src/surfaces/github-auth.ts +16 -20
  418. package/src/surfaces/github-publish.ts +17 -22
  419. package/src/surfaces/grid-cell.ts +30 -31
  420. package/src/surfaces/grid-open.ts +10 -14
  421. package/src/surfaces/grid-panel.ts +13 -9
  422. package/src/surfaces/grid-replace.ts +13 -13
  423. package/src/surfaces/grid-views.ts +15 -18
  424. package/src/surfaces/inspector-dock.ts +13 -12
  425. package/src/surfaces/jump-bar.ts +5 -6
  426. package/src/surfaces/jxsuite-update.ts +16 -22
  427. package/src/surfaces/library-pane.ts +25 -20
  428. package/src/surfaces/logic-panel.ts +17 -30
  429. package/src/surfaces/logic-workspace.ts +13 -15
  430. package/src/surfaces/media-browser.ts +11 -10
  431. package/src/surfaces/media-field.ts +4 -5
  432. package/src/surfaces/media-pane.ts +8 -7
  433. package/src/surfaces/menu.ts +29 -23
  434. package/src/surfaces/navigator-dock.ts +11 -12
  435. package/src/surfaces/new-project.ts +27 -26
  436. package/src/surfaces/pane-context.ts +20 -25
  437. package/src/surfaces/pane-grid.ts +15 -10
  438. package/src/surfaces/panel-activity.ts +5 -6
  439. package/src/surfaces/panel-data.ts +3 -4
  440. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  441. package/src/surfaces/panel-elements.ts +5 -7
  442. package/src/surfaces/panel-i18n.ts +5 -7
  443. package/src/surfaces/panel-imports.ts +6 -13
  444. package/src/surfaces/panel-outline.ts +25 -19
  445. package/src/surfaces/panel-page.ts +11 -18
  446. package/src/surfaces/panel-problems.ts +5 -7
  447. package/src/surfaces/panel-signals.ts +20 -34
  448. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  449. package/src/surfaces/preferences.ts +21 -11
  450. package/src/surfaces/progress-modal.ts +15 -9
  451. package/src/surfaces/properties-panel.json +1 -1
  452. package/src/surfaces/properties-panel.ts +20 -42
  453. package/src/surfaces/publish.ts +18 -18
  454. package/src/surfaces/push-plan.ts +7 -8
  455. package/src/surfaces/rail.json +126 -73
  456. package/src/surfaces/rail.ts +38 -12
  457. package/src/surfaces/reference-field.ts +11 -15
  458. package/src/surfaces/schema-builder.ts +16 -22
  459. package/src/surfaces/schema-form.ts +15 -25
  460. package/src/surfaces/secret-field.ts +9 -6
  461. package/src/surfaces/seo.ts +21 -15
  462. package/src/surfaces/settings-contexts.ts +9 -7
  463. package/src/surfaces/settings-contributed.ts +14 -10
  464. package/src/surfaces/settings-css-vars.ts +5 -12
  465. package/src/surfaces/settings-defs.json +2 -2
  466. package/src/surfaces/settings-defs.ts +17 -21
  467. package/src/surfaces/settings-deploy.ts +8 -15
  468. package/src/surfaces/settings-extensions.ts +5 -6
  469. package/src/surfaces/settings-head.ts +33 -39
  470. package/src/surfaces/settings-locales.ts +8 -20
  471. package/src/surfaces/settings-overview.ts +5 -6
  472. package/src/surfaces/settings-packages.ts +8 -7
  473. package/src/surfaces/settings-pane.ts +9 -18
  474. package/src/surfaces/settings-rawjson.ts +5 -6
  475. package/src/surfaces/shell.ts +1 -2
  476. package/src/surfaces/slash-menu.ts +19 -9
  477. package/src/surfaces/statements.ts +13 -18
  478. package/src/surfaces/statusbar.ts +17 -14
  479. package/src/surfaces/style-panel.ts +18 -31
  480. package/src/surfaces/stylebook-chrome.ts +3 -5
  481. package/src/surfaces/tab-strip.ts +14 -13
  482. package/src/surfaces/target-line.ts +6 -7
  483. package/src/surfaces/welcome.ts +5 -7
  484. package/src/tabs/patch-ops.ts +4 -3
  485. package/src/tabs/project-config.ts +32 -21
  486. package/src/tabs/selection.ts +36 -8
  487. package/src/tabs/tab.ts +52 -41
  488. package/src/tabs/transact.ts +98 -53
  489. package/src/tabs/typing.ts +31 -0
  490. package/src/types.ts +32 -17
  491. package/src/ui/ai-credentials-form.ts +10 -13
  492. package/src/ui/ai-model-picker.ts +3 -3
  493. package/src/ui/cf-account-picker.ts +7 -9
  494. package/src/ui/color-selector.ts +9 -5
  495. package/src/ui/dynamic-slot.ts +7 -8
  496. package/src/ui/expression-editor.ts +112 -105
  497. package/src/ui/form-controls.ts +57 -48
  498. package/src/ui/formula-catalog.ts +239 -230
  499. package/src/ui/formula-chips.ts +33 -18
  500. package/src/ui/layers.ts +44 -31
  501. package/src/ui/media-picker.ts +18 -9
  502. package/src/ui/popover-surface.ts +20 -12
  503. package/src/ui/progress-modal.ts +13 -8
  504. package/src/ui/regions.ts +7 -6
  505. package/src/ui/schema-form.ts +113 -70
  506. package/src/ui/surface.ts +71 -8
  507. package/src/ui/timing.ts +9 -0
  508. package/src/ui/value-source.ts +44 -31
  509. package/src/ui/virtual-window.ts +3 -2
  510. package/src/utils/base64.ts +3 -1
  511. package/src/utils/edit-display.ts +103 -74
  512. package/src/utils/element-selectors.ts +3 -2
  513. package/src/utils/google-fonts.ts +15 -14
  514. package/src/utils/inherited-style.ts +18 -20
  515. package/src/utils/link-target.ts +1 -1
  516. package/src/utils/preview-format.ts +25 -3
  517. package/src/utils/strip-events.ts +49 -22
  518. package/src/utils/studio-utils.ts +29 -14
  519. package/src/view.ts +2 -3
  520. package/src/workspace/pane-derive.ts +10 -12
  521. package/src/workspace/session.ts +53 -43
  522. package/src/workspace/workspace.ts +47 -36
  523. package/dist/chunks/2020-nkxms0ay.js +0 -4
  524. package/dist/chunks/adapter-m948ab5f.js +0 -4
  525. package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
  526. package/dist/chunks/cf-settings-356xdtne.js +0 -4
  527. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  528. package/dist/chunks/color-field-embq5ctg.js +0 -4
  529. package/dist/chunks/color-fpezvnkt.js +0 -4
  530. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  531. package/dist/chunks/combobox-773hdzyj.js +0 -4
  532. package/dist/chunks/components-yk3t844e.js +0 -4
  533. package/dist/chunks/content-source-bawmyc09.js +0 -4
  534. package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
  535. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  536. package/dist/chunks/editor-6sc8nacq.js +0 -4
  537. package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
  538. package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
  539. package/dist/chunks/file-ops-gye0qw56.js +0 -4
  540. package/dist/chunks/files-dmc2xvcq.js +0 -4
  541. package/dist/chunks/format-host-t76b53f8.js +0 -4
  542. package/dist/chunks/fs-events-cg4tpz06.js +0 -4
  543. package/dist/chunks/git-panel-yef7bshy.js +0 -4
  544. package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
  545. package/dist/chunks/icons-qbh8akb1.js +0 -4
  546. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  547. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  548. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  549. package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
  550. package/dist/chunks/index-nag78a9h.js +0 -4
  551. package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
  552. package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
  553. package/dist/chunks/layers-fvz99859.js +0 -4
  554. package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
  555. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  556. package/dist/chunks/lit-html-9agdspkt.js +0 -4
  557. package/dist/chunks/media-picker-rhjvyy00.js +0 -4
  558. package/dist/chunks/menu-2e4y9j7b.js +0 -4
  559. package/dist/chunks/menu-37d07z9m.js +0 -4
  560. package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
  561. package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
  562. package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
  563. package/dist/chunks/notify-h3www560.js +0 -4
  564. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  565. package/dist/chunks/parse-897fvqah.js +0 -4
  566. package/dist/chunks/platform-hz34wcd7.js +0 -4
  567. package/dist/chunks/popover-8htra4er.js +0 -4
  568. package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
  569. package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
  570. package/dist/chunks/references-2cgdxnb8.js +0 -4
  571. package/dist/chunks/right-panel-jf856w5w.js +0 -4
  572. package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
  573. package/dist/chunks/select-n3v7gwas.js +0 -4
  574. package/dist/chunks/split-pff8f3ze.js +0 -4
  575. package/dist/chunks/studio-0f55h9ye.js +0 -5
  576. package/dist/chunks/studio-0sqdhnew.js +0 -12
  577. package/dist/chunks/studio-19x1c75w.js +0 -5
  578. package/dist/chunks/studio-2sqcndak.js +0 -5
  579. package/dist/chunks/studio-3aey7dd3.js +0 -5
  580. package/dist/chunks/studio-3bpdkq2s.js +0 -5
  581. package/dist/chunks/studio-47y6fbpf.js +0 -5
  582. package/dist/chunks/studio-4m3826v2.js +0 -5
  583. package/dist/chunks/studio-4nx2dj1g.js +0 -4
  584. package/dist/chunks/studio-4xv5s47r.js +0 -9
  585. package/dist/chunks/studio-5g4t8v6w.js +0 -5
  586. package/dist/chunks/studio-5py436sf.js +0 -5
  587. package/dist/chunks/studio-77kt594t.js +0 -5
  588. package/dist/chunks/studio-8f87n763.js +0 -10
  589. package/dist/chunks/studio-8mb00b84.js +0 -5
  590. package/dist/chunks/studio-8p51gq2h.js +0 -6
  591. package/dist/chunks/studio-954ds834.js +0 -5
  592. package/dist/chunks/studio-9ft45c83.js +0 -9
  593. package/dist/chunks/studio-a2138x5k.js +0 -7
  594. package/dist/chunks/studio-a9yzstqj.js +0 -5
  595. package/dist/chunks/studio-acdksxx6.js +0 -5
  596. package/dist/chunks/studio-ar8jcf2y.js +0 -5
  597. package/dist/chunks/studio-bmn4mn9j.js +0 -7
  598. package/dist/chunks/studio-e7xxa0sj.js +0 -5
  599. package/dist/chunks/studio-ecaz25vk.js +0 -5
  600. package/dist/chunks/studio-ery42sqr.js +0 -4
  601. package/dist/chunks/studio-fzdywr6p.js +0 -9
  602. package/dist/chunks/studio-g5fmf0c1.js +0 -5
  603. package/dist/chunks/studio-g7nse7zb.js +0 -5
  604. package/dist/chunks/studio-geq1ea6k.js +0 -14
  605. package/dist/chunks/studio-ghkb32r8.js +0 -5
  606. package/dist/chunks/studio-ghrhy2y7.js +0 -5
  607. package/dist/chunks/studio-grawhey1.js +0 -5
  608. package/dist/chunks/studio-h0xgswew.js +0 -5
  609. package/dist/chunks/studio-h9c4p2tx.js +0 -5
  610. package/dist/chunks/studio-jyzj5cxs.js +0 -5
  611. package/dist/chunks/studio-mgx8yhnz.js +0 -64
  612. package/dist/chunks/studio-mpb04y1d.js +0 -6
  613. package/dist/chunks/studio-n17mty64.js +0 -5
  614. package/dist/chunks/studio-nwh2eqsk.js +0 -6
  615. package/dist/chunks/studio-q1h883bt.js +0 -16
  616. package/dist/chunks/studio-q4tv82h7.js +0 -9
  617. package/dist/chunks/studio-qpqa7vk3.js +0 -5
  618. package/dist/chunks/studio-qqz8e5gk.js +0 -5
  619. package/dist/chunks/studio-qvasen3f.js +0 -5
  620. package/dist/chunks/studio-rggdb3hm.js +0 -5
  621. package/dist/chunks/studio-sghy936h.js +0 -4
  622. package/dist/chunks/studio-skprc6ef.js +0 -5
  623. package/dist/chunks/studio-tt2nactf.js +0 -5
  624. package/dist/chunks/studio-tyasmc39.js +0 -5
  625. package/dist/chunks/studio-vk9ezads.js +0 -5
  626. package/dist/chunks/studio-vzacdfsc.js +0 -4
  627. package/dist/chunks/studio-w4c0xmrw.js +0 -5
  628. package/dist/chunks/studio-wfjqhhbk.js +0 -5
  629. package/dist/chunks/studio-wgh5kxpj.js +0 -5
  630. package/dist/chunks/studio-xasj0796.js +0 -5
  631. package/dist/chunks/studio-y78s8r2n.js +0 -5
  632. package/dist/chunks/studio-z8w183sh.js +0 -5
  633. package/dist/chunks/studio-zscd9ty4.js +0 -928
  634. package/dist/chunks/studio-zxp13sss.js +0 -7
  635. package/dist/chunks/studio-zygnmm01.js +0 -5
  636. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  637. package/dist/chunks/tabs-jwthg40w.js +0 -4
  638. package/dist/chunks/textfield-spy3hc77.js +0 -4
  639. package/dist/chunks/toast-4d35zd64.js +0 -4
  640. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  641. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  642. package/dist/chunks/tree-h19v1jfz.js +0 -4
  643. package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
  644. package/dist/chunks/workspace-m15qtcqp.js +0 -4
  645. package/dist/chunks/ws-client-nf61frr1.js +0 -4
@@ -1,4 +1,5 @@
1
1
  /// <reference lib="dom" />
2
+ /// <reference lib="dom.iterable" />
2
3
  /**
3
4
  * Inline-format.js — Inline formatting engine for contenteditable editing
4
5
  *
@@ -22,6 +23,25 @@ const FORMAT_TAGS = new Set([
22
23
  "span",
23
24
  ]);
24
25
 
26
+ /** Whether `node` is an element. Decided by node type, so it holds for a node of any realm. */
27
+ function isElementNode(node: Node): node is Element {
28
+ return node.nodeType === Node.ELEMENT_NODE;
29
+ }
30
+
31
+ /** Whether `node` is a text node (`CDATASection` has its own node type and is excluded). */
32
+ function isTextNode(node: Node): node is Text {
33
+ return node.nodeType === Node.TEXT_NODE;
34
+ }
35
+
36
+ /** One edge-whitespace move {@link liftEdgeWhitespace} applies after its scan. */
37
+ interface EdgeWhitespaceLift {
38
+ type: "lift-leading" | "lift-trailing";
39
+ el: Element;
40
+ /** The wrapper's first (leading) or last (trailing) child, whose edge whitespace moves out. */
41
+ text: Text;
42
+ ws: string;
43
+ }
44
+
25
45
  /**
26
46
  * Check whether `tag` is currently active on both ends of the selection. Walks from anchor and
27
47
  * focus nodes up to editableRoot looking for the tag. Returns false if selection is outside
@@ -59,10 +79,7 @@ export function isTagActiveInSelection(tag: string, editableRoot: HTMLElement |
59
79
  const hasTag = (node: Node | null) => {
60
80
  let current = node;
61
81
  while (current && current !== editableRoot) {
62
- if (
63
- current.nodeType === Node.ELEMENT_NODE &&
64
- (current as Element).tagName.toLowerCase() === tag
65
- ) {
82
+ if (isElementNode(current) && current.tagName.toLowerCase() === tag) {
66
83
  return true;
67
84
  }
68
85
  current = current.parentNode;
@@ -121,20 +138,11 @@ export function toggleInlineFormat(tag: string, editableRoot: HTMLElement | null
121
138
  */
122
139
  function findIntersectingElements(tag: string, range: Range, root: HTMLElement) {
123
140
  const matches: Element[] = [];
124
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
125
- /**
126
- * @param {Node} node
127
- * @returns {number}
128
- */
129
- acceptNode(node: Node) {
130
- if ((node as Element).tagName.toLowerCase() === tag && range.intersectsNode(node)) {
131
- return NodeFilter.FILTER_ACCEPT;
132
- }
133
- return NodeFilter.FILTER_SKIP;
134
- },
135
- });
136
- while (walker.nextNode()) {
137
- matches.push(walker.currentNode as Element);
141
+ // Every descendant element, in document order: the same set a SHOW_ELEMENT tree walk visits.
142
+ for (const el of root.querySelectorAll("*")) {
143
+ if (el.tagName.toLowerCase() === tag && range.intersectsNode(el)) {
144
+ matches.push(el);
145
+ }
138
146
  }
139
147
  return matches;
140
148
  }
@@ -343,21 +351,19 @@ export function normalizeInlineContent(root: HTMLElement | null) {
343
351
  */
344
352
  function mergeAdjacentSiblings(root: HTMLElement) {
345
353
  let changed = false;
346
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
347
354
  const toMerge: [Element, Element][] = [];
348
355
 
349
356
  // Collect pairs first to avoid mutation during walk
350
- while (walker.nextNode()) {
351
- const el = walker.currentNode as Element;
357
+ for (const el of root.querySelectorAll("*")) {
352
358
  const next = el.nextSibling;
353
359
  if (
354
360
  next &&
355
- next.nodeType === Node.ELEMENT_NODE &&
356
- (next as Element).tagName === el.tagName &&
361
+ isElementNode(next) &&
362
+ next.tagName === el.tagName &&
357
363
  FORMAT_TAGS.has(el.tagName.toLowerCase()) &&
358
- attributesMatch(el, next as Element)
364
+ attributesMatch(el, next)
359
365
  ) {
360
- toMerge.push([el, next as Element]);
366
+ toMerge.push([el, next]);
361
367
  }
362
368
  }
363
369
 
@@ -383,27 +389,31 @@ function mergeAdjacentSiblings(root: HTMLElement) {
383
389
  */
384
390
  function collapseRedundantNesting(root: HTMLElement) {
385
391
  let changed = false;
386
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
387
392
  const toCollapse: Element[] = [];
388
393
 
389
- while (walker.nextNode()) {
390
- const el = walker.currentNode as Element;
394
+ for (const el of root.querySelectorAll("*")) {
391
395
  if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {
392
396
  continue;
393
397
  }
394
398
  // Check if only child is an element with the same tag
399
+ const only = el.firstChild;
395
400
  if (
396
401
  el.childNodes.length === 1 &&
397
- el.firstChild !== null &&
398
- el.firstChild.nodeType === Node.ELEMENT_NODE &&
399
- (el.firstChild as Element).tagName === el.tagName
402
+ only !== null &&
403
+ isElementNode(only) &&
404
+ only.tagName === el.tagName
400
405
  ) {
401
406
  toCollapse.push(el);
402
407
  }
403
408
  }
404
409
 
405
410
  for (const el of toCollapse) {
406
- const inner = el.firstChild as Element;
411
+ const inner = el.firstChild;
412
+ if (inner === null) {
413
+ /* Three or more nested identical wrappers: collapsing the outer pair moved this wrapper's only
414
+ child out, leaving it empty. That has always failed here, and is kept rather than changed. */
415
+ throw new TypeError("collapseRedundantNesting: an earlier collapse emptied this wrapper");
416
+ }
407
417
  // Replace outer with inner's children
408
418
  while (inner.firstChild) {
409
419
  inner.before(inner.firstChild);
@@ -422,11 +432,9 @@ function collapseRedundantNesting(root: HTMLElement) {
422
432
  */
423
433
  function removeEmptyInlines(root: HTMLElement) {
424
434
  let changed = false;
425
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
426
435
  const toRemove: Element[] = [];
427
436
 
428
- while (walker.nextNode()) {
429
- const el = walker.currentNode as Element;
437
+ for (const el of root.querySelectorAll("*")) {
430
438
  if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {
431
439
  continue;
432
440
  }
@@ -451,12 +459,9 @@ function removeEmptyInlines(root: HTMLElement) {
451
459
  */
452
460
  function liftEdgeWhitespace(root: HTMLElement) {
453
461
  let changed = false;
454
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
455
- /** @type {{ type: string; el: Element; ws: string }[]} */
456
- const ops = [];
462
+ const ops: EdgeWhitespaceLift[] = [];
457
463
 
458
- while (walker.nextNode()) {
459
- const el = walker.currentNode as Element;
464
+ for (const el of root.querySelectorAll("*")) {
460
465
  if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {
461
466
  continue;
462
467
  }
@@ -465,36 +470,36 @@ function liftEdgeWhitespace(root: HTMLElement) {
465
470
  }
466
471
 
467
472
  const first = el.firstChild;
468
- if (first && first.nodeType === Node.TEXT_NODE) {
469
- const text = first.textContent ?? "";
473
+ if (first && isTextNode(first)) {
474
+ const text = first.textContent;
470
475
  const m = text.match(/^(\s+)/);
471
476
  if (m && text.length > m[1]!.length) {
472
- ops.push({ el, type: "lift-leading", ws: m[1]! });
477
+ ops.push({ el, text: first, type: "lift-leading", ws: m[1]! });
473
478
  }
474
479
  }
475
480
 
476
481
  const last = el.lastChild;
477
- if (last && last.nodeType === Node.TEXT_NODE && last !== first) {
478
- const text = last.textContent ?? "";
482
+ if (last && isTextNode(last) && last !== first) {
483
+ const text = last.textContent;
479
484
  const m = text.match(/(\s+)$/);
480
485
  if (m && text.length > m[1]!.length) {
481
- ops.push({ el, type: "lift-trailing", ws: m[1]! });
486
+ ops.push({ el, text: last, type: "lift-trailing", ws: m[1]! });
482
487
  }
483
488
  }
484
489
  }
485
490
 
491
+ /* Each recorded text node is still its wrapper's edge child when its move runs: a move only edits
492
+ a text node's data and inserts a sibling OUTSIDE its own wrapper, and a wrapper whose edge child
493
+ is an element (the only place a nested move could insert) never recorded a move on that edge. */
486
494
  for (const op of ops) {
487
495
  if (op.type === "lift-leading") {
488
- const firstChild = op.el.firstChild as Text;
489
- firstChild.textContent = (firstChild.textContent ?? "").slice(op.ws.length);
496
+ op.text.textContent = op.text.textContent.slice(op.ws.length);
490
497
  op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el);
491
- changed = true;
492
- } else if (op.type === "lift-trailing") {
493
- const lastChild = op.el.lastChild as Text;
494
- lastChild.textContent = (lastChild.textContent ?? "").slice(0, -op.ws.length);
498
+ } else {
499
+ op.text.textContent = op.text.textContent.slice(0, -op.ws.length);
495
500
  op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el.nextSibling);
496
- changed = true;
497
501
  }
502
+ changed = true;
498
503
  }
499
504
  return changed;
500
505
  }
@@ -508,11 +513,9 @@ function liftEdgeWhitespace(root: HTMLElement) {
508
513
  */
509
514
  function unwrapBareSpans(root: HTMLElement) {
510
515
  let changed = false;
511
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
512
516
  const toUnwrap: Element[] = [];
513
517
 
514
- while (walker.nextNode()) {
515
- const el = walker.currentNode as Element;
518
+ for (const el of root.querySelectorAll("*")) {
516
519
  if (el.tagName.toLowerCase() !== "span") {
517
520
  continue;
518
521
  }
@@ -8,32 +8,57 @@
8
8
  * it here (Phase 4b-2).
9
9
  *
10
10
  * `document.execCommand` is uncoverable under happy-dom (no implementation), so it is wrapped in a
11
- * one-line shim {@link exec} that the branch logic calls; tests stub `document.execCommand` and
12
- * assert at the stub level (documented as stub-level, not behavioral).
11
+ * one-line shim {@link execEditingCommand} that the branch logic calls; tests stub
12
+ * `document.execCommand` and assert at the stub level (documented as stub-level, not behavioral).
13
13
  */
14
14
 
15
15
  import { normalizeInlineContent } from "./inline-format";
16
16
 
17
- /** The one uncoverable call, isolated so the surrounding branch logic stays unit-testable. */
18
- const exec = (cmd: string, val?: string): boolean => document.execCommand(cmd, false, val);
17
+ /**
18
+ * The one uncoverable call, isolated so the surrounding branch logic stays unit-testable, and the
19
+ * one place Studio reaches `document.execCommand`. It is deprecated, and NOT kept for the native
20
+ * undo stack: Studio owns history (`edit.undo` is forwarded out of the frame and a `historyUndo`
21
+ * `beforeinput` is rejected, studio.md §8.2.1). It is kept because it is the only script entry into
22
+ * the browser's editing engine, which a Range rewrite would not reproduce: `insertText` rebalances
23
+ * whitespace into `&nbsp;` runs (and back) around the caret, and `createLink` splits the anchor at
24
+ * inline-formatting boundaries it only partly covers.
25
+ */
26
+ export const execEditingCommand = (cmd: string, val?: string): boolean =>
27
+ // oxlint-disable-next-line typescript/no-deprecated -- no successor API exists: execCommand is the only script entry into the browser's editing engine (whitespace rebalancing, anchor splitting), see the doc comment above
28
+ document.execCommand(cmd, false, val);
29
+
30
+ /** The link the selection sits in, as the format toolbar's Link field shows it. */
31
+ export interface LinkState {
32
+ /** Whether the selection anchor is inside an `<a>`. */
33
+ active: boolean;
34
+ /** The author-entered URL of that `<a>`, or null when there is none. */
35
+ href: string | null;
36
+ }
37
+
38
+ /**
39
+ * Whether `node` is an `<a>` element. Decided by node type and name rather than `instanceof`, so it
40
+ * holds for nodes of another realm; for an element, `nodeName` is its tag name.
41
+ */
42
+ function isAnchorNode(node: Node): node is HTMLAnchorElement | SVGAElement {
43
+ return node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === "a";
44
+ }
19
45
 
20
46
  /**
21
47
  * Read the link state of the current selection relative to `root`: walk the selection's anchor node
22
48
  * up to `root` looking for an `<a>`. Returns the author-entered `href` attribute (NOT the resolved
23
49
  * `.href` property), so relative/templated URLs round-trip unchanged.
24
50
  */
25
- export function linkStateForSelection(root: HTMLElement): { active: boolean; href: string | null } {
51
+ export function linkStateForSelection(root: HTMLElement): LinkState {
26
52
  const sel = window.getSelection();
27
53
  if (!sel || !sel.rangeCount) {
28
54
  return { active: false, href: null };
29
55
  }
30
56
  let node: Node | null = sel.anchorNode;
31
57
  while (node && node !== root) {
32
- if (node.nodeType === Node.ELEMENT_NODE && (node as Element).tagName.toLowerCase() === "a") {
58
+ if (isAnchorNode(node)) {
33
59
  // Design/edit renders anchors de-linked, with the URL on `data-jx-href` — so the toolbar's
34
60
  // Link field must read that first or it shows an empty URL for every existing link.
35
- const el = node as HTMLElement;
36
- return { active: true, href: el.dataset.jxHref ?? el.getAttribute("href") };
61
+ return { active: true, href: node.dataset.jxHref ?? node.getAttribute("href") };
37
62
  }
38
63
  node = node.parentNode;
39
64
  }
@@ -44,17 +69,17 @@ export function linkStateForSelection(root: HTMLElement): { active: boolean; hre
44
69
  * Find the `<a>` that contains the selection anchor (up to `root`), if any.
45
70
  *
46
71
  * @param {HTMLElement} root
47
- * @returns {HTMLAnchorElement | null}
72
+ * @returns {HTMLAnchorElement | SVGAElement | null}
48
73
  */
49
- function anchorInSelection(root: HTMLElement): HTMLAnchorElement | null {
74
+ function anchorInSelection(root: HTMLElement): HTMLAnchorElement | SVGAElement | null {
50
75
  const sel = window.getSelection();
51
76
  if (!sel || !sel.rangeCount) {
52
77
  return null;
53
78
  }
54
79
  let node: Node | null = sel.anchorNode;
55
80
  while (node && node !== root) {
56
- if (node.nodeType === Node.ELEMENT_NODE && (node as Element).tagName.toLowerCase() === "a") {
57
- return node as HTMLAnchorElement;
81
+ if (isAnchorNode(node)) {
82
+ return node;
58
83
  }
59
84
  node = node.parentNode;
60
85
  }
@@ -80,13 +105,13 @@ export function applyLink(root: HTMLElement, href: string | null): void {
80
105
  existing.replaceWith(frag);
81
106
  }
82
107
  } else if (href) {
83
- exec("createLink", href);
108
+ execEditingCommand("createLink", href);
84
109
  }
85
110
  normalizeInlineContent(root);
86
111
  }
87
112
 
88
- /** Insert a `${token}` template expression at the caret inside `root` (joins the native undo stack). */
113
+ /** Insert a `${token}` template expression at the caret inside `root`, through the editing engine. */
89
114
  export function insertTemplateToken(root: HTMLElement, token: string): void {
90
115
  root.focus();
91
- exec("insertText", `\${${token}}`);
116
+ execEditingCommand("insertText", `\${${token}}`);
92
117
  }
@@ -22,7 +22,7 @@ export function runInsertZoneAction(btn: HTMLElement, zone: InsertZone): void {
22
22
  showSlashMenu(btn, "", {
23
23
  onSelect: (cmd) => {
24
24
  const def = defaultDef(cmd.tag);
25
- const insertPath = zone.insertParentPath as JxPath;
25
+ const insertPath: JxPath = zone.insertParentPath;
26
26
  const idx = zone.index;
27
27
  const newPath = [...insertPath, "children", idx];
28
28
  transactDoc(activeTab.value, (t) => {
@@ -9,8 +9,10 @@
9
9
  * Pure and DOM-free: callers pass the data in, this returns plain descriptors.
10
10
  */
11
11
 
12
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
12
13
  import { defCategory } from "../panels/signals-panel";
13
14
  import { dataTypeLabel, unwrapSignal } from "../panels/data-explorer";
15
+ import type { JsonPrimitive, JxStateDefinition } from "@jxsuite/schema/types";
14
16
 
15
17
  export interface MergeTag {
16
18
  /** Insertion token placed between `${` and `}`, e.g. `state.user.name`, `item.title`, `index`. */
@@ -23,20 +25,50 @@ export interface MergeTag {
23
25
  category: string;
24
26
  }
25
27
 
28
+ /**
29
+ * A value in a live render scope, as far as the merge-tag walk reads it: document data, a handler,
30
+ * a pending (`undefined`) entry, or an object — a plain record, a fetched payload, a Vue ref —
31
+ * whose own keys hold further scope values.
32
+ */
33
+ export type ScopeValue =
34
+ | JsonPrimitive
35
+ | undefined
36
+ | bigint
37
+ | symbol
38
+ | ((...args: never[]) => void)
39
+ | ScopeValue[]
40
+ | ScopeRecord;
41
+
42
+ /** A render scope, or any object inside one, read key by key. */
43
+ export interface ScopeRecord {
44
+ readonly [key: string]: ScopeValue;
45
+ }
46
+
26
47
  /** Levels of nesting walked beneath each root name. */
27
48
  const DEPTH_CAP = 3;
28
49
  /** Maximum object keys enumerated per level (mirrors the data-explorer tree cap). */
29
50
  const BREADTH_CAP = 30;
30
51
 
52
+ /** Whether a scope value is an object read by key: non-null, not an array, not a function. */
53
+ function isScopeRecord(value: ScopeValue): value is ScopeRecord {
54
+ return isNonNullObject(value) && !Array.isArray(value);
55
+ }
56
+
57
+ /** The value behind a Vue ref, or the value itself. */
58
+ function unwrapScopeValue(value: ScopeValue): ScopeValue {
59
+ /* SAFETY: unwrapSignal returns its argument unchanged, or a ref's `.value`; a ref is a scope record,
60
+ so its `.value` member is itself a scope value. */
61
+ return unwrapSignal(value) as ScopeValue;
62
+ }
63
+
31
64
  /** Type label plus a short value preview for primitives. */
32
- function previewHint(value: unknown): string {
33
- const v = unwrapSignal(value);
65
+ function previewHint(value: ScopeValue): string {
66
+ const v = unwrapScopeValue(value);
34
67
  const typeLabel = dataTypeLabel(v);
35
- if (v === null || v === undefined || typeof v === "object") {
68
+ if (v === null || v === undefined || isNonNullObject(v)) {
36
69
  return typeLabel; // Null / pending / Array(n) / {n}
37
70
  }
38
- const text =
39
- typeof v === "string" ? (v.length > 24 ? `"${v.slice(0, 24)}…"` : `"${v}"`) : String(v);
71
+ const text = isString(v) ? (v.length > 24 ? `"${v.slice(0, 24)}…"` : `"${v}"`) : String(v);
40
72
  return `${typeLabel} · ${text}`;
41
73
  }
42
74
 
@@ -44,25 +76,25 @@ function previewHint(value: unknown): string {
44
76
  * Walk a resolved value, appending nested-path tags to `out`. Arrays contribute a `.length` tag and
45
77
  * stop (index access is context-dependent); plain objects recurse up to the depth/breadth caps.
46
78
  */
47
- function walk(value: unknown, prefix: string, category: string, depth: number, out: MergeTag[]) {
79
+ function walk(value: ScopeValue, prefix: string, category: string, depth: number, out: MergeTag[]) {
48
80
  if (depth >= DEPTH_CAP) {
49
81
  return;
50
82
  }
51
- const v = unwrapSignal(value);
52
- if (v === null || v === undefined || typeof v !== "object") {
53
- return;
54
- }
83
+ const v = unwrapScopeValue(value);
55
84
  if (Array.isArray(v)) {
56
85
  const token = `${prefix}.length`;
57
86
  out.push({ category, hint: `number · ${v.length}`, label: token, token });
58
87
  return;
59
88
  }
89
+ if (!isScopeRecord(v)) {
90
+ return;
91
+ }
60
92
  const keys = Object.keys(v).slice(0, BREADTH_CAP);
61
93
  for (const key of keys) {
62
94
  if (key.startsWith("$")) {
63
95
  continue; // Internal keys ($children, $ref, reactive plumbing) are not author-facing
64
96
  }
65
- const childVal = (v as Record<string, unknown>)[key];
97
+ const childVal = v[key];
66
98
  const childPrefix = `${prefix}.${key}`;
67
99
  out.push({ category, hint: previewHint(childVal), label: childPrefix, token: childPrefix });
68
100
  walk(childVal, childPrefix, category, depth + 1, out);
@@ -80,9 +112,9 @@ function walk(value: unknown, prefix: string, category: string, depth: number, o
80
112
  * carries a `$map` (repeater) context, `item` / `item.*` / `index` tags are appended.
81
113
  */
82
114
  export function buildMergeTags(
83
- state: Record<string, unknown> | null | undefined,
84
- scope: Record<string, unknown> | null | undefined,
85
- localScope: Record<string, unknown> | null = null,
115
+ state: Readonly<Record<string, JxStateDefinition>> | null | undefined,
116
+ scope: ScopeRecord | null | undefined,
117
+ localScope: ScopeRecord | null = null,
86
118
  ): MergeTag[] {
87
119
  const out: MergeTag[] = [];
88
120
  const defs = state ?? {};
@@ -103,13 +135,20 @@ export function buildMergeTags(
103
135
  }
104
136
 
105
137
  if (localScope) {
106
- const map = unwrapSignal(localScope.$map) as { item?: unknown; index?: unknown } | undefined;
107
- if (map && typeof map === "object") {
108
- out.push({ category: "repeater", hint: previewHint(map.item), label: "item", token: "item" });
109
- walk(map.item, "item", "repeater", 0, out);
138
+ const map = unwrapScopeValue(localScope.$map);
139
+ if (isNonNullObject(map)) {
140
+ // An array `$map` has no `item` / `index` members, so it reads as an empty row.
141
+ const row = isScopeRecord(map) ? map : undefined;
142
+ out.push({
143
+ category: "repeater",
144
+ hint: previewHint(row?.item),
145
+ label: "item",
146
+ token: "item",
147
+ });
148
+ walk(row?.item, "item", "repeater", 0, out);
110
149
  out.push({
111
150
  category: "repeater",
112
- hint: previewHint(map.index),
151
+ hint: previewHint(row?.index),
113
152
  label: "index",
114
153
  token: "index",
115
154
  });
@@ -12,12 +12,22 @@
12
12
  * Pure and DOM-free: deps limited to `@jxsuite/schema` guards/types + {@link getNodeAtPath}.
13
13
  */
14
14
 
15
- import { isRef } from "@jxsuite/schema/guards";
16
- import { getNodeAtPath } from "../state";
15
+ import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
16
+ import {
17
+ isJsonObject,
18
+ isMappedArray,
19
+ isNonNullObject,
20
+ isRef,
21
+ isString,
22
+ } from "@jxsuite/schema/guards";
17
23
 
18
24
  import type { JxPath } from "../state";
19
- import type { ContentSectionEntry } from "../types";
20
- import type { JxMappedArray, JxMutableNode, ProjectConfig } from "@jxsuite/schema/types";
25
+ import type {
26
+ JxMappedArray,
27
+ JxMutableNode,
28
+ JxStateDefinition,
29
+ ProjectConfig,
30
+ } from "@jxsuite/schema/types";
21
31
 
22
32
  /** Cap on how many inferred/declared fields we enumerate (mirrors merge-tags BREADTH_CAP breadth). */
23
33
  const FIELD_CAP = 50;
@@ -44,18 +54,16 @@ export function findEnclosingRepeater(
44
54
  if (mapIdx <= 0) {
45
55
  return null;
46
56
  }
47
- const node = getNodeAtPath(doc, path.slice(0, mapIdx)) as
48
- | (Record<string, unknown> & JxMappedArray)
49
- | undefined;
50
- return node && node.$prototype === "Array" ? (node as JxMappedArray) : null;
57
+ const node = getNodeAtPath(doc, path.slice(0, mapIdx));
58
+ return isMappedArray(node) ? node : null;
51
59
  }
52
60
 
53
61
  /** Strip a `#/state/<name>` JSON-Pointer ref to its bare state name (null when it is not one). */
54
- function refToStateName(ref: unknown): string | null {
55
- if (!isRef(ref)) {
62
+ function refToStateName(binding: JxMappedArray["items"]): string | null {
63
+ if (!isRef(binding)) {
56
64
  return null;
57
65
  }
58
- const { $ref: target } = ref;
66
+ const { $ref: target } = binding;
59
67
  return target.startsWith("#/state/") ? target.slice("#/state/".length) : null;
60
68
  }
61
69
 
@@ -85,25 +93,28 @@ function safeFields(names: string[]): string[] {
85
93
  */
86
94
  export function resolveRepeaterItemFields(
87
95
  arrayNode: JxMappedArray,
88
- state: Record<string, unknown> | null | undefined,
96
+ state: Readonly<Record<string, JxStateDefinition>> | null | undefined,
89
97
  projectConfig: ProjectConfig | null | undefined,
90
98
  ): string[] {
91
99
  const base = ["item", "index"];
92
- const { items } = arrayNode as { items?: unknown };
100
+ const { items } = arrayNode;
93
101
  const defs = state ?? {};
94
102
 
95
103
  const stateName = refToStateName(items);
96
104
  if (stateName) {
97
- const def = defs[stateName] as Record<string, unknown> | undefined;
98
- if (def && typeof def === "object") {
105
+ const def = defs[stateName];
106
+ if (isJsonObject(def)) {
99
107
  // (a) Content collection — `{ contentType: "<name>" }`. Import-aliased `$prototype` still
100
108
  // Matches because we detect on the `contentType` string, not the prototype name.
101
- if (typeof def.contentType === "string") {
102
- const content = (projectConfig?.content ?? {}) as Record<string, ContentSectionEntry>;
103
- const ct = content[def.contentType];
104
- const props = ct?.schema?.properties;
109
+ if (isString(def.contentType)) {
110
+ /* The `content` section is contributed by an extension and absorbed by the project
111
+ config's index signature, so each level is checked before it is read. */
112
+ const content = projectConfig?.content;
113
+ const ct = isJsonObject(content) ? content[def.contentType] : undefined;
114
+ const ctSchema = isJsonObject(ct) ? ct.schema : undefined;
115
+ const props = isJsonObject(ctSchema) ? ctSchema.properties : undefined;
105
116
  const out = [...base, "item.id", "item.body"];
106
- if (props && typeof props === "object") {
117
+ if (isNonNullObject(props)) {
107
118
  for (const f of safeFields(Object.keys(props))) {
108
119
  out.push(`item.data.${f}`);
109
120
  }
@@ -112,14 +123,14 @@ export function resolveRepeaterItemFields(
112
123
  }
113
124
 
114
125
  // (b) State array — declared object item-schema, or inferred from a sample default[0].
115
- const itemsSchema = def.items as Record<string, unknown> | undefined;
116
- const declared = itemsSchema?.properties as Record<string, unknown> | undefined;
117
- if (declared && typeof declared === "object") {
126
+ const itemsSchema = def.items;
127
+ const declared = isJsonObject(itemsSchema) ? itemsSchema.properties : undefined;
128
+ if (isNonNullObject(declared)) {
118
129
  return [...base, ...safeFields(Object.keys(declared)).map((f) => `item.${f}`)];
119
130
  }
120
- const defaults = def.default as unknown[] | undefined;
121
- const sample: unknown = Array.isArray(defaults) ? defaults[0] : undefined;
122
- if (sample && typeof sample === "object" && !Array.isArray(sample)) {
131
+ const defaults = def.default;
132
+ const sample = Array.isArray(defaults) ? defaults[0] : undefined;
133
+ if (isJsonObject(sample)) {
123
134
  return [...base, ...safeFields(Object.keys(sample)).map((f) => `item.${f}`)];
124
135
  }
125
136
  }
@@ -128,8 +139,8 @@ export function resolveRepeaterItemFields(
128
139
 
129
140
  // (c) Inline literal array — infer fields from the first object element.
130
141
  if (Array.isArray(items)) {
131
- const [first] = items as unknown[];
132
- if (first && typeof first === "object" && !Array.isArray(first)) {
142
+ const [first] = items;
143
+ if (isJsonObject(first)) {
133
144
  return [...base, ...safeFields(Object.keys(first)).map((f) => `item.${f}`)];
134
145
  }
135
146
  }