@jxsuite/studio 6.1.1 → 6.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (637) hide show
  1. package/dist/chunks/{2020-va2wwra4.js → 2020-f2gkpy8d.js} +3 -3
  2. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  3. package/dist/chunks/adapter-4912g339.js +4 -0
  4. package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
  5. package/dist/chunks/cf-settings-br6105tr.js +4 -0
  6. package/dist/chunks/color-28ksk2qm.js +4 -0
  7. package/dist/chunks/color-area-0fj8a4ga.js +4 -0
  8. package/dist/chunks/color-field-xch8kx2g.js +4 -0
  9. package/dist/chunks/color-slider-jxd8v350.js +4 -0
  10. package/dist/chunks/combobox-p0efwjke.js +4 -0
  11. package/dist/chunks/components-db68vsn7.js +4 -0
  12. package/dist/chunks/content-source-1449qesq.js +4 -0
  13. package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
  14. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  15. package/dist/chunks/editor-x9jn86a7.js +4 -0
  16. package/dist/chunks/entry-commands-may24cpt.js +4 -0
  17. package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
  18. package/dist/chunks/file-ops-x9v54pcj.js +4 -0
  19. package/dist/chunks/files-j3knqf0s.js +4 -0
  20. package/dist/chunks/format-host-tyre2trb.js +4 -0
  21. package/dist/chunks/fs-events-64ma9htc.js +4 -0
  22. package/dist/chunks/git-panel-84ps5dex.js +4 -0
  23. package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
  24. package/dist/chunks/icons-pnfz478q.js +4 -0
  25. package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
  26. package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
  27. package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
  28. package/dist/chunks/iframe-entry-zap785cw.js +5 -0
  29. package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
  30. package/dist/chunks/index-b8xw3vy9.js +4 -0
  31. package/dist/chunks/{index-2veqmnhr.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-8nbvs12s.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/{jsonMode-s8kt9dsj.js → jsonMode-w15cmrcm.js} +8 -8
  34. package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
  35. package/dist/chunks/layers-h4xp1pss.js +4 -0
  36. package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
  37. package/dist/chunks/listbox-e74qjyq6.js +4 -0
  38. package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
  39. package/dist/chunks/media-picker-2cweexc5.js +4 -0
  40. package/dist/chunks/menu-n6yzswmy.js +4 -0
  41. package/dist/chunks/menu-ynw13y0s.js +4 -0
  42. package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
  43. package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
  44. package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
  45. package/dist/chunks/notify-cj5zbrs2.js +4 -0
  46. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  47. package/dist/chunks/parse-b7ddhr8m.js +4 -0
  48. package/dist/chunks/platform-3dfws9js.js +4 -0
  49. package/dist/chunks/popover-jt2gxmzs.js +4 -0
  50. package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
  51. package/dist/chunks/quick-search-0dajrwqg.js +4 -0
  52. package/dist/chunks/references-49qgt404.js +4 -0
  53. package/dist/chunks/right-panel-jm1bwe53.js +4 -0
  54. package/dist/chunks/section-registry-6kwc4fky.js +4 -0
  55. package/dist/chunks/select-rzds841e.js +4 -0
  56. package/dist/chunks/split-n2gfpm5m.js +4 -0
  57. package/dist/chunks/{studio-1q1sh2ax.js → studio-0q988f9w.js} +3 -3
  58. package/dist/chunks/studio-0rt52vpq.js +5 -0
  59. package/dist/chunks/studio-18vgbhs5.js +5 -0
  60. package/dist/chunks/{studio-h46vtzk8.js → studio-1fxkaaea.js} +4 -4
  61. package/dist/chunks/studio-24mccdrj.js +5 -0
  62. package/dist/chunks/studio-2eh507zk.js +9 -0
  63. package/dist/chunks/studio-2hcbccfv.js +5 -0
  64. package/dist/chunks/studio-2j1cb95x.js +5 -0
  65. package/dist/chunks/studio-2jbs3rxv.js +5 -0
  66. package/dist/chunks/{studio-rv11kfwa.js → studio-485046te.js} +7 -7
  67. package/dist/chunks/studio-4h8k4dw9.js +5 -0
  68. package/dist/chunks/studio-5f6n18kx.js +5 -0
  69. package/dist/chunks/studio-5gthpky6.js +5 -0
  70. package/dist/chunks/studio-5ve6bbep.js +5 -0
  71. package/dist/chunks/studio-6ep3js6b.js +9 -0
  72. package/dist/chunks/studio-6wkmf3wz.js +9 -0
  73. package/dist/chunks/studio-841rf3cg.js +5 -0
  74. package/dist/chunks/studio-8gmwgheg.js +5 -0
  75. package/dist/chunks/studio-8qm0ep50.js +5 -0
  76. package/dist/chunks/{studio-8grwxtqk.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-pre0skq6.js → studio-a3g98wjr.js} +4 -4
  79. package/dist/chunks/studio-a3shpz9y.js +5 -0
  80. package/dist/chunks/studio-amsbaaar.js +6 -0
  81. package/dist/chunks/studio-at5spjbc.js +7 -0
  82. package/dist/chunks/studio-b2xv945e.js +5 -0
  83. package/dist/chunks/studio-bn5nkafw.js +5 -0
  84. package/dist/chunks/studio-bw6q5xjf.js +9 -0
  85. package/dist/chunks/studio-c7q0t9x1.js +5 -0
  86. package/dist/chunks/studio-camnhc96.js +6 -0
  87. package/dist/chunks/studio-cffqvnzd.js +5 -0
  88. package/dist/chunks/studio-d81xfh1g.js +5 -0
  89. package/dist/chunks/studio-dgz8d0c1.js +5 -0
  90. package/dist/chunks/studio-efvfrsf8.js +5 -0
  91. package/dist/chunks/studio-er30bpcx.js +5 -0
  92. package/dist/chunks/studio-ezscgr64.js +5 -0
  93. package/dist/chunks/studio-ffrrncvz.js +5 -0
  94. package/dist/chunks/studio-fpphgn8y.js +10 -0
  95. package/dist/chunks/studio-j1kvhdjk.js +4 -0
  96. package/dist/chunks/{studio-vrmcjf9g.js → studio-j430n16g.js} +5 -5
  97. package/dist/chunks/studio-jjkg84nj.js +5 -0
  98. package/dist/chunks/studio-m0q32ars.js +4 -0
  99. package/dist/chunks/studio-m6bdst11.js +5 -0
  100. package/dist/chunks/studio-nv2cptd4.js +64 -0
  101. package/dist/chunks/studio-nwfrc98n.js +5 -0
  102. package/dist/chunks/studio-p1wgvp7r.js +5 -0
  103. package/dist/chunks/studio-pag2wncm.js +5 -0
  104. package/dist/chunks/studio-qvanvzfd.js +5 -0
  105. package/dist/chunks/studio-qwa64kt7.js +5 -0
  106. package/dist/chunks/studio-rk1zc4x3.js +928 -0
  107. package/dist/chunks/studio-se2r3ptc.js +5 -0
  108. package/dist/chunks/studio-sg2a0dh0.js +5 -0
  109. package/dist/chunks/studio-tjzjhe68.js +5 -0
  110. package/dist/chunks/{studio-wszjyh0j.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-kggey1jt.js → studio-v0jzqdjm.js} +4 -4
  112. package/dist/chunks/studio-v2w7q8r1.js +7 -0
  113. package/dist/chunks/studio-v5vjq1h0.js +4 -0
  114. package/dist/chunks/studio-v8aga3vp.js +14 -0
  115. package/dist/chunks/studio-vfcdrfmv.js +5 -0
  116. package/dist/chunks/studio-vmfkgdjf.js +5 -0
  117. package/dist/chunks/studio-wt1816jj.js +5 -0
  118. package/dist/chunks/studio-wz73q5kq.js +4 -0
  119. package/dist/chunks/studio-y04qtxvp.js +7 -0
  120. package/dist/chunks/studio-y21g8zzg.js +5 -0
  121. package/dist/chunks/{studio-zey7zsdw.js → studio-y64hrt8p.js} +7 -7
  122. package/dist/chunks/studio-ynn90f58.js +16 -0
  123. package/dist/chunks/studio-yxz682sx.js +5 -0
  124. package/dist/chunks/studio-zp7snvkq.js +5 -0
  125. package/dist/chunks/studio-zq4z6tm6.js +5 -0
  126. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  127. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  128. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  129. package/dist/chunks/toast-c9fn075p.js +4 -0
  130. package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
  131. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  132. package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
  133. package/dist/chunks/tree-mdq3v5cw.js +4 -0
  134. package/dist/chunks/{tsMode-2frah6h1.js → tsMode-sf49ee9x.js} +7 -7
  135. package/dist/chunks/workspace-jtfahpee.js +4 -0
  136. package/dist/chunks/ws-client-nze0k6mv.js +4 -0
  137. package/dist/iframe-entry.js +16 -16
  138. package/dist/manifest.json +63 -63
  139. package/dist/studio.js +97 -97
  140. package/package.json +6 -6
  141. package/src/about/about-modal.ts +4 -3
  142. package/src/account/action-flow.ts +45 -38
  143. package/src/account-status.ts +7 -2
  144. package/src/browse/library-layouts.ts +8 -5
  145. package/src/browse/library-model.ts +18 -6
  146. package/src/browse/library-pane.ts +37 -21
  147. package/src/browse/library-preview.ts +14 -9
  148. package/src/browse/library-source.ts +1 -1
  149. package/src/canvas/asset-refs.ts +24 -9
  150. package/src/canvas/asset-resolve.ts +19 -23
  151. package/src/canvas/canvas-helpers.ts +7 -6
  152. package/src/canvas/canvas-live-render.ts +44 -53
  153. package/src/canvas/canvas-patcher.ts +30 -30
  154. package/src/canvas/canvas-perf.ts +11 -5
  155. package/src/canvas/canvas-render.ts +62 -41
  156. package/src/canvas/canvas-surface.ts +5 -3
  157. package/src/canvas/canvas-utils.ts +90 -49
  158. package/src/canvas/dialog-path.ts +9 -4
  159. package/src/canvas/dialog-state.ts +1 -2
  160. package/src/canvas/diff-marks.ts +9 -16
  161. package/src/canvas/diff-toolbar.ts +8 -7
  162. package/src/canvas/edit-width-drag.ts +4 -1
  163. package/src/canvas/edit-width.ts +1 -3
  164. package/src/canvas/iframe-channel.ts +27 -13
  165. package/src/canvas/iframe-drop.ts +13 -12
  166. package/src/canvas/iframe-editable-root.ts +29 -16
  167. package/src/canvas/iframe-entry.ts +80 -63
  168. package/src/canvas/iframe-eval.ts +73 -49
  169. package/src/canvas/iframe-host.ts +135 -96
  170. package/src/canvas/iframe-inline-edit.ts +49 -30
  171. package/src/canvas/iframe-insert.ts +5 -4
  172. package/src/canvas/iframe-interaction.ts +30 -25
  173. package/src/canvas/iframe-overlay.ts +1 -1
  174. package/src/canvas/iframe-patch.ts +18 -15
  175. package/src/canvas/iframe-position.ts +12 -6
  176. package/src/canvas/iframe-protocol.ts +12 -16
  177. package/src/canvas/iframe-render.ts +36 -34
  178. package/src/canvas/iframe-slash.ts +24 -11
  179. package/src/canvas/iframe-subtree.ts +6 -2
  180. package/src/canvas/path-mapping.ts +19 -12
  181. package/src/canvas/popover-path.ts +7 -3
  182. package/src/canvas/popover-state.ts +1 -2
  183. package/src/canvas/serialize-scope.ts +13 -5
  184. package/src/canvas/stage-scrollbar.ts +2 -1
  185. package/src/canvas/surface-registry.ts +21 -3
  186. package/src/collab/collab-commands.ts +7 -2
  187. package/src/collab/collab-session.ts +84 -45
  188. package/src/collab/collab-state.ts +4 -3
  189. package/src/collab/monaco-binding.ts +16 -13
  190. package/src/collab/monaco-cursors.ts +5 -2
  191. package/src/commands/budget.ts +3 -3
  192. package/src/commands/command-args.ts +103 -71
  193. package/src/commands/context.ts +22 -20
  194. package/src/commands/keymap.ts +47 -43
  195. package/src/commands/levels.ts +3 -3
  196. package/src/commands/live-context.ts +7 -7
  197. package/src/commands/reference.ts +2 -1
  198. package/src/commands/registry.ts +12 -10
  199. package/src/commands/run-reported.ts +15 -10
  200. package/src/component-props.ts +46 -30
  201. package/src/content/collection-match.ts +5 -4
  202. package/src/content/draft-state.ts +4 -3
  203. package/src/content/entry-commands.ts +3 -2
  204. package/src/content/entry-editor.ts +29 -17
  205. package/src/content/entry-fields.ts +12 -7
  206. package/src/content/entry-model.ts +21 -12
  207. package/src/editor/canvas-context-menu.ts +1 -2
  208. package/src/editor/canvas-slash-bridge.ts +3 -6
  209. package/src/editor/content-slice.ts +16 -14
  210. package/src/editor/context-menu.ts +35 -22
  211. package/src/editor/convert-targets.ts +30 -35
  212. package/src/editor/convert-to-component.ts +11 -5
  213. package/src/editor/convert-to-repeater.ts +34 -22
  214. package/src/editor/editable-tags.ts +17 -2
  215. package/src/editor/file-drop-action.ts +21 -22
  216. package/src/editor/inline-edit-apply.ts +35 -17
  217. package/src/editor/inline-edit.ts +66 -50
  218. package/src/editor/inline-format.ts +59 -56
  219. package/src/editor/inline-link.ts +40 -15
  220. package/src/editor/insert-zone-action.ts +1 -1
  221. package/src/editor/merge-tags.ts +58 -19
  222. package/src/editor/repeater-scope.ts +39 -28
  223. package/src/editor/shortcuts.ts +32 -20
  224. package/src/editor/slash-menu.ts +1 -6
  225. package/src/files/asset-versions.ts +4 -4
  226. package/src/files/components.ts +15 -10
  227. package/src/files/elements.ts +5 -6
  228. package/src/files/file-ops.ts +77 -36
  229. package/src/files/files.ts +90 -95
  230. package/src/files/media-meta.ts +2 -1
  231. package/src/files/media-paths.ts +3 -0
  232. package/src/files/serialize-document.ts +2 -2
  233. package/src/format/constraints.ts +1 -1
  234. package/src/format/convert-file.ts +27 -13
  235. package/src/format/format-choices.ts +2 -1
  236. package/src/format/format-host.ts +76 -50
  237. package/src/github/github-auth-status.ts +27 -3
  238. package/src/github/github-auth.ts +19 -9
  239. package/src/github/github-publish.ts +24 -20
  240. package/src/grid/cell-editors.ts +46 -31
  241. package/src/grid/cell-popovers.ts +5 -3
  242. package/src/grid/edit-buffer.ts +10 -9
  243. package/src/grid/grid-controller.ts +20 -22
  244. package/src/grid/grid-layout.ts +21 -5
  245. package/src/grid/grid-open.ts +3 -6
  246. package/src/grid/grid-panel.ts +11 -4
  247. package/src/grid/grid-source.ts +8 -8
  248. package/src/grid/grid-view.ts +14 -17
  249. package/src/grid/redirects-grid.ts +14 -5
  250. package/src/grid/redirects.ts +16 -14
  251. package/src/grid/schema-columns.ts +25 -19
  252. package/src/grid/sources/connector-source.ts +47 -20
  253. package/src/grid/sources/content-source.ts +25 -24
  254. package/src/grid/sources/csv-file-source.ts +2 -2
  255. package/src/grid/tabulator-tables.d.ts +55 -34
  256. package/src/hosting/stage.ts +7 -7
  257. package/src/i18n/i18n-commands.ts +1 -2
  258. package/src/media/media-pane.ts +4 -1
  259. package/src/new-project/add-repo-modal.ts +20 -19
  260. package/src/new-project/import-tab.ts +10 -14
  261. package/src/new-project/location-fields.ts +2 -1
  262. package/src/new-project/new-project-modal.ts +12 -9
  263. package/src/packages/jxsuite-update.ts +4 -3
  264. package/src/packages/pull-package-sync.ts +26 -25
  265. package/src/page-params.ts +97 -68
  266. package/src/panels/activity-panel.ts +17 -9
  267. package/src/panels/ai-chat/attached-context.ts +13 -7
  268. package/src/panels/ai-chat/chat-view.ts +80 -73
  269. package/src/panels/ai-chat/composer.ts +30 -33
  270. package/src/panels/ai-chat/sessions-view.ts +1 -2
  271. package/src/panels/ai-panel.ts +23 -20
  272. package/src/panels/block-action-bar.ts +46 -35
  273. package/src/panels/bottom-dock.ts +5 -3
  274. package/src/panels/canvas-dnd-bridge.ts +31 -24
  275. package/src/panels/data-explorer.ts +62 -25
  276. package/src/panels/data-grid.ts +14 -11
  277. package/src/panels/dnd.ts +108 -118
  278. package/src/panels/editors.ts +52 -21
  279. package/src/panels/elements-panel.ts +10 -3
  280. package/src/panels/events-panel.ts +84 -69
  281. package/src/panels/formula-workspace.ts +76 -51
  282. package/src/panels/frontmatter-fields.ts +24 -19
  283. package/src/panels/frontmatter-panel.ts +44 -34
  284. package/src/panels/git-diff-open.ts +4 -4
  285. package/src/panels/git-panel.ts +49 -61
  286. package/src/panels/head-panel.ts +131 -111
  287. package/src/panels/i18n-panel.ts +10 -3
  288. package/src/panels/imports-panel.ts +23 -47
  289. package/src/panels/jump-bar.ts +48 -29
  290. package/src/panels/layers-panel.ts +97 -74
  291. package/src/panels/left-panel.ts +3 -3
  292. package/src/panels/pane-context.ts +31 -22
  293. package/src/panels/pane-grid.ts +49 -20
  294. package/src/panels/panel-registry.ts +22 -37
  295. package/src/panels/properties-panel.ts +175 -121
  296. package/src/panels/quick-search.ts +53 -31
  297. package/src/panels/right-panel.ts +3 -3
  298. package/src/panels/seo-modal.ts +13 -17
  299. package/src/panels/settings-menu.ts +15 -15
  300. package/src/panels/signals-panel.ts +153 -131
  301. package/src/panels/statement-editor.ts +230 -140
  302. package/src/panels/style-panel.ts +218 -205
  303. package/src/panels/style-utils.ts +114 -51
  304. package/src/panels/stylebook-doc.ts +57 -54
  305. package/src/panels/stylebook-layers-panel.ts +9 -9
  306. package/src/panels/stylebook-panel.ts +13 -17
  307. package/src/panels/tab-drop.ts +27 -11
  308. package/src/panels/tab-strip.ts +36 -26
  309. package/src/platform-errors.ts +57 -43
  310. package/src/platform.ts +58 -30
  311. package/src/platforms/cloud.ts +345 -175
  312. package/src/platforms/default-platform.ts +10 -4
  313. package/src/platforms/devserver.ts +129 -117
  314. package/src/platforms/read-batcher.ts +16 -8
  315. package/src/project-list.ts +2 -1
  316. package/src/publish/deploy-checklist.ts +8 -2
  317. package/src/publish/pages-service.ts +28 -13
  318. package/src/publish/publish-commands.ts +5 -4
  319. package/src/publish/publish-panel.ts +10 -6
  320. package/src/recent-projects.ts +15 -8
  321. package/src/resize-edges.ts +26 -36
  322. package/src/services/a11y-report.ts +26 -19
  323. package/src/services/agent-seed.ts +23 -11
  324. package/src/services/ai-ask.ts +9 -12
  325. package/src/services/ai-command-tools.ts +68 -62
  326. package/src/services/ai-import-tools.ts +80 -67
  327. package/src/services/ai-models.ts +17 -13
  328. package/src/services/ai-project-tools.ts +68 -32
  329. package/src/services/ai-session-store.ts +19 -10
  330. package/src/services/ai-system-prompt.ts +46 -20
  331. package/src/services/ai-tools.ts +71 -27
  332. package/src/services/ai-write-report.ts +20 -12
  333. package/src/services/ai-writes.ts +4 -4
  334. package/src/services/automation.ts +58 -31
  335. package/src/services/cem-export.ts +149 -58
  336. package/src/services/clock.ts +6 -1
  337. package/src/services/code-services.ts +37 -31
  338. package/src/services/context-manager.ts +14 -10
  339. package/src/services/context-resolver.ts +20 -8
  340. package/src/services/data-service.ts +19 -15
  341. package/src/services/directory-picker.ts +18 -12
  342. package/src/services/document-assistant.ts +39 -19
  343. package/src/services/gated-registry.ts +10 -6
  344. package/src/services/harness/chat-reducer.ts +23 -1
  345. package/src/services/import-client.ts +91 -38
  346. package/src/services/import-seed.ts +8 -2
  347. package/src/services/jx-validate.ts +28 -31
  348. package/src/services/live-preview.ts +0 -0
  349. package/src/services/live-surfaces.ts +6 -3
  350. package/src/services/model-uri.ts +10 -2
  351. package/src/services/module-preloads.ts +12 -8
  352. package/src/services/monaco-buffer.ts +43 -24
  353. package/src/services/monaco-lazy.ts +7 -8
  354. package/src/services/monaco-setup.ts +23 -16
  355. package/src/services/notify.ts +44 -17
  356. package/src/services/popover-report.ts +25 -10
  357. package/src/services/preview-eval.ts +20 -8
  358. package/src/services/profile.ts +13 -6
  359. package/src/services/project-path.ts +13 -10
  360. package/src/services/references.ts +0 -0
  361. package/src/services/render-critic.ts +8 -7
  362. package/src/services/settings/kernel.ts +13 -4
  363. package/src/services/settings/write-queue.ts +9 -9
  364. package/src/services/token-lint.ts +12 -10
  365. package/src/services/tool-executor.ts +17 -5
  366. package/src/services/tool-outcomes.ts +44 -24
  367. package/src/services/trusted-types.ts +24 -7
  368. package/src/settings/contexts-section.ts +11 -8
  369. package/src/settings/contributed-section.ts +79 -60
  370. package/src/settings/css-vars-editor.ts +37 -16
  371. package/src/settings/defs-editor.ts +38 -35
  372. package/src/settings/extension-rows.ts +16 -8
  373. package/src/settings/extension-sections.ts +23 -13
  374. package/src/settings/extensions-section.ts +4 -1
  375. package/src/settings/general-settings.ts +11 -8
  376. package/src/settings/locales-section.ts +20 -12
  377. package/src/settings/preferences-dialog.ts +9 -6
  378. package/src/settings/preferences-keymap.ts +7 -5
  379. package/src/settings/preferences-sections.ts +11 -5
  380. package/src/settings/project-sections.ts +1 -1
  381. package/src/settings/schema-field-ui.ts +9 -0
  382. package/src/settings/settings-document.ts +5 -5
  383. package/src/shell/tree.ts +6 -5
  384. package/src/shell.ts +104 -81
  385. package/src/site-context.ts +37 -22
  386. package/src/state.ts +41 -49
  387. package/src/store.ts +54 -34
  388. package/src/studio.ts +25 -75
  389. package/src/style/live-preview.ts +1 -1
  390. package/src/style/project-styles.ts +6 -7
  391. package/src/style/token-ref.ts +5 -4
  392. package/src/surfaces/about.ts +18 -19
  393. package/src/surfaces/add-repo.ts +17 -19
  394. package/src/surfaces/ai-chat.ts +31 -36
  395. package/src/surfaces/ai-credentials-form.ts +6 -16
  396. package/src/surfaces/ai-managed-connect.ts +3 -4
  397. package/src/surfaces/ai-model-picker.ts +3 -5
  398. package/src/surfaces/block-action-bar.ts +22 -11
  399. package/src/surfaces/boot-failure.ts +4 -5
  400. package/src/surfaces/bottom-dock.ts +9 -18
  401. package/src/surfaces/canvas-stage.ts +12 -11
  402. package/src/surfaces/cf-account-picker.ts +17 -18
  403. package/src/surfaces/commandbar.ts +14 -9
  404. package/src/surfaces/convert-repeater.ts +17 -19
  405. package/src/surfaces/data-actions.ts +9 -7
  406. package/src/surfaces/dialog.ts +26 -28
  407. package/src/surfaces/diff-toolbar.ts +9 -7
  408. package/src/surfaces/doc-header.ts +10 -19
  409. package/src/surfaces/empty-state.ts +7 -10
  410. package/src/surfaces/entry-editor.ts +14 -11
  411. package/src/surfaces/expression-editor.ts +11 -25
  412. package/src/surfaces/files-panel.ts +27 -14
  413. package/src/surfaces/formula-palette.ts +4 -5
  414. package/src/surfaces/git-panel.ts +7 -15
  415. package/src/surfaces/github-auth.ts +16 -20
  416. package/src/surfaces/github-publish.ts +17 -22
  417. package/src/surfaces/grid-cell.ts +30 -31
  418. package/src/surfaces/grid-open.ts +10 -14
  419. package/src/surfaces/grid-panel.ts +13 -9
  420. package/src/surfaces/grid-replace.ts +13 -13
  421. package/src/surfaces/grid-views.ts +15 -18
  422. package/src/surfaces/inspector-dock.ts +13 -12
  423. package/src/surfaces/jump-bar.ts +5 -6
  424. package/src/surfaces/jxsuite-update.ts +16 -22
  425. package/src/surfaces/library-pane.ts +19 -20
  426. package/src/surfaces/logic-panel.ts +17 -30
  427. package/src/surfaces/logic-workspace.ts +13 -15
  428. package/src/surfaces/media-browser.ts +11 -10
  429. package/src/surfaces/media-field.ts +4 -5
  430. package/src/surfaces/media-pane.ts +8 -7
  431. package/src/surfaces/menu.ts +29 -23
  432. package/src/surfaces/navigator-dock.ts +11 -12
  433. package/src/surfaces/new-project.ts +27 -26
  434. package/src/surfaces/pane-context.ts +20 -25
  435. package/src/surfaces/pane-grid.ts +15 -10
  436. package/src/surfaces/panel-activity.ts +5 -6
  437. package/src/surfaces/panel-data.ts +3 -4
  438. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  439. package/src/surfaces/panel-elements.ts +5 -7
  440. package/src/surfaces/panel-i18n.ts +5 -7
  441. package/src/surfaces/panel-imports.ts +6 -13
  442. package/src/surfaces/panel-outline.ts +25 -19
  443. package/src/surfaces/panel-page.ts +11 -18
  444. package/src/surfaces/panel-problems.ts +5 -7
  445. package/src/surfaces/panel-signals.ts +20 -34
  446. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  447. package/src/surfaces/preferences.ts +21 -11
  448. package/src/surfaces/progress-modal.ts +15 -9
  449. package/src/surfaces/properties-panel.json +1 -1
  450. package/src/surfaces/properties-panel.ts +20 -42
  451. package/src/surfaces/publish.ts +18 -18
  452. package/src/surfaces/push-plan.ts +7 -8
  453. package/src/surfaces/rail.ts +13 -13
  454. package/src/surfaces/reference-field.ts +11 -15
  455. package/src/surfaces/schema-builder.ts +16 -22
  456. package/src/surfaces/schema-form.ts +15 -25
  457. package/src/surfaces/secret-field.ts +9 -6
  458. package/src/surfaces/seo.ts +21 -15
  459. package/src/surfaces/settings-contexts.ts +9 -7
  460. package/src/surfaces/settings-contributed.ts +14 -10
  461. package/src/surfaces/settings-css-vars.ts +5 -12
  462. package/src/surfaces/settings-defs.json +2 -2
  463. package/src/surfaces/settings-defs.ts +17 -21
  464. package/src/surfaces/settings-deploy.ts +8 -15
  465. package/src/surfaces/settings-extensions.ts +5 -6
  466. package/src/surfaces/settings-head.ts +33 -39
  467. package/src/surfaces/settings-locales.ts +8 -20
  468. package/src/surfaces/settings-overview.ts +5 -6
  469. package/src/surfaces/settings-packages.ts +8 -7
  470. package/src/surfaces/settings-pane.ts +9 -18
  471. package/src/surfaces/settings-rawjson.ts +5 -6
  472. package/src/surfaces/shell.ts +1 -2
  473. package/src/surfaces/slash-menu.ts +19 -9
  474. package/src/surfaces/statements.ts +13 -18
  475. package/src/surfaces/statusbar.ts +17 -14
  476. package/src/surfaces/style-panel.ts +18 -31
  477. package/src/surfaces/stylebook-chrome.ts +3 -5
  478. package/src/surfaces/tab-strip.ts +14 -13
  479. package/src/surfaces/target-line.ts +6 -7
  480. package/src/surfaces/welcome.ts +5 -7
  481. package/src/tabs/patch-ops.ts +4 -3
  482. package/src/tabs/project-config.ts +32 -21
  483. package/src/tabs/selection.ts +36 -8
  484. package/src/tabs/tab.ts +52 -41
  485. package/src/tabs/transact.ts +98 -53
  486. package/src/types.ts +32 -17
  487. package/src/ui/ai-credentials-form.ts +10 -13
  488. package/src/ui/ai-model-picker.ts +3 -3
  489. package/src/ui/cf-account-picker.ts +7 -9
  490. package/src/ui/color-selector.ts +9 -5
  491. package/src/ui/dynamic-slot.ts +7 -8
  492. package/src/ui/expression-editor.ts +112 -105
  493. package/src/ui/form-controls.ts +57 -48
  494. package/src/ui/formula-catalog.ts +239 -230
  495. package/src/ui/formula-chips.ts +33 -18
  496. package/src/ui/layers.ts +44 -31
  497. package/src/ui/media-picker.ts +18 -9
  498. package/src/ui/popover-surface.ts +20 -12
  499. package/src/ui/progress-modal.ts +13 -8
  500. package/src/ui/regions.ts +7 -6
  501. package/src/ui/schema-form.ts +113 -70
  502. package/src/ui/surface.ts +71 -8
  503. package/src/ui/timing.ts +9 -0
  504. package/src/ui/value-source.ts +44 -31
  505. package/src/ui/virtual-window.ts +3 -2
  506. package/src/utils/base64.ts +3 -1
  507. package/src/utils/edit-display.ts +73 -73
  508. package/src/utils/element-selectors.ts +3 -2
  509. package/src/utils/google-fonts.ts +15 -14
  510. package/src/utils/inherited-style.ts +18 -20
  511. package/src/utils/link-target.ts +1 -1
  512. package/src/utils/preview-format.ts +25 -3
  513. package/src/utils/strip-events.ts +49 -22
  514. package/src/utils/studio-utils.ts +29 -14
  515. package/src/view.ts +2 -3
  516. package/src/workspace/pane-derive.ts +10 -12
  517. package/src/workspace/session.ts +53 -43
  518. package/src/workspace/workspace.ts +40 -36
  519. package/dist/chunks/adapter-f93pafd7.js +0 -4
  520. package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
  521. package/dist/chunks/cf-settings-125tdm0w.js +0 -4
  522. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  523. package/dist/chunks/color-field-embq5ctg.js +0 -4
  524. package/dist/chunks/color-fpezvnkt.js +0 -4
  525. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  526. package/dist/chunks/combobox-773hdzyj.js +0 -4
  527. package/dist/chunks/components-ax2f1fnn.js +0 -4
  528. package/dist/chunks/content-source-108aqtk1.js +0 -4
  529. package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
  530. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  531. package/dist/chunks/editor-pfgdmkb0.js +0 -4
  532. package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
  533. package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
  534. package/dist/chunks/file-ops-meej5mqf.js +0 -4
  535. package/dist/chunks/files-44vp8a2s.js +0 -4
  536. package/dist/chunks/format-host-7q1petb9.js +0 -4
  537. package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
  538. package/dist/chunks/git-panel-zngbymvd.js +0 -4
  539. package/dist/chunks/grid-view-sx9vynsp.js +0 -51
  540. package/dist/chunks/icons-p44xhjf0.js +0 -4
  541. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  542. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  543. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  544. package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
  545. package/dist/chunks/index-wkyfjeqz.js +0 -4
  546. package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
  547. package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
  548. package/dist/chunks/layers-xd92fg8d.js +0 -4
  549. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  550. package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
  551. package/dist/chunks/media-picker-0svzkdyb.js +0 -4
  552. package/dist/chunks/menu-37d07z9m.js +0 -4
  553. package/dist/chunks/menu-5c55ea3d.js +0 -4
  554. package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
  555. package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
  556. package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
  557. package/dist/chunks/notify-0xgtn8q1.js +0 -4
  558. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  559. package/dist/chunks/parse-897fvqah.js +0 -4
  560. package/dist/chunks/platform-v1qctbe6.js +0 -4
  561. package/dist/chunks/popover-8htra4er.js +0 -4
  562. package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
  563. package/dist/chunks/quick-search-a54e6t5n.js +0 -4
  564. package/dist/chunks/references-gmqp82fs.js +0 -4
  565. package/dist/chunks/right-panel-v7t9awbk.js +0 -4
  566. package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
  567. package/dist/chunks/select-n3v7gwas.js +0 -4
  568. package/dist/chunks/split-pff8f3ze.js +0 -4
  569. package/dist/chunks/studio-0bhx5hz6.js +0 -5
  570. package/dist/chunks/studio-0k1ddnyy.js +0 -6
  571. package/dist/chunks/studio-1b04pd0j.js +0 -64
  572. package/dist/chunks/studio-4dwbj6gb.js +0 -5
  573. package/dist/chunks/studio-4tanh828.js +0 -5
  574. package/dist/chunks/studio-55h4mstj.js +0 -4
  575. package/dist/chunks/studio-5tnvjkz4.js +0 -5
  576. package/dist/chunks/studio-60dqgb0c.js +0 -5
  577. package/dist/chunks/studio-61dp09qg.js +0 -9
  578. package/dist/chunks/studio-63epcrj2.js +0 -5
  579. package/dist/chunks/studio-74k29dy9.js +0 -5
  580. package/dist/chunks/studio-7vg6jcd3.js +0 -5
  581. package/dist/chunks/studio-7zx31knw.js +0 -9
  582. package/dist/chunks/studio-8bxk97km.js +0 -5
  583. package/dist/chunks/studio-933e30n4.js +0 -5
  584. package/dist/chunks/studio-98wnwhbg.js +0 -5
  585. package/dist/chunks/studio-9mccjwjh.js +0 -14
  586. package/dist/chunks/studio-a2ke1e4t.js +0 -5
  587. package/dist/chunks/studio-e3a2a6v3.js +0 -4
  588. package/dist/chunks/studio-e81q1vb9.js +0 -5
  589. package/dist/chunks/studio-epgrmqqm.js +0 -5
  590. package/dist/chunks/studio-ery42sqr.js +0 -4
  591. package/dist/chunks/studio-g1shz58g.js +0 -5
  592. package/dist/chunks/studio-gf0fz03c.js +0 -5
  593. package/dist/chunks/studio-gjtpe62q.js +0 -6
  594. package/dist/chunks/studio-gkskhg7m.js +0 -5
  595. package/dist/chunks/studio-gx4dnjzd.js +0 -5
  596. package/dist/chunks/studio-j03zga3y.js +0 -9
  597. package/dist/chunks/studio-jhpxeckz.js +0 -5
  598. package/dist/chunks/studio-k01r7ykp.js +0 -5
  599. package/dist/chunks/studio-kk7h30ne.js +0 -7
  600. package/dist/chunks/studio-kt1zqney.js +0 -5
  601. package/dist/chunks/studio-m3cwhvye.js +0 -5
  602. package/dist/chunks/studio-mcayt6hz.js +0 -5
  603. package/dist/chunks/studio-myjcghv3.js +0 -5
  604. package/dist/chunks/studio-n8bxwc3y.js +0 -4
  605. package/dist/chunks/studio-ngm8gvpb.js +0 -5
  606. package/dist/chunks/studio-nj5a01jy.js +0 -928
  607. package/dist/chunks/studio-pcgz8heb.js +0 -5
  608. package/dist/chunks/studio-qcsq0t15.js +0 -5
  609. package/dist/chunks/studio-qkstvve9.js +0 -5
  610. package/dist/chunks/studio-qv1pwd3c.js +0 -5
  611. package/dist/chunks/studio-rc6dvxjb.js +0 -7
  612. package/dist/chunks/studio-s8dmmz66.js +0 -5
  613. package/dist/chunks/studio-sp5xzbj4.js +0 -6
  614. package/dist/chunks/studio-szsjbj0g.js +0 -5
  615. package/dist/chunks/studio-t1xzawhr.js +0 -16
  616. package/dist/chunks/studio-t6b6qe31.js +0 -5
  617. package/dist/chunks/studio-tdcprbqb.js +0 -5
  618. package/dist/chunks/studio-vyc0b4he.js +0 -10
  619. package/dist/chunks/studio-w0cgf6jg.js +0 -5
  620. package/dist/chunks/studio-w3hskzqk.js +0 -5
  621. package/dist/chunks/studio-xgrgcdyh.js +0 -9
  622. package/dist/chunks/studio-xz2yxfcb.js +0 -5
  623. package/dist/chunks/studio-y6n42tgs.js +0 -5
  624. package/dist/chunks/studio-yb560vxr.js +0 -5
  625. package/dist/chunks/studio-yn9f8vtx.js +0 -5
  626. package/dist/chunks/studio-yw05w8f0.js +0 -7
  627. package/dist/chunks/studio-z16sgavc.js +0 -5
  628. package/dist/chunks/studio-zyqn40w4.js +0 -5
  629. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  630. package/dist/chunks/tabs-jwthg40w.js +0 -4
  631. package/dist/chunks/textfield-spy3hc77.js +0 -4
  632. package/dist/chunks/toast-4d35zd64.js +0 -4
  633. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  634. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  635. package/dist/chunks/tree-h19v1jfz.js +0 -4
  636. package/dist/chunks/workspace-zt81g1ms.js +0 -4
  637. package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
@@ -27,12 +27,14 @@
27
27
  * `packages/compiler/src/site/head-merger.ts` by `tests/head-panel.test.ts`.
28
28
  */
29
29
 
30
+ import { isString } from "@jxsuite/schema/guards";
30
31
  import { nothing } from "lit-html";
31
32
  import { projectState, renderOnly } from "../store";
32
33
  import type { DirEntry, JsonValue } from "../types";
33
34
  import { activeTab } from "../workspace/workspace";
34
35
  import { activeRegistry } from "../commands/active-registry";
35
36
  import { clearProblems, notify } from "../services/notify";
37
+ import type { NotifyOptions } from "../services/notify";
36
38
  import { registerPanel } from "./panel-registry";
37
39
  import { mutateUpdateFrontmatter, transact, transactDoc } from "../tabs/transact";
38
40
  import { collectFmFields, projectFmField } from "./frontmatter-fields";
@@ -49,13 +51,14 @@ import type { JxHeadEntry, JxMutableNode } from "@jxsuite/schema/types";
49
51
  import type { Tab } from "../tabs/tab";
50
52
  import type * as MediaPickerModule from "../ui/media-picker";
51
53
  import type {
52
- PageChoice,
53
54
  PagePanelActions,
54
55
  PagePanelView,
55
56
  PageRow,
56
57
  PageSection,
57
58
  PageTagRow,
58
59
  } from "../surfaces/panel-page";
60
+ import type { SurfaceOption } from "../ui/surface";
61
+ import type { SeoWarningView } from "../surfaces/seo";
59
62
 
60
63
  interface MetaField {
61
64
  label: string;
@@ -154,6 +157,15 @@ export const RESERVED_FM_KEYS = new Set(["title"]);
154
157
 
155
158
  // ─── Helpers ─────────────────────────────────────────────────────────────
156
159
 
160
+ /**
161
+ * One slot of a `$head` array as it is read off a document.
162
+ *
163
+ * Wider than `JxHeadEntry` on purpose: a Markdown page's `$head` is its frontmatter, which reaches
164
+ * these helpers through {@link buildHeadDoc} without being validated, so an empty YAML list item
165
+ * arrives as `null`. Every reader here steps over such a slot rather than throwing on it.
166
+ */
167
+ type HeadSlot = JxHeadEntry | null | undefined;
168
+
157
169
  /**
158
170
  * Find a `$head` meta entry by attribute match.
159
171
  *
@@ -162,11 +174,8 @@ export const RESERVED_FM_KEYS = new Set(["title"]);
162
174
  * @param {string} key
163
175
  * @returns {JxHeadEntry | undefined}
164
176
  */
165
- export function findMetaEntry(head: JxHeadEntry[], attr: "name" | "property", key: string) {
166
- if (!head) {
167
- return;
168
- }
169
- return head.find((e: JxHeadEntry) => e?.tagName === "meta" && e?.attributes?.[attr] === key);
177
+ export function findMetaEntry(head: readonly HeadSlot[], attr: "name" | "property", key: string) {
178
+ return head.find((e): e is JxHeadEntry => e?.tagName === "meta" && e.attributes?.[attr] === key);
170
179
  }
171
180
 
172
181
  /**
@@ -176,11 +185,8 @@ export function findMetaEntry(head: JxHeadEntry[], attr: "name" | "property", ke
176
185
  * @param {string} rel
177
186
  * @returns {JxHeadEntry | undefined}
178
187
  */
179
- export function findLinkEntry(head: JxHeadEntry[], rel: string) {
180
- if (!head) {
181
- return;
182
- }
183
- return head.find((e: JxHeadEntry) => e?.tagName === "link" && e?.attributes?.rel === rel);
188
+ export function findLinkEntry(head: readonly HeadSlot[], rel: string) {
189
+ return head.find((e): e is JxHeadEntry => e?.tagName === "link" && e.attributes?.rel === rel);
184
190
  }
185
191
 
186
192
  /**
@@ -189,20 +195,20 @@ export function findLinkEntry(head: JxHeadEntry[], rel: string) {
189
195
  * @param {JxHeadEntry} entry
190
196
  * @returns {boolean}
191
197
  */
192
- export function isManagedEntry(entry: JxHeadEntry) {
198
+ export function isManagedEntry(entry: HeadSlot) {
193
199
  if (!entry?.tagName) {
194
200
  return false;
195
201
  }
196
202
  // Managed meta tags
197
203
  if (entry.tagName === "meta") {
198
- const name = String(entry?.attributes?.name ?? "");
199
- const prop = String(entry?.attributes?.property ?? "");
204
+ const name = String(entry.attributes?.name ?? "");
205
+ const prop = String(entry.attributes?.property ?? "");
200
206
  return (
201
207
  Boolean(name && MANAGED_META_KEYS.has(name)) || Boolean(prop && MANAGED_META_KEYS.has(prop))
202
208
  );
203
209
  }
204
210
  // Managed link: favicon
205
- if (entry.tagName === "link" && entry?.attributes?.rel === "icon") {
211
+ if (entry.tagName === "link" && entry.attributes?.rel === "icon") {
206
212
  return true;
207
213
  }
208
214
  return false;
@@ -226,7 +232,7 @@ export function upsertMeta(
226
232
  doc.$head = [];
227
233
  }
228
234
  const idx = doc.$head.findIndex(
229
- (e: JxHeadEntry) => e?.tagName === "meta" && e?.attributes?.[attr] === key,
235
+ (e: HeadSlot) => e?.tagName === "meta" && e.attributes?.[attr] === key,
230
236
  );
231
237
  if (content) {
232
238
  const entry = { attributes: { [attr]: key, content }, tagName: "meta" };
@@ -252,7 +258,7 @@ export function upsertLink(doc: JxMutableNode, rel: string, href: string) {
252
258
  doc.$head = [];
253
259
  }
254
260
  const idx = doc.$head.findIndex(
255
- (e: JxHeadEntry) => e?.tagName === "link" && e?.attributes?.rel === rel,
261
+ (e: HeadSlot) => e?.tagName === "link" && e.attributes?.rel === rel,
256
262
  );
257
263
  if (href) {
258
264
  const entry = { attributes: { href, rel }, tagName: "link" };
@@ -272,7 +278,7 @@ export function upsertLink(doc: JxMutableNode, rel: string, href: string) {
272
278
  * @param {JxHeadEntry} entry
273
279
  * @returns {string}
274
280
  */
275
- export function entryLabel(entry: JxHeadEntry) {
281
+ export function entryLabel(entry: HeadSlot) {
276
282
  if (!entry?.tagName) {
277
283
  return "unknown";
278
284
  }
@@ -301,7 +307,7 @@ export function entryLabel(entry: JxHeadEntry) {
301
307
  * @param {JxHeadEntry} entry
302
308
  * @returns {string}
303
309
  */
304
- export function entryValue(entry: JxHeadEntry) {
310
+ export function entryValue(entry: HeadSlot) {
305
311
  const a = entry?.attributes ?? {};
306
312
  return String(a.content ?? a.href ?? a.src ?? entry?.textContent ?? "");
307
313
  }
@@ -358,11 +364,15 @@ const NOT_SUPPLIED: ResolvedHeadField = { donor: null, source: "none", value: ""
358
364
  * Last rather than first, because the merger folds a layer into a keyed map in array order: a layer
359
365
  * that lists `description` twice emits the second one.
360
366
  */
361
- function metaContentIn(head: JxHeadEntry[], attr: "name" | "property", key: string): string | null {
367
+ function metaContentIn(
368
+ head: readonly HeadSlot[],
369
+ attr: "name" | "property",
370
+ key: string,
371
+ ): string | null {
362
372
  let found: string | null = null;
363
373
  for (const entry of head) {
364
- if (entry?.tagName === "meta" && entry?.attributes?.[attr] === key) {
365
- found = String(entry.attributes?.content ?? "");
374
+ if (entry?.tagName === "meta" && entry.attributes?.[attr] === key) {
375
+ found = String(entry.attributes.content ?? "");
366
376
  }
367
377
  }
368
378
  return found;
@@ -483,12 +493,12 @@ export interface SeoField extends ResolvedHeadField {
483
493
  * a verdict, and the verdict is what gets optimised (§16.6). A count beside a limit says the same
484
494
  * thing without pretending to rank it.
485
495
  */
486
- export const SEO_LIMITS: Readonly<Record<string, number>> = {
487
- description: 160,
488
- "og:description": 200,
489
- "og:title": 60,
490
- title: 60,
491
- };
496
+ export const SEO_LIMITS: ReadonlyMap<string, number> = new Map([
497
+ ["description", 160],
498
+ ["og:description", 200],
499
+ ["og:title", 60],
500
+ ["title", 60],
501
+ ]);
492
502
 
493
503
  /** Counts what a reader sees as one character. See {@link visibleLength}. */
494
504
  const GRAPHEME_SEGMENTER = new Intl.Segmenter("en-US", { granularity: "grapheme" });
@@ -518,15 +528,6 @@ export function visibleLength(value: string): number {
518
528
  return count;
519
529
  }
520
530
 
521
- /** A named thing that is wrong, or absent. Never summed — the list IS the report. */
522
- export interface SeoWarning {
523
- /** Stable id, so a test and a shot name the same warning. */
524
- id: string;
525
- /** The head key the warning is about, so the field row can carry it. */
526
- field: string;
527
- message: string;
528
- }
529
-
530
531
  /** The Problems `source` the SEO warnings carry, so a re-run replaces rather than stacks. */
531
532
  export const SEO_PROBLEM_SOURCE = "Search appearance";
532
533
 
@@ -548,13 +549,16 @@ export const SEO_PROBLEM_SOURCE = "Search appearance";
548
549
  export function reportSeoProblems(preview: SeoPreview, path?: string): number {
549
550
  clearProblems((record) => record.source === SEO_PROBLEM_SOURCE);
550
551
  for (const warning of preview.warnings) {
551
- notify.warn(warning.message, {
552
+ const opts: NotifyOptions = {
552
553
  action: "document.openSeo",
553
554
  key: `seo.${warning.id}`,
554
555
  source: SEO_PROBLEM_SOURCE,
555
556
  tier: "problem",
556
- ...(path === undefined ? {} : { path }),
557
- });
557
+ };
558
+ if (path !== undefined) {
559
+ opts.path = path;
560
+ }
561
+ notify.warn(warning.message, opts);
558
562
  }
559
563
  return preview.warnings.length;
560
564
  }
@@ -564,7 +568,7 @@ export interface SeoPreview {
564
568
  url: SeoUrl;
565
569
  /** In render order: `title`, `description`, then the four OpenGraph keys. */
566
570
  fields: SeoField[];
567
- warnings: SeoWarning[];
571
+ warnings: SeoWarningView[];
568
572
  }
569
573
 
570
574
  /** Look one field up by key — the previews read four of the six by name. */
@@ -574,14 +578,16 @@ export function seoField(preview: SeoPreview, key: string): SeoField {
574
578
  ...NOT_SUPPLIED,
575
579
  key,
576
580
  label: key,
577
- limit: SEO_LIMITS[key] ?? null,
581
+ limit: SEO_LIMITS.get(key) ?? null,
578
582
  }
579
583
  );
580
584
  }
581
585
 
582
586
  /** Whether any layer declares a `<title>` element, which the merger discards. */
583
587
  function hasTitleEntry(layers: HeadLayers): boolean {
584
- return [...layers.site, ...layers.layout, ...layers.page].some((e) => e?.tagName === "title");
588
+ return [...layers.site, ...layers.layout, ...layers.page].some(
589
+ (e: HeadSlot) => e?.tagName === "title",
590
+ );
585
591
  }
586
592
 
587
593
  /**
@@ -593,13 +599,13 @@ function hasTitleEntry(layers: HeadLayers): boolean {
593
599
  *
594
600
  * @param {SeoPreview} preview — `warnings` is ignored; this computes it.
595
601
  * @param {HeadLayers} layers
596
- * @returns {SeoWarning[]}
602
+ * @returns {SeoWarningView[]}
597
603
  */
598
604
  export function seoWarnings(
599
605
  preview: Omit<SeoPreview, "warnings">,
600
606
  layers: HeadLayers,
601
- ): SeoWarning[] {
602
- const warnings: SeoWarning[] = [];
607
+ ): SeoWarningView[] {
608
+ const warnings: SeoWarningView[] = [];
603
609
  const get = (key: string) => preview.fields.find((f) => f.key === key);
604
610
 
605
611
  const title = get("title");
@@ -671,6 +677,14 @@ export function seoWarnings(
671
677
  return warnings;
672
678
  }
673
679
 
680
+ /** What {@link buildSeoPreview} needs besides the layers: the page's own title, route and site. */
681
+ export interface SeoPreviewContext {
682
+ pageTitle: string;
683
+ route: string | null;
684
+ siteName?: string;
685
+ siteUrl?: string;
686
+ }
687
+
674
688
  /**
675
689
  * Build the whole preview from the three layers, the page title, the route and the site config.
676
690
  *
@@ -678,18 +692,15 @@ export function seoWarnings(
678
692
  * (resolving the layout document) happens in {@link layoutHeadEntries} before this is called.
679
693
  *
680
694
  * @param {HeadLayers} layers
681
- * @param {{ pageTitle: string; route: string | null; siteName?: string; siteUrl?: string }} ctx
695
+ * @param {SeoPreviewContext} ctx
682
696
  * @returns {SeoPreview}
683
697
  */
684
- export function buildSeoPreview(
685
- layers: HeadLayers,
686
- ctx: { pageTitle: string; route: string | null; siteName?: string; siteUrl?: string },
687
- ): SeoPreview {
698
+ export function buildSeoPreview(layers: HeadLayers, ctx: SeoPreviewContext): SeoPreview {
688
699
  const field = (key: string, label: string, resolved: ResolvedHeadField): SeoField => ({
689
700
  ...resolved,
690
701
  key,
691
702
  label,
692
- limit: SEO_LIMITS[key] ?? null,
703
+ limit: SEO_LIMITS.get(key) ?? null,
693
704
  });
694
705
 
695
706
  const fields: SeoField[] = [
@@ -765,6 +776,12 @@ export function layoutDisplayName(path: string): string {
765
776
  );
766
777
  }
767
778
 
779
+ /** A layout's `$head` entries, and the name to print for the layout. */
780
+ export interface LayoutHead {
781
+ entries: JxHeadEntry[];
782
+ name: string | null;
783
+ }
784
+
768
785
  /**
769
786
  * The effective layout's `$head`, and the name to print for it.
770
787
  *
@@ -774,15 +791,9 @@ export function layoutDisplayName(path: string): string {
774
791
  *
775
792
  * @param {Tab | null} tab — the tab whose document the entries are being resolved FOR.
776
793
  * @param {string | false} [docLayout]
777
- * @returns {{ entries: JxHeadEntry[]; name: string | null }}
794
+ * @returns {LayoutHead}
778
795
  */
779
- export function layoutHeadEntries(
780
- tab: Tab | null,
781
- docLayout?: string | false,
782
- ): {
783
- entries: JxHeadEntry[];
784
- name: string | null;
785
- } {
796
+ export function layoutHeadEntries(tab: Tab | null, docLayout?: string | false): LayoutHead {
786
797
  const path = isPageDocument(tab) ? getEffectiveLayoutPath(docLayout) : null;
787
798
  if (path === null) {
788
799
  return { entries: [], name: null };
@@ -807,6 +818,17 @@ export function seoPreviewFor(tab: Tab | null, doc: JxMutableNode): SeoPreview {
807
818
  const config = projectState?.projectConfig;
808
819
  const layout = layoutHeadEntries(tab, doc.$layout);
809
820
  const path = tab?.documentPath;
821
+ // A content document's head doc may carry a non-string title (see buildHeadDoc).
822
+ const ctx: SeoPreviewContext = {
823
+ pageTitle: isString(doc.title) ? doc.title : "",
824
+ route: path ? pageRoute(path) : null,
825
+ };
826
+ if (config?.name !== undefined) {
827
+ ctx.siteName = config.name;
828
+ }
829
+ if (config?.url !== undefined) {
830
+ ctx.siteUrl = config.url;
831
+ }
810
832
  return buildSeoPreview(
811
833
  {
812
834
  layout: layout.entries,
@@ -814,12 +836,7 @@ export function seoPreviewFor(tab: Tab | null, doc: JxMutableNode): SeoPreview {
814
836
  page: doc.$head ?? [],
815
837
  site: config?.$head ?? [],
816
838
  },
817
- {
818
- pageTitle: typeof doc.title === "string" ? doc.title : "",
819
- route: path ? pageRoute(path) : null,
820
- ...(config?.name === undefined ? {} : { siteName: config.name }),
821
- ...(config?.url === undefined ? {} : { siteUrl: config.url }),
822
- },
839
+ ctx,
823
840
  );
824
841
  }
825
842
 
@@ -853,14 +870,24 @@ export function isPageDocument(tab: Tab | null): boolean {
853
870
  }
854
871
 
855
872
  /** Overlay content-mode frontmatter title/`$head` onto the document the panel edits. */
856
- export function buildHeadDoc(doc: JxMutableNode, fm: Record<string, unknown>): JxMutableNode {
857
- const title = fm.title as string | undefined;
858
- const $head = fm.$head as JxHeadEntry[] | undefined;
859
- return {
860
- ...doc,
861
- ...(title === undefined ? {} : { title }),
862
- ...($head === undefined ? {} : { $head }),
863
- };
873
+ export function buildHeadDoc(
874
+ doc: JxMutableNode,
875
+ fm: Tab["doc"]["content"]["frontmatter"],
876
+ ): JxMutableNode {
877
+ const headDoc: JxMutableNode = { ...doc };
878
+ if (fm.title !== undefined) {
879
+ /* SAFETY: deliberately not narrowed — a YAML title can be a number, and it is overlaid as
880
+ written. Every reader of a head doc's `title` (titleRow here and in frontmatter-panel.ts,
881
+ seoPreviewFor) tests it with isString before using it as text. */
882
+ headDoc.title = fm.title as string;
883
+ }
884
+ if (fm.$head !== undefined) {
885
+ /* SAFETY: Studio's one writer of the frontmatter `$head` key is applyContentMutation below,
886
+ which stores a JxHeadEntry[] or deletes the key. A hand-written one is trusted exactly as
887
+ far as a JSON page's `doc.$head` is, and the readers step over null slots (HeadSlot). */
888
+ headDoc.$head = fm.$head as JxHeadEntry[];
889
+ }
890
+ return headDoc;
864
891
  }
865
892
 
866
893
  /**
@@ -890,19 +917,25 @@ export function applyContentMutation(
890
917
  if (!tab) {
891
918
  return;
892
919
  }
893
- const fmNow = (tab.doc.content?.frontmatter ?? {}) as Record<string, unknown>;
894
- const fmHead = fmNow.$head as JxHeadEntry[] | undefined;
895
- const tmp: JxMutableNode = {
896
- ...(typeof fmNow.title === "string" ? { title: fmNow.title } : {}),
897
- ...(fmHead ? { $head: [...fmHead] } : {}),
898
- };
920
+ const fmNow = tab.doc.content.frontmatter;
921
+ // The frontmatter `$head`, read through the one place that types it.
922
+ const fmHead = buildHeadDoc({}, fmNow).$head;
923
+ const tmp: JxMutableNode = {};
924
+ if (isString(fmNow.title)) {
925
+ tmp.title = fmNow.title;
926
+ }
927
+ if (fmHead) {
928
+ tmp.$head = [...fmHead];
929
+ }
899
930
  fn(tmp);
900
931
  if (tmp.title !== fmNow.title) {
901
- mutateUpdateFrontmatter(tab, "title", tmp.title as JsonValue);
932
+ mutateUpdateFrontmatter(tab, "title", tmp.title);
902
933
  }
903
934
  const newHead = tmp.$head && tmp.$head.length > 0 ? tmp.$head : undefined;
904
- // JxHeadEntry[] is JSON document content by construction.
905
- mutateUpdateFrontmatter(tab, "$head", newHead as JsonValue);
935
+ /* SAFETY: every entry here either came from the frontmatter (JSON, from the format's split) or
936
+ was built by a head editor out of string attributes; JxHeadEntry is wider than JsonValue only
937
+ through its open index signature, which no head editor writes. */
938
+ mutateUpdateFrontmatter(tab, "$head", newHead as JsonValue | undefined);
906
939
  rerender();
907
940
  }
908
941
 
@@ -957,7 +990,7 @@ const _entries = new Map<string, JxHeadEntry>();
957
990
  const _pending = new Map<string, { commit: () => void; timer: ReturnType<typeof setTimeout> }>();
958
991
 
959
992
  /** The elements the add form offers, in the order a reader meets them. */
960
- const TAG_OPTIONS: PageChoice[] = [
993
+ const TAG_OPTIONS: SurfaceOption[] = [
961
994
  { label: "meta", value: "meta" },
962
995
  { label: "link", value: "link" },
963
996
  { label: "script", value: "script" },
@@ -991,7 +1024,7 @@ function thumbFor(row: PageRow, value: string): void {
991
1024
 
992
1025
  /** The one head value you type while writing, in both realms. */
993
1026
  function titleRow(doc: JxMutableNode, apply: PagePanelContext["applyMutation"]): PageRow {
994
- const title = typeof doc.title === "string" ? doc.title : "";
1027
+ const title = isString(doc.title) ? doc.title : "";
995
1028
  _commits.set("title", {
996
1029
  clear: () =>
997
1030
  apply((d) => {
@@ -1140,8 +1173,7 @@ function frontmatterSection(tab: Tab | null): PageSection | null {
1140
1173
  });
1141
1174
  _commits.set(key, {
1142
1175
  clear: () => transactDoc(tab, (t) => mutateUpdateFrontmatter(t, f.field)),
1143
- commit: (raw) =>
1144
- transactDoc(tab, (t) => mutateUpdateFrontmatter(t, f.field, parse(raw) as JsonValue)),
1176
+ commit: (raw) => transactDoc(tab, (t) => mutateUpdateFrontmatter(t, f.field, parse(raw))),
1145
1177
  });
1146
1178
  return Object.assign(blankRow(key, f.field, row.label), row, {
1147
1179
  clearLabel: `Clear ${f.field}`,
@@ -1158,16 +1190,18 @@ function frontmatterSection(tab: Tab | null): PageSection | null {
1158
1190
  /** The `$head` entries no structured control owns, and the keys a Remove hands back. */
1159
1191
  function customEntries(head: JxHeadEntry[]): PageTagRow[] {
1160
1192
  _entries.clear();
1161
- return head
1162
- .filter(
1163
- (e: JxHeadEntry) => !isManagedEntry(e) && !isGoogleFontEntry(e) && !isGoogleFontPreconnect(e),
1164
- )
1165
- .map((entry, index) => {
1166
- const key = `tag:${index}`;
1167
- _entries.set(key, entry);
1168
- const label = entryLabel(entry);
1169
- return { key, label, removeLabel: `Remove ${label}`, value: entryValue(entry) };
1170
- });
1193
+ const rows: PageTagRow[] = [];
1194
+ for (const entry of head) {
1195
+ if (isManagedEntry(entry) || isGoogleFontEntry(entry) || isGoogleFontPreconnect(entry)) {
1196
+ continue;
1197
+ }
1198
+ // The key counts the LISTED entries, as the index of the filtered list it replaces did.
1199
+ const key = `tag:${rows.length}`;
1200
+ _entries.set(key, entry);
1201
+ const label = entryLabel(entry);
1202
+ rows.push({ key, label, removeLabel: `Remove ${label}`, value: entryValue(entry) });
1203
+ }
1204
+ return rows;
1171
1205
  }
1172
1206
 
1173
1207
  /**
@@ -1436,20 +1470,6 @@ function contentArea(body: HTMLElement): HTMLElement {
1436
1470
  return body.querySelector<HTMLElement>(".panel-content") ?? body;
1437
1471
  }
1438
1472
 
1439
- /**
1440
- * The Navigator no longer draws this panel with lit.
1441
- *
1442
- * The record below returns `nothing` and mounts its document in `afterRender`, so this is a stub:
1443
- * it survives only because `NavigatorPanelDeps` still declares the injection and `studio.ts` still
1444
- * passes it. Both go in the change that deletes this.
1445
- *
1446
- * @deprecated The panel is `surfaces/panel-page.json`; call {@link renderPagePanel}.
1447
- * @returns {typeof nothing}
1448
- */
1449
- export function renderHeadTemplate(_against: PagePanelContext): typeof nothing {
1450
- return nothing;
1451
- }
1452
-
1453
1473
  /**
1454
1474
  * Contribute the Page panel.
1455
1475
  *
@@ -63,6 +63,7 @@ import type {
63
63
  I18nSurfaceHandle,
64
64
  I18nValues,
65
65
  } from "../surfaces/panel-i18n";
66
+ import type { CommandArgValues } from "../commands/command-args";
66
67
  import type { LibraryFile, ScanFailure } from "../browse/library-model";
67
68
  import type { NavigatorPanelContext, PanelBody } from "./panel-registry";
68
69
  import type { ResolvedI18n } from "@jxsuite/schema/locale";
@@ -254,7 +255,7 @@ export function parityRows(
254
255
  /* Every key the paths alone produce, so a declared one can be matched against a real file rather
255
256
  than against a spelling. */
256
257
  const derivedKeys = new Set(
257
- files.filter((f) => f.category !== "Media").map((f) => translationKeyOfPath(f.path, i18n)),
258
+ files.flatMap((f) => (f.category === "Media" ? [] : [translationKeyOfPath(f.path, i18n)])),
258
259
  );
259
260
  const keyOf = (file: LibraryFile): string => {
260
261
  const own = declared.get(file.path);
@@ -401,7 +402,7 @@ function cellTitle(cell: ParityCell, locale: string, refusal: string | undefined
401
402
  * report is what makes the next such drift a sentence in the Problems panel rather than an
402
403
  * exception out of a click.
403
404
  */
404
- function runByName(id: string, args: Record<string, unknown> = {}): void {
405
+ function runByName(id: string, args: CommandArgValues = {}): void {
405
406
  const registry = activeRegistry();
406
407
  if (!registry?.get(id)) {
407
408
  return;
@@ -437,7 +438,13 @@ function projectRow(row: ParityRow, i18n: ResolvedI18n): I18nParityRow {
437
438
  }
438
439
 
439
440
  /** How many squares are not yet a file, and how many are behind their source. */
440
- function countCells(rows: readonly ParityRow[]): { missing: number; stale: number } {
441
+ interface CellCounts {
442
+ missing: number;
443
+ stale: number;
444
+ }
445
+
446
+ /** Tallies {@link CellCounts} over every square of the grid. */
447
+ function countCells(rows: readonly ParityRow[]): CellCounts {
441
448
  let missing = 0;
442
449
  let stale = 0;
443
450
  for (const row of rows) {
@@ -21,6 +21,7 @@
21
21
  * turn, where a Navigator repaint is a frame away and would rebuild far more than one field.
22
22
  */
23
23
 
24
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
24
25
  import { nothing } from "lit-html";
25
26
  import { componentRegistry } from "../files/components";
26
27
  import {
@@ -46,9 +47,9 @@ import type {
46
47
  ImportsActions,
47
48
  ImportsView,
48
49
  PackageRow,
49
- PickerOption,
50
50
  } from "../surfaces/panel-imports";
51
- import type { JxElement, JxMutableNode } from "@jxsuite/schema/types";
51
+ import type { JxMutableNode } from "@jxsuite/schema/types";
52
+ import type { SurfaceOption } from "../ui/surface";
52
53
 
53
54
  /** What the panel is drawn against. `left-panel.ts`'s context, reduced to what this reads. */
54
55
  export interface ImportsContext {
@@ -105,17 +106,19 @@ function groupByPackage() {
105
106
  if (comp.source !== "npm" || !comp.package || !comp.modulePath) {
106
107
  continue;
107
108
  }
108
- if (!groups.has(comp.package)) {
109
- groups.set(comp.package, []);
109
+ let group = groups.get(comp.package);
110
+ if (!group) {
111
+ group = [];
112
+ groups.set(comp.package, group);
110
113
  }
111
- groups.get(comp.package)?.push(comp);
114
+ group.push(comp);
112
115
  }
113
116
  return groups;
114
117
  }
115
118
 
116
119
  /** The project's `$elements`, as the site-level mood reads and rewrites it. */
117
120
  function siteElements(): ElementsEntry[] {
118
- return (projectState?.projectConfig?.$elements ?? []) as ElementsEntry[];
121
+ return projectState?.projectConfig?.$elements ?? [];
119
122
  }
120
123
 
121
124
  /**
@@ -163,19 +166,15 @@ function siteView(): ImportsView {
163
166
  /** The document-level mood: this document's component imports, and what it could still import. */
164
167
  function documentView(ctx: ImportsContext): ImportsView {
165
168
  const { documentElements, documentPath } = ctx;
166
- const refs = documentElements
167
- .filter(
168
- (entry): entry is { $ref: string } =>
169
- Boolean(entry) &&
170
- typeof entry === "object" &&
171
- typeof (entry as { $ref?: unknown }).$ref === "string",
172
- )
173
- .map((entry) => ({ ref: entry.$ref }));
169
+ const refs = documentElements.flatMap((entry) => {
170
+ const ref = isNonNullObject(entry) ? entry.$ref : undefined;
171
+ return isString(ref) ? [{ ref }] : [];
172
+ });
174
173
  /* The checkbox reads the STRING entries only. A `$ref` is a project component and is listed
175
174
  above; letting it answer here would tick an npm box for a file that happens to share a name. */
176
- const npmEntries = documentElements.filter((entry) => typeof entry === "string");
175
+ const npmEntries = documentElements.filter((entry) => isString(entry));
177
176
  const imported = new Set(refs.map((entry) => entry.ref));
178
- const available: PickerOption[] = componentRegistry
177
+ const available: SurfaceOption[] = componentRegistry
179
178
  .filter(
180
179
  (comp: ComponentEntry) =>
181
180
  comp.source !== "npm" &&
@@ -276,7 +275,7 @@ async function onRemovePackage(pkg: string): Promise<void> {
276
275
  const updated = removePackageElements(siteElements(), pkg);
277
276
  const { loadComponentRegistry } = await import("../files/components.js");
278
277
  await loadComponentRegistry();
279
- await updateSiteConfig({ $elements: updated as (string | JxElement)[] });
278
+ await updateSiteConfig({ $elements: updated });
280
279
  context()?.renderLeftPanel();
281
280
  } catch (error) {
282
281
  console.error("Failed to remove package:", error);
@@ -301,17 +300,15 @@ async function onToggleComponent(id: string, checked: boolean): Promise<void> {
301
300
  const updated = checked
302
301
  ? enableElement(before, comp, null)
303
302
  : disableElement(before, comp, null);
304
- await updateSiteConfig({ $elements: updated as (string | JxElement)[] });
303
+ await updateSiteConfig({ $elements: updated });
305
304
  ctx.renderLeftPanel();
306
305
  return;
307
306
  }
308
307
  ctx.applyMutation((doc: JxMutableNode) => {
309
- const before = (doc.$elements ?? []) as ElementsEntry[];
310
- doc.$elements = (
311
- checked
312
- ? enableElement(before, comp, ctx.documentPath)
313
- : disableElement(before, comp, ctx.documentPath)
314
- ) as (string | JxElement)[];
308
+ const before = doc.$elements ?? [];
309
+ doc.$elements = checked
310
+ ? enableElement(before, comp, ctx.documentPath)
311
+ : disableElement(before, comp, ctx.documentPath);
315
312
  });
316
313
  ctx.renderLeftPanel();
317
314
  }
@@ -339,11 +336,7 @@ function onPick(value: string): void {
339
336
  /* Through the service, which is also what makes this idempotent: it checked nothing and pushed a
340
337
  second `$ref` every time you chose the same component. */
341
338
  ctx.applyMutation((doc: JxMutableNode) => {
342
- doc.$elements = enableElement(
343
- (doc.$elements ?? []) as ElementsEntry[],
344
- comp,
345
- ctx.documentPath,
346
- ) as (string | JxElement)[];
339
+ doc.$elements = enableElement(doc.$elements ?? [], comp, ctx.documentPath);
347
340
  });
348
341
  ctx.renderLeftPanel();
349
342
  }
@@ -355,10 +348,7 @@ function onRemoveRef(elementRef: string): void {
355
348
  return;
356
349
  }
357
350
  ctx.applyMutation((doc: JxMutableNode) => {
358
- doc.$elements = removeElementRef((doc.$elements ?? []) as ElementsEntry[], elementRef) as (
359
- | string
360
- | JxElement
361
- )[];
351
+ doc.$elements = removeElementRef(doc.$elements ?? [], elementRef);
362
352
  });
363
353
  ctx.renderLeftPanel();
364
354
  }
@@ -437,20 +427,6 @@ function contentArea(body: HTMLElement): HTMLElement {
437
427
  return body.querySelector<HTMLElement>(".panel-content") ?? body;
438
428
  }
439
429
 
440
- /**
441
- * The Navigator no longer draws this panel with lit.
442
- *
443
- * The record below returns `nothing` and mounts its document in `afterRender`, so this is a stub:
444
- * it survives only because `NavigatorPanelDeps` still declares the injection and `studio.ts` still
445
- * passes it. Both go in the change that deletes this.
446
- *
447
- * @deprecated The panel is `surfaces/panel-imports.json`; call {@link renderImportsPanel}.
448
- * @returns {typeof nothing}
449
- */
450
- export function renderImportsTemplate(_against: ImportsContext): typeof nothing {
451
- return nothing;
452
- }
453
-
454
430
  /**
455
431
  * Contribute the Packages panel.
456
432
  *