@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
@@ -51,11 +51,21 @@ import type {
51
51
  SerializableRect,
52
52
  } from "./iframe-protocol";
53
53
  import type { DocPos } from "./iframe-position";
54
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
54
55
  import type { JxPath } from "../state";
55
56
  import type { JxMutableNode } from "@jxsuite/schema/types";
56
57
 
58
+ /** The commit a block session posts when its text reaches the document. */
59
+ type EditCommitMsg = Extract<IframeToParent, { kind: "editCommit" }>;
60
+
61
+ /** The commit a prop-bound session posts for its instance's `$props` value. */
62
+ type EditCommitPropMsg = Extract<IframeToParent, { kind: "editCommitProp" }>;
63
+
64
+ /** The toolbar commands that toggle an inline tag (every intent but `link` and `insertData`). */
65
+ type InlineFormatCommand = Exclude<ApplyFormatIntent["command"], "link" | "insertData">;
66
+
57
67
  /** Toolbar command → inline tag (mirrors the parent's old `cmdToTag`, now iframe-side). */
58
- const CMD_TO_TAG: Record<string, string> = {
68
+ const CMD_TO_TAG = {
59
69
  bold: "strong",
60
70
  code: "code",
61
71
  italic: "em",
@@ -63,7 +73,19 @@ const CMD_TO_TAG: Record<string, string> = {
63
73
  subscript: "sub",
64
74
  superscript: "sup",
65
75
  underline: "u",
66
- };
76
+ } satisfies Record<InlineFormatCommand, string>;
77
+
78
+ /**
79
+ * The CSS Custom Highlight API as this realm may or may not provide it. lib.dom declares both
80
+ * members unconditionally, but happy-dom and non-Chromium engines ship neither.
81
+ */
82
+ interface HighlightRealm {
83
+ Highlight?: typeof Highlight;
84
+ CSS?: { highlights?: HighlightRegistry };
85
+ }
86
+
87
+ /** The global object, read through the optional shape above so the feature probes stay honest. */
88
+ const highlightRealm: HighlightRealm = globalThis;
67
89
 
68
90
  /** Inline tags whose active state the snapshot reports (everything except `a`, handled via link). */
69
91
  const ACTIVE_TAG_PROBES = ["strong", "em", "u", "del", "sub", "sup", "code"];
@@ -125,19 +147,19 @@ function deliveredOutsideProps(node: JxMutableNode | undefined, prop: string): b
125
147
  if (!node) {
126
148
  return false;
127
149
  }
128
- const attrs = node.attributes as Record<string, unknown> | undefined;
150
+ const attrs = node.attributes;
129
151
  if (attrs) {
130
152
  if (attrs[`props.${prop}`] !== undefined) {
131
153
  return true;
132
154
  }
133
155
  const reflected = new Set([prop.toLowerCase(), camelToKebab(prop).toLowerCase()]);
134
- for (const [name, val] of Object.entries(attrs)) {
135
- if (val !== undefined && reflected.has(name.toLowerCase())) {
156
+ for (const name of Object.keys(attrs)) {
157
+ if (attrs[name] !== undefined && reflected.has(name.toLowerCase())) {
136
158
  return true;
137
159
  }
138
160
  }
139
161
  const payload = attrs["data-jx-props"];
140
- if (typeof payload === "string" && payloadNames(payload, prop)) {
162
+ if (isString(payload) && payloadNames(payload, prop)) {
141
163
  return true;
142
164
  }
143
165
  }
@@ -145,14 +167,14 @@ function deliveredOutsideProps(node: JxMutableNode | undefined, prop: string): b
145
167
  if (RESERVED_KEYS.has(prop) || prop.startsWith("$")) {
146
168
  return false;
147
169
  }
148
- return (node as Record<string, unknown>)[prop] !== undefined;
170
+ return node[prop] !== undefined;
149
171
  }
150
172
 
151
173
  /** Whether a `data-jx-props` JSON payload carries `prop`. Unparseable payloads deliver nothing. */
152
174
  function payloadNames(payload: string, prop: string): boolean {
153
175
  try {
154
176
  const parsed: unknown = JSON.parse(payload);
155
- return typeof parsed === "object" && parsed !== null && prop in parsed;
177
+ return isNonNullObject(parsed) && prop in parsed;
156
178
  } catch {
157
179
  return false;
158
180
  }
@@ -238,11 +260,8 @@ export function startIframeInlineEdit(
238
260
  * `Highlight`/`CSS.highlights`, so this is a silent no-op there (and in non-Chromium engines).
239
261
  */
240
262
  const updateHighlight = () => {
241
- const HighlightCtor = (globalThis as { Highlight?: unknown }).Highlight as
242
- | (new (range: Range) => unknown)
243
- | undefined;
244
- const highlights = (globalThis.CSS as unknown as { highlights?: Map<string, unknown> })
245
- ?.highlights;
263
+ const HighlightCtor = highlightRealm.Highlight;
264
+ const highlights = highlightRealm.CSS?.highlights;
246
265
  if (!HighlightCtor || !highlights) {
247
266
  return;
248
267
  }
@@ -256,9 +275,7 @@ export function startIframeInlineEdit(
256
275
 
257
276
  /** Tear down the Custom Highlight (on teardown / real editEnd). */
258
277
  const clearHighlight = () => {
259
- const highlights = (globalThis.CSS as unknown as { highlights?: Map<string, unknown> })
260
- ?.highlights;
261
- highlights?.delete(HIGHLIGHT_NAME);
278
+ highlightRealm.CSS?.highlights?.delete(HIGHLIGHT_NAME);
262
279
  };
263
280
 
264
281
  /**
@@ -309,6 +326,9 @@ export function startIframeInlineEdit(
309
326
  }
310
327
  };
311
328
 
329
+ /** Whether this typing burst's first keystroke has been announced (`editInput`). */
330
+ let inputAnnounced = false;
331
+
312
332
  const enterEditAt = (el: HTMLElement, path: JxPath) => {
313
333
  // Show raw `${expr}` syntax for editing (the render displays it as ❪ expr ❫).
314
334
  restoreTemplateExpressions(el);
@@ -316,14 +336,14 @@ export function startIframeInlineEdit(
316
336
  startEditing(el, path, {
317
337
  // `inPlace` rides along only when set: a release commit is the common case and the flag is
318
338
  // Optional, so omitting it keeps the message shape unchanged for every non-tick commit.
319
- onCommit: (p, children, textContent, inPlace) =>
320
- channel.post({
321
- children,
322
- kind: "editCommit",
323
- path: p,
324
- textContent,
325
- ...(inPlace ? { inPlace: true } : {}),
326
- }),
339
+ onCommit: (p, children, textContent, inPlace) => {
340
+ inputAnnounced = false;
341
+ const commit: EditCommitMsg = { children, kind: "editCommit", path: p, textContent };
342
+ if (inPlace) {
343
+ commit.inPlace = true;
344
+ }
345
+ channel.post(commit);
346
+ },
327
347
  onEnd: () => {
328
348
  clearHighlight();
329
349
  lastNonEmptyRange = null;
@@ -351,11 +371,11 @@ export function startIframeInlineEdit(
351
371
  if (!shadowDoc) {
352
372
  return true;
353
373
  }
354
- const node = getNodeAtPath(shadowDoc, hostPath) as JxMutableNode | undefined;
374
+ const node = getNodeAtPath(shadowDoc, hostPath);
355
375
  if (deliveredOutsideProps(node, prop)) {
356
376
  return false;
357
377
  }
358
- const raw = (node?.$props as Record<string, unknown> | undefined)?.[prop];
378
+ const raw = node?.$props?.[prop];
359
379
  if (raw == null) {
360
380
  return true; // Unset — editing ADDS the prop, overriding the definition default.
361
381
  }
@@ -366,7 +386,7 @@ export function startIframeInlineEdit(
366
386
  * Objects were already excluded; the scalar cases were not, and are the ones a component
367
387
  * actually declares. They stay editable in the properties panel, which knows their type.
368
388
  */
369
- if (typeof raw !== "string") {
389
+ if (!isString(raw)) {
370
390
  return false;
371
391
  }
372
392
  return !raw.includes("${");
@@ -383,14 +403,19 @@ export function startIframeInlineEdit(
383
403
  el,
384
404
  hostPath,
385
405
  {
386
- onCommit: (p, _children, textContent, inPlace) =>
387
- channel.post({
406
+ onCommit: (p, _children, textContent, inPlace) => {
407
+ inputAnnounced = false;
408
+ const commit: EditCommitPropMsg = {
388
409
  kind: "editCommitProp",
389
410
  path: p,
390
411
  prop,
391
412
  value: textContent ?? "",
392
- ...(inPlace ? { inPlace: true } : {}),
393
- }),
413
+ };
414
+ if (inPlace) {
415
+ commit.inPlace = true;
416
+ }
417
+ channel.post(commit);
418
+ },
394
419
  onEnd: () => {
395
420
  clearHighlight();
396
421
  lastNonEmptyRange = null;
@@ -512,6 +537,7 @@ export function startIframeInlineEdit(
512
537
  if (start === -1 || end === -1 || end <= start) {
513
538
  return false;
514
539
  }
540
+ // SAFETY: `blocksInOrder` selects `[data-jx-path]`, so every block it returns carries the key.
515
541
  const between = blocks
516
542
  .slice(start + 1, end)
517
543
  .map((el) => parseJxPath(el.dataset.jxPath as string));
@@ -566,12 +592,22 @@ export function startIframeInlineEdit(
566
592
  owns what a slash MEANS (start of a block or after a space; anywhere else it is punctuation).
567
593
  The matching `input` half re-filters the open menu, for the same reason: a contenteditable's
568
594
  `input` targets its host, not the block the caret happens to be in. */
569
- const onSlashKey = (e: Event) => handleSlashTrigger(e as KeyboardEvent);
595
+ const onSlashKey = (e: KeyboardEvent) => handleSlashTrigger(e);
570
596
  const onSlashInput = () => {
571
597
  if (isSlashActive()) {
572
598
  refreshSlashMenu();
573
599
  }
574
600
  };
601
+ /* Typed text reaches the document on the idle tick, half a second later. The parent hears about
602
+ the burst on its first keystroke instead, so its Save is not disabled over words a save would
603
+ keep. Once per burst: the flag re-arms when the burst commits. */
604
+ const onEditInput = () => {
605
+ if (!inputAnnounced) {
606
+ inputAnnounced = true;
607
+ channel.post({ kind: "editInput" });
608
+ }
609
+ };
610
+ container.addEventListener("input", onEditInput);
575
611
  container.addEventListener("keydown", onSlashKey);
576
612
  container.addEventListener("input", onSlashInput);
577
613
  doc.addEventListener("mouseup", onMouseUp, true);
@@ -639,6 +675,7 @@ export function startIframeInlineEdit(
639
675
  return () => {
640
676
  container.removeEventListener("keydown", onSlashKey);
641
677
  container.removeEventListener("input", onSlashInput);
678
+ container.removeEventListener("input", onEditInput);
642
679
  doc.removeEventListener("mouseup", onMouseUp, true);
643
680
  doc.removeEventListener("keyup", onKeyUp, true);
644
681
  doc.removeEventListener("blur", onBlurCapture, true);
@@ -17,6 +17,7 @@
17
17
  * (happy-dom's `elementFromPoint` returns null) and lives in iframe-interaction.
18
18
  */
19
19
 
20
+ import { isNumber } from "@jxsuite/schema/guards";
20
21
  import { parseJxPath } from "./path-mapping";
21
22
  import { rectOf } from "../utils/geometry";
22
23
  import { childIndex, parentElementPath } from "../state";
@@ -48,7 +49,7 @@ function isRowLayout(parent: HTMLElement): boolean {
48
49
  const isGrid = display === "grid" || display === "inline-grid";
49
50
  return (
50
51
  (isFlex && style.flexDirection.startsWith("row")) ||
51
- (isGrid && (style.gridAutoFlow ?? "").startsWith("column"))
52
+ (isGrid && style.gridAutoFlow.startsWith("column"))
52
53
  );
53
54
  }
54
55
 
@@ -78,11 +79,11 @@ export function computeInsertZones(
78
79
  shadowDoc: JxMutableNode,
79
80
  ): InsertZone[] | null {
80
81
  void shadowDoc;
81
- const serialized = targetEl.dataset?.jxPath;
82
+ const serialized = targetEl.dataset.jxPath;
82
83
  if (serialized == null) {
83
84
  return null;
84
85
  }
85
- const targetPath = parseJxPath(serialized) as JxPath;
86
+ const targetPath = parseJxPath(serialized);
86
87
 
87
88
  // Empty container: one centered "+" that inserts as the container's first child.
88
89
  if (targetEl.classList.contains(EMPTY_CONTAINER_CLASS)) {
@@ -99,7 +100,7 @@ export function computeInsertZones(
99
100
  return null;
100
101
  }
101
102
  const childIdx = childIndex(targetPath);
102
- if (typeof childIdx !== "number") {
103
+ if (!isNumber(childIdx)) {
103
104
  return null;
104
105
  }
105
106
 
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { jxPathSelector, parseJxPath, serializeJxPath } from "./path-mapping";
10
+ import { isFunction } from "@jxsuite/schema/guards";
10
11
  import { rectOf } from "../utils/geometry";
11
12
  import { computeInsertZones, insertZonesKey } from "./iframe-insert";
12
13
  import { getActiveElement, isEditing } from "../editor/inline-edit";
@@ -32,9 +33,10 @@ function isCanvasLeave(e: Event, doc: Document): boolean {
32
33
 
33
34
  /** Walk up from an element to the nearest ancestor carrying a `data-jx-path`; null if none. */
34
35
  function nearestPathEl(start: Element | null): HTMLElement | null {
35
- let el = start instanceof Element ? (start as HTMLElement) : null;
36
+ let el = start instanceof Element ? start : null;
36
37
  while (el) {
37
- if (el.dataset?.jxPath) {
38
+ // Only HTML elements are stamped (`makeStamper` skips everything else), so only they can match.
39
+ if (el instanceof HTMLElement && el.dataset.jxPath) {
38
40
  return el;
39
41
  }
40
42
  el = el.parentElement;
@@ -57,6 +59,7 @@ export function nearestHit(target: EventTarget | null): NodeHit | null {
57
59
  if (!el) {
58
60
  return null;
59
61
  }
62
+ // SAFETY: nearestPathEl returns only an element whose `data-jx-path` is a non-empty string.
60
63
  return measureHit(el, el.dataset.jxPath as string);
61
64
  }
62
65
 
@@ -75,8 +78,9 @@ export function nearestHit(target: EventTarget | null): NodeHit | null {
75
78
  * from a node that is on screen is a worse failure than drawing one for a node that is not.
76
79
  */
77
80
  function isRendered(el: Element): boolean {
78
- const check = (el as { checkVisibility?: (o?: object) => boolean }).checkVisibility;
79
- return typeof check === "function" ? check.call(el, { checkVisibilityCSS: true }) : true;
81
+ // Absent on engines that predate it, whatever lib.dom says.
82
+ const check: Element["checkVisibility"] | undefined = el.checkVisibility;
83
+ return isFunction(check) ? check.call(el, { checkVisibilityCSS: true }) : true;
80
84
  }
81
85
 
82
86
  /**
@@ -92,10 +96,7 @@ function isRendered(el: Element): boolean {
92
96
  * The serialized path is the same string the renderer stamps, so a stored selection path
93
97
  * round-trips back to its element.
94
98
  */
95
- export function measureHits(
96
- paths: (string | number)[][],
97
- doc: Document = document,
98
- ): { hits: NodeHit[]; hidden: (string | number)[][] } {
99
+ export function measureHits(paths: (string | number)[][], doc: Document = document) {
99
100
  const hits: NodeHit[] = [];
100
101
  const hidden: (string | number)[][] = [];
101
102
  for (const path of paths) {
@@ -119,8 +120,15 @@ export function measureHits(
119
120
  * {@link file://./iframe-drop.ts}'s `startGrabDetector` receives its deps rather than reaching for
120
121
  * module state.
121
122
  */
123
+ type InvokerAction = Extract<IframeToParent, { kind: "popoverTargetClick" }>["action"];
124
+
122
125
  /** The three `popovertargetaction` keywords. Anything else falls back to the HTML default. */
123
- const INVOKER_ACTIONS = new Set(["toggle", "show", "hide"]);
126
+ const INVOKER_ACTIONS = new Set<string>(["toggle", "show", "hide"] satisfies InvokerAction[]);
127
+
128
+ /** Whether an attribute value is one of the {@link INVOKER_ACTIONS} keywords. */
129
+ function isInvokerAction(value: string): value is InvokerAction {
130
+ return INVOKER_ACTIONS.has(value);
131
+ }
124
132
 
125
133
  /**
126
134
  * Report an invoker click, when the click landed on one and it names an addressable popover.
@@ -152,14 +160,14 @@ function postPopoverInvoke(
152
160
  need escaping — a rule this file already keeps in exactly one place (`jxPathSelector`) and
153
161
  should not gain a second spelling of. The set scanned is the addressable POPOVERS, which is
154
162
  also the set the answer has to come from, so the scan is the test. */
155
- const panels = invoker.ownerDocument.querySelectorAll("[data-jx-popover]");
156
- const panel = [...panels].find((el) => el.id === id) as HTMLElement | undefined;
163
+ const panels = invoker.ownerDocument.querySelectorAll<HTMLElement>("[data-jx-popover]");
164
+ const panel = [...panels].find((el) => el.id === id);
157
165
  const serialized = panel?.dataset.jxPath;
158
166
  if (!serialized) {
159
167
  return;
160
168
  }
161
169
  const raw = invoker.getAttribute("popovertargetaction") ?? "toggle";
162
- const action = INVOKER_ACTIONS.has(raw) ? (raw as "toggle" | "show" | "hide") : "toggle";
170
+ const action = isInvokerAction(raw) ? raw : "toggle";
163
171
  channel.post({ action, kind: "popoverTargetClick", targetPath: parseJxPath(serialized) });
164
172
  }
165
173
 
@@ -190,10 +198,10 @@ function postCommandInvoke(
190
198
  }
191
199
  // Scanned, not selected, for the reason `postPopoverInvoke` gives; the addressable overlays are
192
200
  // The de-popovered panels and the stamped dialogs.
193
- const overlays = invoker.ownerDocument.querySelectorAll(
201
+ const overlays = invoker.ownerDocument.querySelectorAll<HTMLElement>(
194
202
  "[data-jx-popover], dialog[data-jx-path]",
195
203
  );
196
- const overlay = [...overlays].find((el) => el.id === id) as HTMLElement | undefined;
204
+ const overlay = [...overlays].find((el) => el.id === id);
197
205
  const serialized = overlay?.dataset.jxPath;
198
206
  if (!serialized) {
199
207
  return;
@@ -270,7 +278,7 @@ export function startInteraction(
270
278
  channel.post({ kind: "paneFocus" });
271
279
  };
272
280
 
273
- const onClick = (e: Event) => {
281
+ const onClick = (e: MouseEvent) => {
274
282
  /*
275
283
  * Preview keeps anchors live, so a click would navigate this iframe and destroy the render (and
276
284
  * the editing session with it). Report the intent so the parent can open the real page in a real
@@ -278,7 +286,8 @@ export function startInteraction(
278
286
  * rather than replacing the canvas with a half-loaded page.
279
287
  *
280
288
  * Design/edit never reach this: the runtime de-links anchors onto `data-jx-href` there, so there
281
- * is no navigation to intercept and a click means "select this element".
289
+ * is no navigation to intercept and a click means "select this element". Project Styles keeps
290
+ * its specimens' links live and refuses the navigation just below.
282
291
  */
283
292
  if (isPreview()) {
284
293
  if (e.target instanceof Element) {
@@ -292,14 +301,18 @@ export function startInteraction(
292
301
  // No hit post: a click in preview is a click on the page, never a selection.
293
302
  return;
294
303
  }
304
+ // Project Styles keeps its link specimen live (`iframe-render.ts`), so a click on it must
305
+ // Select it rather than follow it.
306
+ if (deps?.getMode?.() === "stylebook" && e.target instanceof Element && e.target.closest("a")) {
307
+ e.preventDefault();
308
+ }
295
309
  const hit = nearestHit(e.target);
296
310
  if (hit) {
297
311
  // Ctrl/Cmd is the accumulate gesture (studio-ui-guidelines.md §8.1). The iframe reports the
298
312
  // Modifier and nothing else — it holds no selection state, so what a modified click MEANS is
299
313
  // The parent's to decide, exactly as the unmodified click already was.
300
- const mouse = e as MouseEvent;
301
314
  channel.post({
302
- additive: mouse.ctrlKey === true || mouse.metaKey === true,
315
+ additive: e.ctrlKey === true || e.metaKey === true,
303
316
  hit,
304
317
  kind: "hit",
305
318
  });
@@ -388,11 +401,10 @@ export function startInteraction(
388
401
  reportInsertZones(target, { x: moveX, y: moveY });
389
402
  };
390
403
 
391
- const onMove = (e: Event) => {
392
- const pe = e as PointerEvent;
404
+ const onMove = (e: PointerEvent) => {
393
405
  moveTarget = e.target;
394
- moveX = pe.clientX;
395
- moveY = pe.clientY;
406
+ moveX = e.clientX;
407
+ moveY = e.clientY;
396
408
  if (movePending) {
397
409
  return;
398
410
  }
@@ -409,8 +421,7 @@ export function startInteraction(
409
421
  }
410
422
  };
411
423
 
412
- const onContextMenu = (e: Event) => {
413
- const me = e as MouseEvent;
424
+ const onContextMenu = (e: MouseEvent) => {
414
425
  // Preview keeps the NATIVE menu: the Jx element menu's verbs (duplicate, delete, paste, wrap)
415
426
  // Are document edits, and preview does not edit. Copy Link Address does what it says instead.
416
427
  if (isPreview()) {
@@ -441,8 +452,8 @@ export function startInteraction(
441
452
  channel.post({
442
453
  kind: "contextMenu",
443
454
  path: hit.path,
444
- x: me.clientX,
445
- y: me.clientY,
455
+ x: e.clientX,
456
+ y: e.clientY,
446
457
  });
447
458
  };
448
459
 
@@ -47,7 +47,7 @@ export function parentCursorToIframe(
47
47
  cursor: { x: number; y: number },
48
48
  iframeRect: { left: number; top: number },
49
49
  scale = 1,
50
- ): { x: number; y: number } {
50
+ ) {
51
51
  return {
52
52
  x: (cursor.x - iframeRect.left) / scale,
53
53
  y: (cursor.y - iframeRect.top) / scale,
@@ -15,7 +15,8 @@
15
15
  */
16
16
 
17
17
  import { reapplyStyle } from "@jxsuite/runtime";
18
- import { getNodeAtPath } from "../state";
18
+ import { isNonNullObject, isNumber, isString } from "@jxsuite/schema/guards";
19
+ import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
19
20
  import { applyDocOpToDoc } from "../tabs/doc-op-apply";
20
21
  import { parseJxPath, serializeJxPath } from "./path-mapping";
21
22
  import { disposeSubtree, renderSubtreeIframe } from "./iframe-subtree";
@@ -25,7 +26,7 @@ import {
25
26
  templateToEditDisplay,
26
27
  } from "../utils/edit-display";
27
28
  import type { IframeRenderCtx } from "./iframe-render";
28
- import type { WireDocOp } from "./iframe-protocol";
29
+ import type { JxDocOp } from "../tabs/patch-ops";
29
30
  import type { JxPath } from "../state";
30
31
  import type { JxMutableNode, JxStyle } from "@jxsuite/schema/types";
31
32
 
@@ -36,7 +37,7 @@ import type { JxMutableNode, JxStyle } from "@jxsuite/schema/types";
36
37
  */
37
38
  export function applyIframePatch(
38
39
  shadowDoc: JxMutableNode,
39
- forwardOps: WireDocOp[],
40
+ forwardOps: JxDocOp[],
40
41
  container: HTMLElement,
41
42
  ctx?: IframeRenderCtx,
42
43
  echoPaths?: JxPath[],
@@ -98,7 +99,7 @@ function requireCtx(ctx: IframeRenderCtx | undefined): IframeRenderCtx {
98
99
 
99
100
  function applyOpToDom(
100
101
  doc: JxMutableNode,
101
- op: WireDocOp,
102
+ op: JxDocOp,
102
103
  container: HTMLElement,
103
104
  ctx: IframeRenderCtx | undefined,
104
105
  ): void {
@@ -138,7 +139,7 @@ function applyOpToDom(
138
139
  return;
139
140
  }
140
141
  default: {
141
- // The WireDocOp union is exhaustively handled above; this guards a future op kind.
142
+ // The JxDocOp union is exhaustively handled above; this guards a future op kind.
142
143
  throw new Error(`iframe-patch-unsupported-op:${JSON.stringify(op)}`);
143
144
  }
144
145
  }
@@ -292,7 +293,7 @@ function remapChildPaths(
292
293
  continue;
293
294
  }
294
295
  const idx = p[depth + 1];
295
- if (typeof idx !== "number" || idx < fromIndex) {
296
+ if (!isNumber(idx) || idx < fromIndex) {
296
297
  continue;
297
298
  }
298
299
  if (!parentPath.every((seg, i) => p[i] === seg)) {
@@ -338,7 +339,9 @@ function patchStyle(
338
339
  ): void {
339
340
  const el = requireElement(container, path);
340
341
  const node = getNodeAtPath(doc, path);
341
- const mediaQueries = (ctx?.defs?.["$media"] as Record<string, string> | undefined) ?? {};
342
+ /* SAFETY: buildScope writes `$media` only from the document's own `$media` map or the runtime's
343
+ * root media map, both Record<string, string>, and the host scope may not supply the key. */
344
+ const mediaQueries = (ctx?.defs["$media"] as Record<string, string> | undefined) ?? {};
342
345
  reapplyStyle(el, editModeStyle(node?.style), mediaQueries);
343
346
  }
344
347
 
@@ -372,20 +375,20 @@ function findElement(container: HTMLElement, path: (string | number)[]): HTMLEle
372
375
  * top-level template-string values are blanked so no reactive bindings are created for them.
373
376
  */
374
377
  function editModeStyle(style: JxStyle | undefined): JxStyle | undefined {
375
- if (!style || typeof style !== "object") {
378
+ if (!style || !isNonNullObject(style)) {
376
379
  return undefined;
377
380
  }
378
- const out: Record<string, unknown> = {};
381
+ const out: JxStyle = {};
379
382
  for (const [k, v] of Object.entries(style)) {
380
383
  /* OMITTED, not blanked. It used to be written as `""`, which was a silent no-op while a
381
384
  declaration went to `el.style` and is a malformed declaration now that it goes into a rule.
382
385
  Dropping the key is what blanking always meant: the property falls back to the cascade. */
383
- if (typeof v === "string" && v.includes("${")) {
386
+ if (isString(v) && v.includes("${")) {
384
387
  continue;
385
388
  }
386
389
  out[k] = v;
387
390
  }
388
- return out as JxStyle;
391
+ return out;
389
392
  }
390
393
 
391
394
  /**
@@ -393,15 +396,15 @@ function editModeStyle(style: JxStyle | undefined): JxStyle | undefined {
393
396
  * template-string and $ref display rules (and the legacy patcher's textDisplayValue).
394
397
  */
395
398
  function textDisplayValue(node: JxMutableNode | undefined): string {
396
- const v = (node as { textContent?: unknown } | undefined)?.textContent;
399
+ const v = node?.textContent;
397
400
  if (v == null) {
398
401
  return "";
399
402
  }
400
- if (typeof v === "string") {
403
+ if (isString(v)) {
401
404
  return v.includes("${") ? templateToEditDisplay(v) : v;
402
405
  }
403
- if (typeof v === "object" && (v as Record<string, unknown>).$ref) {
404
- const ref = String((v as Record<string, unknown>).$ref);
406
+ if (isNonNullObject(v) && v.$ref) {
407
+ const ref = String(v.$ref);
405
408
  const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
406
409
  return `{${label}}`;
407
410
  }
@@ -33,6 +33,12 @@ export interface DocRange {
33
33
  head: DocPos;
34
34
  }
35
35
 
36
+ /** A live DOM caret position: a node and an offset into it, as a Selection endpoint carries. */
37
+ export interface DomPosition {
38
+ node: Node;
39
+ offset: number;
40
+ }
41
+
36
42
  /** Whether an element is a block the caret may live inside. Injected so the editable set is policy. */
37
43
  export type EditablePredicate = (el: HTMLElement) => boolean;
38
44
 
@@ -91,7 +97,7 @@ export function elementForPath(container: HTMLElement, path: JxPath): HTMLElemen
91
97
 
92
98
  /** The block's rendered text length — the maximum valid offset within it. */
93
99
  export function blockTextLength(block: HTMLElement): number {
94
- return block.textContent?.length ?? 0;
100
+ return block.textContent.length;
95
101
  }
96
102
 
97
103
  /**
@@ -126,11 +132,12 @@ export function offsetOf(block: HTMLElement, node: Node, offset: number): number
126
132
  * every offset-based editor carries at a line break, and it is invisible for the paths that use
127
133
  * this (caret restore after a patch, and block-boundary edits, which clamp to 0 / length anyway).
128
134
  */
129
- export function domPositionAt(block: HTMLElement, offset: number): { node: Node; offset: number } {
135
+ export function domPositionAt(block: HTMLElement, offset: number): DomPosition {
130
136
  const target = Math.max(0, Math.min(offset, blockTextLength(block)));
131
137
  const walker = block.ownerDocument.createTreeWalker(block, NodeFilter.SHOW_TEXT);
132
138
  let seen = 0;
133
139
  let last: Text | null = null;
140
+ // SAFETY: the walker was created with NodeFilter.SHOW_TEXT, so every node it yields is a Text.
134
141
  let current = walker.nextNode() as Text | null;
135
142
  while (current) {
136
143
  const len = current.length;
@@ -139,6 +146,7 @@ export function domPositionAt(block: HTMLElement, offset: number): { node: Node;
139
146
  }
140
147
  seen += len;
141
148
  last = current;
149
+ // SAFETY: the same SHOW_TEXT walker as above, so the next node is a Text or the walk's end.
142
150
  current = walker.nextNode() as Text | null;
143
151
  }
144
152
  // No text node reaches the target: either the block has no text at all (caret goes to the element
@@ -169,10 +177,7 @@ export function toDocPos(
169
177
  * block whose text shrank under a remote edit lands at the block's new end instead of being
170
178
  * dropped.
171
179
  */
172
- export function toDomPosition(
173
- container: HTMLElement,
174
- pos: DocPos,
175
- ): { node: Node; offset: number } | null {
180
+ export function toDomPosition(container: HTMLElement, pos: DocPos): DomPosition | null {
176
181
  const el = elementForPath(container, pos.path);
177
182
  return el ? domPositionAt(el, pos.offset) : null;
178
183
  }
@@ -246,6 +251,7 @@ export function adjacentBlock(
246
251
  const key = serializeJxPath(path);
247
252
  const index = blocks.findIndex((el) => el.dataset.jxPath === key);
248
253
  const neighbour = index === -1 ? undefined : blocks[index + direction];
254
+ // SAFETY: blocksInOrder collects only elements matching `[data-jx-path]`, so the attribute is set.
249
255
  return neighbour
250
256
  ? { el: neighbour, path: parseJxPath(neighbour.dataset.jxPath as string) }
251
257
  : null;