@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
package/src/panels/dnd.ts CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  monitorForElements,
11
11
  } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
12
12
  import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
13
- import { displayTagName } from "@jxsuite/schema/guards";
13
+ import { displayTagName, isNumber } from "@jxsuite/schema/guards";
14
14
  import { disableNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview";
15
15
  import {
16
16
  attachInstruction,
@@ -38,8 +38,10 @@ import { defaultDef, unsafeTags } from "./shared";
38
38
  import { elementAtPoint } from "../utils/geometry";
39
39
  import type { JxPath } from "../state";
40
40
  import type { Tab } from "../tabs/tab";
41
- import type { JxElement, JxMutableNode } from "@jxsuite/schema/types";
41
+ import type { JxMutableNode } from "@jxsuite/schema/types";
42
42
  import type { ComponentEntry } from "../files/components.js";
43
+ import type { ElementDragPayload } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
44
+ import type { DropTargetRecord } from "@atlaskit/pragmatic-drag-and-drop/types";
43
45
 
44
46
  interface DragCanDragArgs {
45
47
  element: HTMLElement;
@@ -51,17 +53,10 @@ interface DragPreviewArgs {
51
53
  nativeSetDragImage: ((image: Element, x: number, y: number) => void) | null;
52
54
  }
53
55
 
54
- interface DragDropSourceArgs {
55
- source: { data: Record<string, unknown>; element: HTMLElement };
56
- }
57
-
58
- interface DragSelfArgs {
59
- self: { data: Record<string, unknown> };
60
- }
61
-
62
- interface DragMonitorDropArgs {
63
- source: { data: Record<string, unknown>; element: HTMLElement };
64
- location: { current: { dropTargets: { data: Record<string, unknown> }[] } };
56
+ /** Where a drop instruction inserts: the parent's path and the index among its children. */
57
+ interface DropSlot {
58
+ parent: JxPath;
59
+ index: number;
65
60
  }
66
61
 
67
62
  /**
@@ -122,23 +117,25 @@ export function registerLayersDnD() {
122
117
  view.dndCleanups = [];
123
118
  _layersFrame = requestAnimationFrame(() => {
124
119
  _layersFrame = null;
125
- const container = leftPanel?.querySelector(OUTLINE_ROOT) as HTMLElement | null;
120
+ const container = leftPanel?.querySelector<HTMLElement>(OUTLINE_ROOT);
126
121
  if (!container) {
127
122
  return;
128
123
  }
129
124
 
130
- for (const row of container.querySelectorAll("[data-dnd-row]") as NodeListOf<HTMLElement>) {
131
- const rowPath = (row.dataset.value as string)
125
+ for (const row of container.querySelectorAll<HTMLElement>("[data-dnd-row]")) {
126
+ /* SAFETY: every `[data-dnd-row]` row is a `jx-tree-item` from panel-outline.json, and the
127
+ element reflects its `value` (the row's path key) onto the host as `data-value`. */
128
+ const rowPath: JxPath = (row.dataset.value as string)
132
129
  .split("/")
133
- .map((s: string) => (/^\d+$/.test(s) ? Math.trunc(Number(s)) : s)) as JxPath;
134
- const rowDepth = Math.trunc(Number(row.dataset.dndDepth as string)) || 0;
130
+ .map((s: string) => (/^\d+$/.test(s) ? Math.trunc(Number(s)) : s));
131
+ const rowDepth = Math.trunc(Number(row.dataset.dndDepth)) || 0;
135
132
  const isVoid = Object.hasOwn(row.dataset, "dndVoid");
136
133
  const isExpanded = Object.hasOwn(row.dataset, "dndExpanded");
137
134
 
138
135
  const cleanup = combine(
139
136
  draggable({
140
137
  canDrag({ element: _el, input }: DragCanDragArgs) {
141
- const target = elementAtPoint(input.clientX, input.clientY) as HTMLElement;
138
+ const target = elementAtPoint(input.clientX, input.clientY);
142
139
  if (target?.closest(OUTLINE_ACTIONS)) {
143
140
  return false;
144
141
  }
@@ -169,9 +166,10 @@ export function registerLayersDnD() {
169
166
  }),
170
167
  dropTargetForElements({
171
168
  element: row,
172
- canDrop({ source }: DragDropSourceArgs) {
173
- const srcPath = source.data.path as JxPath | undefined;
174
- if (srcPath && isAncestor(srcPath, rowPath)) {
169
+ canDrop({ source }) {
170
+ // Only a tree-node drag carries a path array; a file-tree drag's `path` is a string.
171
+ const srcPath = source.data.path;
172
+ if (Array.isArray(srcPath) && isAncestor(srcPath, rowPath)) {
175
173
  return false;
176
174
  }
177
175
  return true;
@@ -193,12 +191,12 @@ export function registerLayersDnD() {
193
191
  input,
194
192
  mode: isExpanded ? "expanded" : "standard",
195
193
  },
196
- ) as Record<string | symbol, unknown>;
194
+ );
197
195
  },
198
- onDragEnter({ self }: DragSelfArgs) {
196
+ onDragEnter({ self }) {
199
197
  showLayerDropGap(row, self.data, container);
200
198
  },
201
- onDrag({ self }: DragSelfArgs) {
199
+ onDrag({ self }) {
202
200
  showLayerDropGap(row, self.data, container);
203
201
  },
204
202
  // No onDragLeave clear — the gap persists while the pointer crosses dead space
@@ -213,7 +211,7 @@ export function registerLayersDnD() {
213
211
 
214
212
  // Global monitor
215
213
  const monitorCleanup = monitorForElements({
216
- onDrop({ source, location }: DragMonitorDropArgs) {
214
+ onDrop({ source, location }) {
217
215
  clearLayerDropGap(container);
218
216
  const [target] = location.current.dropTargets;
219
217
  if (!target) {
@@ -224,7 +222,13 @@ export function registerLayersDnD() {
224
222
  return;
225
223
  }
226
224
  const srcData = source.data;
227
- const targetPath = target.data.path as JxPath;
225
+ /* Only an Outline row's data carries a path. The Logic tab's statement rows attach tree-item
226
+ instructions too, and the drags they accept (statements) are ones applyDropInstruction
227
+ ignores, so a drop there has nothing to apply. */
228
+ const targetPath = target.data.path;
229
+ if (!Array.isArray(targetPath)) {
230
+ return;
231
+ }
228
232
 
229
233
  // If the source had children, persist collapse at the new location
230
234
  const srcRow = srcData.type === "tree-node" && source.element;
@@ -243,7 +247,7 @@ export function registerLayersDnD() {
243
247
  }
244
248
  }
245
249
  },
246
- onDropTargetChange({ location }: DragMonitorDropArgs) {
250
+ onDropTargetChange({ location }) {
247
251
  // Clear the layer gap when the drag moves onto a non-tree target (e.g. a canvas
248
252
  // Element). When there is no target at all, keep the gap so it persists.
249
253
  const [inner] = location.current.dropTargets;
@@ -259,14 +263,12 @@ export function registerLayersDnD() {
259
263
  /** Register DnD on component rows — called from renderLeftPanel when tab=components */
260
264
  export function registerComponentsDnD() {
261
265
  requestAnimationFrame(() => {
262
- const container = leftPanel?.querySelector(".components-section") as HTMLElement | null;
266
+ const container = leftPanel?.querySelector<HTMLElement>(".components-section");
263
267
  if (!container) {
264
268
  return;
265
269
  }
266
270
 
267
- for (const row of container.querySelectorAll(
268
- "[data-component-tag]",
269
- ) as NodeListOf<HTMLElement>) {
271
+ for (const row of container.querySelectorAll<HTMLElement>("[data-component-tag]")) {
270
272
  const tagName = row.dataset.componentTag;
271
273
  if (!tagName) {
272
274
  continue;
@@ -303,11 +305,12 @@ export function registerComponentsDnD() {
303
305
  /** Register DnD on element (HTML block) rows */
304
306
  export function registerElementsDnD() {
305
307
  requestAnimationFrame(() => {
306
- const container = leftPanel?.querySelector('[part="content"]') as HTMLElement | null;
308
+ const container = leftPanel?.querySelector<HTMLElement>('[part="content"]');
307
309
  if (!container) {
308
310
  return;
309
311
  }
310
- for (const row of container.querySelectorAll("[data-block-tag]") as NodeListOf<HTMLElement>) {
312
+ for (const row of container.querySelectorAll<HTMLElement>("[data-block-tag]")) {
313
+ // SAFETY: the selector matched on `data-block-tag`, so the attribute is present and this is its text.
311
314
  const tag = row.dataset.blockTag as string;
312
315
  const preview = row.querySelector(".element-card-preview");
313
316
  if (preview && !preview.firstChild) {
@@ -338,22 +341,22 @@ export function registerElementsDnD() {
338
341
  */
339
342
  function hideDescendantRows(parentRow: HTMLElement, container: HTMLElement) {
340
343
  const prefix = `${parentRow.dataset.value}/`;
341
- const rows = container.querySelectorAll(OUTLINE_ROWS);
344
+ const rows = container.querySelectorAll<HTMLElement>(OUTLINE_ROWS);
342
345
  for (const r of rows) {
343
- if ((r as HTMLElement).dataset.value?.startsWith(prefix)) {
344
- (r as HTMLElement).style.display = "none";
346
+ if (r.dataset.value?.startsWith(prefix)) {
347
+ r.style.display = "none";
345
348
  }
346
349
  }
347
350
  }
348
351
 
349
352
  /**
350
353
  * @param {HTMLElement} rowEl
351
- * @param {Record<string, unknown>} data
354
+ * @param {DropTargetRecord["data"]} data The row's own drop-target data, carrying its instruction.
352
355
  * @param {HTMLElement} container
353
356
  */
354
357
  export function showLayerDropGap(
355
358
  rowEl: HTMLElement,
356
- data: Record<string, unknown>,
359
+ data: DropTargetRecord["data"],
357
360
  container: HTMLElement,
358
361
  ) {
359
362
  const instruction = extractInstruction(data);
@@ -379,18 +382,18 @@ export function showLayerDropGap(
379
382
  view._currentDropTargetRow = rowEl;
380
383
 
381
384
  // Shift rows to create gap
382
- const rows = [...container.querySelectorAll(OUTLINE_ROWS)];
385
+ const rows = [...container.querySelectorAll<HTMLElement>(OUTLINE_ROWS)];
383
386
  const targetIdx = rows.indexOf(rowEl);
384
387
  const gap = view.layerDragSourceHeight;
385
388
 
386
- for (let i = 0; i < rows.length; i++) {
387
- if ((rows[i] as HTMLElement).dataset.dragging !== undefined) {
389
+ for (const [i, row] of rows.entries()) {
390
+ if (row.dataset.dragging !== undefined) {
388
391
  continue;
389
392
  }
390
393
  if (instruction.type === "reorder-above") {
391
- (rows[i] as HTMLElement).style.transform = i >= targetIdx ? `translateY(${gap}px)` : "";
394
+ row.style.transform = i >= targetIdx ? `translateY(${gap}px)` : "";
392
395
  } else {
393
- (rows[i] as HTMLElement).style.transform = i > targetIdx ? `translateY(${gap}px)` : "";
396
+ row.style.transform = i > targetIdx ? `translateY(${gap}px)` : "";
394
397
  }
395
398
  }
396
399
  }
@@ -401,18 +404,53 @@ export function clearLayerDropGap(container: HTMLElement) {
401
404
  delete view._currentDropTargetRow.dataset.drop;
402
405
  view._currentDropTargetRow = null;
403
406
  }
404
- const rows = container.querySelectorAll(OUTLINE_ROWS);
407
+ const rows = container.querySelectorAll<HTMLElement>(OUTLINE_ROWS);
405
408
  for (const r of rows) {
406
- (r as HTMLElement).style.transform = "";
409
+ r.style.transform = "";
407
410
  // Also clear `display:none` left by hideDescendantRows. The row has no `style`
408
411
  // Lit binding, so an imperative style set during the drag survives the post-drop re-render on
409
412
  // Whichever row keeps that key — and a move is exactly the edit that hands a key to a different
410
413
  // Node. (The rows ARE keyed, by `pathKey`; the earlier form of this note said they were not,
411
414
  // Which made the wrong thing sound load-bearing. What is load-bearing is the missing binding.)
412
- (r as HTMLElement).style.display = "";
415
+ r.style.display = "";
413
416
  }
414
417
  }
415
418
 
419
+ /**
420
+ * Where a drop instruction lands relative to `targetPath`.
421
+ *
422
+ * `make-child` appends to the target itself. A reorder lands beside it, which needs a parent and a
423
+ * numeric index, so a reorder (or any other instruction) around a root-level path answers
424
+ * `undefined`: the drop cannot land there at all. `null` is an instruction that lands but inserts
425
+ * nothing, which this module does not apply.
426
+ *
427
+ * @param {JxMutableNode} doc
428
+ * @param {string} type
429
+ * @param {JxPath} targetPath
430
+ * @returns {DropSlot | null | undefined}
431
+ */
432
+ function dropSlot(
433
+ doc: JxMutableNode,
434
+ type: string,
435
+ targetPath: JxPath,
436
+ ): DropSlot | null | undefined {
437
+ if (type === "make-child") {
438
+ return { index: childList(getNodeAtPath(doc, targetPath)).length, parent: targetPath };
439
+ }
440
+ const parent = parentElementPath(targetPath);
441
+ const index = childIndex(targetPath);
442
+ if (!parent || !isNumber(index)) {
443
+ return undefined;
444
+ }
445
+ if (type === "reorder-above") {
446
+ return { index, parent };
447
+ }
448
+ if (type === "reorder-below") {
449
+ return { index: index + 1, parent };
450
+ }
451
+ return null;
452
+ }
453
+
416
454
  /**
417
455
  * Apply a DnD instruction to `tab`'s document. `tab` is the tab whose canvas the drop resolved in
418
456
  * (host-routed for iframe drops — never the active tab at message time, which may have changed
@@ -420,89 +458,39 @@ export function clearLayerDropGap(container: HTMLElement) {
420
458
  *
421
459
  * @param {Tab | null} tab
422
460
  * @param {{ type: string }} instruction
423
- * @param {Record<string, unknown>} srcData
461
+ * @param {ElementDragPayload["data"]} srcData The drag source's own data, as `getInitialData` made
462
+ * it.
424
463
  * @param {JxPath} targetPath
425
464
  */
426
465
  export function applyDropInstruction(
427
466
  tab: Tab | null,
428
467
  instruction: { type: string },
429
- srcData: Record<string, unknown>,
468
+ srcData: ElementDragPayload["data"],
430
469
  targetPath: JxPath,
431
470
  ) {
432
471
  if (!tab) {
433
472
  return;
434
473
  }
435
- const doc = tab.doc.document as JxMutableNode;
436
474
  if (srcData.type === "tree-node") {
475
+ /* SAFETY: both minters of a "tree-node" payload — an Outline row's `getInitialData` and the
476
+ block action bar's drag handle — set `path` to the dragged node's JxPath. */
437
477
  const fromPath = srcData.path as JxPath;
438
- const targetParent = parentElementPath(targetPath) as JxPath;
439
- const targetIdx = childIndex(targetPath) as number;
440
- // Reordering requires a parent and a numeric index; root-level paths can't be
441
- // Reordered around.
442
- if (instruction.type !== "make-child" && (!targetParent || typeof targetIdx !== "number")) {
443
- return;
444
- }
445
-
446
- switch (instruction.type) {
447
- case "reorder-above": {
448
- transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetParent, targetIdx));
449
- break;
450
- }
451
- case "reorder-below": {
452
- transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetParent, targetIdx + 1));
453
- break;
454
- }
455
- case "make-child": {
456
- const target = getNodeAtPath(doc, targetPath);
457
- const len = childList(target).length;
458
- transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetPath, len));
459
- break;
460
- }
461
- default: {
462
- break;
463
- }
478
+ const slot = dropSlot(tab.doc.document, instruction.type, targetPath);
479
+ if (slot) {
480
+ transactDoc(tab, (t) => mutateMoveNode(t, fromPath, slot.parent, slot.index));
464
481
  }
465
482
  } else if (srcData.type === "block") {
466
- const targetParent = parentElementPath(targetPath) as JxPath;
467
- const targetIdx = childIndex(targetPath) as number;
468
- if (instruction.type !== "make-child" && (!targetParent || typeof targetIdx !== "number")) {
483
+ const slot = dropSlot(tab.doc.document, instruction.type, targetPath);
484
+ if (slot === undefined) {
469
485
  return;
470
486
  }
471
-
472
- switch (instruction.type) {
473
- case "reorder-above": {
474
- transactDoc(tab, (t) =>
475
- mutateInsertNode(
476
- t,
477
- targetParent,
478
- targetIdx,
479
- structuredClone(srcData.fragment as JxMutableNode),
480
- ),
481
- );
482
- break;
483
- }
484
- case "reorder-below": {
485
- transactDoc(tab, (t) =>
486
- mutateInsertNode(
487
- t,
488
- targetParent,
489
- targetIdx + 1,
490
- structuredClone(srcData.fragment as JxMutableNode),
491
- ),
492
- );
493
- break;
494
- }
495
- case "make-child": {
496
- const target = getNodeAtPath(doc, targetPath);
497
- const len = childList(target).length;
498
- transactDoc(tab, (t) =>
499
- mutateInsertNode(t, targetPath, len, structuredClone(srcData.fragment as JxMutableNode)),
500
- );
501
- break;
502
- }
503
- default: {
504
- break;
505
- }
487
+ /* SAFETY: every minter of a "block" payload — the Insert palette's element and component cards
488
+ and the file drop (`file-drop-action.ts`) — sets `fragment` to the JxMutableNode it inserts. */
489
+ const fragment = srcData.fragment as JxMutableNode;
490
+ if (slot) {
491
+ transactDoc(tab, (t) =>
492
+ mutateInsertNode(t, slot.parent, slot.index, structuredClone(fragment)),
493
+ );
506
494
  }
507
495
 
508
496
  /* Auto-import to `$elements` if the dropped block is a custom component.
@@ -510,18 +498,20 @@ export function applyDropInstruction(
510
498
  had its own duplicate rule and matched a local component by `ref.endsWith(basename)`, so
511
499
  dropping `./components/card.json` into a page that already imported `./vendor/card.json`
512
500
  counted as already imported and produced an element the page could not resolve. */
513
- const fragment = srcData.fragment as JxMutableNode | undefined;
514
- const tag = fragment?.tagName;
501
+ const tag = fragment.tagName;
515
502
  if (displayTagName(tag).includes("-")) {
516
503
  const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tag);
517
- const before = (tab.doc.document?.$elements ?? []) as ElementsEntry[];
504
+ /* SAFETY: `$elements` holds module specifiers and `{ $ref }` imports; the document type and
505
+ files/elements.ts spell an inline entry as JxMutableNode and JxElement respectively, two
506
+ editor views of the same JSON object that enableElement only compares by `$ref`. */
507
+ const before = (tab.doc.document.$elements ?? []) as ElementsEntry[];
518
508
  const after = comp ? enableElement(before, comp, tab.documentPath ?? null) : before;
519
509
  // Only when the list actually GREW. A component the registry cannot name — an npm entry with
520
510
  // No package, a local one with no path — returns the list unchanged, and writing that back
521
511
  // Would put an empty `$elements: []` on a document that had none.
522
512
  if (after.length !== before.length) {
523
513
  transact(tab, (d: JxMutableNode) => {
524
- d.$elements = after as (string | JxElement)[];
514
+ d.$elements = after;
525
515
  });
526
516
  }
527
517
  }
@@ -33,9 +33,10 @@
33
33
  import type * as monaco from "monaco-editor";
34
34
  import { loadMonaco, mountStillWanted } from "../services/monaco-lazy";
35
35
  import { monacoTheme } from "../shell";
36
- import { isJsonObject } from "@jxsuite/schema/guards";
36
+ import { isJsonObject, isString } from "@jxsuite/schema/guards";
37
37
 
38
- import { getNodeAtPath, renderOnly, updateUi } from "../store";
38
+ import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
39
+ import { renderOnly, updateUi } from "../store";
39
40
  import { activeTab, tabIsLive } from "../workspace/workspace";
40
41
  import { mutateUpdateDef, mutateUpdateProperty, transactDoc } from "../tabs/transact";
41
42
  import { view } from "../view";
@@ -50,10 +51,12 @@ import {
50
51
  } from "../services/monaco-buffer";
51
52
  import { globalEntries, namedFormulaEntries } from "../ui/formula-catalog";
52
53
  import { notify } from "../services/notify";
54
+ import type { NotifyOptions } from "../services/notify";
53
55
 
54
56
  import type { BufferWrites } from "../services/monaco-buffer";
57
+ import { noteTyping } from "../tabs/typing";
55
58
  import type { OxLintDiagnostic } from "../services/code-services";
56
- import type { JxPrototypeDef } from "@jxsuite/schema/types";
59
+ import type { JsonValue, JxDocumentValue } from "@jxsuite/schema/types";
57
60
  import type { JxPath } from "../state";
58
61
  import type { Tab } from "../tabs/tab";
59
62
 
@@ -77,8 +80,8 @@ type FunctionEditor = NonNullable<typeof view.functionEditor>;
77
80
  function getFunctionBody(tab: Tab | null | undefined, editing: EditingTarget | null | undefined) {
78
81
  const document = tab?.doc.document;
79
82
  // Read body off any object-shaped def (covers legacy entries without $prototype).
80
- const bodyOf = (def: unknown) =>
81
- isJsonObject(def) && typeof def.body === "string" ? def.body : "";
83
+ const bodyOf = (def: JxDocumentValue | undefined) =>
84
+ isJsonObject(def) && isString(def.body) ? def.body : "";
82
85
  if (editing?.type === "def") {
83
86
  return bodyOf(document?.state?.[editing.defName]);
84
87
  } else if (editing?.type === "event") {
@@ -88,6 +91,27 @@ function getFunctionBody(tab: Tab | null | undefined, editing: EditingTarget | n
88
91
  return "";
89
92
  }
90
93
 
94
+ /**
95
+ * Whether one entry of a "lint" answer is an oxlint diagnostic.
96
+ *
97
+ * The code service forwards oxlint's own `--format=json` output (`code-api.ts`), whose every
98
+ * diagnostic carries a string `message` and `severity` and, where it points somewhere, a `labels`
99
+ * array. Those are the members checked here; `setLintMarkers` reads the rest as optional.
100
+ */
101
+ function isLintDiagnostic(value: unknown): value is OxLintDiagnostic {
102
+ return (
103
+ isJsonObject(value) &&
104
+ isString(value.message) &&
105
+ isString(value.severity) &&
106
+ (value.labels === undefined || Array.isArray(value.labels))
107
+ );
108
+ }
109
+
110
+ /** The entries of a "lint" answer that are oxlint diagnostics, in the order they came. */
111
+ function lintDiagnostics(entries: readonly JsonValue[]): OxLintDiagnostic[] {
112
+ return entries.flatMap((entry) => (isLintDiagnostic(entry) ? [entry] : []));
113
+ }
114
+
91
115
  /**
92
116
  * The element the Logic tab draws for Monaco to fill.
93
117
  *
@@ -109,6 +133,10 @@ export const CODE_HOST_SELECTOR = '[part="code-host"]';
109
133
  */
110
134
  export function syncFunctionEditor(host: HTMLElement): void {
111
135
  const tab = activeTab.value;
136
+ /* SAFETY: `editingFunction` is written only by openLogicTarget, and every caller that opens the
137
+ function surface (formula.editDef, formula.editEvent, the Data panel, the Logic tab's Open)
138
+ passes `{ type: "def", defName }` or `{ type: "event", path, eventKey }`, exactly the two
139
+ EditingTarget members. */
112
140
  const editing = tab?.session.ui.editingFunction as EditingTarget | null | undefined;
113
141
  const container = editing && tab ? host.querySelector<HTMLElement>(CODE_HOST_SELECTOR) : null;
114
142
  if (!container || !tab || !editing) {
@@ -119,7 +147,7 @@ export function syncFunctionEditor(host: HTMLElement): void {
119
147
  }
120
148
 
121
149
  const current = view.functionEditor;
122
- const attached = Boolean(current && container.contains(current.getDomNode() as Node | null));
150
+ const attached = Boolean(current && container.contains(current.getDomNode()));
123
151
  /* THE TAB IS HALF OF THE IDENTITY, and the half that used to be missing.
124
152
  `_editingTarget` is a JSON string built from the target alone, and the ordinary target
125
153
  `{"eventKey":"onclick","path":["children",0],"type":"event"}` is the SAME string for the first
@@ -260,7 +288,7 @@ function bodyWriter(tab: Tab, editing: EditingTarget, writes?: BufferWrites) {
260
288
  let wrote = false;
261
289
  if (editing.type === "def") {
262
290
  wrote = transactDoc(tab, (t) => mutateUpdateDef(t, editing.defName, { body: newBody }));
263
- } else if (editing.type === "event") {
291
+ } else {
264
292
  const node = getNodeAtPath(tab.doc.document, editing.path);
265
293
  /* THE ELEMENT THE HANDLER HANGS OFF CAN GO WHILE THE EDITOR IS OPEN — a collaborator's
266
294
  delete arriving over the wire, or the author's own ⌘Z. `editing.path` then resolves to
@@ -274,6 +302,9 @@ function bodyWriter(tab: Tab, editing: EditingTarget, writes?: BufferWrites) {
274
302
  return false;
275
303
  }
276
304
  const current = node[editing.eventKey] || {};
305
+ /* SAFETY: an `on*` key holds an event binding, which the schema makes an object (a `$ref`, a
306
+ function def or an expression def), so the spread copies that binding's fields; `|| {}`
307
+ covers a key with no binding yet. */
277
308
  wrote = transactDoc(tab, (t) =>
278
309
  mutateUpdateProperty(t, editing.path, editing.eventKey, {
279
310
  ...(current as object),
@@ -333,6 +364,8 @@ function bodyWriter(tab: Tab, editing: EditingTarget, writes?: BufferWrites) {
333
364
  */
334
365
  export async function closeFunctionEditor(): Promise<void> {
335
366
  const tab = activeTab.value;
367
+ /* SAFETY: `editingFunction` is written only by openLogicTarget, whose callers pass one of the two
368
+ EditingTarget shapes (see syncFunctionEditor). */
336
369
  const editing = tab?.session.ui.editingFunction as EditingTarget | null | undefined;
337
370
  if (!tab || !editing) {
338
371
  return;
@@ -349,13 +382,13 @@ export async function closeFunctionEditor(): Promise<void> {
349
382
  cancelBufferWrites(editor);
350
383
  const write = editor._commitBody ?? bodyWriter(tab, editing);
351
384
  if (!write(minResult?.code ?? currentCode)) {
385
+ const options: NotifyOptions = { key: "logic.close-refused", source: "Logic" };
386
+ if (tab.documentPath) {
387
+ options.path = tab.documentPath;
388
+ }
352
389
  notify.warn(
353
390
  "The handler could not be saved — source editing holds this document. Your code is still in the editor.",
354
- {
355
- key: "logic.close-refused",
356
- source: "Logic",
357
- ...(tab.documentPath ? { path: tab.documentPath } : {}),
358
- },
391
+ options,
359
392
  );
360
393
  return;
361
394
  }
@@ -486,7 +519,7 @@ async function mountFunctionEditor(
486
519
  tabIsLive(tab) &&
487
520
  bufferIsLive(editor)
488
521
  ) {
489
- setLintMarkers(editor, result.diagnostics as OxLintDiagnostic[]);
522
+ setLintMarkers(editor, lintDiagnostics(result.diagnostics));
490
523
  }
491
524
  });
492
525
 
@@ -500,8 +533,9 @@ async function mountFunctionEditor(
500
533
  // Stated as a fact rather than left to be read off the timer, because the timer is only ONE of
501
534
  // The ways a buffer gets ahead and the other one is invisible to it. `markTyped` rather than
502
535
  // `markAhead`: this text is the AUTHOR'S, so it is also the text a close would destroy, and
503
- // Format-on-open's (below) is not.
536
+ // Format-on-open's (below) is not. Noted for Save too, so it is enabled ahead of the commit.
504
537
  writes.markTyped();
538
+ noteTyping(tab.id);
505
539
 
506
540
  writes.arm(BUFFER_COMMIT, 500, () => {
507
541
  editor._commitBody?.(editor.getValue());
@@ -525,7 +559,7 @@ async function mountFunctionEditor(
525
559
  return;
526
560
  }
527
561
  if (result?.diagnostics) {
528
- setLintMarkers(editor, result.diagnostics as OxLintDiagnostic[]);
562
+ setLintMarkers(editor, lintDiagnostics(result.diagnostics));
529
563
  }
530
564
  });
531
565
  });
@@ -544,7 +578,7 @@ export async function registerFunctionCompletions() {
544
578
  if (!activeTab.value) {
545
579
  return { suggestions: [] };
546
580
  }
547
- const defs = activeTab.value.doc.document?.state || {};
581
+ const defs = activeTab.value.doc.document.state || {};
548
582
  const word = model.getWordUntilPosition(position);
549
583
  const range = {
550
584
  endColumn: word.endColumn,
@@ -559,13 +593,12 @@ export async function registerFunctionCompletions() {
559
593
  const suggestions: monaco.languages.CompletionItem[] = Object.entries(defs).map(
560
594
  ([key, def]) => {
561
595
  let kind = monacoNs.languages.CompletionItemKind.Variable;
562
- if (
563
- (def as JxPrototypeDef)?.$prototype === "Function" ||
564
- (def as Record<string, unknown>)?.$handler ||
565
- formulaDocs.has(key)
566
- ) {
596
+ // A primitive or array entry carries neither field, which is what reading them off it gave.
597
+ const prototype = isJsonObject(def) ? def.$prototype : undefined;
598
+ const handler = isJsonObject(def) ? def.$handler : undefined;
599
+ if (prototype === "Function" || handler || formulaDocs.has(key)) {
567
600
  kind = monacoNs.languages.CompletionItemKind.Function;
568
- } else if ((def as JxPrototypeDef)?.$prototype) {
601
+ } else if (prototype) {
569
602
  kind = monacoNs.languages.CompletionItemKind.Property;
570
603
  }
571
604
  const item: monaco.languages.CompletionItem = {
@@ -20,6 +20,7 @@
20
20
  * @docs studio/design/elements
21
21
  */
22
22
 
23
+ import { isString } from "@jxsuite/schema/guards";
23
24
  import { nothing } from "lit-html";
24
25
  import { buildComponentInstance, componentRegistry } from "../files/components";
25
26
  import { childList, getNodeAtPath } from "../store";
@@ -44,7 +45,7 @@ import type { NavigatorPanelContext, NavigatorPanelDeps, PanelBody } from "./pan
44
45
 
45
46
  /** The palette's source of blocks, as `NavigatorPanelDeps.webdata` carries it. */
46
47
  interface ElementsWebdata {
47
- elements: Record<string, { tag: string }[]>;
48
+ elements?: Record<string, { tag: string }[]>;
48
49
  }
49
50
 
50
51
  /** The Components section's name — its accordion label AND its key in `view.elementsCollapsed`. */
@@ -99,12 +100,15 @@ function categoryViews(webdata: ElementsWebdata, filter: string): ElementCategor
99
100
  */
100
101
  function enabledNpmTags(): Set<string> {
101
102
  const tab = activeTab.value;
103
+ /* SAFETY: getEffectiveElements reads nothing off an object entry but `$ref` (its dedup key), and
104
+ this function keeps only the string entries, so typing the document's node entries as
105
+ JxElement is never observed. */
102
106
  const entries = getEffectiveElements(
103
107
  tab?.doc.document?.$elements as (string | JxElement)[] | undefined,
104
108
  );
105
109
  const tags = new Set<string>();
106
110
  for (const entry of entries) {
107
- if (typeof entry !== "string") {
111
+ if (!isString(entry)) {
108
112
  continue;
109
113
  }
110
114
  const named = componentRegistry.find(
@@ -143,7 +147,9 @@ function componentViews(filter: string): ComponentCardView[] {
143
147
  /** Everything the document draws, as one value. */
144
148
  function panelValues(source: NavigatorPanelDeps): ElementsValues {
145
149
  const filter = needle();
146
- const categories = categoryViews(source.webdata as unknown as ElementsWebdata, filter);
150
+ /* SAFETY: `webdata` is wired in studio.ts from the bundled data/webdata.json, whose `elements`
151
+ maps each category name to an array of `{ tag }` entries. */
152
+ const categories = categoryViews(source.webdata as ElementsWebdata, filter);
147
153
  const components = componentViews(filter);
148
154
  const bare = categories.length === 0 && components.length === 0;
149
155
  return {
@@ -206,6 +212,7 @@ const ACTIONS: ElementsActions = {
206
212
  },
207
213
  insertElement: (tag) => {
208
214
  if (panelDeps) {
215
+ // SAFETY: studio.ts wires `defaultDef` to shared.ts defaultDef, which returns a JxMutableNode.
209
216
  insertAtSelection(panelDeps.defaultDef(tag) as JxMutableNode);
210
217
  }
211
218
  },