@jxsuite/studio 2.0.1 → 2.1.0

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 (419) hide show
  1. package/canvas.html +21 -0
  2. package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
  3. package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
  4. package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
  5. package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
  6. package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
  7. package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
  8. package/dist/chunks/content-source-34gnkbnn.js +38 -0
  9. package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
  10. package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
  11. package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
  12. package/dist/chunks/extension-sections-6mqydz35.js +301 -0
  13. package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
  14. package/dist/chunks/files-8kn321h1.js +70 -0
  15. package/dist/chunks/files-8kn321h1.js.map +9 -0
  16. package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
  17. package/dist/chunks/git-panel-tjbr191d.js +51 -0
  18. package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
  19. package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
  20. package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
  21. package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
  22. package/dist/chunks/layers-panel-87pb25km.js +58 -0
  23. package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
  24. package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
  25. package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
  26. package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
  27. package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
  28. package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
  29. package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
  30. package/dist/chunks/right-panel-zpdxd98t.js +37 -0
  31. package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
  32. package/dist/chunks/section-registry-zmckaxf4.js +30 -0
  33. package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
  34. package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
  35. package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
  36. package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
  37. package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
  38. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
  39. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
  40. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
  41. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
  42. package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
  43. package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
  44. package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
  45. package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
  46. package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
  47. package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
  48. package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
  49. package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
  50. package/dist/chunks/studio-41exgzhq.js +6690 -0
  51. package/dist/chunks/studio-41exgzhq.js.map +38 -0
  52. package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
  53. package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
  54. package/dist/chunks/studio-50k77cca.js +1787 -0
  55. package/dist/chunks/studio-50k77cca.js.map +18 -0
  56. package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
  57. package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
  58. package/dist/chunks/studio-6f0am8f2.js +53 -0
  59. package/dist/chunks/studio-6f0am8f2.js.map +10 -0
  60. package/dist/chunks/studio-6nmjc5qk.js +7002 -0
  61. package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
  62. package/dist/chunks/studio-7afd21nw.js +67 -0
  63. package/dist/chunks/studio-7afd21nw.js.map +10 -0
  64. package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
  65. package/dist/chunks/studio-7bmdvzne.js.map +10 -0
  66. package/dist/chunks/studio-8jpzqk5s.js +128 -0
  67. package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
  68. package/dist/chunks/studio-94m77tgk.js +1482 -0
  69. package/dist/chunks/studio-94m77tgk.js.map +13 -0
  70. package/dist/chunks/studio-9je6w5sq.js +1000 -0
  71. package/dist/chunks/studio-9je6w5sq.js.map +16 -0
  72. package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
  73. package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
  74. package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
  75. package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
  76. package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
  77. package/dist/chunks/studio-bw5dz6km.js +608 -0
  78. package/dist/chunks/studio-bw5dz6km.js.map +21 -0
  79. package/dist/chunks/studio-c6s5getc.js +4232 -0
  80. package/dist/chunks/studio-c6s5getc.js.map +39 -0
  81. package/dist/chunks/studio-cjm7fdjf.js +451 -0
  82. package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
  83. package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
  84. package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
  85. package/dist/chunks/studio-dg7zyt5x.js +28 -0
  86. package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
  87. package/dist/chunks/studio-dzcyvvvz.js +166 -0
  88. package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
  89. package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
  90. package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
  91. package/dist/chunks/studio-f12h6177.js +411 -0
  92. package/dist/chunks/studio-f12h6177.js.map +13 -0
  93. package/dist/chunks/studio-hbp1s8m9.js +1817 -0
  94. package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
  95. package/dist/chunks/studio-k2sxjph5.js +15295 -0
  96. package/dist/chunks/studio-k2sxjph5.js.map +235 -0
  97. package/dist/chunks/studio-myje51t3.js +385 -0
  98. package/dist/chunks/studio-myje51t3.js.map +12 -0
  99. package/dist/chunks/studio-na6rwzhw.js +353 -0
  100. package/dist/chunks/studio-na6rwzhw.js.map +11 -0
  101. package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
  102. package/dist/chunks/studio-p471gg5n.js.map +14 -0
  103. package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
  104. package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
  105. package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
  106. package/dist/chunks/studio-sas7mt3k.js +75 -0
  107. package/dist/chunks/studio-sas7mt3k.js.map +10 -0
  108. package/dist/chunks/studio-t5wqwzdh.js +74 -0
  109. package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
  110. package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
  111. package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
  112. package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
  113. package/dist/chunks/studio-tr20m8g8.js.map +9 -0
  114. package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
  115. package/dist/chunks/studio-v96qfnww.js.map +54 -0
  116. package/dist/chunks/studio-vcetc91k.js +659 -0
  117. package/dist/chunks/studio-vcetc91k.js.map +10 -0
  118. package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
  119. package/dist/chunks/studio-vmymjefp.js.map +98 -0
  120. package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
  121. package/dist/chunks/studio-x9hmy5kr.js +390 -0
  122. package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
  123. package/dist/chunks/studio-xa0ce0n7.js +335 -0
  124. package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
  125. package/dist/chunks/studio-xm3dbxvn.js +378 -0
  126. package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
  127. package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
  128. package/dist/chunks/studio-zv37yrfa.js +1054 -0
  129. package/dist/chunks/studio-zv37yrfa.js.map +13 -0
  130. package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
  131. package/dist/chunks/ws-client-654ts66j.js.map +11 -0
  132. package/dist/iframe-entry.js +668 -230
  133. package/dist/studio.js +21080 -32585
  134. package/index.html +35 -4685
  135. package/package.json +17 -15
  136. package/src/about/about-modal.ts +42 -11
  137. package/src/browse/library-commands.ts +240 -0
  138. package/src/browse/library-layouts.ts +369 -0
  139. package/src/browse/library-model.ts +396 -0
  140. package/src/browse/library-pane.ts +1049 -0
  141. package/src/browse/library-preview.ts +252 -0
  142. package/src/browse/library-source.ts +150 -0
  143. package/src/canvas/canvas-helpers.ts +33 -9
  144. package/src/canvas/canvas-live-render.ts +45 -29
  145. package/src/canvas/canvas-patcher.ts +151 -31
  146. package/src/canvas/canvas-perf.ts +46 -7
  147. package/src/canvas/canvas-render.ts +1092 -220
  148. package/src/canvas/canvas-surface.ts +240 -0
  149. package/src/canvas/canvas-utils.ts +1166 -124
  150. package/src/canvas/iframe-drop.ts +2 -1
  151. package/src/canvas/iframe-entry.ts +241 -4
  152. package/src/canvas/iframe-host.ts +1226 -143
  153. package/src/canvas/iframe-inline-edit.ts +31 -0
  154. package/src/canvas/iframe-interaction.ts +76 -16
  155. package/src/canvas/iframe-keys.ts +107 -45
  156. package/src/canvas/iframe-overlay.ts +38 -1
  157. package/src/canvas/iframe-protocol.ts +137 -2
  158. package/src/canvas/iframe-render.ts +70 -2
  159. package/src/canvas/iframe-slash.ts +6 -0
  160. package/src/canvas/path-mapping.ts +56 -6
  161. package/src/canvas/surface-registry.ts +292 -0
  162. package/src/collab/collab-commands.ts +244 -0
  163. package/src/collab/collab-session.ts +198 -32
  164. package/src/collab/collab-state.ts +28 -2
  165. package/src/collab/presence-chips.ts +100 -9
  166. package/src/commands/active-registry.ts +42 -0
  167. package/src/commands/app-commands.ts +176 -0
  168. package/src/commands/budget.ts +158 -0
  169. package/src/commands/command-args.ts +253 -0
  170. package/src/commands/context.ts +387 -0
  171. package/src/commands/defaults.ts +580 -0
  172. package/src/commands/keymap.ts +571 -0
  173. package/src/commands/levels.ts +345 -0
  174. package/src/commands/live-context.ts +193 -0
  175. package/src/commands/reference.ts +227 -0
  176. package/src/commands/registry.ts +293 -0
  177. package/src/component-props.ts +3 -2
  178. package/src/content/draft-state.ts +106 -0
  179. package/src/content/entry-commands.ts +282 -0
  180. package/src/content/entry-editor.ts +327 -0
  181. package/src/content/entry-fields.ts +116 -0
  182. package/src/content/entry-model.ts +175 -0
  183. package/src/editor/canvas-context-menu.ts +17 -11
  184. package/src/editor/canvas-slash-bridge.ts +11 -4
  185. package/src/editor/context-menu.ts +804 -204
  186. package/src/editor/convert-to-component.ts +31 -10
  187. package/src/editor/convert-to-repeater.ts +3 -2
  188. package/src/editor/inline-edit-apply.ts +5 -5
  189. package/src/editor/inline-edit.ts +86 -50
  190. package/src/editor/insert-zone-action.ts +1 -1
  191. package/src/editor/shortcuts.ts +1043 -329
  192. package/src/editor/slash-menu.ts +1 -0
  193. package/src/files/elements.ts +166 -0
  194. package/src/files/file-ops.ts +178 -31
  195. package/src/files/files.ts +898 -268
  196. package/src/files/fs-events.ts +21 -0
  197. package/src/files/media-meta.ts +203 -0
  198. package/src/files/media-paths.ts +141 -0
  199. package/src/files/media-upload.ts +7 -3
  200. package/src/files/media-usage.ts +189 -0
  201. package/src/github/github-auth.ts +235 -33
  202. package/src/github/github-publish.ts +80 -21
  203. package/src/grid/grid-controller.ts +152 -12
  204. package/src/grid/grid-layout.ts +225 -20
  205. package/src/grid/grid-open.ts +120 -0
  206. package/src/grid/grid-panel.ts +554 -39
  207. package/src/grid/grid-source.ts +27 -1
  208. package/src/grid/redirects-grid.ts +599 -0
  209. package/src/grid/redirects.ts +398 -0
  210. package/src/grid/sources/content-source.ts +108 -2
  211. package/src/i18n/i18n-commands.ts +322 -0
  212. package/src/new-project/add-repo-modal.ts +8 -10
  213. package/src/new-project/import-tab.ts +7 -0
  214. package/src/new-project/location-fields.ts +9 -1
  215. package/src/new-project/new-project-modal.ts +221 -245
  216. package/src/packages/jxsuite-update.ts +97 -48
  217. package/src/packages/pull-package-sync.ts +18 -9
  218. package/src/page-params.ts +2 -1
  219. package/src/panels/activity-bar.ts +152 -91
  220. package/src/panels/activity-panel.ts +481 -0
  221. package/src/panels/ai-chat/chat-markdown.ts +8 -3
  222. package/src/panels/ai-chat/chat-view.ts +245 -18
  223. package/src/panels/ai-chat/composer.ts +31 -5
  224. package/src/panels/ai-chat/sessions-view.ts +17 -10
  225. package/src/panels/ai-panel.ts +279 -53
  226. package/src/panels/block-action-bar.ts +1115 -224
  227. package/src/panels/bottom-dock.ts +337 -0
  228. package/src/panels/canvas-dnd-bridge.ts +37 -8
  229. package/src/panels/chat-panel.ts +29 -12
  230. package/src/panels/data-explorer.ts +254 -112
  231. package/src/panels/data-grid.ts +10 -4
  232. package/src/panels/dnd.ts +28 -51
  233. package/src/panels/editors.ts +434 -107
  234. package/src/panels/elements-panel.ts +66 -2
  235. package/src/panels/empty-state.ts +112 -0
  236. package/src/panels/events-panel.ts +596 -82
  237. package/src/panels/formula-workspace.ts +408 -218
  238. package/src/panels/frontmatter-fields.ts +51 -10
  239. package/src/panels/frontmatter-panel.ts +357 -79
  240. package/src/panels/git-panel.ts +375 -164
  241. package/src/panels/head-panel.ts +791 -85
  242. package/src/panels/i18n-panel.ts +592 -0
  243. package/src/panels/imports-panel.ts +95 -85
  244. package/src/panels/jump-bar.ts +584 -0
  245. package/src/panels/layers-panel.ts +1106 -328
  246. package/src/panels/left-panel.ts +109 -204
  247. package/src/panels/navigator-panels.ts +131 -0
  248. package/src/panels/overlays.ts +7 -2
  249. package/src/panels/pane-context.ts +1477 -0
  250. package/src/panels/pane-grid.ts +406 -0
  251. package/src/panels/panel-registry.ts +340 -0
  252. package/src/panels/panel-scheduler.ts +75 -0
  253. package/src/panels/problems-panel.ts +234 -0
  254. package/src/panels/properties-panel.ts +946 -1139
  255. package/src/panels/provenance.ts +258 -0
  256. package/src/panels/quick-search.ts +791 -122
  257. package/src/panels/right-panel.ts +228 -102
  258. package/src/panels/seo-modal.ts +395 -0
  259. package/src/panels/settings-pane.ts +203 -0
  260. package/src/panels/signals-panel.ts +354 -137
  261. package/src/panels/statement-editor.ts +41 -25
  262. package/src/panels/statusbar.ts +342 -106
  263. package/src/panels/style-panel.ts +974 -463
  264. package/src/panels/style-utils.ts +3 -3
  265. package/src/panels/stylebook-doc.ts +4 -2
  266. package/src/panels/stylebook-layers-panel.ts +3 -2
  267. package/src/panels/stylebook-panel.ts +51 -26
  268. package/src/panels/tab-strip.ts +1058 -78
  269. package/src/panels/target-line.ts +274 -0
  270. package/src/panels/toolbar.ts +631 -484
  271. package/src/panels/welcome-screen.ts +301 -198
  272. package/src/platform-errors.ts +26 -3
  273. package/src/platform.ts +96 -2
  274. package/src/platforms/cloud.ts +71 -8
  275. package/src/platforms/devserver.ts +92 -29
  276. package/src/publish/deploy-checklist.ts +383 -0
  277. package/src/publish/pages-service.ts +10 -1
  278. package/src/publish/publish-commands.ts +218 -0
  279. package/src/publish/publish-panel.ts +110 -16
  280. package/src/recent-projects.ts +3 -2
  281. package/src/services/a11y-report.ts +505 -0
  282. package/src/services/ai-models.ts +30 -1
  283. package/src/services/ai-project-tools.ts +29 -10
  284. package/src/services/ai-system-prompt.ts +53 -14
  285. package/src/services/ai-tools.ts +39 -3
  286. package/src/services/ai-writes.ts +154 -0
  287. package/src/services/announce.ts +97 -0
  288. package/src/services/automation.ts +424 -175
  289. package/src/services/cem-export.ts +9 -4
  290. package/src/services/clock.ts +61 -0
  291. package/src/services/document-assistant.ts +36 -8
  292. package/src/services/idle.ts +179 -0
  293. package/src/services/import-client.ts +26 -0
  294. package/src/services/monaco-buffer.ts +627 -0
  295. package/src/services/monaco-lazy.ts +36 -0
  296. package/src/services/notify.ts +271 -0
  297. package/src/services/profile.ts +155 -0
  298. package/src/services/references.ts +0 -0
  299. package/src/services/token-lint.ts +3 -2
  300. package/src/services/tool-executor.ts +53 -7
  301. package/src/services/trusted-types.ts +123 -0
  302. package/src/settings/contexts-section.ts +427 -0
  303. package/src/settings/contributed-section.ts +149 -11
  304. package/src/settings/css-vars-editor.ts +306 -349
  305. package/src/settings/defs-editor.ts +93 -34
  306. package/src/settings/dependencies-editor.ts +7 -7
  307. package/src/settings/extension-sections.ts +37 -5
  308. package/src/settings/general-settings.ts +204 -121
  309. package/src/settings/locales-section.ts +347 -0
  310. package/src/settings/preferences-accounts.ts +140 -0
  311. package/src/settings/preferences-dialog.ts +620 -0
  312. package/src/settings/preferences-keymap.ts +270 -0
  313. package/src/settings/project-sections.ts +260 -0
  314. package/src/settings/section-registry.ts +169 -0
  315. package/src/settings/settings-document.ts +385 -0
  316. package/src/shell.ts +1549 -0
  317. package/src/site-context.ts +45 -20
  318. package/src/state.ts +14 -275
  319. package/src/store.ts +88 -43
  320. package/src/studio.ts +790 -346
  321. package/src/style/live-preview.ts +36 -0
  322. package/src/style/project-styles.ts +349 -0
  323. package/src/style/token-ref.ts +123 -0
  324. package/src/tabs/patch-ops.ts +16 -4
  325. package/src/tabs/project-config.ts +416 -0
  326. package/src/tabs/selection.ts +323 -0
  327. package/src/tabs/tab.ts +182 -47
  328. package/src/tabs/transact.ts +209 -28
  329. package/src/types.ts +68 -13
  330. package/src/ui/ai-credentials-form.ts +39 -35
  331. package/src/ui/ai-managed-connect.ts +7 -1
  332. package/src/ui/dynamic-slot.ts +224 -81
  333. package/src/ui/expression-editor.ts +71 -63
  334. package/src/ui/field-input.ts +4 -6
  335. package/src/ui/field-row.ts +215 -38
  336. package/src/ui/form-controls.ts +194 -7
  337. package/src/ui/layers.ts +492 -69
  338. package/src/ui/media-picker.ts +115 -25
  339. package/src/ui/panel-resize.ts +109 -91
  340. package/src/ui/progress-modal.ts +131 -50
  341. package/src/ui/regions.ts +462 -0
  342. package/src/ui/schema-form.ts +229 -45
  343. package/src/ui/spectrum.ts +24 -8
  344. package/src/ui/timing.ts +49 -0
  345. package/src/ui/value-selector.ts +20 -0
  346. package/src/ui/value-source.ts +348 -0
  347. package/src/ui/virtual-window.ts +400 -0
  348. package/src/utils/edit-display.ts +3 -2
  349. package/src/utils/inherited-style.ts +67 -37
  350. package/src/view.ts +64 -78
  351. package/src/workspace/pane-derive.ts +1258 -0
  352. package/src/workspace/session.ts +317 -0
  353. package/src/workspace/workspace.ts +1345 -23
  354. package/styles/canvas.css +653 -0
  355. package/styles/forced-colors.css +106 -0
  356. package/styles/inspector.css +1454 -0
  357. package/styles/overlays.css +2704 -0
  358. package/styles/panels.css +1701 -0
  359. package/styles/shell.css +1423 -0
  360. package/styles/tokens.css +151 -0
  361. package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
  362. package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
  363. package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
  364. package/dist/chunks/files-j8a1t06k.js +0 -50
  365. package/dist/chunks/files-j8a1t06k.js.map +0 -9
  366. package/dist/chunks/git-panel-xtq5z81x.js +0 -28
  367. package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
  368. package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
  369. package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
  370. package/dist/chunks/settings-modal-17ttr96g.js +0 -29
  371. package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
  372. package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
  373. package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
  374. package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
  375. package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
  376. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
  377. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
  378. package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
  379. package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
  380. package/dist/chunks/studio-0xgs7xrs.js +0 -429
  381. package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
  382. package/dist/chunks/studio-4d8hzcz5.js +0 -3427
  383. package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
  384. package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
  385. package/dist/chunks/studio-9smfzqhc.js +0 -19
  386. package/dist/chunks/studio-9smfzqhc.js.map +0 -10
  387. package/dist/chunks/studio-jm0z592w.js.map +0 -115
  388. package/dist/chunks/studio-m2t4mdg5.js +0 -1854
  389. package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
  390. package/dist/chunks/studio-n4p11dfy.js +0 -853
  391. package/dist/chunks/studio-n4p11dfy.js.map +0 -12
  392. package/dist/chunks/studio-qkvt37c0.js.map +0 -9
  393. package/dist/chunks/studio-sjh1wt1a.js +0 -3744
  394. package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
  395. package/dist/chunks/studio-v7jkjqng.js.map +0 -46
  396. package/dist/chunks/studio-xq0t7n5t.js +0 -140
  397. package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
  398. package/dist/chunks/studio-xze4zrs1.js.map +0 -10
  399. package/dist/chunks/studio-yfcstdzy.js +0 -399
  400. package/dist/chunks/studio-yfcstdzy.js.map +0 -12
  401. package/dist/chunks/studio-zp7jncs8.js +0 -469
  402. package/dist/chunks/studio-zp7jncs8.js.map +0 -14
  403. package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
  404. package/src/browse/browse-modal.ts +0 -69
  405. package/src/browse/browse.ts +0 -904
  406. package/src/canvas/canvas-diff.ts +0 -216
  407. package/src/canvas/nested-site-style.ts +0 -58
  408. package/src/new-project/design-fields.ts +0 -264
  409. package/src/new-project/templates.ts +0 -61
  410. package/src/panels/tab-bar.ts +0 -548
  411. package/src/settings/settings-modal.ts +0 -203
  412. /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
  413. /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
  414. /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
  415. /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
  416. /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
  417. /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
  418. /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
  419. /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
@@ -0,0 +1,54 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/utils/geometry.ts", "../src/canvas/canvas-surface.ts", "../src/page-params.ts", "../src/panels/shared.ts", "../src/editor/inline-format.ts", "../src/editor/editable-tags.ts", "../src/editor/inline-edit.ts", "../src/canvas/canvas-helpers.ts", "../src/canvas/canvas-utils.ts", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/public-utils/element/disable-native-drag-preview.js", "../../../node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js", "../../../node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox/dist/esm/internal/isShallowEqual.js", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox/dist/esm/internal/stable.js", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox/dist/esm/attach-instruction.js", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox/dist/esm/extract-instruction.js", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox/dist/esm/tree-item.js", "../src/files/elements.ts", "../../schema/src/intl.ts", "../../runtime/src/pointer.ts", "../../runtime/src/expression.ts", "../../runtime/src/statements.ts", "../../runtime/src/cookie.ts", "../../runtime/src/runtime.ts", "../src/panels/component-preview.ts", "../src/panels/dnd.ts", "../src/canvas/iframe-channel.ts", "../src/canvas/canvas-origin.ts", "../src/canvas/preview-navigate.ts", "../src/utils/edit-display.ts", "../src/component-props.ts", "../../schema/src/asset-paths.ts", "../src/canvas/content-assets.ts", "../src/canvas/canvas-live-render.ts", "../src/canvas/canvas-perf.ts", "../src/editor/content-slice.ts", "../src/editor/inline-edit-apply.ts", "../src/canvas/iframe-overlay.ts", "../src/canvas/path-mapping.ts", "../src/panels/drag-ghost.ts", "../src/format/constraints.ts", "../src/canvas/iframe-host.ts", "../src/panels/empty-state.ts", "../src/commands/levels.ts", "../src/panels/panel-registry.ts"],
4
+ "sourcesContent": [
5
+ "/// <reference lib=\"dom\" />\n/**\n * Geometry read funnel — the single place the studio reads element bounds and does point hit-tests.\n *\n * Centralizing these reads is a seam for the iframe-canvas migration: today every call delegates\n * straight to the DOM, but routing them through one module lets later phases redirect\n * CANVAS-element geometry to rects posted out of the iframe (which the parent can't measure\n * directly) without touching dozens of call sites. A test (`geometry.test.ts`) asserts no raw\n * `getBoundingClientRect`/`elementFromPoint`/`elementsFromPoint` calls exist elsewhere in `src`.\n */\n\n/** Bounding rect of an element, in viewport coordinates. */\nexport function rectOf(el: Element): DOMRect {\n return el.getBoundingClientRect();\n}\n\n/**\n * Bounding rect of a Range, in viewport coordinates. Lives here (the one allowlisted home for\n * `getBoundingClientRect`) so the `geometry.test.ts` textual guard passes — the iframe-side\n * selection snapshot funnels its caret/selection geometry through this, never calling\n * `range.getBoundingClientRect()` directly.\n */\nexport function rectOfRange(r: Range): DOMRect {\n return r.getBoundingClientRect();\n}\n\n/** Topmost element at a viewport point, in `root` (defaults to the global document). */\nexport function elementAtPoint(\n x: number,\n y: number,\n root: Document | ShadowRoot = document,\n): Element | null {\n return root.elementFromPoint(x, y);\n}\n\n/** All elements at a viewport point, front-to-back, in `root` (defaults to the global document). */\nexport function elementsAtPoint(\n x: number,\n y: number,\n root: Document | ShadowRoot = document,\n): Element[] {\n return root.elementsFromPoint(x, y);\n}\n",
6
+ "/// <reference lib=\"dom\" />\n/**\n * Canvas surfaces — one stage per pane, asked about the pane it belongs to.\n *\n * A pane is the unit of split, focus and zoom (§4.1), so it is also the unit of RENDER. The panels\n * a pass mounted, the host element they mounted into, the mode that pass was drawn in and the full\n * render a failed patch escalates to are all facts about ONE pane; they were app-level singletons\n * only because the shell had a single stage.\n *\n * The RECORDS live in `./surface-registry`, which knows nothing about tabs (see the note there on\n * the cycle that forced the split). Everything here composes a surface with the workspace: which\n * tab a pane is showing, which stage is showing a tab, which pane mounted an artboard.\n */\n\nimport { PRIMARY_PANE, paneById, workspace } from \"../workspace/workspace\";\nimport { allCanvasSurfaces, stageContaining, surfaceForPane } from \"./surface-registry\";\nimport type { CanvasSurface } from \"./surface-registry\";\nimport type { PaneDerivation } from \"../workspace/workspace\";\nimport type { CanvasPanel } from \"../types\";\nimport type { Tab } from \"../tabs/tab\";\n\nexport {\n STAGE_CLASS,\n allCanvasSurfaces,\n createPaneSurface,\n disposePaneSurface,\n nextRenderGeneration,\n registerCanvasSurface,\n releaseMountedPanels,\n setSurfaceTeardown,\n stageContaining,\n surfaceForPane,\n unregisterCanvasSurface,\n} from \"./surface-registry\";\nexport type { CanvasSurface } from \"./surface-registry\";\n\n/** The focused pane's stage — what \"the canvas\" means to a command the person just ran. */\nexport function activeCanvasSurface(): CanvasSurface {\n return surfaceForPane(workspace.activePaneId);\n}\n\n/**\n * The tab a pane is DISPLAYING, or null when it shows none.\n *\n * `activeTab` answers this for the FOCUSED pane only; a render, a patch classification and an\n * escalation each need it for a named pane instead.\n *\n * **This one hop is the leverage of the whole derivation.** A LENS pane owns no tab — its\n * `tabOrder` is `[]` — and displays the document its source pane owns, so the answer comes from\n * `sourcePaneId`. Every reader that was already written pane-scoped therefore starts working on a\n * lens pane for free: `renderCanvasImpl`, all three `installPaneRenderEffects` effects, the pane\n * context bar, the jump bar, `tabOfContainer`, `tabOfMountedPanel` and `mountSourceEditor`'s\n * post-await guard. That is also why the follow costs nothing: switching tabs in the source pane\n * repaints the lens because it is the same reactive read.\n *\n * A COMPANION pane owns its tabs normally and takes no hop — the derivation only decides which of\n * its own tabs is on screen.\n *\n * The distinction this draws is not a new one in the render path: `mountIframeCanvas(gen, doc,\n * canvasEl, widthPx, tabId, viewTab)` has separated \"where do this frame's mutations go\" from\n * \"whose document path, layout toggle and canvas mode resolve it\" since the git-diff override. A\n * lens lifts that pair to the pane.\n *\n * @param {string} paneId\n * @returns {Tab | null}\n */\nexport function tabOfPane(paneId: string): Tab | null {\n const pane = paneById(paneId);\n const derived = pane?.derived;\n const activeTabId =\n derived?.kind === \"lens\" ? paneById(derived.sourcePaneId)?.activeTabId : pane?.activeTabId;\n return activeTabId ? (workspace.tabs.get(activeTabId) ?? null) : null;\n}\n\n/**\n * The derivation a pane is drawing under, or null for an ordinary pane.\n *\n * Here rather than in `workspace/pane-derive.ts` (which owns the WRITERS) because every reader of\n * it is a pane-scoped renderer already resolving through this module, and `pane-derive.ts` imports\n * {@link tabOfPane} from here — the other direction would be a cycle.\n *\n * @param {string} paneId\n * @returns {PaneDerivation | null}\n */\nexport function derivationOfPane(paneId: string): PaneDerivation | null {\n return paneById(paneId)?.derived ?? null;\n}\n\n/**\n * Every stage displaying `tab` — its owning pane's, plus any derived pane projecting that pane.\n *\n * This is the per-pane replacement for `isTabActive(tab)` in the patcher's gate, and it is strictly\n * more truthful: a tab is patchable because some pane is DISPLAYING it, not because it happens to\n * be the one the keyboard is in.\n *\n * **Plural, and not kept as a singular wrapper.** `surfaceShowingTab` returned the FIRST pane whose\n * `activeTabId` matched, which was a complete answer only while a tab could be on screen in one\n * place. A lens pane displays the tab its source pane owns (`tabOfPane` takes the hop), so a\n * function answering \"the one pane\" when there may be two is precisely the defect this workstream\n * is about: the patcher posted one pane's `renderGeneration` to both hosts, and the host whose own\n * generation was higher dropped the patch without a sound.\n *\n * Resolved through {@link tabOfPane} rather than through `pane.activeTabId`, so the lens hop is\n * written once.\n *\n * @param {Tab | null} tab\n * @returns {CanvasSurface[]}\n */\nexport function surfacesShowingTab(tab: Tab | null): CanvasSurface[] {\n if (!tab) {\n return [];\n }\n const out: CanvasSurface[] = [];\n for (const pane of workspace.panes) {\n if (tabOfPane(pane.id)?.id === tab.id) {\n out.push(surfaceForPane(pane.id));\n }\n }\n return out;\n}\n\n/**\n * The stage and artboard that mounted `canvasEl`, or null when no pane did.\n *\n * The iframe host knows only its own canvas element, and both answers it needs are here: which\n * artboard was clicked (so the breakpoint context follows the click rather than panel 0), and which\n * PANE a `patchError` must escalate — escalating \"the canvas\" would re-render a pane that never saw\n * the patch.\n *\n * @param {HTMLElement} canvasEl\n * @returns {{ surface: CanvasSurface; panel: CanvasPanel } | null}\n */\nexport function panelHostingCanvas(\n canvasEl: HTMLElement,\n): { surface: CanvasSurface; panel: CanvasPanel } | null {\n for (const surface of allCanvasSurfaces()) {\n const panel = surface.panels.find((candidate) => candidate.canvas === canvasEl);\n if (panel) {\n return { panel, surface };\n }\n }\n return null;\n}\n\n/**\n * The tab whose document an already-mounted artboard is drawing, or null when no pane mounted it.\n *\n * The artboard is the addressable thing a click lands on — its header, its canvas — and the pane\n * that mounted it is the only truthful route from there to a document. Reading `activeTab` instead\n * answers with the FOCUSED pane's tab, which is a different document the moment the click is in a\n * pane the keyboard is not in.\n *\n * @param {CanvasPanel} panel\n * @returns {Tab | null}\n */\nexport function tabOfMountedPanel(panel: CanvasPanel): Tab | null {\n const canvasEl = panel.canvas as HTMLElement | null;\n const mounted = canvasEl ? panelHostingCanvas(canvasEl) : null;\n return mounted ? tabOfPane(mounted.surface.paneId) : null;\n}\n\n/**\n * The effective canvas mode of a tab: the per-tab preview toggle composed onto its base mode.\n *\n * The composition is the same one every downstream gate (document resolution, iframe flags,\n * interaction surfaces) reads, and it lives here — beside the panes — because the answer is a\n * property of a pane's tab, never of the application. Consumers needing the BASE mode read\n * `tab.session.ui.canvasMode` directly.\n *\n * @param {Tab | null} tab\n * @returns {string}\n */\nexport function canvasModeOfTab(tab: Tab | null): string {\n const ui = tab?.session.ui;\n const base = ui?.canvasMode ?? \"design\";\n return ui?.preview && (base === \"edit\" || base === \"design\") ? \"preview\" : base;\n}\n\n/**\n * The effective canvas mode a pane is drawing in.\n *\n * A LENS draws the source pane's document in a mode of its OWN — that is most of what a lens is —\n * and that mode is never written onto the tab, because the tab belongs to the pane beside it and\n * writing there would flip the document the author is editing. The per-tab preview toggle still\n * composes onto it, so a preview lens of an edit-mode page is still a preview.\n *\n * @param {string} paneId\n * @returns {string}\n */\nexport function canvasModeOfPane(paneId: string): string {\n const derived = derivationOfPane(paneId);\n if (derived?.kind === \"lens\") {\n const base = derived.mode;\n const ui = tabOfPane(paneId)?.session.ui;\n return ui?.preview && (base === \"edit\" || base === \"design\") ? \"preview\" : base;\n }\n return canvasModeOfTab(tabOfPane(paneId));\n}\n\n/**\n * The breakpoint a pane is drawing at — `null` for base.\n *\n * `session.ui.activeMedia` is per-TAB, so a breakpoint lens reading it would be showing the same\n * artboard as the pane it is a lens of, which is the one thing preset 5 exists not to do. The\n * derivation's own `media` wins for a lens; every other pane answers from its tab exactly as\n * before.\n *\n * @param {string} paneId\n * @returns {string | null}\n */\nexport function activeMediaOfPane(paneId: string): string | null {\n const derived = derivationOfPane(paneId);\n if (derived?.kind === \"lens\" && derived.preset === \"breakpoint\") {\n return derived.media;\n }\n return tabOfPane(paneId)?.session.ui.activeMedia ?? null;\n}\n\n/**\n * Which pane an element is being drawn into, DERIVED from the element itself.\n *\n * The route for stage CONTENT that is handed a host and nothing else. The settings-section registry\n * is the case that forced it — a contribution's `render(host)` takes an element, and widening that\n * contract for every extension to thread a pane id through is not on — but the shape is general:\n * the container is inside a stage, and the stage knows whose it is.\n *\n * Falls back to the primary for a detached container (the tests, and anything drawn outside the\n * pane grid entirely), which is the same answer `resolveRegion(\"pane\")` gives.\n *\n * @param {HTMLElement} container\n * @returns {string}\n */\nexport function paneOfContainer(container: HTMLElement): string {\n return stageContaining(container)?.paneId ?? PRIMARY_PANE;\n}\n\n/** The tab whose document is being edited in the stage `container` sits inside, or null. */\nexport function tabOfContainer(container: HTMLElement): Tab | null {\n return tabOfPane(paneOfContainer(container));\n}\n",
7
+ "/// <reference lib=\"dom\" />\n/**\n * Dynamic route-param helpers for the tab-bar's $params picker.\n *\n * A page like `pages/products/[sku].json` declares its candidate values in a `$paths` block (spec\n * §4.3). At build time the compiler expands those into concrete routes (`resolvePathEntries` in\n * `@jxsuite/compiler`); in the studio the same shapes are resolved live so the author can pick one\n * value to render. The chosen values are substituted into the canvas render document\n * (`substitutePreviewParams`), which mirrors what the compiler's context injection produces for the\n * matching built page.\n */\n\nimport { getPlatform } from \"./platform\";\nimport { loadExtensions } from \"./format/format-host\";\nimport type { JxMutableNode, JxPathsDef } from \"@jxsuite/schema/types\";\n\n/** Param name → candidate values, in `$paths` declaration order. */\nexport type ParamValues = Record<string, string[]>;\n\n/** Bracket route segments: `[param]` (named) and `[...param]` (catch-all). */\nconst PARAM_SEGMENT = /\\[\\.\\.\\.(\\w+)\\]|\\[(\\w+)\\]/g;\n\n/**\n * Param names declared by a document path's bracket segments, e.g. `pages/products/[sku].json` →\n * `[\"sku\"]`. Mirrors the compiler's `fileToRoute` parsing.\n *\n * @param {string | null | undefined} documentPath\n * @returns {string[]}\n */\nexport function dynamicRouteParams(documentPath: string | null | undefined) {\n if (!documentPath) {\n return [];\n }\n const params: string[] = [];\n for (const match of documentPath.matchAll(PARAM_SEGMENT)) {\n params.push((match[1] ?? match[2])!);\n }\n return params;\n}\n\n/**\n * URL pattern for a page document path, mirroring the compiler's `fileToRoute`:\n * `pages/products/[sku].json` → `/products/:sku`, `pages/index.json` → `/`.\n *\n * @param {string | null | undefined} documentPath\n * @returns {string}\n */\nexport function documentUrlPattern(documentPath: string | null | undefined) {\n if (!documentPath) {\n return \"/\";\n }\n let urlPath = documentPath\n .replace(/^\\.\\//, \"\")\n .replace(/^pages\\//, \"\")\n .replace(/\\.[^/.]+$/, \"\");\n if (urlPath.endsWith(\"/index\")) {\n urlPath = urlPath.slice(0, -6) || \"/\";\n } else if (urlPath === \"index\") {\n urlPath = \"/\";\n }\n if (!urlPath.startsWith(\"/\")) {\n urlPath = `/${urlPath}`;\n }\n return urlPath.replaceAll(PARAM_SEGMENT, (_match, spread: string, named: string) =>\n spread ? \"*\" : `:${named}`,\n );\n}\n\n/**\n * The `$paths` declaration of an open document. JSON pages carry it on the document root;\n * format-class pages (markdown) keep it in the frontmatter.\n *\n * @param {{ document?: unknown; frontmatter?: Record<string, unknown> }} doc\n * @returns {JxPathsDef | null}\n */\nexport function pagePathsDef(doc: {\n document?: JxMutableNode | null;\n frontmatter?: Record<string, unknown> | null;\n}) {\n const fromDoc = (doc.document as { $paths?: JxPathsDef } | null | undefined)?.$paths;\n const fromFrontmatter = doc.frontmatter?.$paths as JxPathsDef | undefined;\n return fromDoc ?? fromFrontmatter ?? null;\n}\n\nconst valueCache = new Map<string, Promise<ParamValues>>();\n\n/** Drop all cached enumerations (e.g. after content files change). */\nexport function invalidateParamValues() {\n valueCache.clear();\n}\n\n/**\n * Enumerate candidate values for each param declared by a `$paths` block. Results are cached per\n * (documentPath, $paths) pair; failures are not cached so a transient backend error retries on the\n * next call.\n *\n * @param {string | null | undefined} documentPath - Cache key component\n * @param {JxPathsDef | null} pathsDef\n * @returns {Promise<ParamValues>}\n */\nexport function loadParamValues(\n documentPath: string | null | undefined,\n pathsDef: JxPathsDef | null,\n) {\n if (!pathsDef) {\n return Promise.resolve({} as ParamValues);\n }\n const key = `${documentPath ?? \"\"}::${JSON.stringify(pathsDef)}`;\n let pending = valueCache.get(key);\n if (!pending) {\n pending = resolveParamValues(pathsDef).catch((error: unknown) => {\n valueCache.delete(key);\n console.warn(\"page-params: failed to enumerate $paths values:\", error);\n return {} as ParamValues;\n });\n valueCache.set(key, pending);\n }\n return pending;\n}\n\n/**\n * Resolve one `$paths` shape to values, mirroring the compiler's `resolvePathEntries`.\n *\n * @param {JxPathsDef} pathsDef\n * @returns {Promise<ParamValues>}\n */\nasync function resolveParamValues(pathsDef: JxPathsDef): Promise<ParamValues> {\n // Legacy: array of param objects — group values per param key\n if (Array.isArray(pathsDef)) {\n const out: ParamValues = {};\n for (const entry of pathsDef) {\n for (const [param, value] of Object.entries(entry)) {\n pushValue(out, param, value);\n }\n }\n return out;\n }\n\n // Content type-based: { contentType: \"blog\", param: \"slug\", field: \"id\" } — an open extension\n // Discriminator member on JxPathsDef, so narrow to string. Resolved through the backend's\n // ContentCollection pipeline (the same one the canvas's ContentEntry uses), so every offered\n // Value is guaranteed to resolve in preview.\n if (\n \"contentType\" in pathsDef &&\n typeof pathsDef.contentType === \"string\" &&\n pathsDef.contentType\n ) {\n const param = pathsDef.param ?? \"slug\";\n const field = pathsDef.field ?? \"id\";\n const entries = (await resolveContentCollection(pathsDef.contentType)) as {\n id?: unknown;\n data?: Record<string, unknown>;\n }[];\n const out: ParamValues = { [param]: [] };\n if (!Array.isArray(entries)) {\n return out;\n }\n for (const entry of entries) {\n pushValue(out, param, field === \"id\" ? entry.id : (entry.data?.[field] ?? entry.id));\n }\n return out;\n }\n\n // Explicit values: { values: [\"en\", \"fr\"], param: \"lang\" }\n if (\"values\" in pathsDef && Array.isArray(pathsDef.values)) {\n const param = pathsDef.param ?? \"value\";\n const out: ParamValues = { [param]: [] };\n for (const value of pathsDef.values) {\n pushValue(out, param, value);\n }\n return out;\n }\n\n // Data file ref: { \"$ref\": \"./data/products.json\", param: \"id\", field: \"sku\" } — `$ref` also\n // Reaches here as an open discriminator key, so narrow to a non-empty string.\n if (\"$ref\" in pathsDef && typeof pathsDef.$ref === \"string\" && pathsDef.$ref) {\n const param = pathsDef.param ?? \"id\";\n const field = pathsDef.field ?? \"id\";\n const content = await getPlatform().readFile(pathsDef.$ref.replace(/^\\.\\//, \"\"));\n const data = JSON.parse(content) as unknown;\n const out: ParamValues = { [param]: [] };\n if (!Array.isArray(data)) {\n return out;\n }\n for (const item of data as Record<string, unknown>[]) {\n pushValue(out, param, item?.[field] ?? item?.id ?? item);\n }\n return out;\n }\n\n return {};\n}\n\n/**\n * The `$src` of the ContentCollection class from the enabled extensions payload — whichever\n * extension's manifest declares a class named `ContentCollection` (its backend-resolved descriptor\n * path feeds `/__jx_resolve__` directly). Platforms without an extensions payload fall back to the\n * historical parser-package specifier.\n *\n * @returns {Promise<string>}\n */\nasync function contentCollectionSrc(): Promise<string> {\n const extensions = await loadExtensions();\n for (const ext of extensions) {\n const cls = ext.classes?.find((c) => c.name === \"ContentCollection\");\n if (cls) {\n return cls.path;\n }\n }\n return \"@jxsuite/parser/ContentCollection.class.json\";\n}\n\n/**\n * Resolve a ContentCollection for a content type via the PAL, falling back to a plain dev-proxy\n * fetch on platforms that predate `resolveClass`.\n *\n * @param {string} contentType\n * @returns {Promise<unknown>}\n */\nasync function resolveContentCollection(contentType: string) {\n const body = {\n $prototype: \"ContentCollection\",\n $src: await contentCollectionSrc(),\n contentType,\n };\n const platform = getPlatform();\n if (platform.resolveClass) {\n return platform.resolveClass(body);\n }\n return fetch(\"/__jx_resolve__\", {\n body: JSON.stringify(body),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n }).then((res) => {\n if (!res.ok) {\n throw new Error(`Class resolution failed: ${res.status}`);\n }\n return res.json() as Promise<unknown>;\n });\n}\n\n/**\n * @param {ParamValues} out\n * @param {string} param\n * @param {unknown} value\n */\nfunction pushValue(out: ParamValues, param: string, value: unknown) {\n if (value === null || value === undefined || value === \"\") {\n return;\n }\n const str = String(value);\n out[param] ??= [];\n const list = out[param];\n if (!list.includes(str)) {\n list.push(str);\n }\n}\n\n/**\n * Substitute chosen param values into a canvas render document:\n *\n * - Every `{ \"$ref\": \"#/$params/<name>\" }` value with a chosen `<name>` becomes the literal string\n * (the exact dereference `ContentEntry.resolve()` performs against `route._pathParams`), and\n * - `state.$page` is injected mirroring the compiler's `injectContext`, so `${state.$page.params.x}`\n * template expressions render.\n *\n * Pure: returns a rebuilt tree. The design/edit render doc shares node references with the tab's\n * source document (stripEventHandlers/prepareForEditMode shallow-rebuild), so in-place mutation\n * here would corrupt the document being edited and saved.\n *\n * @param {JxMutableNode} renderDoc\n * @param {Record<string, string>} params\n * @param {string | null | undefined} documentPath\n * @returns {JxMutableNode}\n */\nexport function substitutePreviewParams(\n renderDoc: JxMutableNode,\n params: Record<string, string>,\n documentPath: string | null | undefined,\n): JxMutableNode {\n if (Object.keys(params).length === 0) {\n return renderDoc;\n }\n const doc = substituteParamRefs(renderDoc, params) as JxMutableNode & {\n state?: Record<string, unknown>;\n title?: unknown;\n };\n doc.state ??= {};\n doc.state.$page = {\n params: { ...params },\n title: typeof doc.title === \"string\" ? doc.title : \"\",\n url: documentUrlPattern(documentPath),\n };\n return doc;\n}\n\n/**\n * State keys whose entries are class prototypes ($prototype + $src) referencing a route param.\n * These are the entries `substitutePreviewParams` rewrites, and the ones `resolveParamBoundState`\n * bakes.\n *\n * @param {Record<string, unknown> | null | undefined} state - The ORIGINAL document state (with\n * `$ref`s intact — substitution removes the marker)\n * @returns {string[]}\n */\nexport function paramBoundStateKeys(state: Record<string, unknown> | null | undefined) {\n if (!state) {\n return [];\n }\n return Object.keys(state).filter((key) => {\n const entry = state[key] as Record<string, unknown> | null;\n return (\n entry &&\n typeof entry === \"object\" &&\n typeof entry.$prototype === \"string\" &&\n typeof entry.$src === \"string\" &&\n JSON.stringify(entry).includes('\"#/$params/')\n );\n });\n}\n\n/**\n * Resolve substituted class-prototype state entries through the backend and bake the values into\n * `renderDoc.state` — compiler parity: the built site resolves ContentEntry/ContentCollection\n * BEFORE templates run. Without baking, the iframe runtime resolves these entries asynchronously\n * (null on the first render pass), so preview templates like `${state.product.data.title}`\n * dereference null and abort the whole render.\n *\n * Failures leave the entry in place (the runtime's own async resolution remains the fallback).\n *\n * @param {JxMutableNode} renderDoc - The substituted render doc (mutated in place — it is the fresh\n * rebuild from substitutePreviewParams, never the source doc)\n * @param {string[]} keys - From paramBoundStateKeys(originalDoc.state)\n * @param {string | undefined} docBase - Document base URL for relative-$src rebasing\n */\nexport async function resolveParamBoundState(\n renderDoc: JxMutableNode,\n keys: string[],\n docBase?: string,\n) {\n if (keys.length === 0) {\n return;\n }\n const platform = getPlatform();\n if (!platform.resolveClass) {\n return;\n }\n const { state } = renderDoc as { state?: Record<string, unknown> };\n if (!state) {\n return;\n }\n await Promise.all(\n keys.map(async (key) => {\n const entry = state[key];\n if (!entry || typeof entry !== \"object\") {\n return;\n }\n try {\n state[key] = await platform.resolveClass!({\n ...(entry as Record<string, unknown>),\n ...(docBase ? { $base: docBase } : {}),\n });\n } catch (error) {\n console.warn(`page-params: failed to resolve state.${key} for preview:`, error);\n }\n }),\n );\n}\n\n/**\n * @param {unknown} node\n * @param {Record<string, string>} params\n * @returns {unknown} — a rebuilt copy with matched param refs replaced by literals\n */\nfunction substituteParamRefs(node: unknown, params: Record<string, string>): unknown {\n const replaced = paramRefValue(node, params);\n if (replaced !== null) {\n return replaced;\n }\n if (!node || typeof node !== \"object\") {\n return node;\n }\n if (Array.isArray(node)) {\n return node.map((item) => substituteParamRefs(item, params));\n }\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(node)) {\n out[key] = substituteParamRefs(value, params);\n }\n return out;\n}\n\n/**\n * The chosen literal for a `{ \"$ref\": \"#/$params/<name>\" }` value, or null when the value is not a\n * param ref (or no value was chosen for it).\n *\n * @param {unknown} value\n * @param {Record<string, string>} params\n * @returns {string | null}\n */\nfunction paramRefValue(value: unknown, params: Record<string, string>) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return null;\n }\n const ref = (value as { $ref?: unknown }).$ref;\n if (typeof ref !== \"string\" || !ref.startsWith(\"#/$params/\")) {\n return null;\n }\n return params[ref.slice(\"#/$params/\".length)] ?? null;\n}\n",
8
+ "/// <reference lib=\"dom\" />\n/**\n * Shared panel utilities — portable helpers extracted from studio.js. These functions depend only\n * on store.js / state.js exports (no circular deps).\n */\n\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * Convert a $media key like \"--tablet\" to a friendly display name \"Tablet\". \"--\" returns \"Base\".\n *\n * @param {string} name\n */\nexport function mediaDisplayName(name: string) {\n if (name === \"--\") {\n return \"Base\";\n }\n return (\n name\n .replace(/^--/, \"\")\n .replaceAll(\"-\", \" \")\n .replaceAll(/\\b\\w/g, (c: string) => c.toUpperCase()) || name\n );\n}\n\nexport const unsafeTags = new Set([\"script\", \"style\", \"link\", \"iframe\", \"object\", \"embed\"]);\n\n/**\n * Generate a sensible default Jx node for a given tag name.\n *\n * @param {string} tag\n */\nexport function defaultDef(tag: string): JxMutableNode {\n const def: JxMutableNode = { tagName: tag };\n if (/^h[1-6]$/.test(tag)) {\n def.textContent = \"Heading\";\n } else if (tag === \"p\") {\n def.textContent = \"Paragraph text\";\n } else if (\n tag === \"span\" ||\n tag === \"strong\" ||\n tag === \"em\" ||\n tag === \"small\" ||\n tag === \"mark\" ||\n tag === \"code\" ||\n tag === \"abbr\" ||\n tag === \"q\" ||\n tag === \"sub\" ||\n tag === \"sup\" ||\n tag === \"time\"\n ) {\n def.textContent = \"Text\";\n } else if (tag === \"a\") {\n def.textContent = \"Link\";\n def.attributes = { href: \"#\" };\n } else if (tag === \"button\") {\n def.textContent = \"Button\";\n } else if (tag === \"label\") {\n def.textContent = \"Label\";\n } else if (tag === \"legend\") {\n def.textContent = \"Legend\";\n } else if (tag === \"caption\") {\n def.textContent = \"Caption\";\n } else if (tag === \"summary\") {\n def.textContent = \"Summary\";\n } else if (\n tag === \"li\" ||\n tag === \"dt\" ||\n tag === \"dd\" ||\n tag === \"th\" ||\n tag === \"td\" ||\n tag === \"option\"\n ) {\n def.textContent = \"Item\";\n } else if (tag === \"blockquote\") {\n def.textContent = \"Quote\";\n } else if (tag === \"pre\") {\n def.textContent = \"Preformatted text\";\n } else if (tag === \"input\") {\n def.attributes = { placeholder: \"Enter text...\", type: \"text\" };\n } else if (tag === \"img\") {\n def.attributes = { alt: \"Image\" };\n } else if (tag === \"iframe\") {\n def.attributes = { src: \"\" };\n } else if (tag === \"slot\") {\n // Slot children are the fallback content shown when no slotted content is provided.\n def.children = [{ tagName: \"p\", textContent: \"Slot content\" }];\n } else if (tag === \"select\") {\n def.children = [{ tagName: \"option\", textContent: \"Option 1\" }];\n } else if (tag === \"ul\" || tag === \"ol\") {\n def.children = [{ tagName: \"li\", textContent: \"Item\" }];\n } else if (tag === \"dl\") {\n def.children = [\n { tagName: \"dt\", textContent: \"Term\" },\n { tagName: \"dd\", textContent: \"Definition\" },\n ];\n } else if (tag === \"table\") {\n def.children = [\n {\n children: [\n {\n children: [{ tagName: \"th\", textContent: \"Header\" }],\n tagName: \"tr\",\n },\n ],\n tagName: \"thead\",\n },\n {\n children: [{ children: [{ tagName: \"td\", textContent: \"Cell\" }], tagName: \"tr\" }],\n tagName: \"tbody\",\n },\n ];\n } else if (tag === \"details\") {\n def.children = [\n { tagName: \"summary\", textContent: \"Summary\" },\n { tagName: \"p\", textContent: \"Detail content\" },\n ];\n }\n return def;\n}\n",
9
+ "/// <reference lib=\"dom\" />\n/**\n * Inline-format.js — Inline formatting engine for contenteditable editing\n *\n * Handles toggling inline formatting (bold, italic, code, etc.) with proper wrap/unwrap logic, DOM\n * normalization, and whitespace management.\n */\n\n/** Tags considered inline formatting wrappers */\nconst FORMAT_TAGS = new Set([\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"u\",\n \"del\",\n \"s\",\n \"strike\",\n \"code\",\n \"sub\",\n \"sup\",\n \"span\",\n]);\n\n/**\n * Check whether `tag` is currently active on both ends of the selection. Walks from anchor and\n * focus nodes up to editableRoot looking for the tag. Returns false if selection is outside\n * editableRoot or in plaintext-only mode.\n *\n * @param {string} tag\n * @param {HTMLElement | null} editableRoot\n * @returns {boolean}\n */\nexport function isTagActiveInSelection(tag: string, editableRoot: HTMLElement | null) {\n if (!editableRoot) {\n return false;\n }\n if (editableRoot.contentEditable === \"plaintext-only\") {\n return false;\n }\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return false;\n }\n\n const anchor = sel.anchorNode;\n const focus = sel.focusNode;\n if (!anchor || !focus) {\n return false;\n }\n if (!editableRoot.contains(anchor) || !editableRoot.contains(focus)) {\n return false;\n }\n\n /**\n * @param {Node | null} node\n * @returns {boolean}\n */\n const hasTag = (node: Node | null) => {\n let current = node;\n while (current && current !== editableRoot) {\n if (\n current.nodeType === Node.ELEMENT_NODE &&\n (current as Element).tagName.toLowerCase() === tag\n ) {\n return true;\n }\n current = current.parentNode;\n }\n return false;\n };\n\n return hasTag(anchor) && hasTag(focus);\n}\n\n/**\n * Toggle an inline format tag on/off for the current selection. If the tag is active → unwrap. If\n * not → wrap.\n *\n * @param {string} tag\n * @param {HTMLElement | null} editableRoot\n */\nexport function toggleInlineFormat(tag: string, editableRoot: HTMLElement | null) {\n if (!editableRoot) {\n return;\n }\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return;\n }\n const range = sel.getRangeAt(0);\n if (range.collapsed) {\n return;\n }\n if (!editableRoot.contains(range.commonAncestorContainer)) {\n return;\n }\n\n // Expand selection to fully include any partially-selected ${...} expressions\n expandRangeToTemplateExpressions(range);\n\n // Find all elements matching `tag` that intersect the selection\n const matches = findIntersectingElements(tag, range, editableRoot);\n\n if (matches.length > 0) {\n unwrapTagInRange(tag, range, editableRoot, matches);\n } else {\n wrapRangeInTag(tag, range, editableRoot);\n }\n\n normalizeInlineContent(editableRoot);\n}\n\n/**\n * Find all elements with the given tag that intersect the selection range.\n *\n * @param {string} tag\n * @param {Range} range\n * @param {HTMLElement} root\n * @returns {Element[]}\n */\nfunction findIntersectingElements(tag: string, range: Range, root: HTMLElement) {\n const matches: Element[] = [];\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {\n /**\n * @param {Node} node\n * @returns {number}\n */\n acceptNode(node: Node) {\n if ((node as Element).tagName.toLowerCase() === tag && range.intersectsNode(node)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n return NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) {\n matches.push(walker.currentNode as Element);\n }\n return matches;\n}\n\n/**\n * Unwrap all instances of `tag` within the range. Processes in reverse document order to preserve\n * earlier offsets.\n *\n * @param {string} tag\n * @param {Range} range\n * @param {HTMLElement} editableRoot\n * @param {Element[]} matches\n */\nfunction unwrapTagInRange(\n _tag: string,\n _range: Range,\n _editableRoot: HTMLElement,\n matches: Element[],\n) {\n // Process in reverse so DOM mutations don't shift later nodes\n for (let i = matches.length - 1; i >= 0; i--) {\n const el = matches[i]!;\n unwrapElement(el);\n }\n}\n\n/**\n * Replace an element with its children (unwrap).\n *\n * @param {Element} el\n */\nfunction unwrapElement(el: Element) {\n const parent = el.parentNode;\n if (!parent) {\n return;\n }\n const frag = document.createDocumentFragment();\n while (el.firstChild) {\n frag.append(el.firstChild);\n }\n el.replaceWith(frag);\n}\n\n/**\n * Wrap the current selection range in a new element of the given tag. Handles whitespace:\n * leading/trailing whitespace stays outside the wrapper.\n *\n * @param {string} tag\n * @param {Range} range\n * @param {HTMLElement} _editableRoot\n */\nfunction wrapRangeInTag(tag: string, range: Range, _editableRoot: HTMLElement) {\n const contents = range.extractContents();\n\n // Trim leading whitespace from the fragment\n const leadingWS = trimLeadingWhitespace(contents);\n // Trim trailing whitespace from the fragment\n const trailingWS = trimTrailingWhitespace(contents);\n\n // If nothing left after trimming, re-insert everything and bail\n if (!contents.hasChildNodes()) {\n if (leadingWS) {\n range.insertNode(document.createTextNode(leadingWS));\n }\n if (trailingWS) {\n const t = document.createTextNode(trailingWS);\n range.collapse(false);\n range.insertNode(t);\n }\n return;\n }\n\n const wrapper = document.createElement(tag);\n wrapper.append(contents);\n\n // Build the insertion fragment: [leadingWS] [wrapper] [trailingWS]\n const frag = document.createDocumentFragment();\n if (leadingWS) {\n frag.append(document.createTextNode(leadingWS));\n }\n frag.append(wrapper);\n if (trailingWS) {\n frag.append(document.createTextNode(trailingWS));\n }\n\n range.insertNode(frag);\n\n // Restore selection around the wrapper's contents\n const sel = window.getSelection();\n if (sel) {\n sel.removeAllRanges();\n const newRange = document.createRange();\n newRange.selectNodeContents(wrapper);\n sel.addRange(newRange);\n }\n}\n\n/**\n * Remove and return leading whitespace from a document fragment. Only trims if the first node is a\n * text node starting with whitespace.\n *\n * @param {DocumentFragment} frag\n * @returns {string | null}\n */\nfunction trimLeadingWhitespace(frag: DocumentFragment) {\n const first = frag.firstChild;\n if (!first || first.nodeType !== Node.TEXT_NODE) {\n return null;\n }\n const text = first.textContent ?? \"\";\n const match = text.match(/^(\\s+)/);\n if (!match) {\n return null;\n }\n const ws = match[1]!;\n if (text.length === ws.length) {\n // Entire node is whitespace — remove it\n first.remove();\n } else {\n first.textContent = text.slice(ws.length);\n }\n return ws;\n}\n\n/**\n * Remove and return trailing whitespace from a document fragment. Only trims if the last node is a\n * text node ending with whitespace.\n *\n * @param {DocumentFragment} frag\n * @returns {string | null}\n */\nfunction trimTrailingWhitespace(frag: DocumentFragment) {\n const last = frag.lastChild;\n if (!last || last.nodeType !== Node.TEXT_NODE) {\n return null;\n }\n const text = last.textContent ?? \"\";\n const match = text.match(/(\\s+)$/);\n if (!match) {\n return null;\n }\n const ws = match[1]!;\n if (text.length === ws.length) {\n last.remove();\n } else {\n last.textContent = text.slice(0, -ws.length);\n }\n return ws;\n}\n\n// ─── Normalization ─────────────────────────────────────────────────────────────\n\n/**\n * Normalize the inline content of an editable root. Merges adjacent same-tag siblings, collapses\n * redundant nesting, removes empty inline elements, and lifts edge whitespace. Runs to\n * fixed-point.\n *\n * @param {HTMLElement | null} root\n */\nexport function normalizeInlineContent(root: HTMLElement | null) {\n if (!root) {\n return;\n }\n let changed = true;\n let iterations = 0;\n while (changed && iterations < 10) {\n changed = false;\n iterations += 1;\n\n // 1. Merge adjacent text nodes\n root.normalize();\n\n // 2. Merge adjacent same-tag siblings\n if (mergeAdjacentSiblings(root)) {\n changed = true;\n }\n\n // 3. Collapse redundant nesting (strong > strong → strong)\n if (collapseRedundantNesting(root)) {\n changed = true;\n }\n\n // 4. Remove empty inline elements\n if (removeEmptyInlines(root)) {\n changed = true;\n }\n\n // 5. Lift edge whitespace out of inline wrappers\n if (liftEdgeWhitespace(root)) {\n changed = true;\n }\n\n // 6. Unwrap bare <span> elements (no class, style, or attributes)\n if (unwrapBareSpans(root)) {\n changed = true;\n }\n }\n}\n\n/**\n * Merge adjacent sibling elements with the same tag name. E.g.,\n * <strong>a</strong><strong>b</strong> → <strong>ab</strong>\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction mergeAdjacentSiblings(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toMerge: [Element, Element][] = [];\n\n // Collect pairs first to avoid mutation during walk\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n const next = el.nextSibling;\n if (\n next &&\n next.nodeType === Node.ELEMENT_NODE &&\n (next as Element).tagName === el.tagName &&\n FORMAT_TAGS.has(el.tagName.toLowerCase()) &&\n attributesMatch(el, next as Element)\n ) {\n toMerge.push([el, next as Element]);\n }\n }\n\n // Process in reverse to preserve earlier offsets\n for (let i = toMerge.length - 1; i >= 0; i--) {\n const [el, next] = toMerge[i]!;\n // Move all children from next into el\n while (next.firstChild) {\n el.append(next.firstChild);\n }\n next.remove();\n changed = true;\n }\n return changed;\n}\n\n/**\n * Collapse redundant nesting where a parent and its only child share the same tag. E.g.,\n * <strong><strong>x</strong></strong> → <strong>x</strong>\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction collapseRedundantNesting(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toCollapse: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {\n continue;\n }\n // Check if only child is an element with the same tag\n if (\n el.childNodes.length === 1 &&\n el.firstChild !== null &&\n el.firstChild.nodeType === Node.ELEMENT_NODE &&\n (el.firstChild as Element).tagName === el.tagName\n ) {\n toCollapse.push(el);\n }\n }\n\n for (const el of toCollapse) {\n const inner = el.firstChild as Element;\n // Replace outer with inner's children\n while (inner.firstChild) {\n inner.before(inner.firstChild);\n }\n inner.remove();\n changed = true;\n }\n return changed;\n}\n\n/**\n * Remove empty inline elements.\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction removeEmptyInlines(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toRemove: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {\n continue;\n }\n if (el.childNodes.length === 0 && !el.textContent) {\n toRemove.push(el);\n }\n }\n\n for (const el of toRemove) {\n el.remove();\n changed = true;\n }\n return changed;\n}\n\n/**\n * Lift leading/trailing whitespace out of inline wrapper elements. E.g., <strong> text </strong> →\n * \" \"<strong>text</strong>\" \"\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction liftEdgeWhitespace(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n /** @type {{ type: string; el: Element; ws: string }[]} */\n const ops = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {\n continue;\n }\n if (el === root) {\n continue;\n }\n\n const first = el.firstChild;\n if (first && first.nodeType === Node.TEXT_NODE) {\n const text = first.textContent ?? \"\";\n const m = text.match(/^(\\s+)/);\n if (m && text.length > m[1]!.length) {\n ops.push({ el, type: \"lift-leading\", ws: m[1]! });\n }\n }\n\n const last = el.lastChild;\n if (last && last.nodeType === Node.TEXT_NODE && last !== first) {\n const text = last.textContent ?? \"\";\n const m = text.match(/(\\s+)$/);\n if (m && text.length > m[1]!.length) {\n ops.push({ el, type: \"lift-trailing\", ws: m[1]! });\n }\n }\n }\n\n for (const op of ops) {\n if (op.type === \"lift-leading\") {\n const firstChild = op.el.firstChild as Text;\n firstChild.textContent = (firstChild.textContent ?? \"\").slice(op.ws.length);\n op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el);\n changed = true;\n } else if (op.type === \"lift-trailing\") {\n const lastChild = op.el.lastChild as Text;\n lastChild.textContent = (lastChild.textContent ?? \"\").slice(0, -op.ws.length);\n op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el.nextSibling);\n changed = true;\n }\n }\n return changed;\n}\n\n/**\n * Unwrap bare <span> elements that have no class, style, or meaningful attributes. These are\n * semantically empty wrappers left over from formatting operations.\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction unwrapBareSpans(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toUnwrap: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (el.tagName.toLowerCase() !== \"span\") {\n continue;\n }\n if (el === root) {\n continue;\n }\n // Keep spans with class, style, or any attributes\n if (el.attributes.length > 0) {\n continue;\n }\n toUnwrap.push(el);\n }\n\n for (const el of toUnwrap) {\n unwrapElement(el);\n changed = true;\n }\n return changed;\n}\n\n/**\n * Check if two elements have matching attributes (for merge eligibility). For simple formatting\n * tags, attributes don't matter. For <a>, href must match.\n *\n * @param {Element} a\n * @param {Element} b\n * @returns {boolean}\n */\nfunction attributesMatch(a: Element, b: Element) {\n const tag = a.tagName.toLowerCase();\n if (tag === \"a\") {\n return a.getAttribute(\"href\") === b.getAttribute(\"href\");\n }\n // For simple format tags, always match\n return true;\n}\n\n// ─── Template expression preservation ─────────────────────────────────────────\n\n/**\n * Expand a Range so that it fully includes any `${...}` template expressions that are partially\n * selected. Template expressions are atomic in Jx — if split across inline elements, the template\n * string breaks.\n *\n * Scans the text content of the start and end containers for `${...}` patterns and adjusts the\n * range boundaries outward to include the complete expression.\n *\n * @param {Range} range\n */\nexport function expandRangeToTemplateExpressions(range: Range) {\n expandBoundary(range, true); // Start\n expandBoundary(range, false); // End\n}\n\n/**\n * Expand one boundary (start or end) of a range to avoid splitting a ${...}. `isStart` = true\n * adjusts startContainer/startOffset, `isStart` = false adjusts endContainer/endOffset.\n *\n * @param {Range} range\n * @param {boolean} isStart\n */\nfunction expandBoundary(range: Range, isStart: boolean) {\n const node = isStart ? range.startContainer : range.endContainer;\n const offset = isStart ? range.startOffset : range.endOffset;\n if (node.nodeType !== Node.TEXT_NODE) {\n return;\n }\n\n const text = node.textContent ?? \"\";\n\n // Find all ${...} expression spans in this text node (supporting nested braces)\n const exprs = findTemplateExpressions(text);\n for (const expr of exprs) {\n // Expr = { start, end } — character indices of \"$\" and the closing \"}\" + 1\n if (isStart) {\n // If the range starts inside this expression, move it to include the whole expr\n if (offset > expr.start && offset < expr.end) {\n range.setStart(node, expr.start);\n }\n } else if (offset > expr.start && offset < expr.end) {\n // If the range ends inside this expression, expand to include the whole expr\n range.setEnd(node, expr.end);\n }\n }\n}\n\n/**\n * Find all `${...}` expression spans in a string, handling nested braces. Returns array of { start,\n * end } where start is the index of '$' and end is one past the closing '}'.\n *\n * @param {string} text\n * @returns {{ start: number; end: number }[]}\n */\nexport function findTemplateExpressions(text: string) {\n /** @type {{ start: number; end: number }[]} */\n const results = [];\n let i = 0;\n while (i < text.length - 1) {\n if (text[i] === \"$\" && text[i + 1] === \"{\") {\n const start = i;\n let depth = 1;\n let j = i + 2;\n while (j < text.length && depth > 0) {\n if (text[j] === \"{\") {\n depth += 1;\n } else if (text[j] === \"}\") {\n depth -= 1;\n }\n j += 1;\n }\n if (depth === 0) {\n results.push({ end: j, start });\n i = j;\n continue;\n }\n }\n i += 1;\n }\n return results;\n}\n",
10
+ "/**\n * Which tags can hold a text caret.\n *\n * The canvas carries a document-wide caret, so this set decides where a click lands — a tag missing\n * from it reads to the author as \"this text is not editable\", because clicking simply does nothing.\n * It used to be a hand-maintained list of thirteen tag names, which meant every new text-bearing\n * element had to be remembered here, and the list could disagree with what the document's own\n * vocabulary said.\n *\n * It is now DERIVED, from two sources resolved per tag:\n *\n * 1. **The format class**, when the document has one (`$studio.elements`, via\n * {@link file://../format/constraints.ts}'s `formatEditableVerdicts`). Authoritative for the\n * tags it declares — and able to say NO, which is why this is a per-tag lookup and not a union.\n * 2. **The studio's own element metadata** (`elements-meta.json`) for everything else: HTML that\n * reaches the canvas through a directive, and native `.json` documents, which have no format\n * class at all.\n *\n * The metadata rule is the same in both: a tag holds a caret when it accepts inline children.\n * Containers declare `\"$inlineChildren\": []` and are excluded by it without needing to be named.\n */\n\nimport elementsMeta from \"../../data/elements-meta.json\";\n\ninterface ElementDef {\n $inlineChildren?: string[];\n}\n\n/**\n * Tags the studio's own metadata says accept inline children.\n *\n * `pre` is excluded despite qualifying: its content is preformatted code, where whitespace is\n * significant and the inline-markup path does not apply. Markdown's format class independently\n * agrees (`\"pre\": { \"only\": [\"code\"] }`).\n */\nconst EXCLUDED = new Set([\"pre\"]);\n\nexport const BUILTIN_EDITABLE_TAGS: ReadonlySet<string> = new Set(\n Object.entries(elementsMeta.$defs as Record<string, ElementDef>)\n .filter(([tag, def]) => !EXCLUDED.has(tag) && (def.$inlineChildren?.length ?? 0) > 0)\n .map(([tag]) => tag),\n);\n\n/**\n * The format's per-tag overrides, or null when the document has no format class (a native `.json`\n * document) — in which case the built-in metadata answers on its own.\n */\nexport type EditableVerdicts = Readonly<Record<string, boolean>> | null;\n\n/** Whether `tag` can hold a caret, given the live document's format overrides. */\nexport function isEditableTag(tag: string, verdicts: EditableVerdicts): boolean {\n const declared = verdicts?.[tag.toLowerCase()];\n return declared ?? BUILTIN_EDITABLE_TAGS.has(tag.toLowerCase());\n}\n",
11
+ "/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Inline-edit.js — Contenteditable inline editing for content mode\n *\n * Manages the lifecycle of editing text-bearing block elements directly on the canvas. Handles rich\n * text formatting, Enter for new paragraphs, and slash commands for inserting elements.\n */\n\nimport elementsMeta from \"../../data/elements-meta.json\";\nimport { displayTagName } from \"@jxsuite/schema/guards\";\nimport { normalizeInlineContent } from \"./inline-format\";\nimport { isEditableTag } from \"./editable-tags\";\nimport type { EditableVerdicts } from \"./editable-tags\";\nimport type { JxPath } from \"../state\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * The slash-menu surface inline editing drives. Injected (rather than imported) so this module\n * stays free of the menu's heavy `lit-html` / `ui/layers` dependencies — the editor realm wires the\n * real menu, the canvas iframe supplies its own (or a no-op) without bloating the slim iframe\n * bundle.\n */\nexport interface SlashController {\n show: (\n anchorEl: HTMLElement,\n filter: string,\n cbs: { onSelect: (cmd: SlashCommand) => void; showFilter?: boolean; commands?: SlashCommand[] },\n ) => void;\n dismiss: () => void;\n isOpen: () => boolean;\n}\n\nconst noopSlash: SlashController = {\n dismiss: () => {\n // No slash controller wired in this realm.\n },\n isOpen: () => false,\n show: () => {\n // No slash controller wired in this realm.\n },\n};\nlet slash: SlashController = noopSlash;\n\n/** Inject the slash-menu controller inline editing should drive (call once at realm init). */\nexport function setSlashController(controller: SlashController): void {\n slash = controller;\n}\n\nexport interface InlineAction {\n tag: string;\n label: string;\n icon?: string;\n command?: string;\n /**\n * REMOVED from the data, and the field stays only so an older `elements-meta.json` still parses.\n *\n * It held `\"Cmd+B\"` — a mac spelling, printed verbatim into every tooltip on every platform,\n * which is the hardcoded-chord defect plan §5.3 exists to kill. The chord now lives on the\n * `format.*` record (`panels/block-action-bar.ts`) and is formatted by the keymap's one\n * formatter. Nothing reads this.\n */\n shortcut?: string;\n}\n\ninterface ElementDef {\n $inlineChildren?: string[];\n $inlineActions?: InlineAction[] | string;\n}\n\nexport interface SlashCommand {\n label: string;\n tag: string;\n description: string;\n}\n\nexport interface JxContentResult {\n textContent?: string | null;\n children?: (JxMutableNode | string)[];\n}\n\n// ─── Inline tag set (tags that represent rich text formatting) ─────────────\n\n/** Fallback set — used when parent context is unknown */\nconst INLINE_TAGS = new Set([\n \"em\",\n \"strong\",\n \"del\",\n \"code\",\n \"a\",\n \"span\",\n \"br\",\n \"img\",\n \"b\",\n \"i\",\n \"u\",\n \"sub\",\n \"sup\",\n \"s\",\n]);\n\n// ─── Context-aware inline scoping ─────────────────────────────────────────\n\n/**\n * Check if a child tag is inline within the context of a given parent tag. Uses $inlineChildren\n * from elements-meta.json.\n *\n * @param {string} childTag\n * @param {string} parentTag\n * @returns {boolean}\n */\nexport function isInlineInContext(childTag: string, parentTag: string) {\n if (!parentTag) {\n return INLINE_TAGS.has(childTag);\n }\n const parentDef = (elementsMeta.$defs as Record<string, ElementDef>)[parentTag];\n if (!parentDef || !parentDef.$inlineChildren) {\n return false;\n }\n return parentDef.$inlineChildren.includes(childTag);\n}\n\n/**\n * Get the resolved $inlineActions for a given element tag. Follows string references (e.g., \"h1\" →\n * look up h1's actions).\n *\n * @param {string} tag\n * @returns {InlineAction[] | null}\n */\nexport function getInlineActions(tag: string) {\n const def = (elementsMeta.$defs as Record<string, ElementDef>)[tag];\n if (!def) {\n return null;\n }\n let actions = def.$inlineActions;\n if (typeof actions === \"string\") {\n const refDef = (elementsMeta.$defs as Record<string, ElementDef>)[actions];\n actions = refDef?.$inlineActions ?? undefined;\n }\n if (!Array.isArray(actions)) {\n return null;\n }\n return actions;\n}\n\n// ─── Editing state ─────────────────────────────────────────────────────────\n\nlet activeEl: HTMLElement | null = null; // Currently contenteditable element\nlet activePath: JxPath | null = null; // JSON path to the active element\n/**\n * @type {((\n * path: JxPath,\n * children: (JxMutableNode | string)[] | null,\n * textContent: string | null,\n * ) => void)\n * | null}\n */\nlet commitFn:\n | ((\n path: JxPath,\n children: (JxMutableNode | string)[] | null,\n textContent: string | null,\n inPlace: boolean,\n ) => void)\n | null = null; // Function(path, newChildren, newTextContent, inPlace) to commit changes\n/**\n * @type {((path: JxPath, beforeChildren: JxContentResult, afterChildren: JxContentResult) => void)\n * | null}\n */\nlet splitFn:\n | ((path: JxPath, beforeChildren: JxContentResult, afterChildren: JxContentResult) => void)\n | null = null; // Function(path, beforeChildren, afterChildren) to split paragraph\n/**\n * @type {((path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void)\n * | null}\n */\nlet insertFn:\n | ((path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void)\n | null = null; // Function(path, elementDef, commitData?) to insert after current block\nlet endFn: (() => void) | null = null; // Function() called when editing stops\n\n/**\n * Plain (plaintext-only) session state — used for prop-bound text, where the committed value is a\n * plain string (a directive attribute), so rich formatting, Enter-split, and the slash menu are all\n * disabled: Enter commits, Escape restores `_plainOriginal` and commits unchanged (the host no-ops\n * an unchanged prop value).\n */\nlet _plainMode = false;\nlet _plainOriginal = \"\";\n\n/**\n * The live document's format overrides for which tags hold a caret. Injected per render (the same\n * shape as `setSlashController`), because the answer depends on the document's format class — a\n * `.md` page and a native `.json` component have different vocabularies.\n */\nlet editableVerdicts: EditableVerdicts = null;\n\n/** Adopt the format's per-tag caret verdicts for the live render (null = built-in metadata only). */\nexport function setEditableVerdicts(verdicts: EditableVerdicts): void {\n editableVerdicts = verdicts;\n}\n\n/**\n * Whether an element can hold a text caret.\n *\n * Derived from the document's element vocabulary rather than a hand-maintained list — see\n * {@link file://./editable-tags.ts}.\n */\nexport function isEditableBlock(el: HTMLElement) {\n return isEditableTag(el.tagName, editableVerdicts);\n}\n\n/**\n * Check if a node is an inline child. When parentNode is provided, uses context-aware scoping from\n * metadata. Without parent, uses the fallback INLINE_TAGS set.\n *\n * @param {JxMutableNode} node\n * @param {JxMutableNode} [parentNode]\n * @returns {boolean}\n */\nexport function isInlineElement(node: JxMutableNode, parentNode?: JxMutableNode) {\n if (!node || typeof node !== \"object\") {\n return false;\n }\n const childTag = (displayTagName(node.tagName) || \"div\").toLowerCase();\n if (parentNode) {\n const parentTag = (displayTagName(parentNode.tagName) || \"div\").toLowerCase();\n return isInlineInContext(childTag, parentTag);\n }\n return INLINE_TAGS.has(childTag);\n}\n\n/**\n * Start inline editing on a canvas element.\n *\n * @param {HTMLElement} el - The canvas DOM element to edit\n * @param {JxPath} path - JSON path to the element\n * @param {{\n * onCommit: (\n * path: JxPath,\n * children: (JxMutableNode | string)[] | null,\n * textContent: string | null,\n * ) => void;\n * onSplit: (\n * path: JxPath,\n * beforeChildren: JxContentResult,\n * afterChildren: JxContentResult,\n * ) => void;\n * onInsert: (path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void;\n * onEnd: () => void;\n * }} callbacks\n * @param {{ plainText?: boolean }} [opts] - `plainText` runs a plaintext-only session (prop-bound\n * text: no rich formatting/split/slash; Enter commits, Escape cancels)\n */\nexport function startEditing(\n el: HTMLElement,\n path: JxPath,\n callbacks: {\n onCommit: (\n path: JxPath,\n children: (JxMutableNode | string)[] | null,\n textContent: string | null,\n inPlace: boolean,\n ) => void;\n onSplit: (\n path: JxPath,\n beforeChildren: JxContentResult,\n afterChildren: JxContentResult,\n ) => void;\n onInsert: (path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void;\n onEnd: () => void;\n },\n opts?: { plainText?: boolean },\n) {\n if (activeEl) {\n // Re-enter (e.g. after a split/insert re-render): tear the old session down WITHOUT firing the\n // User-visible `onEnd` — a re-enter must not reset the parent toolbar via a stray `editEnd`.\n stopEditing(true);\n }\n\n activeEl = el;\n activePath = path;\n commitFn = callbacks.onCommit;\n splitFn = callbacks.onSplit;\n insertFn = callbacks.onInsert;\n endFn = callbacks.onEnd;\n _plainMode = opts?.plainText === true;\n _plainOriginal = _plainMode ? (el.textContent ?? \"\") : \"\";\n\n // Mark the caret's block so the empty-block slash hint can target it. The editing host itself is\n // The canvas container (see syncEditableRoot) — activating a block does NOT make it a separate\n // Contenteditable, which is exactly what lets the caret cross block boundaries natively.\n //\n // A prop-bound block is the one exception: it lives inside a `contenteditable=\"false\"` component\n // Island, so it needs its own nested editing host to be reachable at all.\n el.dataset.jxActiveBlock = \"\";\n if (_plainMode) {\n try {\n el.contentEditable = \"plaintext-only\";\n } catch {\n // Engines without plaintext-only support throw on assignment; paste is already plain via\n // HandlePaste, and the keydown plain branch inertifies the format shortcuts.\n el.contentEditable = \"true\";\n }\n el.focus();\n }\n\n // The caret is NOT moved here. It is already wherever the user clicked or arrowed to — moving it\n // To the end of the block (as this used to) is precisely what made editing feel modal.\n\n el.addEventListener(\"keydown\", handleKeydown);\n el.addEventListener(\"input\", handleInput);\n el.addEventListener(\"paste\", handlePaste);\n}\n\n/**\n * Stop editing and commit changes. Pass `silent` to skip the `onEnd` callback (used by the re-enter\n * path so a stop→start sequence doesn't post a user-visible `editEnd`).\n *\n * @param {boolean} [silent]\n */\nexport function stopEditing(silent = false) {\n if (!activeEl) {\n return;\n }\n\n commitChanges(false);\n slash.dismiss();\n\n delete activeEl.dataset.jxActiveBlock;\n // Only a prop-bound block ever claimed its own editing host; page blocks are edited through the\n // Container's, which must stay editable after the caret leaves this block.\n if (_plainMode) {\n activeEl.contentEditable = \"false\";\n }\n\n activeEl.removeEventListener(\"keydown\", handleKeydown);\n activeEl.removeEventListener(\"input\", handleInput);\n activeEl.removeEventListener(\"paste\", handlePaste);\n\n activeEl = null;\n activePath = null;\n commitFn = null;\n splitFn = null;\n insertFn = null;\n _plainMode = false;\n _plainOriginal = \"\";\n\n if (silent) {\n endFn = null;\n } else if (endFn) {\n const fn = endFn;\n endFn = null;\n fn();\n }\n}\n\n/**\n * Commit the active block's content to the document WITHOUT releasing it.\n *\n * The idle-tick counterpart to {@link stopEditing}: the caret stays exactly where it is and the\n * block stays active, so typing continues uninterrupted while the document keeps up. Callers are\n * responsible for preserving the caret across the DOM normalization this performs — the editing\n * host does that in model coordinates (see `commitTick`).\n *\n * A no-op when nothing is active, and the apply side no-ops an unchanged value, so calling this on\n * every pause is cheap.\n */\nexport function commitActiveBlock(): void {\n commitChanges(true);\n}\n\n/**\n * Whether inline editing is currently active.\n *\n * @returns {boolean}\n */\nexport function isEditing() {\n return activeEl !== null;\n}\n\n/**\n * Get the currently editing element.\n *\n * @returns {HTMLElement | null}\n */\nexport function getActiveElement() {\n return activeEl;\n}\n\n/**\n * Get the document path of the currently editing element (null when no session is live).\n *\n * @returns {JxPath | null}\n */\nexport function getActivePath() {\n return activePath;\n}\n\n/**\n * Whether the DI'd slash menu reports itself open — session-lifecycle guards must not commit-and-\n * end on a pointerdown that is really a slash-menu interaction.\n *\n * @returns {boolean}\n */\nexport function isSlashActive() {\n return slash.isOpen();\n}\n\n// ─── Event handlers ────────────────────────────────────────────────────────\n\n/** @param {KeyboardEvent} e */\nfunction handleKeydown(e: KeyboardEvent) {\n if (_plainMode) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n if (activeEl) {\n // Cancel: restore the original text; the commit posts the unchanged value (host no-ops).\n activeEl.textContent = _plainOriginal;\n }\n stopEditing();\n return;\n }\n if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n stopEditing();\n return;\n }\n // Inertify the browser's native rich shortcuts for the contentEditable=\"true\" fallback.\n if ((e.ctrlKey || e.metaKey) && [\"b\", \"i\", \"u\", \"`\"].includes(e.key)) {\n e.preventDefault();\n }\n }\n\n // Escape and Enter are NOT handled here. Enter arrives as a `beforeinput` (`insertParagraph`),\n // Which is the one place structural intent is classified; Escape belongs to the editing host,\n // Which owns dismissing the caret. See {@link file://../canvas/iframe-editable-root.ts}.\n //\n // Neither is the \"/\" gesture, and neither are the format chords. Both used to be here, and\n // Both were DEAD: this listener is attached to the BLOCK, and for an ordinary block the editing\n // Host is the canvas container (see {@link startEditing}), so the focused element — and every\n // Keydown's target — is the container, never a descendant of it. The \"/\" trigger is\n // {@link handleSlashTrigger}, driven from the host; the format chords are `format.*` records\n // Whose chords the frame forwards (`canvas/iframe-keys.ts`). A revived copy here would have\n // Toggled bold twice per press.\n}\n\nfunction handleInput() {\n // Check if slash menu should update or dismiss\n if (slash.isOpen()) {\n refreshSlashMenu();\n }\n}\n\n/** @param {ClipboardEvent} e */\nfunction handlePaste(e: ClipboardEvent) {\n e.preventDefault();\n // Paste as plain text to avoid foreign HTML\n const text = e.clipboardData?.getData(\"text/plain\") ?? \"\";\n document.execCommand(\"insertText\", false, text);\n}\n\n// ─── Enter: split the active block ─────────────────────────────────────────\n\n/**\n * Split the active block at the caret, reporting the two halves through `onSplit`.\n *\n * Called from the editing host's `beforeinput` chokepoint (`insertParagraph`), never from a keydown\n * — Enter is a structural intent, and `beforeinput` is the one place those are recognised.\n *\n * A non-collapsed selection INSIDE the block is dropped by construction: the \"before\" half ends at\n * the selection's start and the \"after\" half begins at its end. A selection spanning two blocks is\n * the caller's to reject (the `after` range could not be built against this block).\n *\n * The active block is released WITHOUT committing — the split writes both halves itself, and a\n * commit racing it would re-apply the pre-split text over the first one. Returns false when there\n * is nothing to split.\n */\nexport function splitActiveBlock(): boolean {\n if (!splitFn || !activeEl || !activePath) {\n return false;\n }\n\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return false;\n }\n\n const range = sel.getRangeAt(0);\n\n const beforeRange = document.createRange();\n beforeRange.setStart(activeEl, 0);\n beforeRange.setEnd(range.startContainer, range.startOffset);\n\n const afterRange = document.createRange();\n afterRange.setStart(range.endContainer, range.endOffset);\n afterRange.setEnd(activeEl, activeEl.childNodes.length);\n\n const beforeChildren = fragmentToJx(beforeRange.cloneContents());\n const afterChildren = fragmentToJx(afterRange.cloneContents());\n\n const path = [...activePath];\n const split = splitFn;\n\n releaseWithoutCommit();\n split(path, beforeChildren, afterChildren);\n return true;\n}\n\n/**\n * Drop the active block's bookkeeping without committing it, firing `onEnd`. Used by the paths that\n * write the block's content themselves (split, slash-insert) — a commit afterwards would clobber\n * what they just wrote.\n */\nfunction releaseWithoutCommit(): void {\n if (!activeEl) {\n return;\n }\n delete activeEl.dataset.jxActiveBlock;\n if (_plainMode) {\n activeEl.contentEditable = \"false\";\n }\n activeEl.removeEventListener(\"keydown\", handleKeydown);\n activeEl.removeEventListener(\"input\", handleInput);\n activeEl.removeEventListener(\"paste\", handlePaste);\n activeEl = null;\n activePath = null;\n commitFn = null;\n splitFn = null;\n insertFn = null;\n _plainMode = false;\n _plainOriginal = \"\";\n\n if (endFn) {\n const fn = endFn;\n endFn = null;\n fn();\n }\n}\n\n// ─── Content sync: DOM → Jx ────────────────────────────────────────────\n\n/**\n * Serialize the active block and hand it to `onCommit`.\n *\n * `inPlace` distinguishes the idle tick (the caret is still in this block) from a release. The\n * parent uses it to suppress the DOM half of the echoed patch, so a commit mid-typing cannot\n * re-render the subtree the caret lives in.\n */\nfunction commitChanges(inPlace: boolean) {\n if (!commitFn || !activeEl || !activePath) {\n return;\n }\n\n if (_plainMode) {\n // A prop value is a plain single-line string (a directive attribute) — flatten any newline\n // That survived plaintext editing and skip the rich DOM→Jx serialization entirely.\n commitFn(activePath, null, (activeEl.textContent ?? \"\").replaceAll(\"\\n\", \" \"), inPlace);\n return;\n }\n\n normalizeInlineContent(activeEl);\n const result = elementToJx(activeEl);\n commitFn(activePath, result.children ?? null, result.textContent ?? null, inPlace);\n}\n\n/**\n * Normalize a node's children array: merge adjacent text nodes and fold all-text children into\n * textContent. Returns `{ textContent }` or `{ children }`.\n *\n * @param {{ children?: (JxMutableNode | string)[] }} node\n * @returns {JxContentResult}\n */\nexport function normalizeChildren(node: { children?: (JxMutableNode | string)[] }) {\n if (!Array.isArray(node.children) || node.children.length === 0) {\n return { textContent: \"\" };\n }\n\n // Step 1: Merge adjacent text nodes\n const merged = [];\n for (const child of node.children) {\n if (typeof child === \"string\" && merged.length > 0 && typeof merged.at(-1) === \"string\") {\n merged[merged.length - 1] += child;\n } else {\n merged.push(child);\n }\n }\n\n // Step 2: If all children are text, fold into textContent\n if (merged.every((c: JxMutableNode | string) => typeof c === \"string\")) {\n return { textContent: merged.join(\"\") };\n }\n\n return { children: merged };\n}\n\n/**\n * Convert a contenteditable element's content to Jx children/textContent. Returns { textContent }\n * for plain text or { children } for rich content.\n *\n * @param {HTMLElement} el\n * @returns {JxContentResult}\n */\nfunction elementToJx(el: HTMLElement): JxContentResult {\n const nodes = el.childNodes;\n\n // If just a single text node, use textContent\n if (nodes.length === 0) {\n return { textContent: \"\" };\n }\n if (nodes.length === 1 && nodes[0]!.nodeType === Node.TEXT_NODE) {\n return { textContent: nodes[0]!.textContent };\n }\n\n // Mixed content → children array\n const children: (JxMutableNode | string)[] = [];\n for (const child of nodes) {\n const jsx = domNodeToJx(child);\n if (jsx !== null && jsx !== undefined) {\n children.push(jsx);\n }\n }\n\n // Normalize: merge adjacent text nodes + fold all-text to textContent\n return normalizeChildren({ children });\n}\n\n/**\n * Convert a DOM node to a Jx element definition.\n *\n * @param {Node} node\n * @returns {JxMutableNode | string | null}\n */\nfunction domNodeToJx(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent;\n if (!text) {\n return null;\n }\n return text; // Bare string — text node child\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return null;\n }\n\n const el = node as HTMLElement;\n const tag = el.tagName.toLowerCase();\n const result: JxMutableNode = { tagName: tag };\n\n // Map browser execCommand output to our tag conventions\n const tagMap: Record<string, string> = {\n b: \"strong\",\n i: \"em\",\n s: \"del\",\n strike: \"del\",\n };\n if (tagMap[tag]) {\n result.tagName = tagMap[tag];\n }\n\n // Attributes\n // A canvas anchor is DE-LINKED in design/edit: the runtime stamps its URL as `data-jx-href` so a\n // Click selects the anchor instead of navigating the iframe (see setCanvasDelinkAnchors). Reading\n // Only `href` here would serialize every edited link as `[text]()` — silently destroying the URL\n // Of any paragraph that happens to contain one.\n const href = el.dataset.jxHref ?? el.getAttribute(\"href\");\n if (tag === \"a\" && href != null) {\n result.attributes = { href };\n if ((el as HTMLAnchorElement).title) {\n result.attributes.title = (el as HTMLAnchorElement).title;\n }\n }\n if (tag === \"code\") {\n result.textContent = el.textContent;\n return result;\n }\n\n // Recurse children\n const { childNodes } = el;\n if (childNodes.length === 0) {\n result.textContent = \"\";\n } else if (childNodes.length === 1 && childNodes[0]!.nodeType === Node.TEXT_NODE) {\n result.textContent = childNodes[0]!.textContent;\n } else {\n result.children = [];\n for (const child of childNodes) {\n const jsx = domNodeToJx(child);\n if (jsx) {\n result.children.push(/** @type {JxMutableNode} */ jsx);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Convert a DocumentFragment to a Jx-compatible structure. Returns { textContent } or { children }.\n *\n * @param {DocumentFragment} frag\n * @returns {JxContentResult}\n */\nfunction fragmentToJx(frag: DocumentFragment) {\n const nodes = frag.childNodes;\n if (nodes.length === 0) {\n return { textContent: \"\" };\n }\n if (nodes.length === 1 && nodes[0]!.nodeType === Node.TEXT_NODE) {\n return { textContent: nodes[0]!.textContent };\n }\n\n const children: (JxMutableNode | string)[] = [];\n for (const child of nodes) {\n const jsx = domNodeToJx(child);\n if (jsx) {\n children.push(jsx);\n }\n }\n\n if (\n children.length === 1 &&\n typeof children[0] !== \"string\" &&\n children[0]!.tagName === \"span\" &&\n typeof children[0]!.textContent === \"string\"\n ) {\n return { textContent: children[0]!.textContent };\n }\n\n return children.length > 0 ? { children } : { textContent: \"\" };\n}\n\n// ─── Rich text helpers ─────────────────────────────────────────────────────\n\n/**\n * @param {Range} range\n * @returns {string}\n */\nfunction getTextBeforeCursor(range: Range) {\n const preRange = document.createRange();\n preRange.setStart(activeEl!, 0);\n preRange.setEnd(range.startContainer, range.startOffset);\n return preRange.toString();\n}\n\n// ─── Slash command menu (delegates to shared slash-menu.js) ──────────────\n\n/** Track the character offset where \"/\" was typed so we can detect backspace-past-slash */\nlet _slashFilterStart = 0;\n\n/**\n * Whether a literal \"/\" in the block anchors the open menu.\n *\n * False when the menu was opened BY NAME — `insert.openSlashMenu`, the palette, the automation\n * runner — where there is no slash in the text at all. Two behaviours hang off it, and both are\n * wrong without it: the filter would be re-derived from the text before the caret and dismiss the\n * menu on the very next keystroke, and selecting a block would delete everything from the previous\n * slash in the line (\"and/or…\") back to the caret. A command-opened menu filters in its own field\n * and deletes nothing.\n */\nlet _slashAnchored = true;\n\n/**\n * Open the slash menu at the caret.\n *\n * Exported because the block-level `keydown` listener that used to call it never fires: for an\n * ordinary block the editing host is the canvas container, so the \"/\" gesture is recognised at the\n * host ({@link handleSlashTrigger}) and a command opens it from the other realm entirely.\n *\n * @param opts.anchored Whether a literal \"/\" precedes the caret. See {@link _slashAnchored}.\n */\nexport function openSlashMenu(opts?: { anchored?: boolean }): void {\n if (!activeEl || !insertFn || !activePath) {\n return;\n }\n\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return;\n }\n const range = sel.getRangeAt(0);\n _slashAnchored = opts?.anchored !== false;\n _slashFilterStart = getTextBeforeCursor(range).length;\n\n // An unanchored menu carries its own filter field: there is no \"/…\" run in the document for the\n // Author to type into, so without one the list could only ever be filtered by scrolling it.\n slash.show(activeEl, \"\", {\n onSelect: handleSlashSelect,\n ...(_slashAnchored ? {} : { showFilter: true }),\n });\n}\n\n/**\n * The \"/\" gesture, driven from the EDITING HOST.\n *\n * A slash opens the menu at the start of a block or after a space — anywhere else it is punctuation\n * (\"and/or\"), and a menu there would be an ambush. The character is allowed to land first, so the\n * document holds what the author typed whether or not they pick anything from the list.\n */\nexport function handleSlashTrigger(e: KeyboardEvent): void {\n if (e.key !== \"/\" || e.ctrlKey || e.metaKey || !activeEl) {\n return;\n }\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) {\n return;\n }\n const textBefore = getTextBeforeCursor(sel.getRangeAt(0));\n if (textBefore === \"\" || textBefore.endsWith(\" \") || textBefore.endsWith(\"\\n\")) {\n requestAnimationFrame(() => openSlashMenu());\n }\n}\n\n/**\n * Re-filter an open menu from the text the author has typed after the \"/\".\n *\n * Exported for the same reason {@link openSlashMenu} is: the `input` listener that called it is on\n * the block, and a contenteditable's `input` targets the editing HOST.\n */\nexport function refreshSlashMenu(): void {\n if (!activeEl || !_slashAnchored) {\n // The menu owns its own filter field; the document has no \"/…\" run to derive one from, and\n // Deriving one would dismiss the menu on the first character.\n return;\n }\n\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n slash.dismiss();\n return;\n }\n\n const range = sel.getRangeAt(0);\n const fullText = getTextBeforeCursor(range);\n const slashIdx = fullText.lastIndexOf(\"/\");\n\n if (slashIdx === -1 || fullText.length < _slashFilterStart - 1) {\n slash.dismiss();\n return;\n }\n\n const filter = fullText.slice(slashIdx + 1).toLowerCase();\n slash.show(activeEl, filter, { onSelect: handleSlashSelect });\n}\n\n/** @param {SlashCommand} cmd */\nfunction handleSlashSelect(cmd: SlashCommand) {\n if (!activeEl || !insertFn || !activePath) {\n return;\n }\n\n /* Remove the \"/command\" run the author typed — but ONLY when a \"/\" is what opened the menu.\n An unanchored menu (opened by name, from the palette or `insert.openSlashMenu`) has no such\n run, and this walk would delete from the last slash ANYWHERE earlier in the block back to the\n caret: type \"and/or\" and pick Heading, and \"or\" goes with it. */\n const sel = _slashAnchored ? window.getSelection() : null;\n if (sel && sel.rangeCount) {\n const range = sel.getRangeAt(0);\n const fullText = getTextBeforeCursor(range);\n const slashIdx = fullText.lastIndexOf(\"/\");\n if (slashIdx !== -1) {\n const walker = document.createTreeWalker(activeEl, NodeFilter.SHOW_TEXT);\n let charCount = 0;\n let slashNode: Text | null = null;\n let slashOffset = 0;\n while (walker.nextNode()) {\n const node = walker.currentNode as Text;\n if (charCount + node.length > slashIdx) {\n slashNode = node;\n slashOffset = slashIdx - charCount;\n break;\n }\n charCount += node.length;\n }\n if (slashNode) {\n const delRange = document.createRange();\n delRange.setStart(slashNode, slashOffset);\n delRange.setEnd(range.startContainer, range.startOffset);\n delRange.deleteContents();\n }\n }\n }\n\n // Compute commit data inline instead of calling commitChanges() — avoids a separate\n // Update() call that would race with the insertFn update() (two concurrent async renders).\n normalizeInlineContent(activeEl);\n const commitResult = elementToJx(activeEl);\n\n const path = [...activePath];\n const insert = insertFn;\n\n // The insert carries `commitResult`, so it writes this block's content itself — releasing without\n // A commit keeps the two from racing.\n releaseWithoutCommit();\n\n // Pass commit data so onInsert can batch commit + insert into a single update()\n insert(path, cmd, commitResult);\n}\n",
12
+ "/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Canvas helpers — extracted from studio.js (Phase 4n). Shared query/utility functions used by\n * multiple canvas-related modules: element lookup, zoom, panel resolution, inline bubbling.\n */\n\nimport { getNodeAtPath, parentElementPath } from \"../store\";\nimport { displayTagName } from \"@jxsuite/schema/guards\";\nimport { activeCanvasSurface, activeMediaOfPane } from \"./canvas-surface\";\nimport { isInlineInContext } from \"../editor/inline-edit\";\nimport type { CanvasSurface } from \"./canvas-surface\";\nimport type { CanvasPanel } from \"../types\";\nimport type { JxPath } from \"../state\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * Convert a canvas panel's mediaName to an activeMedia value. Panels without a breakpoint (content\n * mode, single-panel docs) carry \"\" or \"base\" — both mean the base style context (null).\n *\n * @param {string | null | undefined} mediaName\n * @returns {string | null}\n */\nexport function panelMediaToActiveMedia(mediaName: string | null | undefined) {\n return !mediaName || mediaName === \"base\" ? null : mediaName;\n}\n\n/**\n * The active canvas panel of ONE pane's stage, from that pane's own `activeMedia`.\n *\n * The breakpoint a stage is showing is a fact about the tab in it — `session.ui.activeMedia` — so\n * this reads it from `surface.paneId`'s tab and never from the focus. {@link getActivePanel} is this\n * function applied to the focused pane, which is what \"the active panel\" means when nobody says\n * which one.\n *\n * @param {CanvasSurface} surface\n * @returns {CanvasPanel | null}\n */\nexport function panelOfSurface(surface: CanvasSurface): CanvasPanel | null {\n const canvasPanels = surface.panels;\n if (canvasPanels.length === 0) {\n return null;\n }\n if (canvasPanels.length === 1) {\n return canvasPanels[0]!;\n }\n const activeMedia = activeMediaOfPane(surface.paneId);\n for (const p of canvasPanels) {\n if (activeMedia === null && (p.mediaName === \"base\" || p.mediaName === null)) {\n return p;\n }\n if (p.mediaName === activeMedia) {\n return p;\n }\n }\n return canvasPanels[0]!;\n}\n\n/**\n * Return the active canvas panel of the FOCUSED pane, based on its activeMedia setting.\n *\n * Panels belong to a pane's stage (`canvas-surface.ts`), so \"the active panel\" is only answerable\n * relative to one — this is the pane whose artboards the person is looking at.\n */\nexport function getActivePanel() {\n return panelOfSurface(activeCanvasSurface());\n}\n\n/**\n * Walk up the tree from a path, bubbling past inline elements until we find the nearest non-inline\n * ancestor. Returns the original path if already non-inline.\n *\n * @param {JxMutableNode | undefined} doc\n * @param {JxPath} path\n */\nexport function bubbleInlinePath(doc: JxMutableNode | undefined, path: JxPath) {\n if (!doc) {\n return path;\n }\n let currentPath = path;\n while (currentPath.length >= 2) {\n const node = getNodeAtPath(doc, currentPath);\n const pPath = parentElementPath(currentPath);\n const parentNode = pPath ? getNodeAtPath(doc, pPath) : null;\n if (!node || !parentNode) {\n break;\n }\n const childTag = (displayTagName(node.tagName) || \"div\").toLowerCase();\n const parentTag = (displayTagName(parentNode.tagName) || \"div\").toLowerCase();\n if (!isInlineInContext(childTag, parentTag)) {\n break;\n }\n currentPath = pPath as JxPath;\n }\n return currentPath;\n}\n\n/**\n * Find a canvas DOM element by its document path.\n *\n * @param {JxPath} path\n * @param {HTMLElement} canvasEl\n * @returns {HTMLElement | null}\n */\nexport function findCanvasElement(path: JxPath, canvasEl: HTMLElement) {\n let el: HTMLElement | null | undefined = canvasEl.firstElementChild as HTMLElement | null;\n if (!el) {\n return null;\n }\n if (path.length === 0) {\n return el;\n }\n\n let i = 0;\n while (i < path.length) {\n const seg = path[i];\n // A lone \"map\" segment steps into a repeater perimeter's single template child.\n if (seg === \"map\") {\n el = el.children[0] as HTMLElement | undefined;\n i += 1;\n if (!el) {\n break;\n }\n continue;\n }\n if (seg !== \"children\" && seg !== \"cases\") {\n return null;\n }\n const idx = path[i + 1];\n if (idx === undefined) {\n el = el.children[0] as HTMLElement | undefined;\n } else if (idx === \"map\") {\n // Legacy whole-children template `[..., \"children\", \"map\"]`: perimeter at child[0].\n el = el.children[0]?.children[0] as HTMLElement | undefined;\n } else {\n el = el.children[idx as number] as HTMLElement | undefined;\n }\n if (!el) {\n break;\n }\n i += 2;\n }\n\n return el ?? null;\n}\n",
13
+ "/// <reference lib=\"dom\" />\n/**\n * Canvas panel utilities — extracted from studio.js (Phase 4l). Panzoom infrastructure: panel DOM\n * template creation, centering, transform application, zoom indicator, and fit-to-screen.\n */\n\nimport { html, nothing } from \"lit-html\";\nimport type { CanvasPanel, JsonValue } from \"../types\";\nimport { ref } from \"lit-html/directives/ref.js\";\nimport { classMap } from \"lit-html/directives/class-map.js\";\nimport { styleMap } from \"lit-html/directives/style-map.js\";\nimport { ifDefined } from \"lit-html/directives/if-defined.js\";\n\nimport { renderOnly } from \"../store\";\nimport {\n activeCanvasSurface,\n activeMediaOfPane,\n canvasModeOfPane,\n derivationOfPane,\n tabOfMountedPanel,\n tabOfPane,\n} from \"./canvas-surface\";\nimport type { CanvasSurface } from \"./canvas-surface\";\nimport { activeTab, workspace } from \"../workspace/workspace\";\nimport {\n findCanvasElement,\n getActivePanel,\n panelMediaToActiveMedia,\n panelOfSurface,\n} from \"./canvas-helpers\";\nimport { rectOf } from \"../utils/geometry\";\nimport { getEffectiveLocales, getEffectiveMedia } from \"../site-context\";\nimport { dynamicRouteParams } from \"../page-params\";\nimport {\n argsSchema,\n booleanArg,\n booleanProperty,\n boundedNumberArg,\n enumArg,\n enumProperty,\n numberProperty,\n stringArg,\n stringProperty,\n} from \"../commands/command-args\";\nimport type { TemplateResult } from \"lit-html\";\nimport type { AnyCommand, CommandRegistry } from \"../commands/registry\";\nimport type { CommandArgValues } from \"../commands/command-args\";\nimport type { Tab } from \"../tabs/tab\";\n\n/*\n * There is no `initCanvasUtils`, and no `_ctx`.\n *\n * It injected three functions — `getCanvasMode`, `getZoom`, `setZoomDirect` — and all three were\n * spelled `activeTab.value`, which is the FOCUSED pane's tab. Every geometry function here already\n * takes a `CanvasSurface`, so the pan/zoom offsets and the pan-zoom wrap moved onto it while the\n * SCALE stayed behind the injection, and the two disagreed in four visible ways:\n *\n * 1 · the unfocused pane drew at the focused tab's scale — `scale(1)` for a document at 2×;\n * 2 · the side pane's `+` zoomed the PRIMARY's document, by a factor computed from the side's\n * own zoom (`b.zoom * 1.2` written to `a`);\n * 3 · `getFit()` keyed on `activeTab`, so the unfocused pod reported the focused pane's fit;\n * 4 · the side pane entering Design ran `fitOnCanvasEntry` → `setZoomDirect(0.163)` and the\n * PRIMARY snapped to 16%, because the other pane had fitted itself.\n *\n * `scripts/check-pane-singletons.ts` could not see any of it: it bans `view.<field>` by name and\n * the zoom was never on `view`. The rule it enforces is now the general one — per-stage state is\n * reached through a surface — and this module reads `activeTab` in exactly one place, the command\n * verbs, where \"the active pane\" is the whole meaning of the request.\n */\n\n/** The tab a stage is showing. The one route from a surface to the state its geometry needs. */\nfunction tabOfSurface(surface: CanvasSurface): Tab | null {\n return tabOfPane(surface.paneId);\n}\n\n/**\n * A stage's own pan-zoom scale. 1 when its pane shows nothing.\n *\n * **`session.ui.zoom` is per-TAB, and a LENS shares its tab with the pane beside it** — so under a\n * lens the two stages would zoom together, which is exactly what \"the same page at another\n * breakpoint\" must not do. The derivation carries the lens's own scale.\n */\nfunction zoomOf(surface: CanvasSurface): number {\n const derived = derivationOfPane(surface.paneId);\n if (derived?.kind === \"lens\") {\n return derived.zoom;\n }\n return tabOfSurface(surface)?.session.ui.zoom ?? 1;\n}\n\n/**\n * A stage's own pan-zoom scale, for the CONTROL that reports it.\n *\n * The zoom pod printed `tab.session.ui.zoom`, which is the source pane's number under a lens — so a\n * breakpoint lens zoomed to 40% reported whatever the desktop pane was at, and its `-` divided the\n * wrong figure. Every zoom verb already takes a surface; the readout has to as well.\n */\nexport function stageZoom(surface: CanvasSurface = activeCanvasSurface()): number {\n return zoomOf(surface);\n}\n\n/** Write a stage's own pan-zoom scale. A no-op when its pane shows nothing. See {@link zoomOf}. */\nfunction setZoomOf(surface: CanvasSurface, zoom: number): void {\n const derived = derivationOfPane(surface.paneId);\n if (derived?.kind === \"lens\") {\n derived.zoom = zoom;\n return;\n }\n const tab = tabOfSurface(surface);\n if (tab) {\n tab.session.ui.zoom = zoom;\n }\n}\n\n/**\n * Create the DOM structure for a single canvas panel.\n *\n * @param {string | null} mediaName\n * @param {string | null} label\n * @param {boolean} fullWidth\n * @param {number | null} width\n */\nexport function canvasPanelTemplate(\n mediaName: string | null,\n label: string | null,\n fullWidth: boolean,\n width: number | null = null,\n): { tpl: TemplateResult; panel: CanvasPanel } {\n // The DOM fields start null and are wired by the template's ref() directives,\n // Which lit runs synchronously during render — before any consumer reads them.\n const panel = {\n _width: width || null,\n canvas: null,\n element: null,\n mediaName: mediaName || \"\",\n ready: false,\n renderScope: null,\n scrollContainer: null,\n viewport: null,\n } as unknown as CanvasPanel;\n const tpl = html`\n <div\n class=${classMap({ \"canvas-panel\": true, \"full-width\": fullWidth })}\n data-media=${ifDefined(mediaName !== null ? mediaName : undefined)}\n ${ref((el) => {\n if (el) {\n panel.element = el as HTMLElement;\n }\n })}\n >\n ${\n label\n ? html`\n <div\n class=\"canvas-panel-header\"\n @click=${() => {\n // The breakpoint belongs to the tab of the pane that MOUNTED this artboard — the\n // Parent-side twin of the iframe's `hit` message, resolved the same way.\n // `updateUi` writes to `activeTab`, which is the FOCUSED pane's tab, so clicking\n // A header in an unfocused pane set another document's breakpoint and the Style\n // Panel then edited a compound block the person never opened.\n const tab = tabOfMountedPanel(panel);\n if (tab) {\n tab.session.ui.activeMedia = panelMediaToActiveMedia(mediaName);\n }\n }}\n >\n ${label}\n </div>\n `\n : nothing\n }\n <div\n class=\"canvas-panel-viewport\"\n style=${styleMap({ width: width && !fullWidth ? `${width}px` : \"\" })}\n ${ref((el) => {\n if (el) {\n panel.viewport = el as HTMLElement;\n }\n })}\n >\n <div\n class=\"canvas-panel-canvas\"\n style=${styleMap({ width: width ? `${width}px` : \"\" })}\n ${ref((el) => {\n if (el) {\n panel.canvas = el as HTMLElement;\n }\n })}\n ></div>\n </div>\n </div>\n `;\n return { panel, tpl };\n}\n\n/*\n * Every geometry function below takes its surface EXPLICITLY, and none of them defaults to\n * `activeCanvasSurface()`.\n *\n * A default is how one pane's fit lands on the other's transform: the fit that runs on a mode\n * transition, the observer that re-centres until content settles and the wheel that pans are all\n * scheduled from a render, and a render belongs to the pane it was scheduled for — which is the\n * focused pane only by coincidence. Every call site already holds a surface or a tab.\n */\n\n/** Center a stage's content horizontally in its viewport, top-aligned vertically. */\nexport function centerCanvas(surface: CanvasSurface) {\n if (!surface.panzoomWrap) {\n return;\n }\n const wrapWidth = surface.wrap.clientWidth;\n const contentWidth = surface.panzoomWrap.scrollWidth;\n const zoom = zoomOf(surface);\n const scaledWidth = contentWidth * zoom;\n surface.panX = Math.max(16, (wrapWidth - scaledWidth) / 2);\n surface.panY = 0;\n}\n\n/**\n * Attach a ResizeObserver to view.panzoomWrap that re-centers until the user pans. Handles async\n * content (runtime rendering, data fetching) that changes layout after initial paint.\n */\nexport function observeCenterUntilStable(surface: CanvasSurface) {\n if (surface.centerObserver) {\n surface.centerObserver.disconnect();\n surface.centerObserver = null;\n }\n if (!surface.panzoomWrap) {\n return;\n }\n surface.needsCenter = true;\n surface.centerObserver = new ResizeObserver(() => {\n if (!surface.needsCenter) {\n surface.centerObserver?.disconnect();\n surface.centerObserver = null;\n return;\n }\n centerCanvas(surface);\n applyTransform(surface);\n });\n surface.centerObserver.observe(surface.panzoomWrap);\n centerCanvas(surface);\n}\n\n/** Apply the current zoom + pan transform to the panzoom wrapper. */\nexport function applyTransform(surface: CanvasSurface) {\n if (!surface.panzoomWrap) {\n return;\n }\n const zoom = zoomOf(surface);\n surface.panzoomWrap.style.transform = `translate(${surface.panX}px, ${surface.panY}px) scale(${zoom})`;\n // Overlays live INSIDE the scaled panzoom-wrap (iframe hosts draw there), so no per-mode redraw\n // Is needed here — the flush only re-anchors the fixed block-action-bar. The floating zoom pod\n // Tracks `ui.zoom` reactively, so no explicit indicator refresh is needed either.\n renderOnly(\"overlays\");\n}\n\n// ─── Edit-mode content zoom ──────────────────────────────────────────────────\n// Browser-page-zoom semantics: the canvas footprint stays fixed while the CONTENT reflows at the\n// Zoomed effective width — unlike design mode's panzoom, which visually scales a fixed layout.\n\nexport const EDIT_ZOOM_MIN = 0.25;\n\nexport const EDIT_ZOOM_MAX = 3;\n\n/** Clamp an edit-zoom value to the supported range. */\nexport function clampEditZoom(zoom: number): number {\n return Math.min(EDIT_ZOOM_MAX, Math.max(EDIT_ZOOM_MIN, zoom));\n}\n\n/**\n * Apply the active tab's edit-mode content zoom to the single edit panel.\n *\n * Mechanism: a parent-side transform on the iframe never reflows the iframe's internal document (it\n * is its own layout viewport), so genuine reflow requires resizing the iframe's REAL CSS width to\n * `renderWidth / editZoom` — and a compensating `scale(editZoom)` on the canvas element brings the\n * rendered footprint back to exactly `renderWidth`. The overlay layer (the iframe's DOM sibling\n * inside the canvas element) inherits the transform, so overlay boxes stay drawn at scale 1 (D-2),\n * and `hostDragGeometry`'s empirical `rect.width / clientWidth` evaluates to exactly `editZoom`\n * with no bridge changes.\n *\n * `renderWidth` is measured live from `.content-edit-column` (already `min(baseWidth, available)`\n * via normal block layout) — the nominal `$media[\"--\"]` width would overflow a narrow studio\n * window.\n *\n * HARD INVARIANT: never trigger a canvas re-render from here (`renderCanvas`/`mountIframeCanvas`) —\n * a re-render rebuilds the iframe DOM and would destroy a live inline-edit session. Live zoom is\n * bare style writes only; the iframe's own ResizeObserver re-posts `contentHeight` after the\n * reflow, which also finalizes the viewport height.\n */\nexport function applyEditZoom(surface: CanvasSurface = activeCanvasSurface()) {\n // THIS pane's effective mode. It was the focused pane's, so a side pane in Edit was refused its\n // Own content zoom whenever the primary happened to be in Design.\n if (canvasModeOfPane(surface.paneId) !== \"edit\") {\n return;\n }\n const [panel] = surface.panels;\n if (!panel?.canvas || !panel.viewport) {\n return;\n }\n const canvasEl = panel.canvas;\n const iframe = canvasEl.querySelector(\"iframe\");\n const editZoom = tabOfSurface(surface)?.session.ui.editZoom ?? 1;\n if (editZoom === 1) {\n // Exactly today's fluid behavior — no inline width, no transform, auto viewport height.\n panel._width = null;\n canvasEl.style.width = \"\";\n canvasEl.style.transform = \"\";\n canvasEl.style.transformOrigin = \"\";\n if (iframe) {\n iframe.style.width = \"100%\";\n }\n panel.viewport.style.height = \"\";\n } else {\n const column = surface.wrap.querySelector<HTMLElement>(\".content-edit-column\");\n if (!column) {\n return;\n }\n // The column width is parent-driven (width:100%, max-width:baseWidth), so it is independent of\n // The canvas content — measuring it mid-zoom is stable. No rounding: layoutWidth * editZoom\n // Must equal renderWidth exactly.\n const renderWidth = rectOf(column).width;\n if (renderWidth <= 0) {\n return;\n }\n const layoutWidth = renderWidth / editZoom;\n panel._width = layoutWidth;\n canvasEl.style.width = `${layoutWidth}px`;\n canvasEl.style.transform = `scale(${editZoom})`;\n canvasEl.style.transformOrigin = \"top left\";\n if (iframe) {\n iframe.style.width = `${layoutWidth}px`;\n // Transforms don't affect an ancestor's auto-height, so the viewport (the white \"page\"\n // Surface) needs its height pinned to the SCALED content height. offsetHeight is the\n // Pre-measurement approximation; the next contentHeight message writes the exact value.\n panel.viewport.style.height = `${iframe.offsetHeight * editZoom}px`;\n }\n }\n // Re-anchor the fixed block-action-bar over the rescaled canvas.\n renderOnly(\"overlays\");\n}\n\n/**\n * Set a stage's edit zoom (clamped) and apply it synchronously.\n *\n * The SURFACE decides whose zoom this is, not the focus. Both this and {@link requestEditZoom}\n * opened `activeTab.value`, so the side pane's `+` and the wheel over the side pane's stage — which\n * had already resolved the right surface and the right tab — wrote the primary's `editZoom`.\n */\nexport function setEditZoom(zoom: number, surface: CanvasSurface = activeCanvasSurface()) {\n const tab = tabOfSurface(surface);\n if (!tab) {\n return;\n }\n tab.session.ui.editZoom = clampEditZoom(zoom);\n applyEditZoom(surface);\n}\n\n/**\n * One pending edit-zoom frame PER STAGE.\n *\n * A single `let _editZoomRaf` was a shared slot: a wheel burst over one pane suppressed the other\n * pane's coalesced reflow entirely, and the frame that did run applied whichever surface won the\n * race. Keyed by pane id, for the reason `canvas-render.ts` keys its own render frames that way.\n */\nconst _editZoomRafs = new Map<string, number>();\n\n/**\n * Wheel-rate edit-zoom setter: the reactive `editZoom` write lands immediately (the zoom pod's\n * label tracks it), but the DOM work — an iframe width resize, i.e. a real reflow — is coalesced to\n * one `applyEditZoom()` per animation frame so a fast ctrl+scroll burst doesn't thrash layout.\n */\nexport function requestEditZoom(zoom: number, surface: CanvasSurface = activeCanvasSurface()) {\n const tab = tabOfSurface(surface);\n if (!tab) {\n return;\n }\n tab.session.ui.editZoom = clampEditZoom(zoom);\n if (_editZoomRafs.has(surface.paneId)) {\n return;\n }\n _editZoomRafs.set(\n surface.paneId,\n requestAnimationFrame(() => {\n _editZoomRafs.delete(surface.paneId);\n applyEditZoom(surface);\n }),\n );\n}\n\n/**\n * Compute and apply a geometric fit. Pure arithmetic — it declares nothing.\n *\n * `axis` is the fit's own meaning: `\"page\"` fits both axes (the whole artboard, in view), `\"width\"`\n * fits the horizontal axis and lets the page run off the bottom, which is what you want on a long\n * document you are about to scroll. `maxZoom` caps the result.\n */\nfunction applyGeometricFit(surface: CanvasSurface, axis: \"width\" | \"page\", maxZoom: number): void {\n if (!surface.panzoomWrap) {\n return;\n }\n const wrapWidth = surface.wrap.clientWidth;\n const wrapHeight = surface.wrap.clientHeight;\n const gap = 24;\n const padding = 32;\n let totalPanelWidth = 0;\n const { panels } = surface;\n for (const p of panels) {\n totalPanelWidth += p._width || 800;\n }\n totalPanelWidth += gap * Math.max(0, panels.length - 1) + padding;\n\n const zoom = zoomOf(surface);\n const wrapRect = rectOf(surface.panzoomWrap);\n const unscaledHeight = wrapRect.height / zoom;\n const maxPanelHeight = unscaledHeight + padding;\n\n const fitZoomW = wrapWidth / totalPanelWidth;\n const fitZoomH = wrapHeight / maxPanelHeight;\n const wanted = axis === \"width\" ? fitZoomW : Math.min(fitZoomW, fitZoomH);\n const fitZoom = Math.min(maxZoom, Math.max(PAN_ZOOM_MIN, wanted));\n\n setZoomOf(surface, fitZoom);\n\n const scaledWidth = totalPanelWidth * fitZoom;\n const scaledHeight = maxPanelHeight * fitZoom;\n surface.panX = Math.max(0, (wrapWidth - scaledWidth) / 2);\n surface.panY = Math.max(0, (wrapHeight - scaledHeight) / 2);\n applyTransform(surface);\n}\n\n/**\n * Fit all panels within the viewport, and declare that as the document's fit.\n *\n * `maxZoom` caps the result. The Fit control passes the full {@link PAN_ZOOM_MAX} (asking to fit is\n * asking to magnify a small artboard too); the automatic fit on entering a panzoom mode passes 1,\n * because arriving at a document should never blow it up past life size.\n */\nexport function fitToScreen({\n maxZoom = PAN_ZOOM_MAX,\n surface = activeCanvasSurface(),\n}: { maxZoom?: number; surface?: CanvasSurface } = {}) {\n // Declared before the guard: \"frame the whole page\" is a preference the author expressed, and it\n // Stays true whether or not there is a laid-out artboard to apply it to this instant.\n declareFit(\"page\", surface);\n applyGeometricFit(surface, \"page\", maxZoom);\n}\n\n// ─── Pan-zoom (design / stylebook / git-diff artboards) ──────────────────────\n\nexport const PAN_ZOOM_MIN = 0.05;\n\nexport const PAN_ZOOM_MAX = 5;\n\n/** Clamp a pan-zoom value to the supported range. */\nexport function clampPanZoom(zoom: number): number {\n return Math.min(PAN_ZOOM_MAX, Math.max(PAN_ZOOM_MIN, zoom));\n}\n\n/**\n * How a document is framed when you arrive at it — **declared state**, per tab + document.\n *\n * - `\"page\"` — the whole artboard in view (the default: arriving at a document should show it).\n * - `\"width\"` — fit the horizontal axis; the page runs off the bottom, which is what a long document\n * you are about to scroll actually wants.\n * - `\"none\"` — frame nothing; whatever the zoom is, is the zoom.\n * - A number — that exact pan-zoom.\n *\n * This replaces an IMPLICIT fit-on-entry plus a `Set` of \"documents the author has zoomed by hand\",\n * which had three problems. It could not be read, so the zoom control could not show it. It could\n * not be written, so a preference users expect to persist silently reset. And because entering a\n * mode applied a transform nobody had asked for, anything measuring the canvas from outside had to\n * guess whether a fit had happened — which is precisely how a screen coordinate ends up wrong.\n *\n * \"The author chose 84%\" is not a special case here: it is the fit `0.84`.\n */\nexport type FitMode = \"width\" | \"page\" | \"none\" | number;\n\n/**\n * The fit a document gets when it has not declared one.\n *\n * `\"page\"` because a 1280px artboard used to land clipped mid-word in a ~700px viewport, and\n * arriving at a document should never require a zoom-out before you can read it.\n */\nexport const DEFAULT_FIT: FitMode = \"page\";\n\n/** The three named fits, as the `canvas.setFit` schema and its coercion both read them. */\nexport const FIT_WORDS: readonly string[] = [\"width\", \"page\", \"none\"];\n\n/**\n * Coerce a `canvas.setFit` argument, refusing anything that is neither a named fit nor a scale.\n *\n * Written here rather than in `commands/command-args.ts` because the value space is this module's:\n * {@link FitMode} is declared three lines up, and a second copy of \"which words are fits\" in the\n * shared helpers is exactly the drift the registry projection exists to prevent.\n */\nfunction fitArg(commandId: string, args: Record<string, unknown>, key: string): FitMode {\n const value = args[key];\n if (typeof value === \"string\" && FIT_WORDS.includes(value)) {\n return value as FitMode;\n }\n if (typeof value === \"number\" && value >= PAN_ZOOM_MIN && value <= PAN_ZOOM_MAX) {\n return value;\n }\n throw new RangeError(\n `command \"${commandId}\" argument \"${key}\": expected ${FIT_WORDS.map((w) => `\"${w}\"`).join(\" | \")} ` +\n `or a number in [${PAN_ZOOM_MIN}, ${PAN_ZOOM_MAX}], got ${JSON.stringify(value)}`,\n );\n}\n\n/** Declared fits, keyed per tab + document. */\nconst _fits = new Map<string, FitMode>();\n\n/**\n * The registry key for the document a STAGE is showing (null when its pane shows none).\n *\n * It read `activeTab`, which is why the unfocused pane's zoom pod reported the focused pane's fit —\n * and why \"Fit page\" chosen in one pane changed the label in the other.\n */\nfunction fitKey(surface: CanvasSurface): string | null {\n const tab = tabOfSurface(surface);\n if (!tab) {\n return null;\n }\n /* A LENS shares the tab with the pane it derives from, so the tab alone stops being a key: the\n mobile lens and the desktop pane would declare ONE fit between them and re-frame each other on\n every mode transition. Same reason `zoomOf` reads the derivation. */\n const lens = derivationOfPane(surface.paneId)?.kind === \"lens\" ? `::${surface.paneId}` : \"\";\n return `${tab.id}::${tab.documentPath ?? \"\"}${lens}`;\n}\n\n/** Write a stage's document's fit without applying it — the internal half of {@link setFit}. */\nfunction declareFit(fit: FitMode, surface: CanvasSurface): void {\n const key = fitKey(surface);\n if (key) {\n _fits.set(key, fit);\n }\n}\n\n/** A stage's declared fit, or {@link DEFAULT_FIT}. Readable by that pane's zoom control. */\nexport function getFit(surface: CanvasSurface = activeCanvasSurface()): FitMode {\n const key = fitKey(surface);\n return (key === null ? undefined : _fits.get(key)) ?? DEFAULT_FIT;\n}\n\n/** Whether a stage's document has declared a fit of its own. */\nexport function hasDeclaredFit(surface: CanvasSurface = activeCanvasSurface()): boolean {\n const key = fitKey(surface);\n return key !== null && _fits.has(key);\n}\n\n/** Drop every declared fit — a fresh session, and the tests. */\nexport function resetFits(): void {\n _fits.clear();\n}\n\n/** Honour a fit right now. Defaults to the STAGE's own declared one. */\nexport function applyFit(fit?: FitMode, surface: CanvasSurface = activeCanvasSurface()): void {\n /* Resolved in the body rather than as a parameter default: a default may only read parameters\n declared BEFORE it, and the fit belongs to the surface that comes after. Reading `getFit()`\n with no surface is exactly what made the default answer for the FOCUSED pane. */\n const chosen = fit ?? getFit(surface);\n if (chosen === \"none\") {\n applyTransform(surface);\n return;\n }\n if (typeof chosen === \"number\") {\n setZoomOf(surface, clampPanZoom(chosen));\n applyTransform(surface);\n return;\n }\n // Capped at life size: arriving at a document should never blow it up past 100%.\n applyGeometricFit(surface, chosen, 1);\n}\n\n/** Declare the active document's fit AND honour it. The one writer every control routes through. */\nexport function setFit(fit: FitMode, surface: CanvasSurface = activeCanvasSurface()): void {\n declareFit(fit, surface);\n applyFit(fit, surface);\n}\n\n/**\n * Record the active document's CURRENT pan-zoom as its declared fit.\n *\n * For the gesture paths that move the zoom themselves and then have to say so — ctrl+scroll writes\n * `ui.zoom` directly, pinch will too. An author-chosen zoom is a numeric fit, so re-entering the\n * mode restores it instead of re-framing over the top of it.\n */\nexport function markExplicitZoom(surface: CanvasSurface = activeCanvasSurface()): void {\n declareFit(clampPanZoom(zoomOf(surface)), surface);\n}\n\n/**\n * Set the active tab's pan-zoom on the author's behalf: clamped, declared as this document's fit,\n * and applied. Every author-facing pan-zoom control routes through here.\n */\nexport function setUserZoom(zoom: number, surface: CanvasSurface = activeCanvasSurface()): void {\n const tab = tabOfSurface(surface);\n if (!tab) {\n return;\n }\n // The fit is declared BEFORE the reactive write, not after: `ui.zoom` is tracked, effects run\n // Synchronously on assignment, and the zoom pod reads `getFit()` while it renders — so declaring\n // Second means the control repaints one interaction behind the state it is reporting.\n const next = clampPanZoom(zoom);\n declareFit(next, surface);\n setZoomOf(surface, next);\n applyTransform(surface);\n}\n\n/**\n * Honour the declared fit when a pane enters a panzoom mode (Design, Stylebook).\n *\n * Called on the mode transition only. At that point the panels exist with their declared widths but\n * the iframes have not painted, which is why the geometry is driven by the panel widths rather than\n * by anything measured from content.\n */\nexport function fitOnCanvasEntry(surface: CanvasSurface): void {\n /* An unmeasurable viewport would fit to the 5% floor, which is worse than the clipping this\n replaces. Leave the zoom alone.\n This guard is load-bearing rather than defensive now: a zoomed pane grid hides the other cell\n with `display:none`, so its stage really does measure zero — and unzooming re-fits for free\n through {@link observeCenterUntilStable}'s observer, which fires on the restored layout. */\n if (surface.wrap.clientWidth <= 0) {\n applyTransform(surface);\n return;\n }\n applyFit(getFit(surface), surface);\n}\n\n/** Reset zoom to 100% and re-center horizontally, declaring 100% as this document's fit. */\nexport function resetZoom(surface: CanvasSurface = activeCanvasSurface()) {\n declareFit(1, surface);\n if (!surface.panzoomWrap) {\n return;\n }\n setZoomOf(surface, 1);\n centerCanvas(surface);\n applyTransform(surface);\n}\n\n/**\n * How far, in parent-viewport px, the pane must move down-screen to centre `rect`.\n *\n * Both inputs are `getBoundingClientRect` space, which is also the space the canvas host answers in\n * (`iframe-host.ts`'s `pointForRect` composes the frame offset and the empirical scale before it\n * hands a rect back), so one arithmetic serves a rect measured from a parent DOM element and a rect\n * measured inside a canvas iframe alike.\n */\nfunction centeringOffset(surface: CanvasSurface, rect: { top: number; height: number }): number {\n const wrapRect = rectOf(surface.wrap);\n const elCenterY = rect.top + rect.height / 2 - wrapRect.top;\n return wrapRect.height / 2 - elCenterY;\n}\n\n/**\n * The element a reveal actually MOVES, or `null` when the panzoom transform is the only mover.\n *\n * This is the whole Edit-vs-Design distinction, in one place. Design, Stylebook and git-diff render\n * a `.panzoom-wrap` and are moved by writing `view.panY`; **Edit renders no panzoom wrap at all** —\n * it is an ordinary scrolling column (`.content-edit-canvas`, the edit branch of `renderCanvas`),\n * and the only thing that brings a node below the fold into view there is its scroll container.\n *\n * Reading it off the stage's own active panel is what keeps the two callers from disagreeing. It is\n * the discriminator `_panToEl` has always used, and `renderCanvas` re-establishes it on every\n * render: a surface's `panels` is emptied and its panzoom wrap nulled before any branch runs, so\n * the panel that answers here is this mode's, never the last mode's.\n *\n * **It took its surface as a parameter only after the rule grew a second hop.** It was zero-arity\n * and called `getActivePanel()`, which is the FOCUSED pane's — so `revealBy(surface, …)` was handed\n * one stage and scrolled another's. Benign in the tree, because both callers happened to pass the\n * focused surface, and invisible to the one-hop rule for exactly the wrong reason: a forwarder\n * whose whole body is `getActivePanel()?.scrollContainer` launders a focus read behind a name.\n *\n * @param {CanvasSurface} surface\n * @returns {HTMLElement | null}\n */\nexport function revealScroller(surface: CanvasSurface): HTMLElement | null {\n return panelOfSurface(surface)?.scrollContainer ?? null;\n}\n\n/**\n * Move the pane by `offsetY`, on whichever surface this mode actually moves.\n *\n * `smooth` is the caller's intent, not a property of the surface: the Outline's jump-to-node is a\n * gesture an author watches, so it eases. The panzoom branch always eases — its 250ms tween is the\n * one {@link import(\"./iframe-host\").revealCanvasPath} waits out frame by frame — but a scroll has\n * no such settle protocol, so an un-eased caller gets a scroll that is finished on return.\n */\nfunction revealBy(surface: CanvasSurface, offsetY: number, smooth: boolean): void {\n const scroller = revealScroller(surface);\n if (!scroller) {\n animatePanBy(surface, offsetY);\n return;\n }\n const top = scroller.scrollTop - offsetY;\n if (smooth) {\n scroller.scrollTo({ behavior: \"smooth\", top });\n return;\n }\n // No clamp: the browser clamps `scrollTop` into `[0, scrollHeight - clientHeight]` itself, and\n // Clamping here would only make a unit test agree with arithmetic the DOM never performs.\n scroller.scrollTop = top;\n}\n\n/**\n * Smoothly pan/scroll the canvas vertically to center the given DOM element.\n *\n * @param {HTMLElement} el\n */\nfunction _panToEl(surface: CanvasSurface, el: HTMLElement) {\n revealBy(surface, centeringOffset(surface, rectOf(el)), true);\n}\n\n/**\n * Centre a PARENT-VIEWPORT rect in the pane — for callers whose target lives inside an iframe (no\n * parent DOM element to measure; the host converts the measured iframe rect and passes it here).\n *\n * Was `animatePanBy` unconditionally, which made it a NO-OP on the Edit surface: `view.panY` only\n * reaches the screen through a `.panzoom-wrap` transform, and Edit has none — so `revealCanvasPath`\n * reported a node's unchanged off-screen point and the click that followed selected nothing.\n */\nexport function panToParentRect(\n rect: { top: number; height: number },\n surface: CanvasSurface = activeCanvasSurface(),\n) {\n revealBy(surface, centeringOffset(surface, rect), false);\n}\n\n/** Animate a stage's `panY` by `offsetY` with the shared 250ms ease-out. */\nfunction animatePanBy(surface: CanvasSurface, offsetY: number) {\n const startY = surface.panY;\n const targetY = startY + offsetY;\n const start = performance.now();\n const duration = 250;\n const step = (now: number) => {\n const t = Math.min((now - start) / duration, 1);\n const ease = t * (2 - t);\n surface.panY = startY + (targetY - startY) * ease;\n applyTransform(surface);\n if (t < 1) {\n requestAnimationFrame(step);\n }\n };\n requestAnimationFrame(step);\n}\n\n/**\n * Pan the canvas vertically so the element at `path` is centered in the viewport.\n *\n * @param {(string | number)[]} path\n */\nexport function panToElement(path: (string | number)[]) {\n const surface = activeCanvasSurface();\n const panel = getActivePanel();\n if (!panel?.canvas) {\n return;\n }\n const el = findCanvasElement(path, panel.canvas);\n if (!el) {\n return;\n }\n _panToEl(surface, el);\n}\n\n// ─── Commands ─────────────────────────────────────────────────────────────────\n\n/**\n * Every canvas mode a pane can render, in the order the mode switcher lists them.\n *\n * `\"preview\"` is in the set even though it is not a base mode: `getCanvasMode()` composes the\n * per-tab `ui.preview` flag with an `edit`/`design` base and presents \"preview\" to every downstream\n * gate, and `tab.capabilities.modes` lists it exactly the same way. A caller naming a mode is\n * naming the mode it will observe, so the enum is the observable set, not the storage set.\n */\nexport const CANVAS_MODES = [\n \"edit\",\n \"design\",\n \"preview\",\n \"source\",\n \"stylebook\",\n \"grid\",\n \"git-diff\",\n] as const;\n\nexport type CanvasMode = (typeof CANVAS_MODES)[number];\n\n/** The base modes the preview flag composes with — the two the Canvas view axis shows it beside. */\nconst PREVIEWABLE_BASE_MODES = new Set([\"edit\", \"design\"]);\n\n// ─── §4.2 axis 2 — the Canvas view ───────────────────────────────────────────\n// `Edit │ Design` is a radio and `Preview` is a TOGGLE beside it, because that is what the storage\n// Has always been: `preview` is not a base mode, it is a flag that composes with one.\n//\n// This was argued the other way, and the argument is worth keeping because it is half right. One\n// Three-value control, it said, because a switcher showing \"Design\" selected while the pane was\n// Previewing reports a state the app is not in. But the app IS in Design — with preview composed\n// Over it — and a three-value radio could only ever show one of the two facts. It picked the\n// Composed one and hid the base, so while previewing nothing said what you were previewing or what\n// Leaving would return you to. A pressed toggle beside a marked radio shows both, which is the\n// State, and neither half is silent.\n\n/**\n * Every value of the Canvas view axis. `preview` composes with the other two rather than replacing\n * them.\n */\nexport const CANVAS_VIEWS = [\"edit\", \"design\", \"preview\"] as const;\n\nexport type CanvasView = (typeof CANVAS_VIEWS)[number];\n\n/** A tab's view state, as the axis reads it — its base mode and whether preview composes over it. */\ninterface ViewableTab {\n capabilities: { modes: string[] };\n session: { ui: { canvasMode: string; preview?: boolean } };\n}\n\n/*\n * `canvasViewOf` lived here: it collapsed the base and the preview flag into ONE effective view, so\n * a three-value radio could mark exactly one of Edit/Design/Preview. Splitting that radio into a\n * two-value base plus a preview toggle took its last caller — the two halves are read separately\n * now, by `canvasBaseViewOf` and `previewStateOf` below. `canvasModeOfPane` still composes the two\n * for the RENDERER, which does want one answer.\n */\n\n/**\n * The views this document supports, in axis order — the control's entries.\n *\n * Filtered by `capabilities.modes` for the same reason the editor-kind dropdown is (§4.2): a\n * permanently dead segment is a question the app refuses to answer.\n */\nexport function canvasViewsFor(tab: ViewableTab): CanvasView[] {\n return CANVAS_VIEWS.filter((value) => tab.capabilities.modes.includes(value));\n}\n\n/**\n * The BASE views a document supports — the radio's entries. Preview is not among them.\n *\n * Preview was the third value of a three-way radio, which made it read as a mode you leave Design\n * to enter: while previewing, the control could not tell you which mode you would come back to. It\n * has always been stored as a per-tab flag over an edit/design base, so the radio was describing\n * the storage inaccurately. Split so the two axes are drawn as what they are.\n */\nexport function canvasBaseViewsFor(tab: ViewableTab): CanvasView[] {\n return canvasViewsFor(tab).filter((value) => value !== \"preview\");\n}\n\n/** The base view the tab returns to — what the radio marks while preview is on. */\nexport function canvasBaseViewOf(tab: ViewableTab): CanvasView | null {\n const base = tab.session.ui.canvasMode;\n return PREVIEWABLE_BASE_MODES.has(base) ? (base as CanvasView) : null;\n}\n\n/**\n * Whether this document can be previewed at all, and whether it is being.\n *\n * `available` is a fact about the DOCUMENT (its declared modes) and about the base it is currently\n * in — `source` composes with no preview, so the toggle is not offered there.\n */\nexport function previewStateOf(tab: ViewableTab): { available: boolean; on: boolean } {\n return {\n available:\n tab.capabilities.modes.includes(\"preview\") &&\n PREVIEWABLE_BASE_MODES.has(tab.session.ui.canvasMode),\n on: tab.session.ui.preview === true,\n };\n}\n\n/**\n * Move a pane onto one of the three views. The one writer the segmented control routes through.\n *\n * Idempotent in both directions, which is what `canvas.togglePreview` could not be: arriving at\n * Edit or Design clears the preview flag, so \"Design\" means Design from any starting state.\n *\n * @param tab The pane's tab.\n * @param value The view to land on.\n * @param setCanvasMode Writes the BASE mode of the tab it is GIVEN — `studio.ts`'s own, injected\n * because this module does not own the canvas render loop. It took only a mode, which is how the\n * side pane's `Edit │ Design │ Preview` control cleared its own tab's preview flag and then moved\n * the FOCUSED pane's tab to `design`.\n */\nexport function setCanvasView<T extends ViewableTab>(\n tab: T,\n value: CanvasView,\n setCanvasMode: (tab: T, mode: string) => void,\n): void {\n if (value === \"preview\") {\n if (PREVIEWABLE_BASE_MODES.has(tab.session.ui.canvasMode)) {\n tab.session.ui.preview = true;\n }\n return;\n }\n tab.session.ui.preview = false;\n if (tab.session.ui.canvasMode !== value) {\n setCanvasMode(tab, value);\n }\n}\n\n/** What the canvas view verbs need that this module does not own. */\nexport interface CanvasCommandDeps {\n /** The effective mode, `ui.preview` already composed in — `studio.ts`'s `getCanvasMode`. */\n getCanvasMode: () => string;\n /** Write the BASE mode (`ui.canvasMode`) of the tab it is given — `studio.ts`'s `setCanvasMode`. */\n setCanvasMode: (tab: Tab | null, mode: string) => void;\n /** Open or close a pane's resolving-with popover — `pane-context.ts`'s `setResolvingOpen`. */\n setResolvingOpen: (paneId: string, open: boolean) => void;\n /**\n * Repaint ONE pane's stage — `studio.ts`'s `renderCanvas`, taking the pane.\n *\n * Injected rather than imported: `canvas-render.ts` imports this module, so reaching back for\n * `renderCanvas` would close a cycle. It takes the pane id because the rendering-context verbs\n * do: `renderOnly(\"canvas\")` resolves the FOCUSED pane, so the side bar's size switcher wrote the\n * side pane's tab and repainted the primary, leaving the stage it changed showing the old width.\n */\n renderPane: (paneId: string) => void;\n}\n\n/** A document is open in a pane — every verb here writes that pane's own view state. */\n/* The pan-zoom surface, as one set rather than three spellings of it.\n `canvas.setZoom` and `canvas.setFit` used to gate on `document.open` alone while their peers\n `canvas.zoomIn`/`zoomOut`/`zoomReset` gate on `document.open && editor.kind === \"canvas\"` — so\n driving Studio with a Library pane focused, `setZoom` and `setFit` both SUCCEEDED and wrote a\n zoom the surface they name was not showing, in the same state where the three verbs that mean\n the same thing refused with \"requires an open document\". `pane-context.ts`'s zoom pod already\n draws itself for exactly these three modes; this is that rule, written once. */\nconst PANZOOM_MODES = new Set([\"design\", \"stylebook\", \"git-diff\"]);\n\nconst documentOpen = (ctx: { document: { open: boolean } }) => ctx.document.open;\n\n/** The three values `session.ui.previewColorScheme` may hold (spec §9.5). */\nconst COLOR_SCHEMES = [\"auto\", \"light\", \"dark\"] as const;\n\n/**\n * The canvas view verbs — `setMode`, `setZoom`, `setEditZoom`.\n *\n * **These are the setters that retire `canvas.togglePreview`** (plan §13.3 clause 3). A toggle\n * cannot say which state it ends in, so six screenshots taken through it photographed whichever way\n * the default happened to point that week; `canvas.setMode { mode: \"preview\" }` means the same\n * thing twice in a row and from any starting state.\n *\n * Three refusals, each a wrong picture that used to be accepted silently:\n *\n * - A mode the open document cannot render (`tab.capabilities.modes`) — a `.csv` has no `design`.\n * - `\"preview\"` over a base mode it does not compose with — `ui.preview` is ignored in `source`, so\n * setting it there would report a state the app is not in.\n * - A zoom outside the supported range, which the interactive controls clamp and a caller may not.\n *\n * @param {CanvasCommandDeps} deps\n * @returns {AnyCommand[]}\n */\nexport function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {\n /** The open tab, or a refusal naming why there is nothing to act on. */\n function requireTab(commandId: string) {\n const tab = activeTab.value;\n if (!tab) {\n throw new RangeError(`command \"${commandId}\" needs an open document; no tab is active`);\n }\n return tab;\n }\n\n /**\n * The tab a rendering-context verb addresses: the named pane's, or the focused one's.\n *\n * The bar is drawn once PER PANE (§18), and the side pane's controls have always written the side\n * pane's tab — so a verb that could only reach the focused one would be a narrower capability\n * than the control it replaced, which is the opposite of the point.\n */\n function contextTab(commandId: string, args: CommandArgValues) {\n const { pane } = args as { pane?: unknown };\n if (pane === undefined) {\n return requireTab(commandId);\n }\n const paneId = stringArg(commandId, args, \"pane\");\n const tab = tabOfPane(paneId);\n if (!tab) {\n throw new RangeError(\n `command \"${commandId}\" argument \"pane\": \"${paneId}\" has no open document`,\n );\n }\n return tab;\n }\n\n /** The optional pane selector every rendering-context verb accepts. */\n const paneArg = {\n pane: stringProperty(\"Which pane to render this way. Defaults to the focused one.\"),\n };\n\n /**\n * Repaint the pane a rendering-context verb just wrote — not the focused one.\n *\n * `renderOnly(\"canvas\")` calls `renderCanvas()` with no pane, which resolves the FOCUSED one.\n * These verbs take a `pane` precisely because the side bar addresses the side pane, so the two\n * resolutions disagree exactly when it matters.\n */\n function repaint(args: CommandArgValues): void {\n const { pane } = args as { pane?: unknown };\n deps.renderPane(typeof pane === \"string\" ? pane : workspace.activePaneId);\n }\n\n return [\n {\n args: argsSchema({\n mode: enumProperty(CANVAS_MODES, \"The canvas mode to switch the active pane to.\"),\n }),\n category: \"View\",\n id: \"canvas.setMode\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open document\",\n when: documentOpen,\n aiTool: {\n description:\n \"Switch the active pane's canvas to a mode: edit, design, preview, source, stylebook, \" +\n \"grid or git-diff. Fails when the open document does not support that mode.\",\n name: \"set_canvas_mode\",\n },\n run: (_commandCtx, args) => {\n const mode = enumArg(\"canvas.setMode\", args, \"mode\", CANVAS_MODES);\n const tab = requireTab(\"canvas.setMode\");\n const { modes } = tab.capabilities;\n if (!modes.includes(mode)) {\n throw new RangeError(\n `command \"canvas.setMode\" argument \"mode\": \"${mode}\" is not a mode this document ` +\n `supports — it declares: ${modes.join(\", \")}`,\n );\n }\n /* There is no second refusal here. The pane used to be asked too — the side pane hosted\n Code, Diff, Config, Entry, Grid and Library only, so a Canvas mode was refused by\n NAME with a sentence telling you to unsplit first. Both panes draw a live Canvas now\n (`panels/pane-grid.ts`), so the document's own declared modes are the whole answer. */\n if (mode === \"preview\") {\n const base = tab.session.ui.canvasMode;\n if (!PREVIEWABLE_BASE_MODES.has(base)) {\n throw new RangeError(\n `command \"canvas.setMode\" argument \"mode\": \"preview\" composes with the edit and ` +\n `design base modes; this pane is in \"${base}\"`,\n );\n }\n tab.session.ui.preview = true;\n return;\n }\n // Idempotent in both directions: leaving preview is part of arriving anywhere else, so a\n // Shot that says \"design\" gets design whether or not the previous step turned preview on.\n tab.session.ui.preview = false;\n // The tab `requireTab()` already resolved, not \"whatever is focused when the write lands\".\n deps.setCanvasMode(tab, mode);\n },\n title: \"Set Canvas Mode\",\n },\n {\n args: argsSchema({\n zoom: numberProperty(\"Pan-zoom scale, 1 = 100%.\", {\n maximum: PAN_ZOOM_MAX,\n minimum: PAN_ZOOM_MIN,\n }),\n }),\n category: \"View\",\n id: \"canvas.setZoom\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"a document on the pan-zoom surface\",\n when: documentOpen,\n enablement: () => PANZOOM_MODES.has(deps.getCanvasMode()),\n run: (_commandCtx, args) => {\n requireTab(\"canvas.setZoom\");\n setUserZoom(boundedNumberArg(\"canvas.setZoom\", args, \"zoom\", PAN_ZOOM_MIN, PAN_ZOOM_MAX));\n },\n title: \"Set Zoom\",\n },\n {\n args: argsSchema({\n fit: {\n description:\n 'How the document is framed: \"width\" | \"page\" | \"none\", or a numeric pan-zoom scale.',\n oneOf: [\n { enum: [...FIT_WORDS], type: \"string\" },\n { maximum: PAN_ZOOM_MAX, minimum: PAN_ZOOM_MIN, type: \"number\" },\n ],\n },\n }),\n category: \"View\",\n id: \"canvas.setFit\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n // The sentence has to match the gate, or the refusal teaches the wrong thing.\n requires: \"a document on the pan-zoom surface\",\n when: documentOpen,\n enablement: () => PANZOOM_MODES.has(deps.getCanvasMode()),\n run: (_commandCtx, args) => {\n requireTab(\"canvas.setFit\");\n setFit(fitArg(\"canvas.setFit\", args, \"fit\"));\n },\n title: \"Set Fit\",\n },\n {\n args: argsSchema({\n zoom: numberProperty(\"Edit-mode content zoom, 1 = 100%.\", {\n maximum: EDIT_ZOOM_MAX,\n minimum: EDIT_ZOOM_MIN,\n }),\n }),\n category: \"View\",\n id: \"canvas.setEditZoom\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"a document in edit mode\",\n when: documentOpen,\n enablement: () => deps.getCanvasMode() === \"edit\",\n run: (_commandCtx, args) => {\n requireTab(\"canvas.setEditZoom\");\n setEditZoom(\n boundedNumberArg(\"canvas.setEditZoom\", args, \"zoom\", EDIT_ZOOM_MIN, EDIT_ZOOM_MAX),\n );\n },\n title: \"Set Edit Zoom\",\n },\n /*\n * ── The rendering context (§4.2's control ③) ──────────────────────────────────────────────\n *\n * Three setters for the three axes the Context popover offers. The popover wrote\n * `session.ui.activeMedia` / `previewColorScheme` / `showLayout` through `updateUi` directly, so\n * none of them was a command: not in the palette, not scriptable, not addressable by the\n * assistant, and not bindable — in a design whose first principle is that a capability exists\n * as a `Command` record and every surface projects it.\n *\n * SETTERS, not cycles. §5.3's keymap declares `⌘⌥↑`/`⌘⌥↓` and `⌘⌥⇧S` to cycle the size and\n * scheme axes, and a chord carries no argument, so those chords need `next`/`prev` records of\n * their own — a delta each, which is what §13's R1 forbids a screenshot from naming. Naming the\n * state you end in works from every surface; the chords are a separate decision and are not\n * made here.\n */\n {\n args: {\n additionalProperties: false,\n properties: {\n ...paneArg,\n media: {\n description:\n \"A breakpoint key the document renders under, or null for the base rendering.\",\n type: [\"string\", \"null\"],\n },\n },\n required: [\"media\"],\n type: \"object\",\n },\n category: \"View\",\n id: \"canvas.setBreakpoint\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open document\",\n when: documentOpen,\n run: (_commandCtx, args) => {\n const tab = contextTab(\"canvas.setBreakpoint\", args);\n const { media } = args as { media?: unknown };\n if (media !== null && typeof media !== \"string\") {\n throw new RangeError(\n `command \"canvas.setBreakpoint\" argument \"media\": expected a breakpoint key or null`,\n );\n }\n /* REFUSES a key the document cannot render under, rather than rendering at a breakpoint\n that does not exist — the rule `data.expandRow` applies to a state entry's name.\n `getEffectiveMedia` and not `document.$media`: the popover offers the SITE's breakpoints\n too, and a command that refused what the control offers would be worse than no command. */\n const declared = Object.keys(\n getEffectiveMedia(tab.doc.document?.$media as Record<string, string> | undefined),\n );\n if (media !== null && !declared.includes(media)) {\n throw new RangeError(\n `command \"canvas.setBreakpoint\" argument \"media\": \"${media}\" is not a breakpoint this ` +\n `document defines — it defines: ${declared.length > 0 ? declared.join(\", \") : \"nothing\"}`,\n );\n }\n tab.session.ui.activeMedia = media;\n repaint(args);\n },\n title: \"Set Breakpoint\",\n },\n {\n args: argsSchema({\n ...paneArg,\n scheme: enumProperty(COLOR_SCHEMES, \"Which color scheme the canvas renders in.\"),\n }),\n category: \"View\",\n id: \"canvas.setColorScheme\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open document\",\n when: documentOpen,\n run: (_commandCtx, args) => {\n const tab = contextTab(\"canvas.setColorScheme\", args);\n tab.session.ui.previewColorScheme = enumArg(\n \"canvas.setColorScheme\",\n args,\n \"scheme\",\n COLOR_SCHEMES,\n ) as \"auto\" | \"dark\" | \"light\";\n repaint(args);\n },\n title: \"Set Color Scheme\",\n },\n /*\n * The language a pane RENDERS AS — and only that.\n *\n * Jx has no message catalogue: a translation is a different file in a different directory\n * (site-architecture §13.3), so \"show this page in French\" is a navigation and the locale\n * preset owns it. What is left over is genuinely a rendering context, and it is the half of\n * §13.4 the canvas can show today: the artboard root's `lang` and `dir`. That is why this is a\n * verb and not a label — an RTL locale mirrors the layout on screen. (§13.4's other half,\n * `$page.locale` in the rendered state, is injected by the compiler and not by the canvas's\n * `substitutePreviewParams`; previewing it is a separate change to the render path.)\n *\n * It lives in this file rather than in `i18n/i18n-commands.ts` because `contextTab`, `paneArg`\n * and `repaint` are local closures here, and every rendering-context verb needs all three: the\n * bar is drawn per pane, so a verb that could only reach the focused one would repaint the\n * wrong stage. `insert.data` sits outside its namespace's module for the same reason.\n */\n {\n args: argsSchema(\n {\n ...paneArg,\n locale: stringProperty(\"BCP 47 tag this pane renders as.\"),\n },\n [\"locale\"],\n ),\n category: \"View\",\n id: \"i18n.switchLocale\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open document in a project that declares more than one locale\",\n when: (ctx) => ctx.document.open && ctx.project.isMultilingual,\n run: (_commandCtx, args) => {\n const tab = contextTab(\"i18n.switchLocale\", args);\n const locale = stringArg(\"i18n.switchLocale\", args, \"locale\");\n /* Read at RUN time. `projectState` is replaced wholesale rather than mutated, so a value\n cached at module scope answers for whichever project was open when this file loaded. */\n const i18n = getEffectiveLocales();\n /* REFUSES a tag the project does not declare, rather than clamping to the default — the\n rule `canvas.setBreakpoint` applies to a breakpoint key. A locale is a URL prefix and an\n `hreflang` at the same time, so rendering \"as\" a language the site does not have would\n preview a page that cannot exist. */\n if (i18n === null || !i18n.locales.includes(locale)) {\n throw new RangeError(\n `command \"i18n.switchLocale\" argument \"locale\": \"${locale}\" is not a locale this ` +\n `project declares — it declares: ${i18n === null ? \"nothing\" : i18n.locales.join(\", \")}`,\n );\n }\n tab.session.ui.previewLocale = locale;\n repaint(args);\n },\n title: \"Set Rendering Language\",\n },\n {\n args: argsSchema({\n ...paneArg,\n visible: booleanProperty(\"True to draw the page's layout elements, false to hide them.\"),\n }),\n category: \"View\",\n id: \"canvas.setLayoutVisible\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open document\",\n when: documentOpen,\n run: (_commandCtx, args) => {\n const tab = contextTab(\"canvas.setLayoutVisible\", args);\n tab.session.ui.showLayout = booleanArg(\"canvas.setLayoutVisible\", args, \"visible\");\n repaint(args);\n },\n title: \"Show Layout Elements\",\n },\n {\n args: {\n additionalProperties: false,\n properties: {\n ...paneArg,\n open: {\n default: true,\n description: \"True to open the resolving-with popover, false to close it.\",\n type: \"boolean\",\n },\n },\n required: [],\n type: \"object\",\n },\n category: \"View\",\n id: \"canvas.setResolvingOpen\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open document\",\n when: documentOpen,\n /*\n * The route params and component test props live in a popover now, and a transient surface\n * opens by COMMAND rather than by clicking (plan §13.2) — otherwise the one shot that types a\n * test value would need a CSS selector to reach it, which §13's contract forbids outright.\n * The pointer and the camera use the same door.\n */\n run: (_commandCtx, args) => {\n // Resolve the tab first, so a pane with no document refuses before anything opens.\n contextTab(\"canvas.setResolvingOpen\", args);\n const { open, pane } = args as { open?: unknown; pane?: unknown };\n // `open` defaults to true and is never COERCED: `{ open: \"no\" }` would otherwise read as a\n // Close, the class of silent wrong answer this setter family exists to stop.\n deps.setResolvingOpen(\n typeof pane === \"string\" ? pane : workspace.activePaneId,\n open === undefined || booleanArg(\"canvas.setResolvingOpen\", args, \"open\"),\n );\n },\n title: \"Show Resolving Values\",\n },\n /*\n * ── The values a render resolves WITH ─────────────────────────────────────────────────────\n *\n * The two controls in that popover wrote `session.ui` through `updateUi` directly, while every\n * control in the rendering-context popover beside them runs a command — and `runContextCommand`\n * says why in as many words: \"the popover WAS the capability, and the palette, the assistant and\n * `__jxAutomation` had no name for it.\" Moving these behind a click without naming them would\n * have reintroduced that, one layer deeper: a value you can now only reach by opening a popover\n * and typing.\n *\n * The screenshot budget agrees. `counter-test-prop` typed into `pane.primary/prop:count`; with\n * a verb it spends a `cmd` instead, so `inputSteps` falls 14 → 13 and the region leaves the\n * manifest, dropping `nonDerivedRegions` 11 → 10. Both budgets may only ratchet down, and this\n * ratchets both.\n */\n {\n args: {\n additionalProperties: false,\n properties: {\n ...paneArg,\n name: stringProperty(\"The prop's name, as the component's state declares it.\"),\n value: {\n description:\n \"The test value — any JSON. Null clears it and the prop returns to its default.\",\n type: [\"string\", \"number\", \"boolean\", \"array\", \"object\", \"null\"],\n },\n },\n required: [\"name\"],\n type: \"object\",\n },\n category: \"View\",\n id: \"canvas.setTestProp\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open component document\",\n when: documentOpen,\n run: (_commandCtx, args) => {\n const tab = contextTab(\"canvas.setTestProp\", args);\n const name = stringArg(\"canvas.setTestProp\", args, \"name\");\n // REFUSES a prop the component does not declare, rather than seeding a value nothing reads\n // — the rule `data.expandRow` and `canvas.setBreakpoint` both apply to their own names.\n const declared = Object.keys(\n (tab.doc.document?.state as Record<string, unknown> | undefined) ?? {},\n );\n if (!declared.includes(name)) {\n throw new RangeError(\n `command \"canvas.setTestProp\" argument \"name\": \"${name}\" is not a prop this component ` +\n `declares — it declares: ${declared.length > 0 ? declared.join(\", \") : \"nothing\"}`,\n );\n }\n const { value } = args as { value?: unknown };\n const next = { ...tab.session.ui.previewProps };\n if (value === null || value === undefined) {\n delete next[name];\n } else {\n next[name] = value as JsonValue;\n }\n tab.session.ui.previewProps = Object.keys(next).length > 0 ? next : null;\n repaint(args);\n },\n title: \"Set Test Value\",\n },\n {\n args: {\n additionalProperties: false,\n properties: {\n ...paneArg,\n name: stringProperty(\"The route parameter's name, without brackets.\"),\n value: stringProperty(\"The value to preview the route with. Empty clears it.\"),\n },\n required: [\"name\", \"value\"],\n type: \"object\",\n },\n category: \"View\",\n id: \"canvas.setRouteParam\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"3_canvas\",\n requires: \"an open page with a dynamic route\",\n when: documentOpen,\n run: (_commandCtx, args) => {\n const tab = contextTab(\"canvas.setRouteParam\", args);\n const name = stringArg(\"canvas.setRouteParam\", args, \"name\");\n const declared = dynamicRouteParams(tab.documentPath);\n if (!declared.includes(name)) {\n throw new RangeError(\n `command \"canvas.setRouteParam\" argument \"name\": \"${name}\" is not a parameter of this ` +\n `route — it has: ${declared.length > 0 ? declared.join(\", \") : \"none\"}`,\n );\n }\n tab.session.ui.previewParams = {\n ...tab.session.ui.previewParams,\n [name]: stringArg(\"canvas.setRouteParam\", args, \"value\"),\n };\n repaint(args);\n },\n title: \"Set Route Parameter\",\n },\n ];\n}\n\n/**\n * Register the canvas view verbs. Called from the bootstrap, beside the transforms they drive.\n *\n * @param {CommandRegistry} registry\n * @param {CanvasCommandDeps} deps\n */\nexport function registerCanvasViewCommands(\n registry: CommandRegistry,\n deps: CanvasCommandDeps,\n): void {\n registry.registerAll(canvasViewCommands(deps));\n}\n\n/**\n * Toggle the \"active\" class on a stage's artboard headers, from that stage's own `activeMedia`.\n *\n * Surface-taking for the same reason everything else here is: the breakpoint a header reports is a\n * fact about the document that stage is drawing, and reading `activeTab` drew the focused pane's\n * breakpoint onto the other pane's artboards.\n */\nexport function updateActivePanelHeaders(surface: CanvasSurface = activeCanvasSurface()) {\n const activeMedia = activeMediaOfPane(surface.paneId);\n for (const p of surface.panels) {\n const header = p.element?.querySelector(\".canvas-panel-header\");\n if (header) {\n const isActive =\n (activeMedia === null && p.mediaName === \"base\") ||\n (activeMedia === null && p.mediaName === null) ||\n activeMedia === p.mediaName;\n header.classList.toggle(\"active\", isActive);\n }\n }\n}\n",
14
+ "// In order to disable the native drag preview you can\n// use `event.dataTransfer.setDragImage()` to set a small\n// invisible image as the drag preview.\n// There are alternative techniques,\n// (eg setting opacity to in onGenerateDragPreview and then 1 in onDragStart)\n// but the technique in this file worked best across browsers and platforms\n\n// Here we are preloading the image so that it is ready for the first drag.\n// Even though the image is base64 encoded, the browser queues an async task\n// to decode the image. The image needs to be decoded before it can be used\nvar tinyTransparentImage = function () {\n // SSR safe\n if (typeof window === 'undefined') {\n return null;\n }\n\n // Image generated by: https://png-pixel.com/\n // It is a 1x1 transparent gif\n // It is the smallest possible transparent image we could find that works on all platforms\n // Note: using an encoded SVG would be nicer code, but it doesn't work on iOS\n var img = new Image();\n img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';\n return img;\n}();\nexport function disableNativeDragPreview(_ref) {\n var nativeSetDragImage = _ref.nativeSetDragImage;\n if (nativeSetDragImage && tinyTransparentImage) {\n nativeSetDragImage(tinyTransparentImage, 0, 0);\n }\n}",
15
+ "function _objectWithoutPropertiesLoose(r, e) {\n if (null == r) return {};\n var t = {};\n for (var n in r) if ({}.hasOwnProperty.call(r, n)) {\n if (-1 !== e.indexOf(n)) continue;\n t[n] = r[n];\n }\n return t;\n}\nexport { _objectWithoutPropertiesLoose as default };",
16
+ "import objectWithoutPropertiesLoose from \"./objectWithoutPropertiesLoose.js\";\nfunction _objectWithoutProperties(e, t) {\n if (null == e) return {};\n var o,\n r,\n i = objectWithoutPropertiesLoose(e, t);\n if (Object.getOwnPropertySymbols) {\n var n = Object.getOwnPropertySymbols(e);\n for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);\n }\n return i;\n}\nexport { _objectWithoutProperties as default };",
17
+ "export function isShallowEqual(a, b) {\n var aKeys = Object.keys(a);\n var bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n return aKeys.every(function (key) {\n return Object.is(a[key], b[key]);\n });\n}",
18
+ "import { isShallowEqual } from './isShallowEqual';\n/**\n * Used to store a stable object, which returns a new object only if one of the values has changed\n */\n// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports\nexport function stable() {\n var isEqual = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : isShallowEqual;\n var cache = null;\n return function (value) {\n if (cache && isEqual(cache.value, value)) {\n return cache.value;\n }\n cache = {\n value: value\n };\n return cache.value;\n };\n}",
19
+ "import _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nvar _excluded = [\"block\"];\nfunction ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nimport { isShallowEqual } from './internal/isShallowEqual';\nimport { stable } from './internal/stable';\nimport { uniqueKey } from './tree-item';\nfunction getCenter(rect) {\n return {\n x: (rect.right + rect.left) / 2,\n y: (rect.bottom + rect.top) / 2\n };\n}\nfunction standardHitbox(_ref) {\n var client = _ref.client,\n borderBox = _ref.borderBox;\n var quarterOfHeight = borderBox.height / 4;\n\n // In the top 1/4: reorder-above\n // On the line = in the top 1/4 to give this zone a bit more space\n if (client.y <= borderBox.top + quarterOfHeight) {\n return 'reorder-above';\n }\n // In the bottom 1/4: reorder-below\n // On the line = in the bottom 1/4 to give this zone a bit more space\n if (client.y >= borderBox.bottom - quarterOfHeight) {\n return 'reorder-below';\n }\n return 'make-child';\n}\nfunction getInstruction(_ref2) {\n var element = _ref2.element,\n input = _ref2.input,\n currentLevel = _ref2.currentLevel,\n indentPerLevel = _ref2.indentPerLevel,\n mode = _ref2.mode;\n var client = {\n x: input.clientX,\n y: input.clientY\n };\n var borderBox = element.getBoundingClientRect();\n if (mode === 'standard') {\n var type = standardHitbox({\n borderBox: borderBox,\n client: client\n });\n return {\n type: type,\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n var center = getCenter(borderBox);\n if (mode === 'expanded') {\n // leveraging \"standard\" hitbox to ensure that the 'reorder-above' hit zone is\n // exactly the same for \"standard\" and \"expanded\" items\n var _type = standardHitbox({\n borderBox: borderBox,\n client: client\n });\n return {\n // Use the \"standard\" hitbox for \"reorder above\",\n // The rest of the item is \"make-child\"\n type: _type === 'reorder-above' ? _type : 'make-child',\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n\n // `mode` is \"last-in-group\"\n\n var visibleInset = indentPerLevel * currentLevel;\n\n // Before the left edge of the visible item\n if (client.x < borderBox.left + visibleInset) {\n // Above the center: `reorder-above`\n if (client.y < center.y) {\n return {\n type: 'reorder-above',\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n // On or below the center: `reparent`\n // On the center = `reparent` as we are giving a slightly bigger hitbox to this\n // action as it is the only place a user can do it\n var rawLevel = (client.x - borderBox.left) / indentPerLevel;\n // We can get sub pixel negative numbers as getBoundingClientRect gives sub-pixel accuracy,\n // where as clientX is rounded to the nearest pixel.\n // Using Math.max() ensures we can never get a negative level\n var desiredLevel = Math.max(Math.floor(rawLevel), 0);\n return {\n type: 'reparent',\n desiredLevel: desiredLevel,\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n // On the visible item\n return {\n type: standardHitbox({\n borderBox: borderBox,\n client: client\n }),\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n}\nfunction areInstructionsEqual(a, b) {\n // Shortcut\n if (a.type !== b.type) {\n return false;\n }\n if (a.type === 'instruction-blocked' && b.type === 'instruction-blocked') {\n return areInstructionsEqual(a.desired, b.desired);\n }\n return isShallowEqual(a, b);\n}\n\n// Note: not using `memoize-one` as all we need is a cached value.\n// We do not need to avoid executing an expensive function.\nvar memoizeInstruction = stable(areInstructionsEqual);\nfunction applyInstructionBlock(_ref3) {\n var desired = _ref3.desired,\n block = _ref3.block;\n if (block !== null && block !== void 0 && block.includes(desired.type) && desired.type !== 'instruction-blocked') {\n var blocked = {\n type: 'instruction-blocked',\n desired: desired\n };\n return blocked;\n }\n return desired;\n}\nexport function attachInstruction(userData, _ref4) {\n var block = _ref4.block,\n rest = _objectWithoutProperties(_ref4, _excluded);\n var desired = getInstruction(rest);\n var withBlock = applyInstructionBlock({\n desired: desired,\n block: block\n });\n var memoized = memoizeInstruction(withBlock);\n return _objectSpread(_objectSpread({}, userData), {}, _defineProperty({}, uniqueKey, memoized));\n}",
20
+ "import { uniqueKey } from './tree-item';\n// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports\nexport function extractInstruction(userData) {\n var _ref;\n return (_ref = userData[uniqueKey]) !== null && _ref !== void 0 ? _ref : null;\n}",
21
+ "/* eslint-disable @repo/internal/deprecations/deprecation-ticket-required -- VOLTC-139 tracks removal of these deprecated re-export shims. */\n\n// using a symbol so we can guarantee a key with a unique value\nexport var uniqueKey = Symbol('tree-item-instruction');\n\n// eslint-disable-next-line @atlaskit/volt-strict-mode/no-re-exports -- Disabled via Volt Codemod. Do not add more exports to this file.\nexport { attachInstruction } from './attach-instruction';\n// eslint-disable-next-line @atlaskit/volt-strict-mode/no-re-exports -- Disabled via Volt Codemod. Do not add more exports to this file.\nexport { extractInstruction } from './extract-instruction';",
22
+ "/**\n * Elements.ts — what belongs in a document's (or a project's) `$elements`, decided once.\n *\n * `$elements` is the list of component modules a document may use. Three surfaces wrote it, each\n * with its own idea of what \"already imported\" means, and plan §11.2 names all three: the Packages\n * panel's cherry-pick checkboxes, its \"Add component…\" picker, and the automatic push when a\n * component is dropped on the canvas. \"One `enableElement()` / `disableElement()` service behind\n * all three. Today the same array is written three ways with no shared UI and no shared\n * validation.\"\n *\n * They really did disagree. The canvas drop matched a local component by `ref.endsWith(basename)`,\n * so `./components/card.json` counted `./vendor/card.json` as already imported and the drop\n * silently produced an element the page could not resolve. The picker checked nothing at all and\n * pushed a duplicate `$ref` every time you chose the same component twice. Only the checkbox knew\n * that a legacy full-package entry (`@acme/ui`) satisfies a cherry-picked one (`@acme/ui/card`), so\n * enabling one component through the picker left the package-wide import beside it.\n *\n * **Pure functions over the array.** They return the new list rather than writing it, because the\n * two levels persist differently and genuinely should: a document's `$elements` goes through\n * `transact` and is undoable, and the project's goes through `updateSiteConfig` and is not. What\n * they must not differ on is WHICH entries the list should hold.\n */\n\nimport { computeRelativePath } from \"./components\";\nimport type { ComponentEntry } from \"./components\";\nimport type { JxElement } from \"@jxsuite/schema/types\";\n\n/** One `$elements` entry: an npm specifier, or a `$ref` to a file in this project. */\nexport type ElementsEntry = string | JxElement | { $ref: string };\n\n/** The `$ref` of an entry, when it has one. */\nfunction refOf(entry: ElementsEntry): string | null {\n return typeof entry === \"object\" && entry !== null && typeof entry.$ref === \"string\"\n ? entry.$ref\n : null;\n}\n\n/**\n * The npm specifier a component is imported by — its cherry-picked subpath, or the bare package.\n *\n * `null` for a project-local component, which is imported by path instead.\n */\nexport function npmSpecifier(comp: ComponentEntry): string | null {\n if (comp.source !== \"npm\" || !comp.package) {\n return null;\n }\n return comp.modulePath ? `${comp.package}/${comp.modulePath}` : comp.package;\n}\n\n/**\n * The entry that imports `comp` into a document at `fromPath`.\n *\n * `null` when the component can be named neither way — an npm entry with no package, or a local one\n * with no path — which is a registry the caller should not be writing from.\n */\nexport function elementsEntryFor(\n comp: ComponentEntry,\n fromPath: string | null,\n): ElementsEntry | null {\n const specifier = npmSpecifier(comp);\n if (specifier) {\n return specifier;\n }\n return comp.path ? { $ref: computeRelativePath(fromPath, comp.path) } : null;\n}\n\n/**\n * Is `comp` already imported by this list?\n *\n * ONE rule, and it is the union of what the three call sites each knew separately:\n *\n * - An npm component matches its cherry-picked specifier **or** a legacy whole-package entry;\n * - A local component matches a `$ref` that resolves to the same file, compared on the resolved path\n * rather than on its last segment — `endsWith(\"card.json\")` called two different cards the same\n * component, and the drop that trusted it produced an unresolvable element.\n */\nexport function hasElement(\n elements: readonly ElementsEntry[],\n comp: ComponentEntry,\n fromPath: string | null,\n): boolean {\n const specifier = npmSpecifier(comp);\n if (specifier) {\n return elements.some(\n (entry) => typeof entry === \"string\" && (entry === specifier || entry === comp.package),\n );\n }\n if (!comp.path) {\n return false;\n }\n const wanted = normalizeRef(computeRelativePath(fromPath, comp.path));\n return elements.some((entry) => {\n const ref = refOf(entry);\n return ref !== null && normalizeRef(ref) === wanted;\n });\n}\n\n/** A `$ref` reduced to a comparable form: `./a/b.json`, `a/b.json` and `././a/b.json` are one file. */\nfunction normalizeRef(ref: string): string {\n return ref.replace(/^(?:\\.\\/)+/, \"\");\n}\n\n/**\n * Import `comp`, and return the new list. Idempotent, and it drops what the new entry supersedes.\n *\n * Enabling a cherry-picked npm component removes the whole-package entry it replaces — otherwise\n * the page keeps pulling in every component of that package while the panel shows one ticked.\n */\nexport function enableElement(\n elements: readonly ElementsEntry[],\n comp: ComponentEntry,\n fromPath: string | null,\n): ElementsEntry[] {\n const entry = elementsEntryFor(comp, fromPath);\n if (!entry) {\n return [...elements];\n }\n const specifier = npmSpecifier(comp);\n // The legacy whole-package import goes when a cherry-picked one arrives — but never when the\n // Component IS the package (`modulePath` absent), where the two are the same entry.\n const kept =\n specifier && comp.modulePath ? elements.filter((e) => e !== comp.package) : [...elements];\n return hasElement(kept, comp, fromPath) ? kept : [...kept, entry];\n}\n\n/** Remove `comp`'s import, and return the new list. Idempotent. */\nexport function disableElement(\n elements: readonly ElementsEntry[],\n comp: ComponentEntry,\n fromPath: string | null,\n): ElementsEntry[] {\n const specifier = npmSpecifier(comp);\n if (specifier) {\n // Both spellings: a component ticked off must not stay imported through the package entry.\n return elements.filter(\n (entry) => !(typeof entry === \"string\" && (entry === specifier || entry === comp.package)),\n );\n }\n if (!comp.path) {\n return [...elements];\n }\n const wanted = normalizeRef(computeRelativePath(fromPath, comp.path));\n return elements.filter((entry) => {\n const ref = refOf(entry);\n return ref === null || normalizeRef(ref) !== wanted;\n });\n}\n\n/** Remove every entry belonging to `pkg` — what uninstalling a package leaves behind. */\nexport function removePackageElements(\n elements: readonly ElementsEntry[],\n pkg: string,\n): ElementsEntry[] {\n return elements.filter(\n (entry) => typeof entry !== \"string\" || !(entry === pkg || entry.startsWith(`${pkg}/`)),\n );\n}\n\n/** Remove the entry naming `ref` exactly — the Packages panel's per-row × on a local import. */\nexport function removeElementRef(elements: readonly ElementsEntry[], ref: string): ElementsEntry[] {\n const wanted = normalizeRef(ref);\n return elements.filter((entry) => {\n const found = refOf(entry);\n return found === null || normalizeRef(found) !== wanted;\n });\n}\n",
23
+ "/**\n * The blessed `Intl` helpers: one list, read by everything that needs to know them.\n *\n * **The list used to exist in four places** — the runtime's allow-set, the runtime's dispatch\n * table, the compiler's emitter, and a prose JSON-Schema description enumerating them by name. The\n * description was the dangerous one: nothing checked it, so a helper could ship and the schema go\n * on telling authors it did not exist. The names live here; the runtime and the schema description\n * both read them, and a test asserts the two agree.\n *\n * **Why helpers and not the constructors.** ECMA-402's formatters are constructors, and a formula\n * is a pure call — `new` is not in the expression grammar and should not be. Each helper wraps\n * construct-then-format, which is the shape a document author wants anyway.\n *\n * **Every helper takes an explicit locale.** `new Intl.NumberFormat(undefined)` reads the _host's_\n * locale, so the same document compiled on two machines emits different text. A call that names no\n * locale gets the **page's** — which is a function of the route, not of the build machine — and\n * failing that the fixed default below; see `site-architecture.md` §13.7.\n *\n * Pure data and no imports, so a browser bundle, the compiler and the schema generator can all read\n * it without pulling anything else in.\n *\n * @docs studio/logic/formulas\n */\n\n/**\n * The locale a helper uses when a formula names none **and there is no page to ask**.\n *\n * **Not the host's.** `new Intl.NumberFormat(undefined)` reads the machine's locale, so the same\n * document renders `1,234.5` on one build machine and `1.234,5` on another, and a site's output\n * stops being a function of its input.\n *\n * A page's own locale is the better answer where there is one — a page under `/fr/` that formats a\n * date means French, and it already said so in `<html lang>` — so `$page.locale` is consulted first\n * (see `INTL_LOCALE_PARAM`). That preserves the property this constant exists for, because\n * `$page.locale` is a function of the route and the document rather than of the machine. This value\n * is what remains for a scope with no page: a component's own state, or the runtime evaluated\n * standalone.\n */\nexport const DEFAULT_FORMAT_LOCALE = \"en-US\";\n\n/**\n * The time zone `Intl/formatDate` uses when the formula's options name none.\n *\n * The same determinism argument as the locale, and worse in effect: a locale changes how a date\n * reads, a time zone can change **which day it is**. A post timestamped `2026-08-16T02:00Z` renders\n * as the 16th in UTC and the 15th in New York, so a build machine's zone would silently move dates\n * in published HTML. UTC is the one zone that is the same everywhere.\n */\nexport const DEFAULT_TIME_ZONE = \"UTC\";\n\n/** One blessed helper: its callee path (after `window#/`) and what it wraps. */\nexport interface IntlHelper {\n /** The callee path an expression names, e.g. `Intl/formatNumber`. */\n path: string;\n /** The ECMA-402 constructor it wraps. */\n api: string;\n /** Parameter names, in order, for documentation and for the compiled call. */\n params: string[];\n /** One line, for the formula catalogue and the schema description. */\n summary: string;\n}\n\n/**\n * Every blessed `Intl` helper, in the order they are documented.\n *\n * **`DurationFormat` is deliberately absent.** Its baseline support is not universal, and a blessed\n * global that throws on a browser Jx claims to support is worse than one that does not exist: the\n * author writes a formula that works on their machine and fails on a visitor's.\n */\nexport const INTL_HELPERS: readonly IntlHelper[] = [\n {\n api: \"Intl.NumberFormat\",\n params: [\"value\", \"locale\", \"options\"],\n path: \"Intl/formatNumber\",\n summary: \"Format a number for a locale — grouping, decimals, currency, percent, units.\",\n },\n {\n api: \"Intl.DateTimeFormat\",\n params: [\"value\", \"locale\", \"options\"],\n path: \"Intl/formatDate\",\n summary: \"Format a date or timestamp for a locale. Pass `timeZone` in options.\",\n },\n {\n api: \"Intl.RelativeTimeFormat\",\n params: [\"value\", \"unit\", \"locale\", \"options\"],\n path: \"Intl/formatRelativeTime\",\n summary: 'Format a relative time — `-3, \"day\"` becomes \"3 days ago\".',\n },\n {\n api: \"Intl.ListFormat\",\n params: [\"values\", \"locale\", \"options\"],\n path: \"Intl/formatList\",\n summary: 'Join a list the way a locale does — \"a, b, and c\", not a hand-written comma join.',\n },\n {\n api: \"Intl.PluralRules\",\n params: [\"value\", \"locale\", \"options\"],\n path: \"Intl/plural\",\n summary:\n 'Which plural category a number falls in (\"one\", \"few\", \"other\") — many languages have ' +\n \"more than two, so a ternary on `n === 1` is wrong outside English.\",\n },\n {\n api: \"Intl.Collator\",\n params: [\"a\", \"b\", \"locale\", \"options\"],\n path: \"Intl/compare\",\n summary:\n \"Compare two strings for sorting. `<` and `sort()` order by UTF-16 code unit, which puts \" +\n '\"Zebra\" before \"apple\" and sorts every accented word into the wrong place.',\n },\n {\n api: \"Intl.DisplayNames\",\n params: [\"code\", \"type\", \"locale\", \"options\"],\n path: \"Intl/displayName\",\n summary:\n 'The name of a language, region, script or currency in a locale — \"de\" as \"German\" or ' +\n '\"Deutsch\", from CLDR rather than a hand-kept table.',\n },\n {\n api: \"Intl.Segmenter\",\n params: [\"value\", \"granularity\", \"locale\"],\n path: \"Intl/segment\",\n summary:\n \"Split text into graphemes, words or sentences (UAX #29). `[...str]` splits code points, \" +\n \"so it cuts an emoji with a skin-tone modifier in half.\",\n },\n] as const;\n\n/** Just the callee paths, for the runtime's allow-set. */\nexport const INTL_HELPER_PATHS: readonly string[] = INTL_HELPERS.map((helper) => helper.path);\n\n/**\n * Where each helper's `locale` argument sits, so a call that omits it can be given the page's.\n *\n * Derived from `params` rather than written out, for the reason this module exists at all: a\n * hand-kept second list is what let the schema description drift from the implementation. The\n * position differs per helper — `formatNumber` takes it second, `formatRelativeTime` third — and a\n * table that disagreed with the signature would pass the wrong argument silently, which reads as a\n * formatting bug rather than a wiring one.\n */\nexport const INTL_LOCALE_PARAM: Readonly<Record<string, number>> = Object.fromEntries(\n INTL_HELPERS.map((helper) => [helper.path, helper.params.indexOf(\"locale\")]),\n);\n\n/**\n * The helper names as one clause, for the `call` operator's JSON-Schema description.\n *\n * Generated rather than typed out, because a hand-written enumeration is what let the schema drift\n * from the implementation in the first place.\n *\n * @returns {string}\n */\nexport function intlHelpersClause(): string {\n return `the Intl helpers ${INTL_HELPER_PATHS.join(\", \")}`;\n}\n",
24
+ "/**\n * The one `$ref` path grammar — the tokenizer, and the JavaScript accessor built from it.\n *\n * There used to be five, and they disagreed. Two read paths split a path on `/` **and** `.`; the\n * compiler's build-time evaluator split on `/` alone; `resolveWritableRef` split on `/` alone, so a\n * write to `#/state/a/b.c` landed on a key the matching read could never see; and four lowering\n * functions did neither — they ran `replaceAll(\"/\", \".\")` and emitted the result as raw member\n * access. That last one is why `#/state/items/0` compiled to `s.items.0`, a SyntaxError, while the\n * build reported success.\n *\n * Segments are separated by `/` and nothing else, which is RFC 6901 §3: the ABNF excludes only `/`\n * and `~` from a reference token, so `.` is an ordinary character and `#/state/user.name` denotes\n * one member literally named `user.name`. Making the dot ordinary is what lets all five paths share\n * this file — it was the only rule they differed on.\n *\n * @docs framework/concepts/references\n */\n\n/** `~1` is `/` and `~0` is `~`; RFC 6901 §4 fixes this order so `~01` becomes `~1`, not `/`. */\nexport function unescapeToken(token: string): string {\n return token.replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\");\n}\n\n/** `~` and `/` are the two characters a token cannot carry literally (RFC 6901 §3). */\nexport function escapeToken(key: string): string {\n return key.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\");\n}\n\n/**\n * Split a `$ref` path — the part after its scheme — into member names.\n *\n * An empty path is no segments rather than one empty segment, so `#/state/` reads `state` itself\n * rather than a member named \"\".\n *\n * @param {string} path - E.g. `user/name`, `items/0`, `a~1b`\n * @returns {string[]} Unescaped member names\n */\nexport function refSegments(path: string): string[] {\n if (path === \"\") {\n return [];\n }\n return path.split(\"/\").map((token) => unescapeToken(token));\n}\n\n/**\n * Walk a value along a `$ref` path, or `undefined` where the path leaves the object.\n *\n * @param {unknown} root\n * @param {string} path\n * @returns {unknown}\n */\nexport function readPath(root: unknown, path: string): unknown {\n let current = root;\n for (const key of refSegments(path)) {\n current = (current as Record<string, unknown> | null | undefined)?.[key];\n }\n return current;\n}\n\n/**\n * A segment that can follow a `.` — deliberately ASCII-only, so anything exotic takes the bracket\n * branch rather than relying on this regex to model ECMAScript's full identifier grammar. Reserved\n * words are fine: `s.class` and `s.new` are legal member accesses.\n */\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * A JavaScript expression reading `path` from `base`.\n *\n * Dotted where a segment is genuinely an identifier, bracketed with a JSON-quoted key where it is\n * not — the emitted module is read in devtools by the site's author, and `state.cart.push(3)` is\n * worth keeping over `state[\"cart\"].push(3)`.\n *\n * The bug was never dot notation; it was dot notation with no other branch. The compiler ran\n * `replaceAll(\"/\", \".\")` unconditionally, so `#/state/items/0` became `s.items.0` — a SyntaxError\n * emitted by a build that reported success — and a key holding a hyphen or a space did the same.\n * `$args/` already bracketed everything, which is why shipped `$args/values/0` formulas worked\n * while `#/state/items/0` did not. One rule now, with the safe branch as the fallback.\n *\n * @param {string} base - Receiver expression, e.g. `s` or `_args`\n * @param {string} path\n * @returns {string}\n */\nexport function refAccessor(base: string, path: string): string {\n let expr = base;\n for (const key of refSegments(path)) {\n expr += IDENTIFIER.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`;\n }\n return expr;\n}\n\n/**\n * An object-literal key: bare where it is an identifier, JSON-quoted where it is not.\n *\n * Both forms are valid JavaScript, so this is only about what the emitted module reads like — and\n * quoting is the branch that has to exist, because a document may legally declare a state key of\n * `user.name` and pasting that raw produced `user.name: 1,`, a SyntaxError.\n *\n * @param {string} key\n * @returns {string}\n */\nexport function objectKey(key: string): string {\n return IDENTIFIER.test(key) ? key : JSON.stringify(key);\n}\n\n/**\n * A safe identifier naming one binding in a generated `bind`/`on` map.\n *\n * The key is emitted as an object-literal key _and_ as a `data-bind` attribute value _and_ as\n * `on.<key>` member access, so unlike {@link objectKey} it cannot fall back to quoting — it has to\n * be an identifier outright. Every character outside `[A-Za-z0-9_$]` becomes `_` and a leading\n * digit gains a prefix; nothing else is touched.\n *\n * `$` is deliberately kept. Folding it would rename the `$handler` key while the emitted call site\n * still said `on.$handler`, unbinding the handler with no error anywhere. Runs of `_` are likewise\n * left alone: collapsing them made `a__b` and `a_b` collide for cosmetic reasons.\n *\n * Distinct paths can still collide (`a/b` and `a.b` both give `a_b`); callers needing uniqueness\n * compare the paths themselves.\n *\n * @param {string} ref - The ref, prefix already stripped by the caller\n * @returns {string}\n */\nexport function refBindingKey(ref: string): string {\n const safe = ref.replaceAll(/[^A-Za-z0-9_$]/g, \"_\");\n if (safe === \"\") {\n return \"ref\";\n }\n return /^\\d/.test(safe) ? `_${safe}` : safe;\n}\n",
25
+ "/// <reference lib=\"dom\" />\n/**\n * Jx Declarative Expression Engine (spec §19)\n *\n * Shared module used by both runtime (evaluateExpression) and compiler (compileExpression).\n *\n * @module expression\n */\n\nimport {\n DEFAULT_FORMAT_LOCALE,\n DEFAULT_TIME_ZONE,\n INTL_HELPER_PATHS,\n INTL_LOCALE_PARAM,\n} from \"@jxsuite/schema/intl\";\nimport type { JxExpressionNode, JxExpressionOperand } from \"@jxsuite/schema/types\";\nimport type { JxScope } from \"./types.ts\";\nimport { readPath, refAccessor, refSegments } from \"./pointer.ts\";\n\n/** The runtime's expression node — the schema's expression model. */\nexport type ExpressionNode = JxExpressionNode;\nexport type ExpressionOperand = JxExpressionOperand;\n\n/** The `$map` iteration context object stored in scope during mapped rendering. */\ninterface ScopeMapCtx {\n item?: unknown;\n index?: number;\n [key: string]: unknown;\n}\n\n/** View the scope's `$map` iteration context, if present. */\nfunction scopeMap(state: JxScope): ScopeMapCtx | undefined {\n const map = state.$map;\n return map && typeof map === \"object\" ? (map as ScopeMapCtx) : undefined;\n}\n\ninterface CompileOpts {\n statePrefix?: string;\n eventParam?: string;\n /**\n * Parameter-name order per named-formula state key, used by `call` sites to map positional\n * argument lists onto the emitted formula functions' named-args object.\n */\n formulaParams?: Record<string, string[]>;\n}\n\nconst MUTATING_OPS = new Set([\n \"=\",\n \"+=\",\n \"-=\",\n \"*=\",\n \"/=\",\n \"push\",\n \"pop\",\n \"shift\",\n \"unshift\",\n \"splice\",\n]);\nconst UNARY_OPS = new Set([\"!\", \"-\"]);\nconst BINARY_OPS = new Set([\n \"+\",\n \"-\",\n \"*\",\n \"/\",\n \"%\",\n \"===\",\n \"!==\",\n \"<\",\n \"<=\",\n \">\",\n \">=\",\n \"&&\",\n \"||\",\n \"??\",\n]);\nconst ASSIGNMENT_OPS = new Set([\"=\", \"+=\", \"-=\", \"*=\", \"/=\"]);\nconst ARRAY_METHOD_OPS = new Set([\"push\", \"pop\", \"shift\", \"unshift\", \"splice\"]);\nconst AGGREGATE_OPS = new Set([\"reduce\", \"map\", \"filter\"]);\nconst CONDITIONAL_OPS = new Set([\"?:\", \"switch\"]);\n\n/**\n * Pure standard-library method operators (spec §19.4d): genuine `String.prototype` /\n * `Array.prototype` / `Number.prototype` methods that never mutate their receiver — the ES2023\n * change-by-copy family stands in where mutation would otherwise occur (`toSorted`, not `sort`).\n * Receiver in `target`; `value` carries the argument (bare scalar) or argument list (array), the\n * splice precedent. No token is invented.\n */\nexport const PURE_METHOD_OPS = new Set([\n // Array.prototype (and the String.prototype homonyms: includes/indexOf/slice/at/concat)\n \"includes\",\n \"indexOf\",\n \"lastIndexOf\",\n \"join\",\n \"slice\",\n \"concat\",\n \"at\",\n \"flat\",\n \"toSorted\",\n \"toReversed\",\n \"toSpliced\",\n \"with\",\n // String.prototype\n \"toUpperCase\",\n \"toLowerCase\",\n \"trim\",\n \"trimStart\",\n \"trimEnd\",\n \"split\",\n \"startsWith\",\n \"endsWith\",\n \"padStart\",\n \"padEnd\",\n \"replaceAll\",\n \"repeat\",\n \"charAt\",\n \"normalize\",\n \"toLocaleUpperCase\",\n \"toLocaleLowerCase\",\n // Number.prototype\n \"toFixed\",\n \"toPrecision\",\n \"toLocaleString\",\n]);\n\nexport const BLESSED_OPERATORS = new Set([\n ...MUTATING_OPS,\n ...UNARY_OPS,\n ...BINARY_OPS,\n ...AGGREGATE_OPS,\n ...CONDITIONAL_OPS,\n ...PURE_METHOD_OPS,\n \"call\",\n]);\n\n/**\n * Pure globals a `call` node may target through the `window#/` scheme (spec §19.4c). Every entry is\n * a genuine ECMAScript or WHATWG standard-library function with no side effects; anything off this\n * list is a compile-time error, keeping formula purity decidable.\n */\nexport const BLESSED_GLOBALS = new Set([\n // Global functions\n \"isNaN\",\n \"isFinite\",\n \"parseFloat\",\n \"parseInt\",\n \"encodeURIComponent\",\n \"decodeURIComponent\",\n \"structuredClone\",\n // Math\n \"Math/abs\",\n \"Math/ceil\",\n \"Math/floor\",\n \"Math/round\",\n \"Math/trunc\",\n \"Math/sign\",\n \"Math/sqrt\",\n \"Math/cbrt\",\n \"Math/pow\",\n \"Math/exp\",\n \"Math/log\",\n \"Math/log2\",\n \"Math/log10\",\n \"Math/min\",\n \"Math/max\",\n \"Math/hypot\",\n // Number\n \"Number/isInteger\",\n \"Number/isFinite\",\n \"Number/isNaN\",\n \"Number/parseFloat\",\n \"Number/parseInt\",\n // JSON\n \"JSON/parse\",\n \"JSON/stringify\",\n // Object\n \"Object/keys\",\n \"Object/values\",\n \"Object/entries\",\n \"Object/fromEntries\",\n // Array\n \"Array/from\",\n \"Array/isArray\",\n \"Array/of\",\n // String\n \"String/fromCharCode\",\n \"String/fromCodePoint\",\n // Intl helpers come from @jxsuite/schema/intl — see BLESSED_HELPERS. One list, so the runtime,\n // The compiler and the JSON-Schema description cannot drift apart.\n ...INTL_HELPER_PATHS,\n]);\n\n/**\n * Synthetic blessed helpers (spec §19.4c): pure functions that have no direct `window` global\n * because the underlying standard-library API is a constructor. The interpreter dispatches to\n * these; the compiler emits the equivalent inline construct-then-format expression.\n */\nconst BLESSED_HELPERS: Record<string, (...a: unknown[]) => unknown> = {\n \"Intl/compare\": (a, b, locale, options) =>\n new Intl.Collator(\n (locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE,\n options as Intl.CollatorOptions | undefined,\n ).compare(a as string, b as string),\n \"Intl/displayName\": (code, type, locale, options) =>\n new Intl.DisplayNames((locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE, {\n ...(options as Intl.DisplayNamesOptions | undefined),\n type: (type as Intl.DisplayNamesType | undefined) ?? \"language\",\n }).of(code as string),\n \"Intl/formatDate\": (value, locale, options) =>\n new Intl.DateTimeFormat((locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE, {\n timeZone: DEFAULT_TIME_ZONE,\n ...(options as Intl.DateTimeFormatOptions | undefined),\n }).format(new Date(value as string | number | Date)),\n \"Intl/formatList\": (values, locale, options) =>\n new Intl.ListFormat(\n (locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE,\n options as Intl.ListFormatOptions | undefined,\n ).format(values as string[]),\n \"Intl/formatNumber\": (value, locale, options) =>\n new Intl.NumberFormat(\n (locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE,\n options as Intl.NumberFormatOptions | undefined,\n ).format(value as number),\n \"Intl/formatRelativeTime\": (value, unit, locale, options) =>\n new Intl.RelativeTimeFormat(\n (locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE,\n options as Intl.RelativeTimeFormatOptions | undefined,\n ).format(value as number, unit as Intl.RelativeTimeFormatUnit),\n \"Intl/plural\": (value, locale, options) =>\n new Intl.PluralRules(\n (locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE,\n options as Intl.PluralRulesOptions | undefined,\n ).select(value as number),\n /* Returns the segments as plain strings, because a formula's value has to be JSON — the\n Segmenter's own iterator of {segment, index, isWordLike} records is not. */\n \"Intl/segment\": (value, granularity, locale) =>\n [\n ...new Intl.Segmenter((locale as string | undefined) ?? DEFAULT_FORMAT_LOCALE, {\n granularity: (granularity as \"grapheme\" | \"sentence\" | \"word\" | undefined) ?? \"grapheme\",\n }).segment(value as string),\n ].map((part) => part.segment),\n};\n\n/**\n * Fill in a helper's omitted `locale` argument from the page's own locale.\n *\n * A page under `/fr/` that formats a date without naming a locale means French: the route said so,\n * `<html lang>` says so, and `hreflang` tells every crawler so. Requiring the author to repeat it\n * at every call site is how a translated page ends up with English dates and English number\n * grouping on it — a defect that is invisible to the person who built the site in their own\n * language, and obvious to every reader of the other one.\n *\n * Determinism is untouched, which is the property `DEFAULT_FORMAT_LOCALE` exists to protect:\n * `$page.locale` is a function of the route and the document (site-architecture.md §13.4), not of\n * the machine the build runs on. A scope with no `$page` — a component's own state, the runtime\n * used standalone — keeps the fixed default.\n *\n * @param {string} path - Helper callee path, e.g. `Intl/formatNumber`\n * @param {unknown[]} args - Resolved arguments, in declaration order\n * @param {JxScope} state\n * @returns {unknown[]}\n */\nfunction withPageLocale(path: string, args: unknown[], state: JxScope): unknown[] {\n const index = INTL_LOCALE_PARAM[path];\n if (index === undefined || index < 0 || args[index] != null) {\n return args;\n }\n const page = (state as { $page?: { locale?: unknown } }).$page;\n const locale = page?.locale;\n if (typeof locale !== \"string\" || locale === \"\") {\n return args;\n }\n const filled = [...args];\n filled[index] = locale;\n return filled;\n}\n\n/** Whether a `window#/…` callee ref is on the blessed pure-globals list. */\nexport function isBlessedGlobal(ref: string): boolean {\n return ref.startsWith(\"window#/\") && BLESSED_GLOBALS.has(ref.slice(\"window#/\".length));\n}\n\n/**\n * @param {string} op\n * @returns {boolean}\n */\nexport function isMutating(op: string) {\n return MUTATING_OPS.has(op);\n}\n\n// ─── Runtime Evaluation ──────────────────────────────────────────────────────\n\ninterface IterCtx {\n acc?: unknown;\n item?: unknown;\n index?: number;\n /** Named-formula arguments bound for the current `call` body ($args/<name> refs). */\n args?: Record<string, unknown>;\n /** Call-nesting depth; capped at MAX_CALL_DEPTH to bound recursive formulas. */\n callDepth?: number;\n}\n\n/** Recursion bound for `call` chains (formula → formula), mirroring MAX_REPORT_DEPTH. */\nexport const MAX_CALL_DEPTH = 64;\n\n/**\n * Editor-mode evaluation trace (spec §19.9). When passed, every node and operand reports its\n * evaluated value keyed by its path within the expression tree, and the branch-selecting operators\n * (`?:`, `switch` — plus the eager `&&`/`||`/`??`) yield values for ALL branches so a visual editor\n * can badge every node. Absent (production), evaluation is untouched.\n */\nexport interface ExpressionTrace {\n report: (path: (string | number)[], value: unknown) => void;\n /** Current node path — internal; leave unset at the call boundary. */\n path?: (string | number)[];\n /** Recursion depth — internal; reporting stops beyond MAX_REPORT_DEPTH. */\n depth?: number;\n}\n\n/** Reporting recursion bound: branch-forcing removes natural exit conditions, so cap the walk. */\nexport const MAX_REPORT_DEPTH = 64;\n\n/** Derive the trace for a child operand at path segment(s) `seg`; undefined once capped. */\nfunction subTrace(\n trace: ExpressionTrace | undefined,\n seg: string | number | (string | number)[],\n): ExpressionTrace | undefined {\n if (!trace) {\n return undefined;\n }\n const depth = (trace.depth ?? 0) + 1;\n if (depth > MAX_REPORT_DEPTH) {\n return undefined;\n }\n return {\n depth,\n path: [...(trace.path ?? []), ...(Array.isArray(seg) ? seg : [seg])],\n report: trace.report,\n };\n}\n\n/** Resolve an operand to its runtime value. */\nfunction resolveOperand(\n operand: unknown,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n trace?: ExpressionTrace,\n): unknown {\n if (operand === null || operand === undefined) {\n return operand;\n }\n\n // Nested expression node\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"operator\" in operand) {\n return evaluateExpression(operand as ExpressionNode, state, event, iterCtx, trace);\n }\n\n // $ref pointer\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"$ref\" in operand) {\n const resolved = resolveExprRef((operand as { $ref: string }).$ref, state, event, iterCtx);\n trace?.report(trace.path ?? [], resolved);\n return resolved;\n }\n\n // Array of operands (e.g., splice args)\n if (Array.isArray(operand)) {\n return operand.map((o: unknown, i: number) =>\n resolveOperand(o, state, event, iterCtx, subTrace(trace, i)),\n );\n }\n\n // Literal\n trace?.report(trace.path ?? [], operand);\n return operand;\n}\n\n/** Resolve a $ref string within expression context. */\nfunction resolveExprRef(ref: string, state: JxScope, event: Event | null, iterCtx?: IterCtx) {\n if (ref === \"$reduce/acc\") {\n return iterCtx?.acc;\n }\n if (ref.startsWith(\"$reduce/\")) {\n return iterCtx?.acc;\n }\n if (ref.startsWith(\"$args/\")) {\n const parts = ref.slice(\"$args/\".length).split(\"/\");\n const base = iterCtx?.args?.[parts[0]!];\n return parts.length > 1 ? getPath(base, parts.slice(1).join(\"/\")) : base;\n }\n if (ref.startsWith(\"event#/\")) {\n const path = ref.slice(\"event#/\".length);\n return getPath(event, path);\n }\n if (ref.startsWith(\"$map/\")) {\n const parts = ref.split(\"/\");\n const [, key] = parts;\n let base;\n const map = scopeMap(state);\n if (key === \"item\") {\n base = iterCtx?.item ?? map?.item ?? state[\"$map/item\"];\n } else if (key === \"index\") {\n base = iterCtx?.index ?? map?.index ?? state[\"$map/index\"];\n } else {\n base = map?.[key!] ?? state[`$map/${key}`];\n }\n return parts.length > 2 ? getPath(base, parts.slice(2).join(\"/\")) : base;\n }\n if (ref.startsWith(\"#/state/\")) {\n // One call, not a hand-split leading token: slicing at the first `/` skipped unescaping it, so\n // `#/state/a~1b/c` looked for a member called `a~1b` rather than `a/b`.\n return readPath(state, ref.slice(\"#/state/\".length));\n }\n if (ref.startsWith(\"parent#/\")) {\n /*\n * A prop name may be a path into the prop. This read the whole path as one key and returned\n * undefined for `parent#/user/name`, while the lowerer above compiled it to a walk.\n */\n return readPath(state, ref.slice(\"parent#/\".length));\n }\n if (ref.startsWith(\"window#/\")) {\n return getPath(globalThis.window, ref.slice(\"window#/\".length));\n }\n if (ref.startsWith(\"document#/\")) {\n return getPath(globalThis.document, ref.slice(\"document#/\".length));\n }\n return readPath(state, ref) ?? null;\n}\n\n/** Resolve a $ref to a writable location — returns { obj, key } for assignment. */\nfunction resolveWritableRef(\n ref: string,\n state: JxScope,\n _event: Event | null,\n iterCtx?: IterCtx,\n): { obj: JxScope; key: string } {\n if (ref.startsWith(\"$map/\")) {\n const parts = ref.split(\"/\");\n const [, key] = parts;\n let base;\n const map = scopeMap(state);\n if (key === \"item\") {\n base = iterCtx?.item ?? map?.item ?? state[\"$map/item\"];\n } else if (key === \"index\") {\n base = iterCtx?.index ?? map?.index ?? state[\"$map/index\"];\n } else {\n base = map?.[key!] ?? state[`$map/${key}`];\n }\n if (parts.length > 2) {\n const pathParts = parts.slice(2);\n const lastKey = pathParts.pop();\n const obj = pathParts.length > 0 ? getPath(base, pathParts.join(\"/\")) : base;\n return { key: lastKey as string, obj: obj as JxScope };\n }\n return {\n key: key === \"item\" ? \"$map/item\" : \"$map/index\",\n obj: scopeMap(state) ?? state,\n };\n }\n if (ref.startsWith(\"#/state/\")) {\n const sub = ref.slice(\"#/state/\".length);\n const slash = sub.indexOf(\"/\");\n if (slash === -1) {\n return { key: sub, obj: state };\n }\n /*\n * The same tokenizer the read path uses. It used to split on `/` alone while the read split on\n * `/[./]/`, so a write to `#/state/a/b.c` created a key `\"b.c\"` that the matching read — which\n * walked `b` then `c` — could never see. The write simply vanished.\n */\n const parts = refSegments(sub);\n const lastKey = parts.pop();\n let obj = state;\n // Pointer paths address objects by construction (validated by the schema).\n for (const p of parts) {\n obj = obj[p] as JxScope;\n }\n return { key: lastKey as string, obj };\n }\n return { key: ref, obj: state };\n}\n\n/** Evaluate an expression node at runtime. */\nexport function evaluateExpression(\n node: ExpressionNode,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n trace?: ExpressionTrace,\n): unknown {\n const result = evaluateNode(node, state, event, iterCtx, trace);\n trace?.report(trace.path ?? [], result);\n return result;\n}\n\nfunction evaluateNode(\n node: ExpressionNode,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n trace?: ExpressionTrace,\n): unknown {\n const { operator, target, value, initial } = node;\n\n if (!BLESSED_OPERATORS.has(operator)) {\n throw new Error(`$expression: unknown operator \"${operator}\"`);\n }\n\n // ─── Unary ───\n if (UNARY_OPS.has(operator) && !(\"value\" in node)) {\n const operand: unknown = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n );\n if (operator === \"!\") {\n return !operand;\n }\n if (operator === \"-\") {\n return -(operand as number);\n }\n }\n\n // ─── Call (spec §19.4c) ───\n if (operator === \"call\") {\n const calleeRef = (target as { $ref?: string } | null)?.$ref;\n if (typeof calleeRef !== \"string\") {\n throw new TypeError(\"$expression: call target must be a $ref pointer\");\n }\n const callDepth = (iterCtx?.callDepth ?? 0) + 1;\n if (callDepth > MAX_CALL_DEPTH) {\n throw new Error(`$expression: call depth exceeded (${MAX_CALL_DEPTH})`);\n }\n const argValues = Array.isArray(value)\n ? value.map((o: unknown, i: number) =>\n resolveOperand(o, state, event, iterCtx, subTrace(trace, [\"value\", i])),\n )\n : [];\n\n // Blessed pure global via the window#/ scheme (Math.max, JSON.parse, …).\n if (calleeRef.startsWith(\"window#/\")) {\n if (!isBlessedGlobal(calleeRef)) {\n throw new Error(`$expression: \"${calleeRef}\" is not a blessed pure global`);\n }\n const globalPath = calleeRef.slice(\"window#/\".length);\n const helper = BLESSED_HELPERS[globalPath];\n if (helper) {\n return helper(...withPageLocale(globalPath, argValues, state));\n }\n const fn = getPath(globalThis.window, globalPath) as (...a: unknown[]) => unknown;\n const lastSlash = globalPath.lastIndexOf(\"/\");\n const thisArg =\n lastSlash === -1\n ? globalThis.window\n : getPath(globalThis.window, globalPath.slice(0, lastSlash));\n return fn.apply(thisArg, argValues);\n }\n\n const callee = resolveExprRef(calleeRef, state, event, iterCtx);\n // A scope callable (buildScope lowers parameterized formula entries to functions).\n if (typeof callee === \"function\") {\n return (callee as (...a: unknown[]) => unknown)(...argValues);\n }\n // A raw named-formula def (standalone evaluation, e.g. editor preview).\n if (callee && typeof callee === \"object\" && \"$expression\" in callee) {\n const def = callee as { $expression: ExpressionNode; parameters?: unknown[] };\n const args: Record<string, unknown> = {};\n for (const [i, p] of (def.parameters ?? []).entries()) {\n const name = typeof p === \"string\" ? p : ((p as { name?: string } | null)?.name ?? \"\");\n if (!name) {\n continue;\n }\n args[name] =\n argValues[i] === undefined && typeof p === \"object\" && p !== null && \"default\" in p\n ? (p as { default?: unknown }).default\n : argValues[i];\n }\n // The callee body's node paths are its own tree, not the call site's — no trace inside.\n return evaluateExpression(def.$expression, state, event, { args, callDepth });\n }\n throw new TypeError(`$expression: call target \"${calleeRef}\" is not callable`);\n }\n\n // ─── Conditional (pure) ───\n if (CONDITIONAL_OPS.has(operator)) {\n if (operator === \"?:\") {\n const test = resolveOperand(target, state, event, iterCtx, subTrace(trace, \"target\"));\n if (trace) {\n // Editor mode: evaluate both branches so each carries a live value.\n const consequent = resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\"));\n const alternate = resolveOperand(\n initial,\n state,\n event,\n iterCtx,\n subTrace(trace, \"initial\"),\n );\n return test ? consequent : alternate;\n }\n return test\n ? resolveOperand(value, state, event, iterCtx)\n : resolveOperand(initial, state, event, iterCtx);\n }\n // Switch — value-keyed selection; discriminant matched against case keys by string form.\n const discriminant = resolveOperand(target, state, event, iterCtx, subTrace(trace, \"target\"));\n const key = String(discriminant);\n const cases = node.cases ?? {};\n const matched = Object.hasOwn(cases, key);\n if (trace) {\n let result: unknown;\n for (const [k, caseOperand] of Object.entries(cases)) {\n const v = resolveOperand(caseOperand, state, event, iterCtx, subTrace(trace, [\"cases\", k]));\n if (k === key) {\n result = v;\n }\n }\n const fallback = resolveOperand(\n node.default,\n state,\n event,\n iterCtx,\n subTrace(trace, \"default\"),\n );\n return matched ? result : fallback;\n }\n return matched\n ? resolveOperand(cases[key], state, event, iterCtx)\n : resolveOperand(node.default, state, event, iterCtx);\n }\n\n // ─── Binary (pure) ───\n if (BINARY_OPS.has(operator)) {\n const left = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n ) as number & string;\n const right = resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")) as number &\n string;\n switch (operator) {\n case \"+\": {\n return left + right;\n }\n case \"-\": {\n return left - right;\n }\n case \"*\": {\n return left * right;\n }\n case \"/\": {\n return left / right;\n }\n case \"%\": {\n return left % right;\n }\n case \"===\": {\n return left === right;\n }\n case \"!==\": {\n return left !== right;\n }\n case \"<\": {\n return left < right;\n }\n case \"<=\": {\n return left <= right;\n }\n case \">\": {\n return left > right;\n }\n case \">=\": {\n return left >= right;\n }\n case \"&&\": {\n return left && right;\n }\n case \"||\": {\n return left || right;\n }\n case \"??\": {\n return (left as unknown) ?? (right as unknown);\n }\n default: {\n break;\n }\n }\n }\n\n // ─── Assignment ───\n if (ASSIGNMENT_OPS.has(operator)) {\n const rhs = resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")) as number;\n const { obj, key } = resolveWritableRef(\n (target as { $ref: string }).$ref,\n state,\n event,\n iterCtx,\n );\n switch (operator) {\n case \"=\": {\n obj[key] = rhs;\n break;\n }\n case \"+=\": {\n const current = obj[key] as number;\n obj[key] = current + rhs;\n break;\n }\n case \"-=\": {\n const current = obj[key] as number;\n obj[key] = current - rhs;\n break;\n }\n case \"*=\": {\n const current = obj[key] as number;\n obj[key] = current * rhs;\n break;\n }\n case \"/=\": {\n const current = obj[key] as number;\n obj[key] = current / rhs;\n break;\n }\n default: {\n break;\n }\n }\n return;\n }\n\n // ─── Array methods ───\n if (ARRAY_METHOD_OPS.has(operator)) {\n const arr: unknown[] = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n ) as unknown[];\n switch (operator) {\n case \"push\": {\n return arr.push(resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")));\n }\n case \"unshift\": {\n return arr.unshift(resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")));\n }\n case \"pop\": {\n return arr.pop();\n }\n case \"shift\": {\n return arr.shift();\n }\n case \"splice\": {\n const args: unknown[] = resolveOperand(\n value,\n state,\n event,\n iterCtx,\n subTrace(trace, \"value\"),\n ) as unknown[];\n return (arr.splice as (...a: unknown[]) => unknown[])(...args);\n }\n default: {\n break;\n }\n }\n }\n\n // ─── Pure standard-library methods (spec §19.4d) ───\n if (PURE_METHOD_OPS.has(operator)) {\n const receiver = resolveOperand(target, state, event, iterCtx, subTrace(trace, \"target\"));\n const args =\n value === undefined\n ? []\n : Array.isArray(value)\n ? (resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")) as unknown[])\n : [resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\"))];\n const method = (receiver as Record<string, unknown> | null | undefined)?.[operator];\n if (typeof method !== \"function\") {\n // Null-safe, like path reads: a missing receiver or method yields undefined, not a throw.\n return undefined;\n }\n return (method as (...a: unknown[]) => unknown).apply(receiver, args);\n }\n\n // ─── Aggregates (pure) ───\n if (AGGREGATE_OPS.has(operator)) {\n const arr: unknown[] = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n ) as unknown[];\n // Trace only the first iteration's per-item expression — one sample badge per node,\n // Not one report per array element.\n if (operator === \"reduce\") {\n let acc: unknown = resolveOperand(initial, state, event, iterCtx, subTrace(trace, \"initial\"));\n for (const [index, item] of arr.entries()) {\n acc = evaluateExpression(\n value as ExpressionNode,\n state,\n event,\n { acc, index, item },\n index === 0 ? subTrace(trace, \"value\") : undefined,\n );\n }\n return acc;\n }\n if (operator === \"map\") {\n return arr.map((item: unknown, index: number) =>\n evaluateExpression(\n value as ExpressionNode,\n state,\n event,\n { ...iterCtx, index, item },\n index === 0 ? subTrace(trace, \"value\") : undefined,\n ),\n );\n }\n if (operator === \"filter\") {\n return arr.filter((item: unknown, index: number) =>\n evaluateExpression(\n value as ExpressionNode,\n state,\n event,\n { ...iterCtx, index, item },\n index === 0 ? subTrace(trace, \"value\") : undefined,\n ),\n );\n }\n }\n\n return undefined;\n}\n\n// ─── Compiler: Expression → JS Source ────────────────────────────────────────\n\n/** Compile an operand to a JS source string. */\nfunction compileOperand(operand: unknown, opts: CompileOpts): string {\n if (operand === null) {\n return \"null\";\n }\n if (operand === undefined) {\n return \"undefined\";\n }\n\n // Nested expression node\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"operator\" in operand) {\n return compileExpression(operand as ExpressionNode, opts);\n }\n\n // $ref pointer\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"$ref\" in operand) {\n return compileRef((operand as { $ref: string }).$ref, opts);\n }\n\n // Array of operands\n if (Array.isArray(operand)) {\n return operand.map((o: unknown) => compileOperand(o, opts)).join(\", \");\n }\n\n // Literal\n return JSON.stringify(operand);\n}\n\n/**\n * The module-scope function name a named formula compiles to. Shared by call-site emission here and\n * the declaration emission in the compiler targets.\n *\n * @param {string} key\n * @returns {string}\n */\nexport function formulaFnName(key: string) {\n return `_fx_${key.replaceAll(/[^A-Za-z0-9_$]/g, \"_\")}`;\n}\n\n/**\n * Compile a $ref to its JS equivalent.\n *\n * @param {string} ref\n * @param {CompileOpts} opts\n * @returns {string}\n */\nfunction compileRef(ref: string, opts: CompileOpts) {\n const s = opts.statePrefix ?? \"state\";\n const e = opts.eventParam ?? \"event\";\n\n if (ref === \"$reduce/acc\") {\n return \"_acc\";\n }\n if (ref.startsWith(\"$reduce/\")) {\n return \"_acc\";\n }\n if (ref.startsWith(\"$args/\")) {\n return refAccessor(\"_args\", ref.slice(\"$args/\".length));\n }\n\n if (ref.startsWith(\"event#/\")) {\n return refAccessor(e, ref.slice(\"event#/\".length));\n }\n\n if (ref.startsWith(\"$map/\")) {\n const parts = ref.split(\"/\");\n const [, key] = parts;\n if (key === \"item\") {\n return parts.length > 2 ? refAccessor(\"_item\", parts.slice(2).join(\"/\")) : \"_item\";\n }\n if (key === \"index\") {\n return \"_index\";\n }\n return `_${key}`;\n }\n\n if (ref.startsWith(\"#/state/\")) {\n return refAccessor(s, ref.slice(\"#/state/\".length));\n }\n\n if (ref.startsWith(\"parent#/\")) {\n return refAccessor(s, ref.slice(\"parent#/\".length));\n }\n if (ref.startsWith(\"window#/\")) {\n return refAccessor(\"window\", ref.slice(\"window#/\".length));\n }\n if (ref.startsWith(\"document#/\")) {\n return refAccessor(\"document\", ref.slice(\"document#/\".length));\n }\n\n /*\n * An unrecognized scheme is still a path under state. Pasting it raw emitted `s.a/b`, which is\n * not a parse error but a division against an undeclared identifier.\n */\n return refAccessor(s, ref);\n}\n\n/** Compile a writable $ref target to its JS equivalent (for LHS of assignment). */\nfunction compileTarget(target: unknown, opts: CompileOpts): string {\n if (typeof target === \"object\" && target !== null && \"$ref\" in target) {\n return compileRef((target as { $ref: string }).$ref, opts);\n }\n return compileOperand(target, opts);\n}\n\n/**\n * Compile an expression node to a JS source string. Returns a statement for mutating ops, a value\n * expression for pure ops.\n *\n * @param {ExpressionNode} node\n * @param {CompileOpts} [opts]\n * @returns {string}\n */\n/**\n * Emit the inline JS for a synthetic blessed helper (see BLESSED_HELPERS), or null for ordinary\n * globals that compile to a plain `window.<path>` call.\n *\n * @param {string} path - The `window#/`-stripped callee path (e.g. \"Intl/formatNumber\")\n * @param {string[]} args - Already-compiled argument expressions\n * @param {CompileOpts} opts\n * @returns {string | null}\n */\nfunction compileHelperCall(path: string, args: string[], opts: CompileOpts): string | null {\n const a = (i: number) => args[i] ?? \"undefined\";\n /*\n * The same defaults the interpreter applies, inlined — see @jxsuite/schema/intl. The page's own\n * locale comes first and the fixed one behind it, so an island formats in the language of the\n * page it is on. `?.` and not `.`: a component's state has no `$page`, and neither does the\n * runtime evaluated standalone.\n */\n const L = `(${opts.statePrefix ?? \"state\"}?.$page?.locale ?? ${JSON.stringify(DEFAULT_FORMAT_LOCALE)})`;\n const Z = JSON.stringify(DEFAULT_TIME_ZONE);\n switch (path) {\n case \"Intl/formatNumber\": {\n return `new Intl.NumberFormat(${a(1)} ?? ${L}, ${a(2)}).format(${a(0)})`;\n }\n case \"Intl/formatDate\": {\n return (\n `new Intl.DateTimeFormat(${a(1)} ?? ${L}, ` +\n `{timeZone: ${Z}, ...${a(2)}}).format(new Date(${a(0)}))`\n );\n }\n case \"Intl/formatRelativeTime\": {\n return `new Intl.RelativeTimeFormat(${a(2)} ?? ${L}, ${a(3)}).format(${a(0)}, ${a(1)})`;\n }\n case \"Intl/formatList\": {\n return `new Intl.ListFormat(${a(1)} ?? ${L}, ${a(2)}).format(${a(0)})`;\n }\n case \"Intl/plural\": {\n return `new Intl.PluralRules(${a(1)} ?? ${L}, ${a(2)}).select(${a(0)})`;\n }\n case \"Intl/compare\": {\n return `new Intl.Collator(${a(2)} ?? ${L}, ${a(3)}).compare(${a(0)}, ${a(1)})`;\n }\n case \"Intl/displayName\": {\n return (\n `new Intl.DisplayNames(${a(2)} ?? ${L}, ` +\n `{...${a(3)}, type: ${a(1)} ?? 'language'}).of(${a(0)})`\n );\n }\n case \"Intl/segment\": {\n return (\n `[...new Intl.Segmenter(${a(2)} ?? ${L}, {granularity: ${a(1)} ?? 'grapheme'})` +\n `.segment(${a(0)})].map((p) => p.segment)`\n );\n }\n default: {\n return null;\n }\n }\n}\n\nexport function compileExpression(node: ExpressionNode, opts: CompileOpts = {}): string {\n const { operator, target, value, initial } = node;\n\n // ─── Unary ───\n if (UNARY_OPS.has(operator) && !(\"value\" in node)) {\n const operand: string = compileOperand(target, opts);\n if (operator === \"!\") {\n return `!(${operand})`;\n }\n if (operator === \"-\") {\n return `-(${operand})`;\n }\n }\n\n // ─── Call (spec §19.4c) ───\n if (operator === \"call\") {\n const calleeRef = (target as { $ref?: string } | null)?.$ref ?? \"\";\n const args = Array.isArray(value) ? value.map((o: unknown) => compileOperand(o, opts)) : [];\n if (calleeRef.startsWith(\"window#/\")) {\n if (!isBlessedGlobal(calleeRef)) {\n throw new Error(`$expression: \"${calleeRef}\" is not a blessed pure global`);\n }\n const helperJs = compileHelperCall(calleeRef.slice(\"window#/\".length), args, opts);\n if (helperJs) {\n return helperJs;\n }\n return `window.${calleeRef.slice(\"window#/\".length).replaceAll(\"/\", \".\")}(${args.join(\", \")})`;\n }\n if (calleeRef.startsWith(\"#/state/\")) {\n const key = calleeRef.slice(\"#/state/\".length);\n const params = opts.formulaParams?.[key];\n if (params) {\n const named = params\n .map((p, i) => `${JSON.stringify(p)}: ${args[i] ?? \"undefined\"}`)\n .join(\", \");\n return `${formulaFnName(key)}(${opts.statePrefix ?? \"state\"}, { ${named} })`;\n }\n }\n // Fallback: the scope member itself is callable.\n return `${compileRef(calleeRef, opts)}(${args.join(\", \")})`;\n }\n\n // ─── Conditional (pure) ───\n if (CONDITIONAL_OPS.has(operator)) {\n if (operator === \"?:\") {\n const test: string = compileOperand(target, opts);\n const consequent: string = compileOperand(value, opts);\n const alternate: string = compileOperand(initial, opts);\n return `(${test} ? ${consequent} : ${alternate})`;\n }\n // Switch — bind the discriminant's string form once, then chain strict-equality tests.\n const discriminant: string = compileOperand(target, opts);\n const chain = Object.entries(node.cases ?? {})\n .map(([k, v]) => `_d === ${JSON.stringify(k)} ? ${compileOperand(v, opts)} : `)\n .join(\"\");\n const fallback = \"default\" in node ? compileOperand(node.default, opts) : \"undefined\";\n return `((_d) => ${chain}${fallback})(String(${discriminant}))`;\n }\n\n // ─── Binary (pure) ───\n if (BINARY_OPS.has(operator)) {\n const left: string = compileOperand(target, opts);\n const right: string = compileOperand(value, opts);\n return `(${left} ${operator} ${right})`;\n }\n\n // ─── Assignment ───\n if (ASSIGNMENT_OPS.has(operator)) {\n const lhs: string = compileTarget(target, opts);\n const rhs: string = compileOperand(value, opts);\n return `${lhs} ${operator} ${rhs}`;\n }\n\n // ─── Array methods ───\n if (ARRAY_METHOD_OPS.has(operator)) {\n const arr: string = compileTarget(target, opts);\n switch (operator) {\n case \"push\": {\n return `${arr}.push(${compileOperand(value, opts)})`;\n }\n case \"unshift\": {\n return `${arr}.unshift(${compileOperand(value, opts)})`;\n }\n case \"pop\": {\n return `${arr}.pop()`;\n }\n case \"shift\": {\n return `${arr}.shift()`;\n }\n case \"splice\": {\n const args: string = Array.isArray(value)\n ? value.map((o: unknown) => compileOperand(o, opts)).join(\", \")\n : compileOperand(value, opts);\n return `${arr}.splice(${args})`;\n }\n default: {\n break;\n }\n }\n }\n\n // ─── Pure standard-library methods (spec §19.4d) ───\n if (PURE_METHOD_OPS.has(operator)) {\n const receiver: string = compileOperand(target, opts);\n const args: string =\n value === undefined\n ? \"\"\n : Array.isArray(value)\n ? value.map((o: unknown) => compileOperand(o, opts)).join(\", \")\n : compileOperand(value, opts);\n // ?.method?.() matches the interpreter: missing receiver or method yields undefined.\n return `(${receiver})?.${operator}?.(${args})`;\n }\n\n // ─── Aggregates (pure) ───\n if (AGGREGATE_OPS.has(operator)) {\n const arr: string = compileOperand(target, opts);\n const itemExpr: string = compileExpression(value as ExpressionNode, opts);\n if (operator === \"reduce\") {\n const seed: string = compileOperand(initial, opts);\n return `${arr}.reduce((_acc, _item, _index) => ${itemExpr}, ${seed})`;\n }\n if (operator === \"map\") {\n return `${arr}.map((_item, _index) => ${itemExpr})`;\n }\n if (operator === \"filter\") {\n return `${arr}.filter((_item, _index) => ${itemExpr})`;\n }\n }\n\n return \"undefined\";\n}\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\n/** Resolve a `$ref` path on an object, through the one tokenizer (`pointer.ts`). */\nfunction getPath(obj: unknown, path: string): unknown {\n return readPath(obj, path);\n}\n\n// ─── Statement-Engine Surface (spec §20) ─────────────────────────────────────\n\n/**\n * Evaluate a bare operand (pointer, literal, or nested node) outside a node position — used by\n * statement execution (spec §20) for `if` tests and `$switch` discriminants.\n */\nexport function evaluateOperand(\n operand: unknown,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n): unknown {\n return resolveOperand(operand, state, event, iterCtx);\n}\n\n/** Compile a bare operand to JS source — the statement compiler's counterpart to evaluateOperand. */\nexport function compileOperandSource(operand: unknown, opts: CompileOpts = {}): string {\n return compileOperand(operand, opts);\n}\n\nexport type { CompileOpts, IterCtx };\n",
26
+ "/// <reference lib=\"dom\" />\n/**\n * Jx Statement Engine (spec §20) — structured function bodies.\n *\n * A Function entry's `body` may be a statement array instead of opaque JS source. This module is\n * the statements counterpart to expression.ts, with the same dual shape: `runStatements`\n * (interpreter) and `compileStatements` (JS emitter), shared by the runtime and every compiler\n * target. Statement kinds reuse web-platform names only: bare expression nodes (§19), the JSON\n * Schema `if`/`then`/`else` triple, `$switch`/`cases` in statement position, and WHATWG's\n * `dispatchEvent` with `CustomEventInit` members.\n */\n\nimport {\n compileExpression,\n compileOperandSource,\n evaluateExpression,\n evaluateOperand,\n} from \"./expression.ts\";\n\nimport type { JxStatement } from \"@jxsuite/schema/types\";\nimport type { CompileOpts, ExpressionNode, IterCtx } from \"./expression.ts\";\nimport type { JxScope } from \"./types.ts\";\n\ninterface RunOpts {\n /** Named-formula-style arguments bound for $args/<name> refs in the body. */\n args?: Record<string, unknown>;\n /** Dispatch target for dispatchEvent statements; defaults to event?.currentTarget. */\n target?: EventTarget | null;\n}\n\nfunction statementKind(statement: JxStatement): \"expression\" | \"if\" | \"switch\" | \"dispatch\" {\n if (\"operator\" in statement) {\n return \"expression\";\n }\n if (\"if\" in statement) {\n return \"if\";\n }\n if (\"$switch\" in statement) {\n return \"switch\";\n }\n return \"dispatch\";\n}\n\n/**\n * Execute a statement list sequentially against the reactive scope. A statement whose value is a\n * thenable is awaited before the next runs (ECMA async/await semantics); purely synchronous bodies\n * complete synchronously before the returned promise settles.\n */\nexport async function runStatements(\n statements: JxStatement[],\n state: JxScope,\n event: Event | null,\n opts: RunOpts = {},\n): Promise<void> {\n const iterCtx: IterCtx | undefined = opts.args ? { args: opts.args } : undefined;\n for (const statement of statements) {\n switch (statementKind(statement)) {\n case \"expression\": {\n const result = evaluateExpression(statement as ExpressionNode, state, event, iterCtx);\n if (result && typeof (result as PromiseLike<unknown>).then === \"function\") {\n await (result as PromiseLike<unknown>);\n }\n break;\n }\n case \"if\": {\n const branch = statement as { if: unknown; then: JxStatement[]; else?: JxStatement[] };\n const taken = evaluateOperand(branch.if, state, event, iterCtx) ? branch.then : branch.else;\n if (Array.isArray(taken)) {\n await runStatements(taken, state, event, opts);\n }\n break;\n }\n case \"switch\": {\n const branch = statement as {\n $switch: unknown;\n cases: Record<string, JxStatement[]>;\n default?: JxStatement[];\n };\n const key = String(evaluateOperand(branch.$switch, state, event, iterCtx));\n const cases = branch.cases ?? {};\n const taken = Object.hasOwn(cases, key) ? cases[key] : branch.default;\n if (Array.isArray(taken)) {\n await runStatements(taken, state, event, opts);\n }\n break;\n }\n case \"dispatch\": {\n const dispatch = statement as {\n dispatchEvent: string;\n detail?: unknown;\n bubbles?: boolean;\n composed?: boolean;\n };\n const target = opts.target ?? event?.currentTarget;\n if (!target) {\n break;\n }\n const init: CustomEventInit = {};\n if (\"detail\" in dispatch) {\n init.detail = evaluateOperand(dispatch.detail, state, event, iterCtx);\n }\n if (dispatch.bubbles !== undefined) {\n init.bubbles = dispatch.bubbles;\n }\n if (dispatch.composed !== undefined) {\n init.composed = dispatch.composed;\n }\n target.dispatchEvent(new CustomEvent(dispatch.dispatchEvent, init));\n break;\n }\n default: {\n break;\n }\n }\n }\n}\n\ninterface StatementCompileOpts extends CompileOpts {\n /** JS expression for the dispatchEvent target; defaults to `(event && event.currentTarget)`. */\n dispatchTarget?: string;\n /** Indentation prefix for emitted lines. */\n indent?: string;\n}\n\n/**\n * Compile a statement list to a JS statement block (no surrounding braces). Mirrors `runStatements`\n * exactly; each statement kind lowers to its genuine ECMAScript form — expression statements,\n * `if`/`else`, `switch` over the discriminant's string form, and `dispatchEvent(new\n * CustomEvent(...))`.\n */\nexport function compileStatements(\n statements: JxStatement[],\n opts: StatementCompileOpts = {},\n): string {\n const indent = opts.indent ?? \"\";\n const lines: string[] = [];\n for (const statement of statements) {\n switch (statementKind(statement)) {\n case \"expression\": {\n lines.push(`${indent}${compileExpression(statement as ExpressionNode, opts)};`);\n break;\n }\n case \"if\": {\n const branch = statement as { if: unknown; then: JxStatement[]; else?: JxStatement[] };\n const test = compileOperandSource(branch.if, opts);\n const inner = { ...opts, indent: `${indent} ` };\n lines.push(`${indent}if (${test}) {`, compileStatements(branch.then ?? [], inner));\n if (branch.else) {\n lines.push(`${indent}} else {`, compileStatements(branch.else, inner));\n }\n lines.push(`${indent}}`);\n break;\n }\n case \"switch\": {\n const branch = statement as {\n $switch: unknown;\n cases: Record<string, JxStatement[]>;\n default?: JxStatement[];\n };\n const disc = compileOperandSource(branch.$switch, opts);\n const inner = { ...opts, indent: `${indent} ` };\n lines.push(`${indent}switch (String(${disc})) {`);\n for (const [key, caseStatements] of Object.entries(branch.cases ?? {})) {\n lines.push(\n `${indent} case ${JSON.stringify(key)}: {`,\n compileStatements(caseStatements, inner),\n `${indent} break;`,\n `${indent} }`,\n );\n }\n if (branch.default) {\n lines.push(\n `${indent} default: {`,\n compileStatements(branch.default, inner),\n `${indent} }`,\n );\n }\n lines.push(`${indent}}`);\n break;\n }\n case \"dispatch\": {\n const dispatch = statement as {\n dispatchEvent: string;\n detail?: unknown;\n bubbles?: boolean;\n composed?: boolean;\n };\n const eventName = opts.eventParam ?? \"event\";\n const target = opts.dispatchTarget ?? `(${eventName} && ${eventName}.currentTarget)`;\n const init: string[] = [];\n if (\"detail\" in dispatch) {\n init.push(`detail: ${compileOperandSource(dispatch.detail, opts)}`);\n }\n if (dispatch.bubbles !== undefined) {\n init.push(`bubbles: ${JSON.stringify(dispatch.bubbles)}`);\n }\n if (dispatch.composed !== undefined) {\n init.push(`composed: ${JSON.stringify(dispatch.composed)}`);\n }\n const initSource = init.length > 0 ? `, { ${init.join(\", \")} }` : \"\";\n lines.push(\n `${indent}${target}?.dispatchEvent(new CustomEvent(${JSON.stringify(dispatch.dispatchEvent)}${initSource}));`,\n );\n break;\n }\n default: {\n break;\n }\n }\n }\n return lines.join(\"\\n\");\n}\n",
27
+ "/**\n * The `Cookie` state `$prototype`'s reading and writing, split out because both halves are exactly\n * the places a cookie binding goes wrong (RFC 6265bis).\n *\n * **Reading does not build a regular expression.** The cookie's name comes from the document, and\n * the old reader interpolated it straight into a pattern — so a name containing a dot, a paren or a\n * star silently matched the wrong cookie, and one containing an unbalanced bracket threw\n * SyntaxError from a document that validates. There is nothing to escape here: the cookie header is\n * a semicolon-separated list, so splitting it and comparing names is both correct and cheaper.\n *\n * **`HttpOnly` is absent on purpose, and must stay absent.** A cookie this prototype writes is\n * written by script through `document.cookie`; the browser refuses to _set_ `HttpOnly` from script\n * and refuses to _read back_ an `HttpOnly` cookie, so adding the attribute would produce a binding\n * that writes a value it can never see again. Its absence is the correct behavior for a\n * script-written cookie, not a missing feature.\n *\n * **`Expires` is not supported, and that is also deliberate.** `Max-Age` covers the same ground,\n * RFC 6265bis §5.5 makes `Max-Age` win wherever both appear, and `Expires` takes an HTTP-date whose\n * mis-spelling fails silently in the direction of a cookie that never expires.\n */\n\n/** The cookie attributes an `external-class-def` may declare for the `Cookie` `$prototype`. */\nexport interface CookieOptions {\n domain?: string | undefined;\n maxAge?: number | undefined;\n path?: string | undefined;\n sameSite?: string | undefined;\n secure?: boolean | undefined;\n}\n\n/** Cookie names carrying RFC 6265bis §4.1.3 prefixes, which constrain their own attributes. */\nconst HOST_PREFIX = \"__Host-\";\nconst SECURE_PREFIX = \"__Secure-\";\n\n/**\n * The raw (still percent-encoded) value of `name` in a `document.cookie` header, or null.\n *\n * @param {string} header The full `name=value; name=value` string.\n * @param {string} name\n * @returns {string | null}\n */\nexport function readCookie(header: string, name: string): string | null {\n for (const pair of header.split(\";\")) {\n const eq = pair.indexOf(\"=\");\n if (eq === -1) {\n continue;\n }\n if (pair.slice(0, eq).trim() === name) {\n return pair.slice(eq + 1);\n }\n }\n return null;\n}\n\n/**\n * Serialize one `document.cookie` assignment, applying the attribute rules a name's prefix and its\n * `SameSite` value already imply.\n *\n * Three of those rules are enforced rather than left to the author, because a browser that\n * disagrees with the attributes **silently drops the cookie** — the write appears to succeed and\n * the value is simply never there again:\n *\n * - `__Host-` requires `Secure`, requires `Path=/`, and forbids `Domain` (RFC 6265bis §4.1.3.2). A\n * declared `path` or `domain` is overridden rather than honored, since honoring it would produce\n * a cookie no browser will store.\n * - `__Secure-` requires `Secure` (§4.1.3.1).\n * - `SameSite=None` requires `Secure` (§5.4.7); without it the cookie is rejected outright.\n *\n * @param {string} name\n * @param {unknown} value JSON-encoded, then percent-encoded.\n * @param {CookieOptions} options\n * @returns {string}\n */\nexport function serializeCookie(name: string, value: unknown, options: CookieOptions): string {\n const hostPrefixed = name.startsWith(HOST_PREFIX);\n const parts = [`${name}=${encodeURIComponent(JSON.stringify(value))}`];\n\n if (options.maxAge !== undefined) {\n parts.push(`Max-Age=${options.maxAge}`);\n }\n\n const path = hostPrefixed ? \"/\" : options.path;\n if (path) {\n parts.push(`Path=${path}`);\n }\n if (options.domain && !hostPrefixed) {\n parts.push(`Domain=${options.domain}`);\n }\n\n const { sameSite } = options;\n const secure =\n options.secure === true ||\n hostPrefixed ||\n name.startsWith(SECURE_PREFIX) ||\n sameSite?.toLowerCase() === \"none\";\n if (secure) {\n parts.push(\"Secure\");\n }\n if (sameSite) {\n parts.push(`SameSite=${sameSite}`);\n }\n\n return parts.join(\"; \");\n}\n",
28
+ "/// <reference lib=\"dom\" />\n/**\n * Jx — JSON-native reactive web component runtime\n * @version 3.0.0\n * @license MIT\n *\n * Four-step pipeline:\n * 1. resolve — fetch JSON source (or accept raw object)\n * 2. buildScope — state detection + reactive proxy construction\n * 3. render — walk resolved tree, build DOM, wire reactive effects\n * 4. output — append to target\n *\n * @module jx\n */\n\nimport {\n computed,\n effect,\n effectScope,\n isRef,\n onEffectCleanup,\n reactive,\n ref,\n toRaw,\n} from \"@vue/reactivity\";\nimport { evaluateExpression, evaluateOperand, isMutating } from \"./expression.ts\";\nimport { readPath } from \"./pointer.ts\";\nimport type { DynamicClass, JxEventHandler, JxPath, JxRenderOptions, JxScope } from \"./types.ts\";\nimport {\n bodyReturnsValue,\n hasStructuredBody,\n isExpressionDef,\n isFunctionDef,\n isJsonObject,\n isMappedArray,\n isNamedFormulaDef,\n isPrivateStateKey,\n isPrototypeDef,\n isRef as isRefValue,\n isServerFnDef,\n isTagExpression,\n isTemplateString,\n paramNames,\n} from \"@jxsuite/schema/guards\";\nimport { runStatements } from \"./statements.ts\";\nimport { readCookie, serializeCookie } from \"./cookie.ts\";\nimport type {\n JxAttributeValue,\n JxClassDef,\n JxDocument,\n JxElement,\n JxFunctionDef,\n JxHeadEntry,\n JxMappedArray,\n JxPrototypeDef,\n JxRef,\n JxServerFnDef,\n JxStyle,\n} from \"@jxsuite/schema/types\";\nimport type { Ref } from \"@vue/reactivity\";\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Mount a Jx document into a DOM container.\n *\n * @example\n * import { Jx } from \"@jxsuite/runtime\";\n * const state = await Jx(\"./counter.json\", document.getElementById(\"app\"));\n *\n * @param {string | JxDocument} source - Path to .json file, URL, or raw document object\n * @param {HTMLElement} [target] Default is `document.body`\n * @param {JxRenderOptions} [options]\n * @returns {Promise<JxScope>} Resolves with the live component scope (state reactive\n * proxy)\n */\n/** The document-schema version this runtime understands (the `/schema/vN` in a hosted `$schema`). */\nexport const SUPPORTED_SCHEMA_VERSION = 1;\nlet _schemaVersionWarned = false;\n\n/**\n * Warn once when a document declares a hosted `$schema` whose version differs from the one this\n * runtime supports. A relative or non-hosted `$schema` (local dev schema paths) is ignored. This is\n * a diagnostic only — there is no document-format migration story yet (see spec §3.2 / §21.4).\n */\nfunction checkSchemaVersion($schema: unknown): void {\n if (_schemaVersionWarned || typeof $schema !== \"string\") {\n return;\n }\n const match = $schema.match(/\\/schema\\/v(\\d+)\\b/);\n if (match && Number(match[1]) !== SUPPORTED_SCHEMA_VERSION) {\n _schemaVersionWarned = true;\n console.warn(\n `Jx: document $schema is version v${match[1]} but this runtime supports ` +\n `v${SUPPORTED_SCHEMA_VERSION}. Behavior may be undefined; there is no format migrator yet.`,\n );\n }\n}\n\nexport async function Jx(\n source: string | JxDocument,\n target: HTMLElement = document.body,\n options?: JxRenderOptions,\n) {\n const base = typeof source === \"string\" ? new URL(source, location.href).href : location.href;\n const doc = await resolve(source);\n checkSchemaVersion(doc.$schema);\n\n // Register custom elements declared in $elements (depth-first)\n if (doc.$elements) {\n await registerElements(doc.$elements, base);\n }\n\n // Inject <head> elements declared in $head (link, meta, script, etc.)\n if (doc.$head) {\n injectHead(doc.$head, base);\n }\n\n if (doc.$media) {\n _rootMedia = doc.$media;\n }\n\n const state = await buildScope(doc, {}, base);\n target.append(renderNode(doc, state, options));\n if (typeof state.onMount === \"function\") {\n (state.onMount as (s: JxScope) => unknown)(state);\n }\n return state;\n}\n\n// ─── Step 1: Resolve ──────────────────────────────────────────────────────────\n\nconst _resolveCache = new Map<string, Promise<JxDocument>>();\n\nexport async function resolve(source: string | JxDocument): Promise<JxDocument> {\n if (typeof source !== \"string\") {\n return source;\n }\n if (_resolveCache.has(source)) {\n return _resolveCache.get(source)!;\n }\n const p = fetch(source).then((res) => {\n if (!res.ok) {\n throw new Error(`Jx: failed to fetch ${source} (${res.status})`);\n }\n // Trust boundary: fetched sources are Jx documents by contract.\n return res.json() as Promise<JxDocument>;\n });\n _resolveCache.set(source, p);\n return p;\n}\n\n// ─── Step 2: Build scope ──────────────────────────────────────────────────────\n\n/** JSON Schema keywords used to identify pure type definitions (Shape 2b). */\nconst SCHEMA_KEYWORDS = new Set([\n \"type\",\n \"properties\",\n \"items\",\n \"enum\",\n \"minimum\",\n \"maximum\",\n \"minLength\",\n \"maxLength\",\n \"pattern\",\n \"required\",\n \"examples\",\n]);\n\n/** /** @type {{ skip: boolean }} */\nconst _serverFnConfig = { skip: false };\n/** Set to true to suppress timing: \"server\" resolution (used by Studio edit mode). */\nexport function setSkipServerFunctions(v: boolean) {\n _serverFnConfig.skip = v;\n}\n\n/** @type {{ skip: boolean }} */\nconst _autoRequestConfig = { skip: false };\n/**\n * Set to true to suppress AUTOMATIC `$prototype: \"Request\"` fetches — the sibling of\n * {@link setSkipServerFunctions}, and used by Studio for the same reason.\n *\n * `buildScope` re-resolves every `state` entry on each full canvas render, so an auto-request\n * re-issued its HTTP call every time the canvas rebuilt. In edit/design mode that meant authoring\n * actions — a signal edit, or pressing Enter inside component-wrapped content, both of which force\n * a full render — fired network requests. Live data belongs to preview and to the deployed site.\n *\n * Only non-`manual` requests are gated: a `manual` one fires from an event handler, and edit mode\n * strips handlers before rendering. The returned ref is unchanged either way — it simply stays at\n * its initial `null`, which is the same state bindings observe before any fetch resolves.\n */\nexport function setSkipAutoRequests(v: boolean) {\n _autoRequestConfig.skip = v;\n}\n\n// ─── Dev-proxy auth token (Studio cross-origin canvas) ────────────────────────\n// The Studio canvas iframe is served from a token-gated loopback origin (createProjectServer): its\n// POST /__jx_resolve__ + /__jx_server__ routes 403 without ?token=<rpcToken>. The iframe boot reads\n// The token from its URL and calls setResolveToken so these dev-proxy fetches authenticate. Unset by\n// Default, leaving production + same-origin dev untouched (bare path, no query appended).\nlet _resolveToken: string | null = null;\nexport function setResolveToken(token: string | null) {\n _resolveToken = token || null;\n}\n/** Append the dev-proxy auth token to a privileged resolve path when one is configured. */\nfunction resolveProxyPath(path: string): string {\n return _resolveToken ? `${path}?token=${encodeURIComponent(_resolveToken)}` : path;\n}\n\n/** @deprecated No longer needed — ContentCollection/ContentEntry resolve via generic class path */\nexport function setSkipContentResolution(_v: boolean) {\n // No-op retained for API compatibility\n}\n\n/**\n * Observe runtime-created reactive values: runs `fn` immediately inside a reactive effect and\n * re-runs it whenever a tracked value changes; returns a disposer. Dep tracking in @vue/reactivity\n * is per module INSTANCE, so an effect created from another copy of the package (e.g. the studio's\n * own pin) can never track a ref/reactive created here — consumers that want to observe\n * runtime-resolved scope values (the Studio canvas iframe's dataScope re-post) must use this.\n *\n * @param {() => void} fn - Read the reactive values to observe inside this callback.\n * @returns {() => void} Disposer — stops the effect and its scope.\n */\nexport function observeScope(fn: () => void): () => void {\n const scope = effectScope(true);\n scope.run(() => {\n effect(fn);\n });\n return () => scope.stop();\n}\n\n/**\n * Run `fn` inside a detached reactive scope of THIS module's reactivity instance, returning its\n * result plus a disposer that stops every effect `fn` created. Callers that render via\n * {@link renderNode} and later tear the render down (the Studio canvas full render and its surgical\n * subtree re-renders) MUST use this instead of their own effectScope: scope collection is per\n * vue-reactivity module instance, so a scope from another copy of the package collects NOTHING and\n * its stop() silently leaks every binding effect of the superseded render.\n *\n * @param {() => T} fn - Work that may create reactive effects (typically a renderNode call).\n * @returns {{ result: T; stop: () => void }} The callback result and the scope disposer.\n */\nexport function runScoped<T>(fn: () => T): { result: T; stop: () => void } {\n const scope = effectScope(true);\n try {\n const result = scope.run(fn) as T;\n return { result, stop: () => scope.stop() };\n } catch (error) {\n // A throwing fn would otherwise leak the effects it created before failing.\n scope.stop();\n throw error;\n }\n}\n\n/**\n * Studio-canvas viewport-unit transpose. The canvas iframe is sized to its document's height, so\n * any viewport unit (`vh`/`vw`/`vmin`/`vmax`/`svh`/…) — which resolves against the iframe ELEMENT —\n * would feed back into an ever-growing height. When this is on, the runtime transposes them to\n * CONTAINER units (`cqh`/`cqw`/…) that resolve against the canvas's fixed-size query container (see\n * `canvas.html`): a predictable, feedback-free stand-in for the viewport. Off (the default) leaves\n * CSS untouched for real production rendering.\n */\nlet _canvasViewportTranspose = false;\nexport function setCanvasViewportTranspose(on: boolean) {\n _canvasViewportTranspose = on;\n}\n\nconst VIEWPORT_UNIT_RE = /(-?\\d*\\.?\\d+)(?:s|l|d)?v(h|w|min|max|i|b)\\b/gi;\nconst VIEWPORT_UNIT_MAP: Record<string, string> = {\n b: \"cqb\",\n h: \"cqh\",\n i: \"cqi\",\n max: \"cqmax\",\n min: \"cqmin\",\n w: \"cqw\",\n};\n\n/**\n * Transpose CSS viewport units → container-query units in a value string, but only when the\n * studio-canvas flag is set (otherwise the value is returned untouched). `100vh` → `100cqh`,\n * `50svw` → `50cqw`, `10vmin` → `10cqmin`, etc.\n */\nexport function transposeCanvasUnits(value: string): string {\n if (!_canvasViewportTranspose || !value.includes(\"v\")) {\n return value;\n }\n return value.replace(\n VIEWPORT_UNIT_RE,\n (_m, num: string, dim: string) => `${num}${VIEWPORT_UNIT_MAP[dim.toLowerCase()] ?? `cq${dim}`}`,\n );\n}\n\n/**\n * Studio-canvas anchor de-linking. In the editor canvas a rendered `<a href>` would navigate the\n * iframe when clicked, fighting element selection. When this is on, the runtime stamps the value on\n * `data-jx-href` instead of `href` so the anchor is inert (selectable, not a live link) while the\n * original target stays recoverable for richer link handling later. Off (the default) leaves\n * production rendering untouched; the studio sets it for design/edit (not preview — see\n * iframe-render).\n */\nlet _canvasDelinkAnchors = false;\nexport function setCanvasDelinkAnchors(on: boolean) {\n _canvasDelinkAnchors = on;\n}\n\n/** The attribute name to stamp `key` on `el` under — `href` → `data-jx-href` on de-linked anchors. */\nfunction canvasAttrName(el: HTMLElement, key: string): string {\n if (_canvasDelinkAnchors && key === \"href\" && (el.tagName === \"A\" || el.tagName === \"AREA\")) {\n return \"data-jx-href\";\n }\n return key;\n}\n\n/**\n * Studio-canvas prop-binding markers. When on, `bindProperty` stamps `data-jx-bound-prop=\"<key>\"`\n * on elements whose `textContent` is an invertible single-key state binding — the pure template\n * `\"${state.key}\"` or `{ \"$ref\": \"#/state/key\" }`. The studio canvas uses the marker to offer\n * inline editing of component-instance prop values; the rendered text must BE the prop value\n * verbatim, so mixed templates and deep paths are never stamped. Off (the default) leaves\n * production rendering untouched; the studio sets it for design/edit (not preview — see\n * iframe-render).\n */\nlet _stampPropBindings = false;\nexport function setStampPropBindings(on: boolean) {\n _stampPropBindings = on;\n}\n\n/** The single invertible template form: the whole string is exactly one `${state.key}` access. */\nconst PURE_STATE_TEMPLATE = /^\\s*\\$\\{\\s*state\\.(\\w+)\\s*\\}\\s*$/;\n\n/** The state key of an invertible `textContent` binding, or null (mixed template, deep path). */\nfunction boundPropKey(key: string, val: unknown, state: JxScope): string | null {\n if (!_stampPropBindings || key !== \"textContent\") {\n return null;\n }\n let sub: string | null = null;\n if (isRefObj(val)) {\n if (!val.$ref.startsWith(\"#/state/\")) {\n return null;\n }\n const rest = val.$ref.slice(\"#/state/\".length);\n sub = rest && !rest.includes(\"/\") ? rest : null;\n } else if (typeof val === \"string\") {\n sub = PURE_STATE_TEMPLATE.exec(val)?.[1] ?? null;\n }\n if (!sub) {\n return null;\n }\n // Only plain writable data entries are per-instance props. Computed/signal entries live as refs\n // In the raw scope (auto-unwrapped by the reactive proxy), and function/object entries (handlers,\n // $prototype instances) are not prop-overridable either — an instance $props write against any of\n // Them would clobber the definition's behavior, so their bindings are never marked editable.\n const stored = (toRaw(state) as Record<string, unknown>)[sub];\n if (isRef(stored) || typeof stored === \"function\") {\n return null;\n }\n if (typeof stored === \"object\" && stored !== null) {\n return null;\n }\n return sub;\n}\n\n/**\n * Build the reactive scope (state) from the document using the five-shape detection algorithm.\n *\n * @param {JxDocument} doc\n * @param {JxScope} [parentScope] Default is `{}`\n * @param {string} [base] Base URL for resolving $src imports. Default is `location.href`\n * @returns {Promise<JxScope>} Reactive proxy (state)\n */\nexport async function buildScope(\n doc: JxDocument,\n parentScope: JxScope = {},\n base: string = location.href,\n) {\n const raw: JxScope = {};\n\n // Merge parent scope properties\n for (const [key, val] of Object.entries(parentScope)) {\n raw[key] = val;\n }\n\n const defs = doc.state ?? {};\n\n // Pass 0: resolve bare $prototype names via import map\n const imports = doc.imports ?? {};\n for (const [, def] of Object.entries(defs)) {\n if (isPrototypeDef(def) && !def.$src) {\n const mapped = imports[def.$prototype];\n if (mapped) {\n if (!mapped.endsWith(\".class.json\")) {\n console.warn(\n `Jx: import \"${def.$prototype}\" must map to a .class.json path, got \"${mapped}\"`,\n );\n continue;\n }\n def.$src = mapped;\n }\n }\n }\n\n // First pass: collect naked values, expanded defaults, plain objects\n for (const [key, def] of Object.entries(defs)) {\n // 1. String value\n if (typeof def === \"string\") {\n if (!def.includes(\"${\")) {\n raw[key] = def;\n } // Shape 1: naked string\n continue; // Template strings handled in second pass\n }\n\n // 2. Number, boolean, null\n if (typeof def === \"number\" || typeof def === \"boolean\" || def === null) {\n raw[key] = def;\n continue;\n }\n\n // 3. Array\n if (Array.isArray(def)) {\n raw[key] = def;\n continue;\n }\n\n // 4. Object\n if (typeof def === \"object\") {\n if (def.$prototype) {\n continue;\n } // Handled in later passes\n if (isExpressionDef(def)) {\n continue;\n } // Handled in pass 2.5\n if (isServerFnDef(def)) {\n continue;\n } // Handled in fifth pass\n if (\"default\" in def) {\n raw[key] = def.default;\n continue;\n } // Shape 2: expanded signal\n if (hasSchemaKeywords(def)) {\n continue;\n } // Shape 2b: pure type def\n raw[key] = def; // Shape 1: plain object\n }\n }\n\n // Wrap in Vue reactive proxy — deep reactivity from this point on\n const state = reactive(raw);\n\n // Second pass: template strings → computed\n for (const [key, def] of Object.entries(defs)) {\n if (typeof def === \"string\" && def.includes(\"${\")) {\n state[key] = computed(() => evaluateTemplate(def, state));\n }\n }\n\n // Pass 2.5: $expression entries (Shape 5)\n for (const [key, def] of Object.entries(defs)) {\n if (isExpressionDef(def)) {\n const node = def.$expression;\n if (isNamedFormulaDef(def)) {\n // A named formula: callable with positional args mapped onto its declared parameters.\n const params = def.parameters as (string | { name?: string; default?: unknown })[];\n state[key] = (...argValues: unknown[]) => {\n const args: Record<string, unknown> = {};\n for (const [i, p] of params.entries()) {\n const name = typeof p === \"string\" ? p : (p?.name ?? \"\");\n if (!name) {\n continue;\n }\n args[name] =\n argValues[i] === undefined && typeof p === \"object\" && p !== null && \"default\" in p\n ? p.default\n : argValues[i];\n }\n return evaluateExpression(node, state, null, { args });\n };\n } else if (isMutating(node.operator)) {\n const handler: JxEventHandler = (s, event) => evaluateExpression(node, s, event);\n state[key] = handler;\n } else {\n state[key] = computed(() => evaluateExpression(node, state, null));\n }\n }\n }\n\n // Third pass: $prototype: \"Function\" entries\n for (const [key, def] of Object.entries(defs)) {\n if (hasStructuredBody(def)) {\n // Structured body (spec §20): with parameters → a callable mapping positional args onto\n // $args names (invoked via the call operator); without → an event handler.\n const { body } = def;\n if (Array.isArray(def.parameters) && def.parameters.length > 0) {\n const params = def.parameters as (string | { name?: string; default?: unknown })[];\n state[key] = (...argValues: unknown[]) => {\n const args: Record<string, unknown> = {};\n for (const [i, p] of params.entries()) {\n const name = typeof p === \"string\" ? p : (p?.name ?? \"\");\n if (!name) {\n continue;\n }\n args[name] =\n argValues[i] === undefined && typeof p === \"object\" && p !== null && \"default\" in p\n ? p.default\n : argValues[i];\n }\n return runStatements(body, state, null, { args });\n };\n } else {\n const handler: JxEventHandler = (s, event) => {\n void runStatements(body, s, event ?? null);\n };\n state[key] = handler;\n }\n } else if (isFunctionDef(def)) {\n state[key] = await resolveFunction(def, state, key, base);\n }\n }\n\n // Fourth pass: other $prototype entries (Request, Set, Map, etc.)\n for (const [key, def] of Object.entries(defs)) {\n if (isPrototypeDef(def)) {\n state[key] = await resolvePrototype(def, state, key, base);\n }\n }\n\n // Fifth pass: timing: \"server\" entries (dev mode — execute client-side, boundary unenforced)\n if (!_serverFnConfig.skip) {\n for (const [key, def] of Object.entries(defs)) {\n if (isServerFnDef(def)) {\n state[key] = await resolveServerFunction(def, state, key, base);\n }\n }\n }\n\n if (doc.$media) {\n state[\"$media\"] = doc.$media;\n } else if (!state[\"$media\"] && Object.keys(_rootMedia).length > 0) {\n state[\"$media\"] = _rootMedia;\n }\n\n return state;\n}\n\n/**\n * Check whether an object contains any JSON Schema keywords. Used to discriminate Shape 2b (pure\n * type definition) from Shape 1 (naked object).\n *\n * @param {JxScope} obj\n * @returns {boolean}\n */\nfunction hasSchemaKeywords(obj: object) {\n for (const k of Object.keys(obj)) {\n if (SCHEMA_KEYWORDS.has(k)) {\n return true;\n }\n }\n return false;\n}\nexport { hasSchemaKeywords };\n\n/**\n * Evaluate a template string in the context of state and optional $map. Templates use\n * `state.varName` and `$map.item` syntax.\n *\n * @param {string} str\n * @param {JxScope} state\n * @returns {string}\n */\nfunction evaluateTemplate(str: string, state: JxScope): string {\n const $map = state?.$map as { item?: unknown; index?: number } | undefined;\n const fn = new Function(\"state\", \"$map\", \"item\", \"index\", `return \\`${str}\\``) as (\n state: JxScope,\n $map: unknown,\n item: unknown,\n index: number | undefined,\n ) => string;\n return fn(state, $map, $map?.item, $map?.index);\n}\n\n// ─── Step 2b: Function resolution (Shape 4) ─────────────────────────────────\n\n/** Shape of a dynamically imported module: named exports plus an optional default. */\ntype ImportedModule = Record<string, unknown> & { default?: Record<string, unknown> };\n\n/** Minimal contract an externally-imported resolver class may implement. */\ninterface ExternalClassInstance {\n value?: unknown;\n resolve?: () => unknown;\n subscribe?: (cb: (newVal: unknown) => void) => void;\n}\n\n/** Module cache for $src imports (shared with external class resolution). */\nconst _moduleCache = new Map<string, ImportedModule>();\n\n/**\n * Resolve a $prototype: \"Function\" entry into a function or computed.\n *\n * Functions receive state as their first parameter at call time. Functions with a return statement\n * in their body are wrapped in computed() for reactive evaluation.\n *\n * @param {JxFunctionDef} def - State entry with $prototype: \"Function\"\n * @param {JxScope} state - Reactive scope proxy\n * @param {string} key - Def key name\n * @param {string} [base] - Base URL for resolving $src imports\n * @returns {Promise<unknown>}\n */\nasync function resolveFunction(def: JxFunctionDef, state: JxScope, key: string, base?: string) {\n if (def.body && def.$src) {\n throw new Error(`Jx: '${key}' declares both body and $src — these are mutually exclusive`);\n }\n if (!def.body && !def.$src) {\n const params = resolveParamNames(def);\n const noop = new Function(...params, \"\");\n Object.defineProperty(noop, \"name\", {\n configurable: true,\n value: def.name ?? key,\n });\n return noop;\n }\n\n let fn: ((...args: unknown[]) => unknown) | undefined;\n\n if (typeof def.body === \"string\") {\n const params = resolveParamNames(def);\n fn = new Function(...params, def.body) as (...args: unknown[]) => unknown;\n Object.defineProperty(fn, \"name\", {\n configurable: true,\n value: def.name ?? key,\n });\n } else {\n // $src: dynamic import (the body/$src dichotomy was validated above)\n const src = def.$src;\n if (!src) {\n throw new Error(`Jx: '${key}' has neither body nor $src`);\n }\n const exportName = def.$export ?? key;\n let mod: ImportedModule;\n if (_moduleCache.has(src)) {\n mod = _moduleCache.get(src)!;\n } else {\n if (base) {\n const resolvedSrc = new URL(src, base).href;\n try {\n mod = (await import(resolvedSrc)) as ImportedModule;\n } catch {\n mod = (await import(src)) as ImportedModule;\n }\n } else {\n mod = (await import(src)) as ImportedModule;\n }\n _moduleCache.set(src, mod);\n }\n const candidate = mod[exportName] ?? mod.default?.[exportName];\n if (typeof candidate !== \"function\") {\n throw new TypeError(`Jx: export \"${exportName}\" not found or not a function in \"${src}\"`);\n }\n fn = candidate as (...args: unknown[]) => unknown;\n }\n\n // Detect computed: body contains a return statement, or $src function introspection.\n // Functions with parameters (event handlers, callbacks) are never computed.\n const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;\n let isComputed = false;\n if (!hasParams) {\n if (typeof def.body === \"string\") {\n isComputed = bodyReturnsValue(def.body);\n } else if (fn) {\n isComputed = fn.length <= 1 && bodyReturnsValue(fn.toString());\n }\n }\n if (isComputed) {\n return computed(() => fn(state));\n }\n\n return fn;\n}\n\n// ─── Step 3: Render ───────────────────────────────────────────────────────────\n\n/**\n * Extract parameter names from a function definition. Supports both legacy \"arguments\" (string\n * array) and CEM-compatible \"parameters\" (object array). Always ensures \"state\" is the first\n * parameter.\n *\n * @param {JxFunctionDef | JxPrototypeDef} def\n * @returns {string[]}\n */\nfunction resolveParamNames(def: JxFunctionDef | JxPrototypeDef) {\n const names = def.parameters ? paramNames(def.parameters) : (def.arguments ?? []);\n return names.length > 0 && names[0] === \"state\" ? names : [\"state\", ...names];\n}\n\n/**\n * Reserved Jx keys — never set as DOM properties.\n *\n * @type {Set<string>}\n */\nexport const RESERVED_KEYS = new Set([\n \"$schema\",\n \"$id\",\n \"$defs\",\n \"state\",\n \"$ref\",\n \"$props\",\n \"$elements\",\n \"$title\",\n \"$description\",\n \"$switch\",\n \"$prototype\",\n \"$src\",\n \"$export\",\n \"$media\",\n \"$map\",\n \"timing\",\n \"default\",\n \"description\",\n \"body\",\n \"parameters\",\n \"arguments\",\n \"name\",\n \"tagName\",\n \"children\",\n \"style\",\n \"attributes\",\n \"items\",\n \"map\",\n \"filter\",\n \"sort\",\n \"cases\",\n \"observedAttributes\",\n]);\n\n/**\n * Recursively render a Jx element definition into a DOM element.\n *\n * @param {JxElement | string | number | boolean} def\n * @param {JxScope} state - Reactive scope proxy (or child scope via Object.create)\n * @param {JxRenderOptions} [options]\n * @returns {HTMLElement | Text}\n */\n/** Refs already warned about, so the §13 diagnostic fires once per distinct target. */\nconst warnedRefChildren = new Set<string>();\n\nexport function renderNode(\n def: JxElement | string | number | boolean,\n state: JxScope,\n options?: JxRenderOptions,\n): HTMLElement | Text {\n const path = options?._path ?? [];\n\n // Text node children: bare strings/numbers/booleans produce DOM Text nodes\n if (typeof def === \"string\" || typeof def === \"number\" || typeof def === \"boolean\") {\n const textNode = document.createTextNode(String(def));\n if (typeof def === \"string\" && isTemplateString(def)) {\n effect(() => {\n textNode.textContent = evaluateTemplate(def, state);\n });\n }\n return textNode;\n }\n\n // Extend scope with any $-prefixed local bindings declared on this node\n let localState: JxScope = state;\n for (const [key, val] of Object.entries(def)) {\n if (key.startsWith(\"$\") && !RESERVED_KEYS.has(key)) {\n if (localState === state) {\n localState = Object.create(state) as JxScope;\n }\n localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;\n }\n }\n\n /*\n * §13 diagnostic: a node-level external `$ref` (the withdrawn component-instance syntax) has no\n * tagName and silently renders an empty <div>. Warn once per target instead of failing silently —\n * the supported mechanism is $elements + a custom-element tag (see spec §13).\n */\n if (\"$ref\" in def && !def.tagName) {\n const refTarget = String((def as { $ref?: unknown }).$ref ?? \"\");\n if (!warnedRefChildren.has(refTarget)) {\n warnedRefChildren.add(refTarget);\n console.warn(\n `Jx: a $ref child (\"${refTarget}\") is not a supported component instance; register the ` +\n `component in $elements and use its custom-element tag instead (spec §13).`,\n );\n }\n }\n\n /* RESOLVED ONCE, HERE, before anything branches on it.\n A tag may be a name or a choice between names (`ElementTagName`). Resolving at the top means\n every test below — the hyphen check that routes to the custom-element path, `customElements.get`,\n `createElement` itself — sees a literal, exactly as it did when a tag could only be written out.\n\n It is not tracked. `tagName` is in RESERVED_KEYS so no binding sweep reaches it, and a tag that\n changed after mount would mean replacing the node: the subtree's listeners, its focus, its typed\n input values and its component instances all go with it, and this runtime has no dispose walk to\n pay that bill (renderSwitch, two hundred lines up, still leaks its previous case's effects).\n `jx validate` warns when a tag discriminant is also an assignment target, so the case where this\n rule bites is caught before it ships rather than found as a `<div>` that never became an `<a>`. */\n const tagName = resolveTagName(def.tagName, localState);\n const isCustomEl = tagName.includes(\"-\") && customElements.get(tagName);\n\n if (def.$props && isCustomEl) {\n return renderCustomElementWithProps(def, localState, options, path);\n }\n\n if (def.$props) {\n // A hyphenated tag carrying $props is a component instance whose definition has not finished\n // Registering yet (async defineElement — e.g. the Studio desktop canvas, where the component\n // Fetch can land after this node renders). Render via the property-first path anyway: it sets\n // The instance props as JS properties on the bare element, which the eventual upgrade's\n // ConnectedCallback reads back off `this` (see the def.state merge below), so the instance's\n // Props win. The old branch stripped the props here, so a late upgrade painted the component's\n // State DEFAULTS instead (\"0\"/\"DESCRIPTION\" for every instance). A non-custom tag can never\n // Upgrade, so it keeps the historical mergeProps-into-scope behavior.\n if (tagName.includes(\"-\")) {\n return renderCustomElementWithProps(def, localState, options, path);\n }\n const { $props: _$props, ...rest } = def;\n return renderNode(rest, mergeProps(def, localState), options);\n }\n if (def.$switch) {\n return renderSwitch(def, localState, options);\n }\n\n const el = document.createElement(tagName);\n\n if (options?.onNodeCreated) {\n options.onNodeCreated(el, path, def, localState);\n }\n\n applyProperties(el, def, localState);\n applyStyle(\n el,\n def.style ?? {},\n (localState[\"$media\"] as Record<string, string>) ?? {},\n localState,\n );\n applyAttributes(el, def.attributes ?? {}, localState);\n\n const kids = def.children;\n if (isMappedArray(kids)) {\n // Legacy whole-children repeater: the items render directly into `el` (which keeps its own\n // TagName, e.g. <ul>), with no extra wrapper element.\n const arrOpts = options ? { ...options, _path: [...path, \"children\"] } : undefined;\n renderMappedArrayInto(el, kids, localState, arrOpts);\n } else if (Array.isArray(kids)) {\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i]!;\n const childOpts = options ? { ...options, _path: [...path, \"children\", i] } : undefined;\n if (isMappedArray(child)) {\n // Array pseudo-element among siblings: expand inline, no wrapper.\n renderMappedArrayInto(el, child, localState, childOpts);\n } else {\n el.append(renderNode(child, localState, childOpts));\n }\n }\n }\n\n return el;\n}\n\n// ─── Template string utilities ────────────────────────────────────────────────\n\n/**\n * Check if a value is a template string (contains ${}).\n *\n * @param {unknown} val\n * @returns {boolean}\n */\n// ─── Property / style / attribute application ─────────────────────────────────\n\n/**\n * @param {HTMLElement} el\n * @param {JxElement} def\n * @param {JxScope} state\n */\nfunction applyProperties(el: HTMLElement, def: JxElement, state: JxScope) {\n for (const [key, val] of Object.entries(def)) {\n if (RESERVED_KEYS.has(key)) {\n continue;\n }\n if (key.startsWith(\"$\")) {\n continue;\n } // Scope bindings — handled in renderNode\n\n if (key.startsWith(\"on\")) {\n // Event handler: $ref to a function\n if (isRefObj(val)) {\n const handler = resolveRef(val.$ref, state);\n if (typeof handler === \"function\") {\n const scope = state;\n const handlerFn = handler as (s: JxScope, e: Event) => unknown;\n el.addEventListener(key.slice(2), (e) => handlerFn(scope, e));\n }\n continue;\n }\n // Event handler: inline $prototype: \"Function\" with a structured body (spec §20)\n if (hasStructuredBody(val)) {\n const { body } = val;\n const scope = state;\n el.addEventListener(key.slice(2), (e) => {\n void runStatements(body, scope, e);\n });\n continue;\n }\n // Event handler: inline $prototype: \"Function\"\n if (isFunctionDef(val) && typeof val.body === \"string\") {\n const params = resolveParamNames(val);\n const fn = new Function(...params, val.body) as (s: JxScope, e: Event) => unknown;\n const scope = state;\n el.addEventListener(key.slice(2), (e) => fn(scope, e));\n continue;\n }\n // Event handler: inline $expression\n if (isExpressionDef(val)) {\n const node = val.$expression;\n const scope = state;\n el.addEventListener(key.slice(2), (e) => evaluateExpression(node, scope, e));\n continue;\n }\n }\n\n bindProperty(el, key, val, state);\n }\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} key\n * @param {unknown} val\n * @param {JxScope} state\n */\nfunction bindProperty(el: HTMLElement, key: string, val: unknown, state: JxScope) {\n const target = el as unknown as Record<string, unknown>;\n const boundProp = boundPropKey(key, val, state);\n if (boundProp) {\n el.dataset.jxBoundProp = boundProp;\n }\n if (isRefObj(val)) {\n const refVal = val as { $ref: string };\n if (key === \"id\") {\n target[key] = resolveRef(refVal.$ref, state) as string;\n return;\n }\n effect(() => {\n target[key] = resolveRef(refVal.$ref, state);\n });\n return;\n }\n\n // Universal ${} reactivity — template strings in element properties\n if (isTemplateString(val)) {\n effect(() => {\n target[key] = evaluateTemplate(val as string, state);\n });\n return;\n }\n\n target[key] = val;\n}\n\n/**\n * Apply inline styles and emit a scoped <style> block for nested CSS selectors and @custom-media\n * breakpoint rules.\n *\n * @param {HTMLElement} el\n * @param {JxStyle} styleDef\n * @param {Record<string, string>} [mediaQueries] Named breakpoints from root $media. Default is\n * `{}`\n * @param {JxScope} [state] Component scope for template string evaluation. Default is `{}`\n */\nexport function applyStyle(\n el: HTMLElement,\n styleDef: JxStyle,\n mediaQueries: Record<string, string> = {},\n state: JxScope = {},\n) {\n const nested: Record<string, JxStyle> = {};\n const media: Record<string, JxStyle> = {};\n const baseDecls: Record<string, string> = {};\n\n // Collect properties overridden by media queries so we can avoid inline styles for them\n const mediaOverriddenProps = new Set<string>();\n for (const [prop, val] of Object.entries(styleDef)) {\n if (prop.startsWith(\"@\") && val && typeof val === \"object\") {\n for (const k of Object.keys(val)) {\n if (\n !k.startsWith(\":\") &&\n !k.startsWith(\".\") &&\n !k.startsWith(\"&\") &&\n !k.startsWith(\"[\") &&\n !k.startsWith(\"@\")\n ) {\n mediaOverriddenProps.add(k);\n }\n }\n }\n }\n\n for (const [prop, val] of Object.entries(styleDef)) {\n if (val !== null && typeof val === \"object\" && !Array.isArray(val)) {\n if (prop.startsWith(\"@\")) {\n media[prop] = val;\n } else {\n nested[prop] = val;\n }\n continue;\n }\n if (prop.startsWith(\"@\") || isNestedSelector(prop)) {\n // Scalar under a selector/media key — invalid style shape, drop it.\n continue;\n }\n if (val === undefined) {\n continue;\n }\n const scalar = String(val);\n if (prop.startsWith(\"--\")) {\n if (isTemplateString(val)) {\n effect(() => {\n el.style.setProperty(prop, transposeCanvasUnits(evaluateTemplate(val, state)));\n });\n } else {\n el.style.setProperty(prop, transposeCanvasUnits(scalar));\n }\n } else if (isTemplateString(val)) {\n effect(() => {\n (el.style as unknown as Record<string, string>)[prop] = transposeCanvasUnits(\n evaluateTemplate(val, state),\n );\n });\n } else if (mediaOverriddenProps.has(prop)) {\n // Goes through toCSSText (which transposes) — don't double-transpose here.\n baseDecls[prop] = scalar;\n } else {\n (el.style as unknown as Record<string, string>)[prop] = transposeCanvasUnits(scalar);\n }\n }\n\n const hasNested = Object.keys(nested).length > 0;\n const hasMedia = Object.keys(media).length > 0;\n const hasBaseDecls = Object.keys(baseDecls).length > 0;\n if (!hasNested && !hasMedia && !hasBaseDecls) {\n return;\n }\n\n const uid = `jx-${Math.random().toString(36).slice(2, 7)}`;\n el.dataset.jx = uid;\n\n let css = \"\";\n const baseCSS = toCSSText(baseDecls);\n if (baseCSS) {\n css += `[data-jx=\"${uid}\"] { ${baseCSS} }\\n`;\n }\n\n function emitNested(scope: string, rules: JxStyle) {\n const props = toCSSText(rules);\n if (props) {\n css += `${scope} { ${props} }\\n`;\n }\n for (const [sel, sub] of Object.entries(rules)) {\n if (sub === null || typeof sub !== \"object\" || Array.isArray(sub)) {\n continue;\n }\n if (sel.startsWith(\"@\")) {\n continue;\n }\n const resolved = sel.startsWith(\"&\")\n ? sel.replace(\"&\", scope)\n : sel.startsWith(\"[\")\n ? `${scope}${sel}`\n : sel.startsWith(\":\") || sel.startsWith(\".\")\n ? `${scope}${sel}`\n : `${scope} ${sel}`;\n emitNested(resolved, sub);\n }\n }\n\n for (const [sel, rules] of Object.entries(nested)) {\n const resolved = sel.startsWith(\"&\")\n ? sel.replace(\"&\", `[data-jx=\"${uid}\"]`)\n : sel.startsWith(\"[\")\n ? `[data-jx=\"${uid}\"]${sel}`\n : sel.startsWith(\":\") || sel.startsWith(\".\")\n ? `[data-jx=\"${uid}\"]${sel}`\n : `[data-jx=\"${uid}\"] ${sel}`;\n emitNested(resolved, rules);\n }\n\n function emitMediaNested(atRule: string, parentSel: string, obj: JxStyle) {\n for (const [sel, sub] of Object.entries(obj)) {\n if (sub === null || typeof sub !== \"object\" || Array.isArray(sub)) {\n continue;\n }\n if (sel.startsWith(\"@\")) {\n continue;\n }\n const resolved = sel.startsWith(\"&\")\n ? sel.replace(\"&\", parentSel)\n : sel.startsWith(\"[\")\n ? `${parentSel}${sel}`\n : sel.startsWith(\":\") || sel.startsWith(\".\")\n ? `${parentSel}${sel}`\n : `${parentSel} ${sel}`;\n const props = toCSSText(sub);\n if (props) {\n css += `${atRule} { ${resolved} { ${props} } }\\n`;\n }\n emitMediaNested(atRule, resolved, sub);\n }\n }\n\n for (const [key, rules] of Object.entries(media)) {\n if (key === \"@--\") {\n continue;\n } // Base canvas width, not a real media query\n const query = key.startsWith(\"@--\")\n ? (mediaQueries[key.slice(1)] ?? key.slice(1))\n : key.startsWith(\"@(\")\n ? key.slice(1)\n : null;\n const atRule = query === null ? key : `@media ${query}`;\n const scope = `[data-jx=\"${uid}\"]`;\n const scheme = query === null ? null : pureSchemeOf(query);\n if (scheme) {\n // Dual-emit scheme rules: a media-guarded copy for auto plus a forced-attribute copy.\n // The forced root attribute wins over the OS preference.\n const { auto, forced } = schemeSelectors(scope, scheme);\n css += `${atRule} { ${auto} { ${toCSSText(rules)} } }\\n`;\n emitMediaNested(atRule, auto, rules);\n emitNested(forced, rules);\n } else {\n css += `${atRule} { ${scope} { ${toCSSText(rules)} } }\\n`;\n emitMediaNested(atRule, scope, rules);\n }\n }\n\n const tag = document.createElement(\"style\");\n tag.textContent = css;\n tag.dataset.jxOwner = uid;\n document.head.append(tag);\n elementStyleTags.set(el, tag);\n}\n\n/**\n * Scoped <style> tags emitted per element by applyStyle (latest wins). Lets callers replace an\n * element's emitted styles instead of accumulating orphaned tags.\n */\nexport const elementStyleTags = new WeakMap<HTMLElement, HTMLStyleElement>();\n\n/**\n * Re-apply an element's style definition in place: removes the previously emitted scoped <style>\n * tag (if any), clears inline styles, and applies the new definition.\n *\n * @param {HTMLElement} el\n * @param {JxStyle | undefined} styleDef\n * @param {Record<string, string>} [mediaQueries]\n * @param {JxScope} [state]\n */\nexport function reapplyStyle(\n el: HTMLElement,\n styleDef: JxStyle | undefined,\n mediaQueries: Record<string, string> = {},\n state: JxScope = {},\n) {\n const prev = elementStyleTags.get(el);\n if (prev) {\n prev.remove();\n elementStyleTags.delete(el);\n }\n el.style.cssText = \"\";\n delete el.dataset.jx;\n applyStyle(el, styleDef ?? {}, mediaQueries, state);\n}\n\n/**\n * @param {HTMLElement} el\n * @param {Record<string, import(\"@jxsuite/schema/types\").JxAttributeValue>} attrs\n * @param {JxScope} state\n */\nfunction applyAttributes(el: HTMLElement, attrs: Record<string, JxAttributeValue>, state: JxScope) {\n for (const [k, v] of Object.entries(attrs)) {\n const attr = canvasAttrName(el, k);\n if (isRefObj(v)) {\n effect(() => el.setAttribute(attr, String(resolveRef(v.$ref, state) ?? \"\")));\n } else if (isTemplateString(v)) {\n effect(() => el.setAttribute(attr, String(evaluateTemplate(v, state))));\n } else {\n el.setAttribute(attr, String(v));\n }\n }\n}\n\n// ─── Array mapping ────────────────────────────────────────────────────────────\n\n/**\n * Render a mapped array (repeater) wrapper-less: its item instances are inserted directly into\n * `parentEl`, in place, ahead of an anchor comment that marks the array's position among the\n * parent's other children. Re-renders reactively when `items` (or the filter/sort sources) change;\n * each generation's item renders live in their own detached effect scope so nested arrays and\n * template bindings are disposed — not leaked or double-fired — on the next change.\n *\n * `options._path` is the array node's own document path (`[…, \"children\", i]`, or `[…, \"children\"]`\n * for a legacy whole-children repeater); item instances render at `[…that…, \"map\", index]`.\n *\n * @param {HTMLElement} parentEl\n * @param {import(\"@jxsuite/schema/types\").JxMappedArray} arrayDef\n * @param {JxScope} state\n * @param {JxRenderOptions} [options]\n */\nfunction renderMappedArrayInto(\n parentEl: HTMLElement,\n arrayDef: JxMappedArray,\n state: JxScope,\n options?: JxRenderOptions,\n) {\n const path = options?._path ?? [];\n const anchor = document.createComment(\"jx-array\");\n parentEl.append(anchor);\n const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = arrayDef;\n\n effect(() => {\n let items: unknown = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;\n if (Array.isArray(items) && isRefObj(filterRef)) {\n const fn = resolveRef(filterRef.$ref, state);\n if (typeof fn === \"function\") {\n items = items.filter(fn as (v: unknown) => boolean);\n }\n }\n if (Array.isArray(items) && isRefObj(sortRef)) {\n const fn = resolveRef(sortRef.$ref, state);\n if (typeof fn === \"function\") {\n items = [...(items as unknown[])].toSorted(fn as (a: unknown, b: unknown) => number);\n }\n }\n if (!Array.isArray(items) || !mapDef) {\n return;\n }\n\n // Render this generation's items inside a detached scope; the cleanup (run before the next\n // Re-render and when the enclosing render scope stops) tears it down and removes its nodes.\n const scope = effectScope(true);\n const nodes: ChildNode[] = [];\n scope.run(() => {\n for (const [index, item] of (items as unknown[]).entries()) {\n const child = Object.create(state) as JxScope;\n child.$map = { index, item };\n child[\"$map/item\"] = item;\n child[\"$map/index\"] = index;\n const childOpts = options ? { ...options, _path: [...path, \"map\", index] } : undefined;\n const node = renderNode(mapDef, child, childOpts);\n anchor.before(node);\n nodes.push(node);\n }\n });\n onEffectCleanup(() => {\n scope.stop();\n for (const n of nodes) {\n n.remove();\n }\n });\n });\n}\n\n/**\n * An element's tag: a name, or the branch of a {@link JxTagExpression} the state selects.\n *\n * Every branch of the expression is itself a `TagName`, so this can only ever return something the\n * schema already held to the tag-name pattern — the property that lets the compiler enumerate the\n * candidates and lets `createElement` be called without a second thought here.\n *\n * @param {unknown} tagName The element's declared tag.\n * @param {JxScope} scope The state the discriminant reads.\n * @returns {string} A literal tag name; `\"div\"` when nothing is declared.\n */\nexport function resolveTagName(tagName: unknown, scope: JxScope): string {\n if (typeof tagName === \"string\") {\n return tagName;\n }\n if (!isTagExpression(tagName)) {\n return \"div\";\n }\n const expression = tagName.$expression;\n if (expression.operator === \"?:\") {\n // `evaluateOperand`, not `evaluateExpression`: the discriminant is an OPERAND — a pointer, a\n // Literal or a nested node — exactly as it is for a `$switch`, whose docstring names this.\n return evaluateOperand(expression.target, scope, null) ? expression.value : expression.initial;\n }\n const key = evaluateOperand(expression.target, scope, null);\n return expression.cases[String(key)] ?? expression.default;\n}\n\n// ─── $switch ──────────────────────────────────────────────────────────────────\n\n/**\n * @param {JxElement} def\n * @param {JxScope} state\n * @param {JxRenderOptions} [options]\n * @returns {HTMLElement}\n */\nfunction renderSwitch(def: JxElement, state: JxScope, options?: JxRenderOptions) {\n const path = options?._path ?? [];\n const container = document.createElement(resolveTagName(def.tagName, state));\n\n if (options?.onNodeCreated) {\n options.onNodeCreated(container, path, def, state);\n }\n\n applyProperties(container, def, state);\n applyStyle(container, def.style ?? {}, (state[\"$media\"] as Record<string, string>) ?? {}, state);\n applyAttributes(container, def.attributes ?? {}, state);\n let generation = 0;\n\n effect(() => {\n /* `replaceChildren()` rather than `innerHTML = \"\"`: identical semantics, and it is not a\n Trusted Types injection sink — under `require-trusted-types-for 'script'` an innerHTML write\n needs a policy even when the string is empty. Four sinks that were never injecting anything\n is four fewer things a policy has to be permissive about. */\n container.replaceChildren();\n if (!isRefObj(def.$switch)) {\n return;\n }\n const key = resolveRef(def.$switch.$ref, state) as string;\n const caseDef = def.cases?.[key];\n if (!caseDef) {\n return;\n }\n\n if (isRefObj(caseDef)) {\n // External $ref — fetch and render asynchronously\n generation += 1;\n const gen = generation;\n const { href } = new URL(caseDef.$ref, location.href);\n resolve(href)\n .then(async (doc) => {\n if (gen !== generation) {\n return;\n }\n const childScope = await buildScope(doc, {}, href);\n if (gen !== generation) {\n return;\n }\n container.replaceChildren();\n const childOpts = options ? { ...options, _path: [...path, \"cases\", key] } : undefined;\n container.append(renderNode(doc, childScope, childOpts));\n })\n .catch((error: unknown) =>\n console.error(\"Jx $switch: failed to load external case\", caseDef.$ref, error),\n );\n return;\n }\n\n const childOpts = options ? { ...options, _path: [...path, \"cases\", key] } : undefined;\n container.append(renderNode(caseDef, state, childOpts));\n });\n\n return container;\n}\n\n// ─── Prototype namespaces (Shape 5) ──────────────────────────────────────────\n\n/**\n * Resolve a $prototype definition into a value for the reactive scope.\n *\n * Returns a ref() for async/persistent entries (Request, Storage, Cookie, IndexedDB), or a plain\n * value for simple entries (Set, Map, FormData, Blob).\n *\n * @param {JxPrototypeDef} def - State entry with $prototype\n * @param {JxScope} state - Reactive scope proxy\n * @param {string} key - Def key (for diagnostics)\n * @param {string} [base] - Base URL for resolving $src imports\n * @returns {Promise<unknown>}\n */\nexport async function resolvePrototype(\n def: JxPrototypeDef,\n state: JxScope,\n key: string,\n base?: string,\n) {\n // ── External class via $src ─────────────────────────────────────────────────\n if (def.$src) {\n return resolveExternalPrototype(def, state, key, base);\n }\n\n switch (def.$prototype) {\n case \"Request\": {\n const s: Ref<unknown> = ref(null);\n const debounceMs = def.debounce ?? 0;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n if (!def.manual && !_autoRequestConfig.skip) {\n effect(() => {\n let url: string | undefined;\n if (isTemplateString(def.url)) {\n url = evaluateTemplate(def.url, state);\n } else {\n ({ url } = def);\n }\n if (!url || url === \"undefined\" || url.includes(\"undefined\")) {\n return;\n }\n\n const controller = new AbortController();\n onEffectCleanup(() => {\n controller.abort();\n if (debounceTimer !== null) {\n clearTimeout(debounceTimer);\n }\n });\n\n const doFetch = () =>\n fetch(url, {\n method: def.method ?? \"GET\",\n signal: controller.signal,\n ...(def.headers && { headers: def.headers }),\n ...(def.body && {\n body: typeof def.body === \"object\" ? JSON.stringify(def.body) : def.body,\n }),\n })\n .then((r) => (r.ok ? r.json() : Promise.reject(r.statusText)))\n .then((d) => {\n s.value = d;\n })\n .catch((error: unknown) => {\n if (!(error instanceof Error && error.name === \"AbortError\")) {\n s.value = { error: String(error) };\n }\n });\n\n if (debounceMs > 0) {\n debounceTimer = setTimeout(doFetch, debounceMs);\n } else {\n void doFetch();\n }\n });\n }\n\n return s;\n }\n\n case \"URLSearchParams\": {\n return computed(() => {\n const p: Record<string, string> = {};\n for (const [k, v] of Object.entries(def)) {\n if (k !== \"$prototype\") {\n p[k] = (\n isRefObj(v)\n ? resolveRef(v.$ref, state)\n : isTemplateString(v)\n ? evaluateTemplate(v, state)\n : v\n ) as string;\n }\n }\n return new URLSearchParams(p).toString();\n });\n }\n\n case \"LocalStorage\":\n case \"SessionStorage\": {\n const store = def.$prototype === \"LocalStorage\" ? localStorage : sessionStorage;\n const k = def.key ?? key;\n let init: unknown;\n try {\n const s = store.getItem(k);\n init = s !== null ? (JSON.parse(s) as unknown) : (def.default ?? null);\n } catch {\n init = def.default ?? null;\n }\n const storageState: Ref<unknown> = ref(init);\n // Persist on change\n effect(() => {\n const v = storageState.value;\n if (v === null) {\n try {\n store.removeItem(k);\n } catch {}\n } else {\n try {\n store.setItem(k, JSON.stringify(v));\n } catch {}\n }\n });\n return storageState;\n }\n\n case \"Cookie\": {\n const name = def.name ?? key;\n const read = () => {\n const raw = readCookie(document.cookie, name);\n if (raw === null) {\n return null;\n }\n try {\n return JSON.parse(decodeURIComponent(raw));\n } catch {\n return raw;\n }\n };\n const cookieState: Ref<unknown> = ref(read() ?? def.default ?? null);\n // Persist on change\n effect(() => {\n // oxlint-disable-next-line unicorn/no-document-cookie -- the Cookie $prototype IS the cookie store binding\n document.cookie = serializeCookie(name, cookieState.value, def);\n });\n return cookieState;\n }\n\n case \"IndexedDB\": {\n const idbState: Ref<unknown> = ref(null);\n const {\n database,\n store,\n version = 1,\n keyPath = \"id\",\n autoIncrement = true,\n indexes = [],\n } = def;\n if (!database || !store) {\n throw new Error(`Jx: IndexedDB entry '${key}' requires database and store`);\n }\n const req = indexedDB.open(database, version);\n req.addEventListener(\"upgradeneeded\", (e) => {\n const db: IDBDatabase = (e.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(store)) {\n const os = db.createObjectStore(store, { autoIncrement, keyPath });\n for (const i of indexes) {\n os.createIndex(i.name, i.keyPath, { unique: i.unique ?? false });\n }\n }\n });\n req.addEventListener(\"success\", (e) => {\n const db: IDBDatabase = (e.target as IDBOpenDBRequest).result;\n idbState.value = {\n database,\n getStore: (mode: IDBTransactionMode = \"readwrite\") =>\n Promise.resolve(db.transaction(store, mode).objectStore(store)),\n isReady: true,\n store,\n version,\n };\n });\n req.addEventListener(\"error\", () => {\n idbState.value = { error: req.error?.message };\n });\n return idbState;\n }\n\n case \"Set\": {\n return new Set(Array.isArray(def.default) ? def.default : []);\n }\n\n case \"Map\": {\n return new Map(Object.entries(isJsonObject(def.default) ? def.default : {}));\n }\n\n case \"FormData\": {\n const fd = new FormData();\n for (const [k, v] of Object.entries(def.fields ?? {})) {\n fd.append(k, v as string);\n }\n return fd;\n }\n\n case \"Blob\": {\n return new Blob((def.parts as BlobPart[]) ?? [], {\n type: typeof def.type === \"string\" ? def.type : \"text/plain\",\n });\n }\n\n case \"ReadableStream\": {\n return null;\n }\n\n default: {\n console.warn(\n `Jx: unknown $prototype \"${def.$prototype}\" for \"${key}\". Did you mean to add '$src'?`,\n );\n return ref(null);\n }\n }\n}\n\n// ─── External class resolution ────────────────────────────────────────────────\n\n/** Reserved keys stripped from the config object passed to external class constructors. */\nconst EXTERNAL_RESERVED = new Set([\n \"$prototype\",\n \"$src\",\n \"$export\",\n \"timing\",\n \"default\",\n \"description\",\n \"body\",\n \"parameters\",\n \"arguments\",\n \"name\",\n]);\n\n/**\n * Resolve an external class prototype via $src.\n *\n * @param {JxPrototypeDef} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveExternalPrototype(\n def: JxPrototypeDef,\n state: JxScope,\n key: string,\n base?: string,\n) {\n const src = def.$src;\n\n // Non-Function $prototype must use .class.json as entrypoint\n if (!src || !src.endsWith(\".class.json\")) {\n throw new Error(\n `Jx: $prototype \"${def.$prototype}\" requires a .class.json $src, got \"${src}\". ` +\n `Wrap the class in a .class.json schema with $implementation.`,\n );\n }\n\n return resolveClassJson(def, state, key, base);\n}\n\n/**\n * Import a JS module and instantiate a class from it. Internal helper used by resolveClassJson for\n * $implementation.\n *\n * @param {JxScope} def - Original state entry (for config extraction)\n * @param {string} src - JS module URL to import\n * @param {string} exportName - Export name to look up\n * @param {string} [base] - Base URL for resolution\n * @returns {Promise<unknown>}\n */\nasync function importAndInstantiate(def: JxScope, src: string, exportName: string, base?: string) {\n let mod: ImportedModule;\n if (_moduleCache.has(src)) {\n mod = _moduleCache.get(src)!;\n } else {\n try {\n mod = (await import(src)) as ImportedModule;\n } catch {\n if (base) {\n const resolvedSrc = new URL(src, base).href;\n mod = (await import(resolvedSrc)) as ImportedModule;\n } else {\n throw new Error(`Failed to import \"${src}\"`);\n }\n }\n _moduleCache.set(src, mod);\n }\n\n const ExportedClass = mod[exportName] ?? mod.default?.[exportName];\n if (!ExportedClass) {\n throw new Error(`Jx: export \"${exportName}\" not found in \"${src}\"`);\n }\n if (typeof ExportedClass !== \"function\") {\n throw new TypeError(`Jx: \"${exportName}\" from \"${src}\" is not a class`);\n }\n\n const config: JxScope = {};\n for (const [k, v] of Object.entries(def)) {\n if (!EXTERNAL_RESERVED.has(k)) {\n config[k] = v;\n }\n }\n\n const Ctor = ExportedClass as new (config: JxScope) => ExternalClassInstance;\n const instance = new Ctor(config);\n\n let value: unknown;\n if (typeof instance.resolve === \"function\") {\n value = await instance.resolve();\n } else if (\"value\" in instance) {\n ({ value } = instance);\n } else {\n value = instance;\n }\n\n // Always wrap in ref for reactivity with external classes\n const s: Ref<unknown> = ref(value);\n if (typeof instance.subscribe === \"function\") {\n instance.subscribe((newVal: unknown) => {\n s.value = newVal;\n });\n }\n return s;\n}\n\n/**\n * Resolve a .class.json schema-defined class. Fetches the schema, follows $implementation if\n * hybrid, or constructs dynamically if self-contained.\n *\n * @param {JxPrototypeDef} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveClassJson(def: JxPrototypeDef, state: JxScope, key: string, base?: string) {\n const src = def.$src;\n if (!src) {\n throw new Error(`Jx: class entry '${key}' has no $src`);\n }\n let classDef: JxClassDef;\n\n // Bare specifiers (package references like @scope/pkg/file) can't be fetched directly —\n // Go straight to dev proxy which can resolve them via node_modules.\n const isBareSpecifier =\n !src.startsWith(\".\") &&\n !src.startsWith(\"/\") &&\n !src.startsWith(\"http\") &&\n !src.startsWith(\"file:\");\n if (isBareSpecifier) {\n return resolveViaDevProxy(def, state, key, base);\n }\n\n // Try fetching the .class.json file directly\n try {\n const url = base ? new URL(src, base).href : src;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n // Trust boundary: fetched .class.json sources are class definitions by contract.\n classDef = (await res.json()) as JxClassDef;\n } catch {\n // Fall back to dev proxy (server will handle .class.json resolution)\n return resolveViaDevProxy(def, state, key, base);\n }\n\n // Hybrid mode: $implementation points to the real JS module\n if (classDef.$implementation) {\n // If the schema references $context (e.g. content types), the browser cannot provide\n // The required server-side context — go directly to dev proxy.\n const schemaStr = JSON.stringify(classDef);\n if (schemaStr.includes('\"#/$context/')) {\n return resolveViaDevProxy(def, state, key, base);\n }\n const schemaUrl = base ? new URL(src, base).href : new URL(src, location.href).href;\n const implSrc = new URL(classDef.$implementation, schemaUrl).href;\n const exportName = def.$export ?? classDef.title ?? def.$prototype;\n try {\n return await importAndInstantiate(def, implSrc, exportName, base);\n } catch {\n return resolveViaDevProxy(def, state, key, base);\n }\n }\n\n // Self-contained: construct class dynamically from schema\n const DynClass = classFromSchema(classDef);\n const config: JxScope = {};\n for (const [k, v] of Object.entries(def)) {\n if (!EXTERNAL_RESERVED.has(k)) {\n config[k] = v;\n }\n }\n const instance = new DynClass(config) as ExternalClassInstance;\n\n let value: unknown;\n if (typeof instance.resolve === \"function\") {\n value = await instance.resolve();\n } else if (\"value\" in instance) {\n ({ value } = instance);\n } else {\n value = instance;\n }\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(value);\n if (typeof instance.subscribe === \"function\") {\n instance.subscribe((newVal: unknown) => {\n s.value = newVal;\n });\n }\n return s;\n}\n\n/**\n * Dynamically construct a class from a .class.json schema definition. Browser-side: maps private\n * fields to _-prefixed public fields.\n *\n * @param {import(\"@jxsuite/schema/types\").JxClassDef} classDef\n * @returns {DynamicClass}\n */\nfunction classFromSchema(classDef: JxClassDef) {\n const fields = classDef.$defs?.fields ?? {};\n // JSON objects inherit Object.prototype.constructor — only an own object value counts.\n const rawCtor = classDef.$defs?.constructor;\n const ctor = typeof rawCtor === \"object\" ? rawCtor : undefined;\n const methods = classDef.$defs?.methods ?? {};\n\n // oxlint-disable-next-line typescript/no-extraneous-class -- methods are attached to the prototype dynamically below\n class DynClass {\n constructor(config: Record<string, unknown> = {}) {\n for (const [key, typedField] of Object.entries(fields)) {\n const id = typedField.identifier ?? key;\n const propName = typedField.access === \"private\" ? `_${id}` : id;\n if (config[id] !== undefined) {\n (this as Record<string, unknown>)[propName] = config[id];\n } else if (typedField.initializer !== undefined) {\n (this as Record<string, unknown>)[propName] = typedField.initializer;\n } else if (typedField.default !== undefined) {\n (this as Record<string, unknown>)[propName] = structuredClone(typedField.default);\n } else {\n (this as Record<string, unknown>)[propName] = null;\n }\n }\n if (ctor?.body) {\n const bodyStr = Array.isArray(ctor.body) ? ctor.body.join(\"\\n\") : ctor.body;\n (\n new Function(\"config\", bodyStr) as (\n this: unknown,\n config: Record<string, unknown>,\n ) => void\n ).call(this, config);\n }\n }\n }\n\n for (const [key, typedMethod] of Object.entries(methods)) {\n const name = typedMethod.identifier ?? key;\n const params = (typedMethod.parameters ?? []).map((p) => {\n if (p.$ref) {\n return p.$ref.split(\"/\").pop() as string;\n }\n const n = p.identifier ?? p.name;\n return typeof n === \"string\" ? n : \"arg\";\n });\n const bodyStr = Array.isArray(typedMethod.body)\n ? typedMethod.body.join(\"\\n\")\n : (typedMethod.body ?? \"\");\n\n if (typedMethod.role === \"accessor\") {\n const descriptor: PropertyDescriptor = {};\n if (typedMethod.getter) {\n descriptor.get = new Function(typedMethod.getter.body ?? \"\") as () => unknown;\n }\n if (typedMethod.setter) {\n const sp = (typedMethod.setter.parameters ?? []).map(\n (p) => p.$ref?.split(\"/\").pop() ?? \"v\",\n );\n descriptor.set = new Function(...sp, typedMethod.setter.body ?? \"\") as (v: unknown) => void;\n }\n Object.defineProperty(DynClass.prototype, name, {\n ...descriptor,\n configurable: true,\n });\n } else if (typedMethod.scope === \"static\") {\n (DynClass as unknown as DynamicClass)[name] = new Function(...params, bodyStr);\n } else {\n (DynClass as unknown as DynamicClass).prototype[name] = new Function(...params, bodyStr);\n }\n }\n\n Object.defineProperty(DynClass, \"name\", {\n configurable: true,\n value: classDef.title,\n });\n const dynCtor = DynClass as unknown as DynamicClass;\n return dynCtor;\n}\n\n/**\n * Dev-mode fallback: when an $src module cannot run in the browser, proxy the resolve() call\n * through the Jx dev server (POST /**jx_resolve**). Supports reactive template strings in config\n * values via Vue effect().\n *\n * @param {JxPrototypeDef} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveViaDevProxy(def: JxPrototypeDef, state: JxScope, key: string, base?: string) {\n const config: JxScope = {};\n for (const [k, v] of Object.entries(def)) {\n if (!EXTERNAL_RESERVED.has(k)) {\n config[k] = v;\n }\n }\n\n const hasTemplates = Object.values(config).some((v: unknown) => isTemplateString(v));\n\n /** @param {JxScope} resolvedConfig */\n const doResolve = (resolvedConfig: JxScope) =>\n fetch(resolveProxyPath(\"/__jx_resolve__\"), {\n body: JSON.stringify({\n $base: base,\n $export: def.$export,\n $prototype: def.$prototype,\n $src: def.$src,\n ...resolvedConfig,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n }).then((r) => {\n if (!r.ok) {\n throw new Error(`Jx dev proxy ${r.status} for \"${key}\"`);\n }\n return r.json();\n });\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(null);\n if (hasTemplates) {\n effect(() => {\n const resolvedConfig: JxScope = {};\n for (const [k, v] of Object.entries(config)) {\n resolvedConfig[k] = isTemplateString(v) ? evaluateTemplate(v, state) : v;\n }\n doResolve(resolvedConfig)\n .then((value: unknown) => {\n s.value = value;\n })\n .catch((error: unknown) => console.error(\"Jx dev proxy:\", error));\n });\n } else {\n doResolve(config)\n .then((value: unknown) => {\n s.value = value;\n })\n .catch((error: unknown) => console.error(\"Jx dev proxy:\", error));\n }\n return s;\n}\n\n// ─── Server function resolution (dev mode) ────────────────────────────────────\n\n/**\n * Resolve a timing: \"server\" entry in dev mode by executing the function client-side. In\n * production, the compiler replaces this with a fetch to the generated server handler.\n *\n * @param {JxScope} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveServerFunction(\n def: JxServerFnDef,\n state: JxScope,\n key: string,\n base?: string,\n) {\n const src = def.$src;\n const exportName = def.$export;\n\n let mod: ImportedModule;\n if (_moduleCache.has(src)) {\n mod = _moduleCache.get(src)!;\n } else {\n try {\n mod = (await import(src)) as ImportedModule;\n } catch {\n if (base) {\n try {\n const resolvedSrc = new URL(src, base).href;\n mod = (await import(resolvedSrc)) as ImportedModule;\n } catch {\n // Module cannot run in the browser — fall back to dev server proxy\n return resolveServerFunctionViaProxy(def, state, key, base);\n }\n } else {\n return resolveServerFunctionViaProxy(def, state, key, base);\n }\n }\n _moduleCache.set(src, mod);\n }\n\n const candidate = mod[exportName] ?? mod.default?.[exportName];\n if (!candidate) {\n throw new Error(`Jx: export \"${exportName}\" not found in \"${src}\" for \"${key}\"`);\n }\n if (typeof candidate !== \"function\") {\n throw new TypeError(`Jx: \"${exportName}\" from \"${src}\" is not a function`);\n }\n const fn = candidate as (args: JxScope) => Promise<unknown>;\n\n const rawArgs = def.arguments ?? {};\n const hasReactiveArg = Object.values(rawArgs).some((v: unknown) => isRefObj(v));\n const resolveArgs = () => {\n const args: JxScope = {};\n for (const [k, v] of Object.entries(rawArgs)) {\n args[k] = isRefObj(v) ? resolveRef(v.$ref, state) : v;\n }\n return args;\n };\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(null);\n if (hasReactiveArg) {\n effect(() => {\n const args = resolveArgs();\n onEffectCleanup(() => {});\n fn(args)\n .then((result: unknown) => {\n s.value = result;\n })\n .catch(() => {});\n });\n } else {\n s.value = await fn(resolveArgs());\n }\n return s;\n}\n\n/**\n * Dev-mode fallback: when a timing: \"server\" module cannot run in the browser, proxy the function\n * call through the Jx dev server (POST /**jx_server**). Supports reactive $ref arguments via Vue\n * effect().\n *\n * @param {JxScope} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveServerFunctionViaProxy(\n def: JxScope,\n state: JxScope,\n key: string,\n base?: string,\n) {\n const rawArgs = def.arguments ?? {};\n const hasReactiveArg = Object.values(rawArgs).some((v: unknown) => isRefObj(v));\n\n const resolveArgs = () => {\n const args: JxScope = {};\n for (const [k, v] of Object.entries(rawArgs)) {\n args[k] = isRefObj(v) ? resolveRef((v as { $ref: string }).$ref, state) : v;\n }\n return args;\n };\n\n /** @param {JxScope} args */\n const doResolve = (args: JxScope) =>\n fetch(resolveProxyPath(\"/__jx_server__\"), {\n body: JSON.stringify({\n $base: base,\n $export: def.$export,\n $src: def.$src,\n arguments: args,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n }).then((r) => {\n if (!r.ok) {\n throw new Error(`Jx server proxy ${r.status} for \"${key}\"`);\n }\n return r.json();\n });\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(null);\n if (hasReactiveArg) {\n effect(() => {\n const args = resolveArgs();\n onEffectCleanup(() => {});\n doResolve(args)\n .then((result: unknown) => {\n s.value = result;\n })\n .catch((error: unknown) => console.error(\"Jx server proxy:\", error));\n });\n } else {\n doResolve(resolveArgs())\n .then((result: unknown) => {\n s.value = result;\n })\n .catch((error: unknown) => console.error(\"Jx server proxy:\", error));\n }\n return s;\n}\n\n/**\n * Resolve a $ref string to a value in scope.\n *\n * With Vue reactivity, this reads directly from the reactive proxy. When called inside a effect or\n * computed, the read is tracked.\n *\n * @param {string} ref\n * @param {JxScope} state - Reactive scope proxy (or child scope)\n * @returns {unknown}\n */\nexport function resolveRef(refPath: string, state: JxScope) {\n if (typeof refPath !== \"string\") {\n return refPath;\n }\n if (refPath.startsWith(\"$map/\")) {\n const parts = refPath.split(\"/\");\n const [, key] = parts; // \"item\" or \"index\"\n const map = state.$map as Record<string, unknown> | undefined;\n const base = map?.[key!] ?? state[`$map/${key}`];\n return parts.length > 2 ? getPath(base, parts.slice(2).join(\"/\")) : base;\n }\n if (refPath.startsWith(\"#/state/\")) {\n // One call, not a hand-split leading token: slicing at the first `/` skipped unescaping it, so\n // `#/state/a~1b/c` looked for a member called `a~1b` rather than `a/b`.\n return readPath(state, refPath.slice(\"#/state/\".length));\n }\n if (refPath.startsWith(\"parent#/\")) {\n /*\n * A prop name may be a path into the prop. This read the whole path as one key and returned\n * undefined for `parent#/user/name`, while the compiler lowered it to a walk.\n */\n return readPath(state, refPath.slice(\"parent#/\".length));\n }\n if (refPath.startsWith(\"window#/\")) {\n return getPath(globalThis.window, refPath.slice(\"window#/\".length));\n }\n if (refPath.startsWith(\"document#/\")) {\n return getPath(globalThis.document, refPath.slice(\"document#/\".length));\n }\n return readPath(state, refPath) ?? null;\n}\n\n// ─── Utilities ────────────────────────────────────────────────────────────────\n\n/**\n * Check if v is a Vue ref (including computed).\n *\n * @param {unknown} v\n * @returns {boolean}\n */\nexport function isSignal(v: unknown) {\n return isRef(v);\n}\n\n/**\n * @param {unknown} v\n * @returns {v is import(\"@jxsuite/schema/types\").JxRef}\n */\nfunction isRefObj(v: unknown): v is JxRef {\n return isRefValue(v);\n}\n\n/**\n * @param {string} k\n * @returns {boolean}\n */\nfunction isNestedSelector(k: string) {\n return k.startsWith(\":\") || k.startsWith(\".\") || k.startsWith(\"&\") || k.startsWith(\"[\");\n}\n\n/**\n * Walk a path off a value. Delegates to the one tokenizer (`pointer.ts`) — this used to split on\n * `/[./]/`, which no other path in the codebase agreed with.\n *\n * @param {unknown} obj\n * @param {string} path\n * @returns {unknown}\n */\nfunction getPath(obj: unknown, path: string) {\n return readPath(obj, path);\n}\n\n/** Keys already reported, so a component rendered in a loop warns once rather than per instance. */\nconst _privatePropWarned = new Set<string>();\n\n/**\n * Refuse a `$props` write against a private (`#`) state key — `spec.md` §5.6.\n *\n * Ignored rather than thrown. A `$props` block naming a private entry is an authoring mistake, not\n * a broken document: the rest of the instance is well-formed and refusing to render it would turn a\n * typo into a blank page. But silence was the previous behavior and it is the wrong kind — the\n * author sees a prop that looks accepted and does nothing — so the write is dropped and named.\n *\n * @param {string} key\n * @param {string} [where] - The site refusing it, for a message that points somewhere\n * @returns {boolean} True when the key is private and the caller must skip it\n */\nfunction refusePrivateProp(key: string, where?: string): boolean {\n if (!isPrivateStateKey(key)) {\n return false;\n }\n const seen = where === undefined ? key : `${where}:${key}`;\n if (!_privatePropWarned.has(seen)) {\n _privatePropWarned.add(seen);\n console.warn(\n `Jx: \"${key}\" is private state (spec.md §5.6) and cannot be set through $props` +\n `${where === undefined ? \"\" : ` (${where})`}. The write was ignored; rename the entry ` +\n \"without the leading # to make it part of the component's interface.\",\n );\n }\n return true;\n}\n\n/** Tests only — the warn-once set outlives a single render by design. */\nexport function _resetPrivatePropWarnings(): void {\n _privatePropWarned.clear();\n}\n\n/**\n * @param {JxElement} def\n * @param {JxScope} parentState\n * @returns {JxScope}\n */\nfunction mergeProps(def: JxElement, parentState: JxScope): JxScope {\n const child = Object.create(parentState) as JxScope;\n for (const [k, v] of Object.entries(def.$props ?? {})) {\n if (refusePrivateProp(k, \"$props\")) {\n continue;\n }\n child[k] = isRefObj(v) ? resolveRef(v.$ref, parentState) : v;\n }\n return child;\n}\n\n/**\n * Convert camelCase to kebab-case.\n *\n * @param {string} s\n * @returns {string}\n */\nexport function camelToKebab(s: string) {\n return s.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n}\n\n/**\n * Convert a style rules object to a CSS text string (skipping nested selectors).\n *\n * @param {Record<string, unknown> | object} rules\n * @returns {string}\n */\nexport function toCSSText(rules: Record<string, unknown> | object) {\n return Object.entries(rules)\n .filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== \"object\"))\n .map(([p, v]) => `${camelToKebab(p)}: ${transposeCanvasUnits(String(v))}`)\n .join(\"; \");\n}\n\n// ─── Color Schemes ────────────────────────────────────────────────────────────\n\n/**\n * Attribute on the root element (`<html>`) that forces a color scheme. Absent = auto (follow the OS\n * `prefers-color-scheme`). Values: \"light\" | \"dark\".\n *\n * @docs framework/concepts/color-schemes\n */\nexport const COLOR_SCHEME_ATTR = \"data-color-scheme\";\n\n/**\n * The localStorage key a site switcher persists the visitor's forced scheme under; read by the\n * compiler-injected pre-paint script. Values: \"light\" | \"dark\" (absent = auto).\n *\n * @docs framework/concepts/color-schemes\n */\nexport const COLOR_SCHEME_STORAGE_KEY = \"jx-color-scheme\";\n\n/**\n * The scheme a _pure_ `prefers-color-scheme` media query targets. Compound queries (any other\n * conditions attached) return null — they are not eligible for forced-scheme dual emission.\n *\n * @param {string} query\n * @returns {\"light\" | \"dark\" | null}\n * @docs framework/concepts/color-schemes\n */\nexport function pureSchemeOf(query: string): \"light\" | \"dark\" | null {\n const m = /^\\(\\s*prefers-color-scheme\\s*:\\s*(light|dark)\\s*\\)$/.exec(query.trim());\n return (m?.[1] as \"light\" | \"dark\") ?? null;\n}\n\n/**\n * Selector pair for a scheme-conditional rule: `auto` applies inside the scheme's media query only\n * while no scheme is forced; `forced` applies unconditionally when the root attribute forces the\n * scheme. Guards are wrapped in `:where()` so specificity matches the unguarded selector and source\n * order decides the cascade.\n *\n * @param {string} selector\n * @param {\"light\" | \"dark\"} scheme\n * @returns {{ auto: string; forced: string }}\n * @docs framework/concepts/color-schemes\n */\nexport function schemeSelectors(\n selector: string,\n scheme: \"light\" | \"dark\",\n): { auto: string; forced: string } {\n if (selector === \":root\" || selector === \"html\") {\n return {\n auto: `${selector}:where(:not([${COLOR_SCHEME_ATTR}]))`,\n forced: `${selector}:where([${COLOR_SCHEME_ATTR}=\"${scheme}\"])`,\n };\n }\n return {\n auto: `:where(:root:not([${COLOR_SCHEME_ATTR}])) ${selector}`,\n forced: `:where(:root[${COLOR_SCHEME_ATTR}=\"${scheme}\"]) ${selector}`,\n };\n}\n\n// ─── Custom Element Registration ──────────────────────────────────────────────\n\nlet _rootMedia: Record<string, string> = {};\nconst _elementDefs = new Map();\n\n/**\n * Seed the module-level root `$media` map used as the fallback for components that declare their\n * own `@--name` style blocks but carry no own `$media` (buildScope ~279-280). `Jx()` sets this from\n * the document during a full top-level render, but the Studio iframe canvas calls `buildScope`/\n * `renderNode` directly (never `Jx()`), so without seeding it a component's `@--md` would resolve\n * to the invalid `@media md`. Callers on the direct path MUST set it (with the merged `$media`)\n * before `buildScope`, and re-set it every render so a stale map from a previous document cannot\n * leak.\n *\n * @param {Record<string, string>} map\n */\nexport function setRootMedia(map: Record<string, string>): void {\n _rootMedia = map ?? {};\n}\n\n/**\n * Resolve and register $elements entries (depth-first).\n *\n * @param {JxDocument[\"$elements\"]} elements\n * @param {string} base\n * @returns {Promise<void>}\n */\nasync function registerElements(elements: NonNullable<JxDocument[\"$elements\"]>, base: string) {\n for (const entry of elements) {\n // Bare string: npm package side-effect import (registers custom elements)\n if (typeof entry === \"string\") {\n try {\n // Bare specifiers need a URL path for the browser; the dev server resolves\n // /node_modules/<pkg> to the package entry point via exports/module/main.\n const specifier =\n entry.startsWith(\"/\") || entry.startsWith(\".\") ? entry : `/node_modules/${entry}`;\n await import(specifier);\n } catch (error) {\n console.warn(`Jx: failed to import package \"${entry}\"`, error);\n }\n continue;\n }\n if (!isRefObj(entry)) {\n continue;\n }\n const { href } = new URL(entry.$ref, base);\n const doc = await resolve(href);\n if (!doc.tagName || !doc.tagName.includes(\"-\")) {\n continue;\n }\n if (customElements.get(doc.tagName)) {\n continue;\n }\n\n // Depth-first: register sub-dependencies first\n if (doc.$elements) {\n await registerElements(doc.$elements, href);\n }\n\n await defineElement(doc, href);\n }\n}\n\n/**\n * Inject head elements from $head declarations. Each entry is { tagName, attributes } — bare npm\n * specifiers in href/src are rewritten to /node_modules/ paths for the dev server.\n *\n * @param {import(\"@jxsuite/schema/types\").JxHeadEntry[]} entries\n * @param {string} _base - Document base URL for resolving relative paths\n */\nfunction injectHead(entries: JxHeadEntry[], _base: string) {\n for (const entry of entries) {\n if (!entry || !entry.tagName) {\n continue;\n }\n const tag = entry.tagName.toLowerCase();\n const attrs = { ...entry.attributes };\n // Resolve href/src: bare npm specifiers -> /node_modules/ path\n for (const key of [\"href\", \"src\"] as const) {\n const v = attrs[key];\n if (\n typeof v === \"string\" &&\n v &&\n !v.startsWith(\"/\") &&\n !v.startsWith(\".\") &&\n !v.startsWith(\"http\")\n ) {\n attrs[key] = `/node_modules/${v}`;\n }\n }\n\n // Deduplicate: skip if an identical element already exists\n const selector = `${tag}${attrs.href ? `[href=\"${attrs.href}\"]` : \"\"}${attrs.src ? `[src=\"${attrs.src}\"]` : \"\"}`;\n if (selector !== tag && document.head.querySelector(selector)) {\n continue;\n }\n\n const el = document.createElement(tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, String(v));\n }\n if (entry.textContent) {\n // An object is a structured data block (JSON-LD, site-architecture.md §8.5). The compiler\n // Serializes it the same way, so the interpreted page and the built page agree.\n el.textContent =\n typeof entry.textContent === \"object\"\n ? JSON.stringify(entry.textContent, null, 2)\n : entry.textContent;\n }\n document.head.append(el);\n }\n}\n\n/**\n * Register a custom element from a Jx document.\n *\n * @param {string | JxDocument} source - URL to .json file, or raw document object\n * @param {string} [base] - Base URL for resolving $src imports\n * @returns {Promise<void>}\n */\nconst _definedSources = new Set<string>();\n\nexport async function defineElement(source: string | JxDocument, baseUrl?: string) {\n let base = baseUrl;\n let doc = source;\n if (typeof source === \"string\") {\n base = new URL(source, base ?? location.href).href;\n if (_definedSources.has(base)) {\n return;\n }\n _definedSources.add(base);\n doc = await resolve(source);\n }\n base ??= location.href;\n\n const source_: JxDocument = doc as JxDocument;\n\n const { tagName } = source_;\n if (!tagName || !tagName.includes(\"-\")) {\n throw new Error(`Jx defineElement: tagName \"${tagName}\" must contain a hyphen`);\n }\n if (customElements.get(tagName)) {\n return;\n }\n\n // Register sub-dependencies first\n if (source_.$elements) {\n await registerElements(source_.$elements, base);\n }\n\n _elementDefs.set(tagName, { base, doc: source_ });\n\n const def = source_;\n const observedAttrs = def.observedAttributes ?? [];\n\n const ElementClass = class extends HTMLElement {\n _jxInitialized = false;\n _state: JxScope | null = null;\n\n static get observedAttributes() {\n return observedAttrs;\n }\n\n async connectedCallback() {\n // An element carrying `data-jx-definition-root` IS the definition being rendered by an\n // External renderer (the studio canvas editing this component's own document) — its subtree\n // Is authored DOM, not an instantiation site. Self-initializing here would wipe that tree\n // And re-render it with default state (the \"component editor shows a live instance\" bug).\n if (this.dataset.jxDefinitionRoot !== undefined) {\n return;\n }\n if (this._jxInitialized) {\n return;\n }\n this._jxInitialized = true;\n\n const state = await buildScope(def, {}, base);\n\n // Read properties from directive encoding (markdown → data-jx-props)\n const propsAttr = this.dataset.jxProps;\n if (propsAttr) {\n try {\n const props = JSON.parse(propsAttr) as Record<string, unknown>;\n for (const [key, val] of Object.entries(props)) {\n if (refusePrivateProp(key, \"data-jx-props\")) {\n continue;\n }\n if (key in (def.state ?? {})) {\n state[key] = val;\n }\n }\n } catch {}\n delete this.dataset.jxProps;\n }\n\n // Read literal `props.*` attributes (JSON-authored instances pass props this way; the\n // Compiler lifts them into $props at build, and this is the live-render mirror). String\n // Values only — HTML lowercases attribute names, so state keys must be lowercase to match.\n // Collect first: removing while iterating the live NamedNodeMap skips entries.\n const propAttrNames = this.getAttributeNames().filter(\n (name) => name.startsWith(\"props.\") && name.length > \"props.\".length,\n );\n for (const name of propAttrNames) {\n const key = name.slice(\"props.\".length);\n if (refusePrivateProp(key, \"props.* attribute\")) {\n this.removeAttribute(name);\n continue;\n }\n if (key in (def.state ?? {})) {\n state[key] = this.getAttribute(name);\n this.removeAttribute(name);\n }\n }\n\n // Merge $props set as JS properties by parent before connection\n for (const key of Object.keys(def.state ?? {})) {\n if (isPrivateStateKey(key)) {\n continue;\n }\n if (key in this && (this as Record<string, unknown>)[key] !== undefined) {\n state[key] = (this as Record<string, unknown>)[key];\n }\n }\n /*\n * Set up property getters/setters that forward into reactive state. Private entries get NO\n * accessor: the property-first interface IS the props mechanism, so defining one would leave\n * `el[\"#cache\"] = x` writing straight through everything above.\n */\n for (const key of Object.keys(def.state ?? {})) {\n if (isPrivateStateKey(key)) {\n continue;\n }\n if (!(key in HTMLElement.prototype)) {\n Object.defineProperty(this, key, {\n configurable: true,\n get: () => state[key],\n set: (v: unknown) => {\n state[key] = v;\n },\n });\n }\n }\n\n this._state = state;\n\n // Capture light DOM children (for slot distribution) before rendering\n const slottedChildren = [...this.childNodes];\n this.replaceChildren();\n\n // Custom elements default to display:inline — use block so they behave as\n // Containers (matching <div> semantics). The component's own style can\n // Override this if needed.\n if (!this.style.display) {\n this.style.display = \"block\";\n }\n\n // Render template into light DOM (once, not in effect — inner effects handle reactivity)\n applyStyle(this, def.style ?? {}, (state[\"$media\"] as Record<string, string>) ?? {}, state);\n applyAttributes(this, def.attributes ?? {}, state);\n\n const children = Array.isArray(def.children) ? def.children : [];\n for (const childDef of children) {\n this.append(renderNode(childDef, state));\n }\n\n // Slot distribution (light DOM)\n distributeSlots(this, slottedChildren);\n\n // Lifecycle: onMount\n const { onMount } = state;\n if (typeof onMount === \"function\") {\n queueMicrotask(() => (onMount as (s: JxScope) => unknown)(state));\n }\n }\n\n disconnectedCallback() {\n if (typeof this._state?.onUnmount === \"function\") {\n (this._state.onUnmount as (s: JxScope) => unknown)(this._state);\n }\n }\n\n adoptedCallback() {\n if (typeof this._state?.onAdopted === \"function\") {\n (this._state.onAdopted as (s: JxScope) => unknown)(this._state);\n }\n }\n\n attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null) {\n if (!this._state || oldVal === newVal) {\n return;\n }\n const camelKey = name.replaceAll(/-([a-z])/g, (_: string, c: string) => c.toUpperCase());\n const current = this._state[camelKey];\n if (typeof current === \"number\") {\n this._state[camelKey] = Number(newVal);\n } else if (typeof current === \"boolean\") {\n this._state[camelKey] = newVal !== null && newVal !== \"false\";\n } else {\n this._state[camelKey] = newVal;\n }\n }\n };\n\n customElements.define(tagName, ElementClass);\n}\n\n/**\n * Render a registered custom element with $props (property-first interface).\n *\n * @param {JxElement} def\n * @param {JxScope} state\n * @param {JxRenderOptions} [options]\n * @param {JxPath} [path]\n * @returns {HTMLElement}\n */\nfunction renderCustomElementWithProps(\n def: JxElement,\n state: JxScope,\n options?: JxRenderOptions,\n path?: JxPath,\n) {\n const el = document.createElement(resolveTagName(def.tagName, state));\n\n if (options?.onNodeCreated) {\n options.onNodeCreated(el, path ?? [], def, state);\n }\n\n // Set JS properties from $props (before connection)\n for (const [key, val] of Object.entries(def.$props ?? {})) {\n if (refusePrivateProp(key, \"$props\")) {\n continue;\n }\n if (isRefObj(val)) {\n const refVal = val;\n const resolved = resolveRef(refVal.$ref, state);\n (el as unknown as Record<string, unknown>)[key] = resolved;\n // Reactive forwarding: re-set the property when the source changes\n effect(() => {\n (el as unknown as Record<string, unknown>)[key] = resolveRef(refVal.$ref, state);\n });\n } else if (isTemplateString(val)) {\n effect(() => {\n (el as unknown as Record<string, unknown>)[key] = evaluateTemplate(val, state);\n });\n } else {\n (el as unknown as Record<string, unknown>)[key] = val;\n }\n }\n\n // Apply host-level style and attributes from the usage site\n applyStyle(el, def.style ?? {}, (state[\"$media\"] as Record<string, string>) ?? {}, state);\n applyAttributes(el, def.attributes ?? {}, state);\n\n // Append slotted children\n const children = Array.isArray(def.children) ? def.children : [];\n for (let i = 0; i < children.length; i++) {\n const childOpts = options && path ? { ...options, _path: [...path, \"children\", i] } : undefined;\n el.append(renderNode(children[i]!, state, childOpts));\n }\n\n return el;\n}\n\n/**\n * Light DOM slot distribution.\n *\n * @param {HTMLElement} host\n * @param {ChildNode[]} slottedChildren\n */\nfunction distributeSlots(host: HTMLElement, slottedChildren: ChildNode[]) {\n if (slottedChildren.length === 0) {\n return;\n }\n\n const slots = host.querySelectorAll(\"slot\");\n if (slots.length === 0) {\n return;\n }\n\n const named = new Map<string | null, ChildNode[]>();\n const unnamed: ChildNode[] = [];\n\n for (const child of slottedChildren) {\n if (child.nodeType === Node.ELEMENT_NODE && (child as Element).getAttribute(\"slot\")) {\n const name = (child as Element).getAttribute(\"slot\");\n if (!named.has(name)) {\n named.set(name, []);\n }\n (named.get(name) as ChildNode[]).push(child);\n } else {\n unnamed.push(child);\n }\n }\n\n for (const slot of slots) {\n const name = slot.getAttribute(\"name\");\n const matches = name ? (named.get(name) ?? []) : unnamed;\n if (matches.length > 0) {\n slot.replaceChildren();\n for (const child of matches) {\n slot.append(child);\n }\n }\n }\n}\n",
29
+ "/// <reference lib=\"dom\" />\n/**\n * Parent-realm live component preview — registers a project component's custom element and\n * instantiates it in the editor document. Used by the browse grid and the components-palette DnD\n * cards. (The stylebook renders components inside the canvas iframe instead, via `$elements` refs\n * in its generated specimen doc.)\n */\n\nimport { defineElement, setSkipServerFunctions } from \"@jxsuite/runtime\";\nimport { projectState } from \"../store\";\nimport type { ComponentEntry } from \"../files/components\";\n\n/**\n * Render a live component preview by registering its custom element and instantiating it.\n *\n * @param {ComponentEntry} comp\n * @returns {Promise<HTMLElement>}\n */\nexport async function renderComponentPreview(comp: ComponentEntry) {\n setSkipServerFunctions(true);\n try {\n if (comp.source === \"npm\") {\n if (!customElements.get(comp.tagName)) {\n return _componentFallback(comp.tagName);\n }\n } else {\n if (comp.path && !comp.path.endsWith(\".json\")) {\n // Format-class component sources (e.g. markdown) can't be imported as modules\n return _componentFallback(comp.tagName);\n }\n const root = projectState?.projectRoot;\n const url = `${location.origin}/${root ? `${root}/` : \"\"}${comp.path}`;\n await defineElement(url);\n }\n const el = document.createElement(comp.tagName);\n for (const p of comp.props || []) {\n if (p.default !== undefined && p.default !== \"false\" && p.default !== \"''\") {\n const val = String(p.default).replaceAll(/^'|'$/g, \"\");\n el.setAttribute(p.name, val);\n }\n }\n return el;\n } catch (error) {\n console.warn(\"Component preview failed:\", comp.tagName, error);\n return _componentFallback(comp.tagName);\n }\n}\n\n/** @param {string} tagName */\nfunction _componentFallback(tagName: string) {\n const fallback = document.createElement(\"div\");\n fallback.style.cssText =\n \"padding:12px;border:1px dashed var(--border);border-radius:var(--radius);color:var(--fg-dim)\";\n fallback.textContent = `<${tagName}>`;\n return fallback;\n}\n",
30
+ "/// <reference lib=\"dom\" />\n/**\n * DnD registration functions — extracted from studio.js (Phase 4). Registers drag-and-drop behavior\n * on layer rows, component cards, and element cards.\n */\n\nimport {\n draggable,\n dropTargetForElements,\n monitorForElements,\n} from \"@atlaskit/pragmatic-drag-and-drop/element/adapter\";\nimport { combine } from \"@atlaskit/pragmatic-drag-and-drop/combine\";\nimport { displayTagName } from \"@jxsuite/schema/guards\";\nimport { disableNativeDragPreview } from \"@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview\";\nimport {\n attachInstruction,\n extractInstruction,\n} from \"@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item\";\n\nimport {\n childIndex,\n childList,\n getNodeAtPath,\n isAncestor,\n leftPanel,\n parentElementPath,\n renderOnly,\n} from \"../store\";\nimport { mutateInsertNode, mutateMoveNode, transact, transactDoc } from \"../tabs/transact\";\nimport { primarySelection } from \"../tabs/selection\";\nimport { activeTab } from \"../workspace/workspace\";\nimport { view } from \"../view\";\nimport { buildComponentInstance, componentRegistry } from \"../files/components\";\nimport { enableElement } from \"../files/elements\";\nimport type { ElementsEntry } from \"../files/elements\";\nimport { renderComponentPreview } from \"./component-preview\";\nimport { defaultDef, unsafeTags } from \"./shared\";\nimport { elementAtPoint } from \"../utils/geometry\";\nimport type { JxPath } from \"../state\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxElement, JxMutableNode } from \"@jxsuite/schema/types\";\nimport type { ComponentEntry } from \"../files/components.js\";\n\ninterface DragCanDragArgs {\n element: HTMLElement;\n input: { clientX: number; clientY: number };\n}\n\n/** The `onGenerateDragPreview` argument subset we forward to {@link disableNativeDragPreview}. */\ninterface DragPreviewArgs {\n nativeSetDragImage: ((image: Element, x: number, y: number) => void) | null;\n}\n\ninterface DragDropSourceArgs {\n source: { data: Record<string, unknown>; element: HTMLElement };\n}\n\ninterface DragSelfArgs {\n self: { data: Record<string, unknown> };\n}\n\ninterface DragMonitorDropArgs {\n source: { data: Record<string, unknown>; element: HTMLElement };\n location: { current: { dropTargets: { data: Record<string, unknown> }[] } };\n}\n\n/** Register DnD on layer rows — called from left-panel.js after render */\nexport function registerLayersDnD() {\n requestAnimationFrame(() => {\n const container = leftPanel?.querySelector(\".layers-container\") as HTMLElement | null;\n if (!container) {\n return;\n }\n\n for (const row of container.querySelectorAll(\"[data-dnd-row]\") as NodeListOf<HTMLElement>) {\n const rowPath = (row.dataset.path as string)\n .split(\"/\")\n .map((s: string) => (/^\\d+$/.test(s) ? Math.trunc(Number(s)) : s)) as JxPath;\n const rowDepth = Math.trunc(Number(row.dataset.dndDepth as string)) || 0;\n const isVoid = Object.hasOwn(row.dataset, \"dndVoid\");\n const isExpanded = Object.hasOwn(row.dataset, \"dndExpanded\");\n\n const cleanup = combine(\n draggable({\n canDrag({ element: _el, input }: DragCanDragArgs) {\n const target = elementAtPoint(input.clientX, input.clientY) as HTMLElement;\n if (target?.closest(\".layer-actions\")) {\n return false;\n }\n return true;\n },\n element: row,\n getInitialData() {\n return { path: rowPath, type: \"tree-node\" };\n },\n onGenerateDragPreview({ nativeSetDragImage }: DragPreviewArgs) {\n // Suppress the browser's native drag image — the cross-frame ghost (Phase 4c) is the\n // Only drag affordance, so a duplicate native preview would double up.\n disableNativeDragPreview({ nativeSetDragImage });\n },\n onDragStart() {\n row.classList.add(\"dragging\");\n view.layerDragSourceHeight = row.offsetHeight;\n if (isExpanded) {\n hideDescendantRows(row, container);\n }\n },\n onDrop() {\n row.classList.remove(\"dragging\");\n if (isExpanded) {\n renderOnly(\"leftPanel\");\n }\n },\n }),\n dropTargetForElements({\n element: row,\n canDrop({ source }: DragDropSourceArgs) {\n const srcPath = source.data.path as JxPath | undefined;\n if (srcPath && isAncestor(srcPath, rowPath)) {\n return false;\n }\n return true;\n },\n getData({\n input,\n element,\n }: {\n input: Parameters<typeof attachInstruction>[1][\"input\"];\n element: Element;\n }) {\n return attachInstruction(\n { path: rowPath },\n {\n block: isVoid ? [\"make-child\"] : [],\n currentLevel: rowDepth,\n element,\n indentPerLevel: 16,\n input,\n mode: isExpanded ? \"expanded\" : \"standard\",\n },\n ) as Record<string | symbol, unknown>;\n },\n onDragEnter({ self }: DragSelfArgs) {\n showLayerDropGap(row, self.data, container);\n },\n onDrag({ self }: DragSelfArgs) {\n showLayerDropGap(row, self.data, container);\n },\n // No onDragLeave clear — the gap persists while the pointer crosses dead space\n // Between rows; the monitor clears it when the drag moves to a non-tree target.\n onDrop() {\n clearLayerDropGap(container);\n },\n }),\n );\n view.dndCleanups.push(cleanup);\n }\n\n // Global monitor\n const monitorCleanup = monitorForElements({\n onDrop({ source, location }: DragMonitorDropArgs) {\n clearLayerDropGap(container);\n const [target] = location.current.dropTargets;\n if (!target) {\n return;\n }\n const instruction = extractInstruction(target.data);\n if (!instruction || instruction.type === \"instruction-blocked\") {\n return;\n }\n const srcData = source.data;\n const targetPath = target.data.path as JxPath;\n\n // If the source had children, persist collapse at the new location\n const srcRow = srcData.type === \"tree-node\" && source.element;\n const wasExpanded = srcRow && Object.hasOwn(srcRow.dataset, \"dndExpanded\");\n\n // Parent-originated layer drops legitimately target the active tab.\n applyDropInstruction(activeTab.value, instruction, srcData, targetPath);\n\n if (wasExpanded) {\n const tab = activeTab.value;\n const newPath = primarySelection(tab?.session.selection);\n if (newPath) {\n view._layersCollapsed ||= new Set();\n const collapsed = view._layersCollapsed;\n collapsed.add(newPath.join(\"/\"));\n }\n }\n },\n onDropTargetChange({ location }: DragMonitorDropArgs) {\n // Clear the layer gap when the drag moves onto a non-tree target (e.g. a canvas\n // Element). When there is no target at all, keep the gap so it persists.\n const [inner] = location.current.dropTargets;\n if (inner && !extractInstruction(inner.data)) {\n clearLayerDropGap(container);\n }\n },\n });\n view.dndCleanups.push(monitorCleanup);\n });\n}\n\n/** Register DnD on component rows — called from renderLeftPanel when tab=components */\nexport function registerComponentsDnD() {\n requestAnimationFrame(() => {\n const container = leftPanel?.querySelector(\".components-section\") as HTMLElement | null;\n if (!container) {\n return;\n }\n\n for (const row of container.querySelectorAll(\n \"[data-component-tag]\",\n ) as NodeListOf<HTMLElement>) {\n const tagName = row.dataset.componentTag;\n if (!tagName) {\n continue;\n }\n const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tagName);\n if (!comp) {\n continue;\n }\n\n // Fill preview with live rendered component\n const preview = row.querySelector(\".element-card-preview\");\n if (preview && !preview.querySelector(tagName)) {\n void renderComponentPreview(comp).then((el: HTMLElement) => {\n preview.textContent = \"\";\n preview.append(el);\n });\n }\n\n const instanceDef = buildComponentInstance(comp);\n const cleanup = draggable({\n element: row,\n getInitialData() {\n return { fragment: structuredClone(instanceDef), type: \"block\" };\n },\n onGenerateDragPreview({ nativeSetDragImage }: DragPreviewArgs) {\n disableNativeDragPreview({ nativeSetDragImage });\n },\n });\n view.dndCleanups.push(cleanup);\n }\n });\n}\n\n/** Register DnD on element (HTML block) rows */\nexport function registerElementsDnD() {\n requestAnimationFrame(() => {\n const container = leftPanel?.querySelector(\".panel-body\") as HTMLElement | null;\n if (!container) {\n return;\n }\n for (const row of container.querySelectorAll(\"[data-block-tag]\") as NodeListOf<HTMLElement>) {\n const tag = row.dataset.blockTag as string;\n const preview = row.querySelector(\".element-card-preview\");\n if (preview && !preview.firstChild) {\n const el = document.createElement(unsafeTags.has(tag) ? \"span\" : tag);\n el.textContent = tag;\n preview.append(el);\n }\n const def = defaultDef(tag);\n const cleanup = draggable({\n element: row,\n getInitialData() {\n return { fragment: structuredClone(def), type: \"block\" };\n },\n onGenerateDragPreview({ nativeSetDragImage }: DragPreviewArgs) {\n disableNativeDragPreview({ nativeSetDragImage });\n },\n });\n view.dndCleanups.push(cleanup);\n }\n });\n}\n\n/**\n * Hide descendant rows of the dragged item so it appears collapsed during drag.\n *\n * @param {HTMLElement} parentRow\n * @param {HTMLElement} container\n */\nfunction hideDescendantRows(parentRow: HTMLElement, container: HTMLElement) {\n const prefix = `${parentRow.dataset.path}/`;\n const rows = container.querySelectorAll(\".layers-tree .layer-row\");\n for (const r of rows) {\n if ((r as HTMLElement).dataset.path?.startsWith(prefix)) {\n (r as HTMLElement).style.display = \"none\";\n }\n }\n}\n\n/**\n * @param {HTMLElement} rowEl\n * @param {Record<string, unknown>} data\n * @param {HTMLElement} container\n */\nexport function showLayerDropGap(\n rowEl: HTMLElement,\n data: Record<string, unknown>,\n container: HTMLElement,\n) {\n const instruction = extractInstruction(data);\n\n // Clear previous drop-target highlight\n if (view._currentDropTargetRow && view._currentDropTargetRow !== rowEl) {\n view._currentDropTargetRow.classList.remove(\"drop-target\");\n }\n\n if (!instruction || instruction.type === \"instruction-blocked\") {\n clearLayerDropGap(container);\n return;\n }\n\n if (instruction.type === \"make-child\") {\n clearLayerDropGap(container);\n rowEl.classList.add(\"drop-target\");\n view._currentDropTargetRow = rowEl;\n return;\n }\n\n rowEl.classList.remove(\"drop-target\");\n view._currentDropTargetRow = rowEl;\n\n // Shift rows to create gap\n const rows = [...container.querySelectorAll(\".layers-tree .layer-row\")];\n const targetIdx = rows.indexOf(rowEl);\n const gap = view.layerDragSourceHeight;\n\n for (let i = 0; i < rows.length; i++) {\n if ((rows[i] as HTMLElement).classList.contains(\"dragging\")) {\n continue;\n }\n if (instruction.type === \"reorder-above\") {\n (rows[i] as HTMLElement).style.transform = i >= targetIdx ? `translateY(${gap}px)` : \"\";\n } else {\n (rows[i] as HTMLElement).style.transform = i > targetIdx ? `translateY(${gap}px)` : \"\";\n }\n }\n}\n\n/** @param {HTMLElement} container */\nexport function clearLayerDropGap(container: HTMLElement) {\n if (view._currentDropTargetRow) {\n view._currentDropTargetRow.classList.remove(\"drop-target\");\n view._currentDropTargetRow = null;\n }\n const rows = container.querySelectorAll(\".layers-tree .layer-row\");\n for (const r of rows) {\n (r as HTMLElement).style.transform = \"\";\n // Also clear `display:none` left by hideDescendantRows. The `.layer-row` div has no `style`\n // Lit binding, so an imperative style set during the drag survives the post-drop re-render on\n // Whichever row keeps that key — and a move is exactly the edit that hands a key to a different\n // Node. (The rows ARE keyed, by `pathKey`; the earlier form of this note said they were not,\n // Which made the wrong thing sound load-bearing. What is load-bearing is the missing binding.)\n (r as HTMLElement).style.display = \"\";\n }\n}\n\n/**\n * Apply a DnD instruction to `tab`'s document. `tab` is the tab whose canvas the drop resolved in\n * (host-routed for iframe drops — never the active tab at message time, which may have changed\n * while the dropResult was in flight); a null tab is a no-op.\n *\n * @param {Tab | null} tab\n * @param {{ type: string }} instruction\n * @param {Record<string, unknown>} srcData\n * @param {JxPath} targetPath\n */\nexport function applyDropInstruction(\n tab: Tab | null,\n instruction: { type: string },\n srcData: Record<string, unknown>,\n targetPath: JxPath,\n) {\n if (!tab) {\n return;\n }\n const doc = tab.doc.document as JxMutableNode;\n if (srcData.type === \"tree-node\") {\n const fromPath = srcData.path as JxPath;\n const targetParent = parentElementPath(targetPath) as JxPath;\n const targetIdx = childIndex(targetPath) as number;\n // Reordering requires a parent and a numeric index; root-level paths can't be\n // Reordered around.\n if (instruction.type !== \"make-child\" && (!targetParent || typeof targetIdx !== \"number\")) {\n return;\n }\n\n switch (instruction.type) {\n case \"reorder-above\": {\n transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetParent, targetIdx));\n break;\n }\n case \"reorder-below\": {\n transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetParent, targetIdx + 1));\n break;\n }\n case \"make-child\": {\n const target = getNodeAtPath(doc, targetPath);\n const len = childList(target).length;\n transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetPath, len));\n break;\n }\n default: {\n break;\n }\n }\n } else if (srcData.type === \"block\") {\n const targetParent = parentElementPath(targetPath) as JxPath;\n const targetIdx = childIndex(targetPath) as number;\n if (instruction.type !== \"make-child\" && (!targetParent || typeof targetIdx !== \"number\")) {\n return;\n }\n\n switch (instruction.type) {\n case \"reorder-above\": {\n transactDoc(tab, (t) =>\n mutateInsertNode(\n t,\n targetParent,\n targetIdx,\n structuredClone(srcData.fragment as JxMutableNode),\n ),\n );\n break;\n }\n case \"reorder-below\": {\n transactDoc(tab, (t) =>\n mutateInsertNode(\n t,\n targetParent,\n targetIdx + 1,\n structuredClone(srcData.fragment as JxMutableNode),\n ),\n );\n break;\n }\n case \"make-child\": {\n const target = getNodeAtPath(doc, targetPath);\n const len = childList(target).length;\n transactDoc(tab, (t) =>\n mutateInsertNode(t, targetPath, len, structuredClone(srcData.fragment as JxMutableNode)),\n );\n break;\n }\n default: {\n break;\n }\n }\n\n /* Auto-import to `$elements` if the dropped block is a custom component.\n Through the ONE service (`files/elements.ts`), which is the whole point of it: this call site\n had its own duplicate rule and matched a local component by `ref.endsWith(basename)`, so\n dropping `./components/card.json` into a page that already imported `./vendor/card.json`\n counted as already imported and produced an element the page could not resolve. */\n const fragment = srcData.fragment as JxMutableNode | undefined;\n const tag = fragment?.tagName;\n if (displayTagName(tag).includes(\"-\")) {\n const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tag);\n const before = (tab.doc.document?.$elements ?? []) as ElementsEntry[];\n const after = comp ? enableElement(before, comp, tab.documentPath ?? null) : before;\n // Only when the list actually GREW. A component the registry cannot name — an npm entry with\n // No package, a local one with no path — returns the list unchanged, and writing that back\n // Would put an empty `$elements: []` on a document that had none.\n if (after.length !== before.length) {\n transact(tab, (d: JxMutableNode) => {\n d.$elements = after as (string | JxElement)[];\n });\n }\n }\n }\n}\n",
31
+ "/// <reference lib=\"dom\" />\n/**\n * IframeChannel — the typed message boundary between the editor (parent) and the canvas iframe.\n *\n * Per the migration's cross-origin bridge decision, the parent never touches the iframe's\n * `contentDocument`; everything (render commands, patches, geometry, selection, hit-tests) crosses\n * as serializable messages through this one interface. Phases 1+ instantiate it with concrete\n * message unions (`ParentToIframe`/`IframeToParent`); this module owns only the transport contract\n * plus an in-memory `fakeChannelPair` so cross-frame logic is unit-testable without a live iframe.\n */\n\n/**\n * A typed, bidirectional message channel. `TOut` is what this side sends; `TIn` is what it\n * receives. Implementations: a real `postMessage` channel over an `<iframe>` (added with the iframe\n * host), and {@link fakeChannelPair} for tests.\n */\nexport interface IframeChannel<TOut, TIn> {\n /** Send a message to the other side. */\n post: (message: TOut) => void;\n /** Subscribe to messages from the other side. Returns an unsubscribe function. */\n onMessage: (handler: (message: TIn) => void) => () => void;\n /** Detach all handlers and release the transport. */\n dispose: () => void;\n}\n\n/** Envelope key that tags every cross-frame message so foreign `message` events are ignored. */\nconst ENVELOPE = \"jx:canvas\";\n\ninterface PostMessageTarget {\n postMessage: (message: unknown, targetOrigin: string) => void;\n}\n\ninterface MessageSource {\n addEventListener: (type: \"message\", listener: (event: MessageEvent) => void) => void;\n removeEventListener: (type: \"message\", listener: (event: MessageEvent) => void) => void;\n}\n\n/**\n * A real `IframeChannel` over `window.postMessage`. Outbound messages are wrapped in an envelope\n * tagged with a shared `token`; inbound messages are dropped unless their `event.origin` matches\n * `acceptOrigin` (pass `\"*\"` to skip the origin check) AND they carry the same token. This is the\n * origin + secret-token authentication that keeps other local pages from driving the canvas.\n *\n * Parent side: `target` = the iframe's `contentWindow`, `source` = `window`, origins = the iframe\n * origin. Iframe side: `target` = `window.parent`, `source` = `window`, origins = the editor\n * origin.\n */\nexport function postMessageChannel<TOut, TIn>(opts: {\n target: PostMessageTarget;\n source: MessageSource;\n targetOrigin: string;\n acceptOrigin: string;\n token: string;\n}): IframeChannel<TOut, TIn> {\n const { target, source, targetOrigin, acceptOrigin, token } = opts;\n const handlers = new Set<(message: TIn) => void>();\n\n const listener = (event: MessageEvent) => {\n if (acceptOrigin !== \"*\" && event.origin !== acceptOrigin) {\n return;\n }\n const data = event.data as { [ENVELOPE]?: string; payload?: TIn } | null;\n if (!data || typeof data !== \"object\" || data[ENVELOPE] !== token) {\n return;\n }\n for (const handler of handlers) {\n handler(data.payload as TIn);\n }\n };\n source.addEventListener(\"message\", listener);\n\n return {\n dispose() {\n handlers.clear();\n source.removeEventListener(\"message\", listener);\n },\n onMessage(handler) {\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n post(message) {\n target.postMessage({ [ENVELOPE]: token, payload: message }, targetOrigin);\n },\n };\n}\n\n/**\n * Two in-memory channels wired to each other for tests. A message `parent.post(x)` is delivered to\n * the `iframe` side's handlers (and vice versa) only when `flush()` is called — so tests drive the\n * inherently-async postMessage ordering deterministically. Messages posted _during_ a flush are\n * queued for the next flush, never delivered re-entrantly.\n */\nexport function fakeChannelPair<ParentOut, IframeOut>(): {\n parent: IframeChannel<ParentOut, IframeOut>;\n iframe: IframeChannel<IframeOut, ParentOut>;\n flush: () => void;\n /** Number of messages waiting to be delivered (both directions). */\n pending: () => number;\n} {\n let toIframe: ParentOut[] = [];\n let toParent: IframeOut[] = [];\n const iframeHandlers = new Set<(m: ParentOut) => void>();\n const parentHandlers = new Set<(m: IframeOut) => void>();\n\n const parent: IframeChannel<ParentOut, IframeOut> = {\n dispose() {\n parentHandlers.clear();\n },\n onMessage(handler) {\n parentHandlers.add(handler);\n return () => parentHandlers.delete(handler);\n },\n post(message) {\n toIframe.push(message);\n },\n };\n\n const iframe: IframeChannel<IframeOut, ParentOut> = {\n dispose() {\n iframeHandlers.clear();\n },\n onMessage(handler) {\n iframeHandlers.add(handler);\n return () => iframeHandlers.delete(handler);\n },\n post(message) {\n toParent.push(message);\n },\n };\n\n function flush() {\n const forIframe = toIframe;\n const forParent = toParent;\n toIframe = [];\n toParent = [];\n for (const message of forIframe) {\n for (const handler of iframeHandlers) {\n handler(message);\n }\n }\n for (const message of forParent) {\n for (const handler of parentHandlers) {\n handler(message);\n }\n }\n }\n\n return {\n flush,\n iframe,\n parent,\n pending: () => toIframe.length + toParent.length,\n };\n}\n",
32
+ "/// <reference lib=\"dom\" />\n/**\n * Canvas origin derivation. The canvas iframe may load same-origin (dev server / chromium /\n * electrobun gate-off, where the platform canvasUrl is a relative path) or cross-origin (electrobun\n * loopback, where canvasUrl is an absolute http://127.0.0.1:<port> URL).\n *\n * CanvasBaseOrigin() returns the origin the canvas document lives on, so callers that build\n * absolute asset/doc URLs target the right server. For a relative canvasUrl this resolves to\n * location.origin — IDENTITY for the same-origin paths, so dev/chromium/electrobun-gate-off are\n * byte-identical to before.\n */\n\nimport { getPlatform, hasPlatform } from \"../platform\";\n\n/**\n * The origin serving the canvas document. When the platform registers an absolute canvasUrl\n * (electrobun loopback), this is that URL's origin; otherwise it falls back to the parent's own\n * origin (a relative canvasUrl resolves against location.href to location.origin).\n */\nexport function canvasBaseOrigin(): string {\n const canvasUrl = hasPlatform() ? getPlatform().canvasUrl : undefined;\n if (canvasUrl) {\n return new URL(canvasUrl, location.href).origin;\n }\n return location.origin;\n}\n\n/**\n * Build an absolute loopback-origin src for a PROJECT asset path referenced by a PARENT-realm\n * (shell) preview <img>. On the views:// shell a relative \"/images/foo.png\" resolves to\n * views://studio/images/foo.png, which the browser fetches immediately on paint — a stray request\n * the desktop MutationObserver only rewrites asynchronously. Rendering the src loopback-absolute up\n * front eliminates that race for direct-parent <img> sites.\n *\n * Guarded: this ONLY rewrites when a real cross-origin http(s) loopback is registered (electrobun\n * loopback, canvasUrl set to an absolute http URL) whose origin differs from location.origin.\n * Otherwise — dev server, chromium, electrobun gate-off, and the pre-activate window — it returns\n * the ORIGINAL relative path unchanged, keeping those cases byte-identical (an absolute\n * ${location.origin}/... on the shell would just reintroduce views://... — the exact bug).\n *\n * Only for PROJECT asset srcs; NEVER call it for shell-packaged views:// assets (sp-icons, bundled\n * chrome). Already-absolute inputs (data:/blob:/http/views://) are returned untouched, so it is\n * safe for user-typed media values too.\n *\n * @param {string} path — a project asset path (relative, e.g. \"/public/logo.png\" or \"logo.png\") or\n * an already-absolute URL.\n * @returns {string} The loopback-absolute src when a cross-origin loopback is active, else `path`.\n */\nexport function loopbackAssetSrc(path: string): string {\n if (\n path.startsWith(\"data:\") ||\n path.startsWith(\"blob:\") ||\n path.startsWith(\"http\") ||\n path.startsWith(\"views://\")\n ) {\n return path;\n }\n const origin = canvasBaseOrigin();\n // Only rewrite when a real cross-origin http(s) loopback is registered. When canvasBaseOrigin()\n // Yields location.origin (the views:// shell / dev / chromium / gate-off) an absolute rewrite\n // Would produce views://... on the shell, so fall back to the relative path unchanged.\n if ((origin.startsWith(\"http:\") || origin.startsWith(\"https:\")) && origin !== location.origin) {\n return `${origin}/${path.replace(/^\\.?\\//, \"\")}`;\n }\n return path;\n}\n",
33
+ "/**\n * Where a Preview link goes.\n *\n * Preview keeps anchors live (editable modes de-link them onto `data-jx-href`), so a click would\n * navigate the canvas iframe and destroy the render along with the editing session. The iframe\n * reports the intent instead and the shell opens the target for real — see `specs/studio.md` §4.2.\n *\n * A separate module from the canvas host so an embedder can override the destination without\n * importing the host's internals: the desktop app routes it through the OS so the page opens in the\n * user's own browser rather than a webview with no address bar, history or devtools.\n */\n\n/** Handles a fully-resolved absolute URL. */\nexport type PreviewNavigateHandler = (url: string) => void;\n\nlet handler: PreviewNavigateHandler | null = null;\n\n/** Override where preview links open. Pass null to restore the default (a new browser tab). */\nexport function setPreviewNavigateHandler(next: PreviewNavigateHandler | null): void {\n handler = next;\n}\n\n/** The registered override, or null when the default applies. */\nexport function getPreviewNavigateHandler(): PreviewNavigateHandler | null {\n return handler;\n}\n",
34
+ "/// <reference lib=\"dom\" />\n/**\n * Edit-mode display transforms — extracted from studio.js (Phase 4i). Pure stateless functions that\n * convert document trees for visual editing (template expressions, $map, $switch, empty\n * placeholders).\n */\n\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\nimport { displayTagName } from \"@jxsuite/schema/guards\";\n\nconst mediaTags = new Set([\"img\", \"video\", \"source\", \"iframe\", \"audio\"]);\nconst TRANSPARENT_PX =\n \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\";\n// A neutral, visible gray placeholder for image-like bindings in edit mode (e.g. a component `image`\n// Prop bound to ${...}). The component renders <img src={prop}> internally, so a transparent pixel\n// Would collapse to nothing — a gray SVG box reads as an intentional placeholder instead.\nconst PLACEHOLDER_IMG =\n \"data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='32'%20height='32'%3E%3Crect%20width='32'%20height='32'%20fill='%23d0d0d0'/%3E%3C/svg%3E\";\n\n// Prop/attribute names that feed an <img>/background, so a ${...} binding would otherwise render a\n// Broken image in edit mode. Matched by exact name or common camelCase suffix (featuredImage, heroBg).\nconst IMAGE_KEY_RE =\n /(src|poster|image|bg|background|icon|logo|photo|avatar|thumbnail|cover|banner)$/i;\nfunction isImageUrlKey(key: string): boolean {\n return IMAGE_KEY_RE.test(key);\n}\n\nconst textTags = new Set([\n \"p\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"blockquote\",\n \"li\",\n \"dt\",\n \"dd\",\n \"th\",\n \"td\",\n \"span\",\n \"strong\",\n \"em\",\n \"small\",\n \"mark\",\n \"code\",\n \"abbr\",\n \"q\",\n \"sub\",\n \"sup\",\n \"time\",\n \"a\",\n \"button\",\n \"label\",\n \"legend\",\n \"caption\",\n \"summary\",\n \"pre\",\n \"option\",\n]);\n\nconst containerTags = new Set([\n \"div\",\n \"section\",\n \"article\",\n \"aside\",\n \"header\",\n \"footer\",\n \"main\",\n \"nav\",\n \"figure\",\n \"figcaption\",\n \"details\",\n \"fieldset\",\n \"form\",\n \"ul\",\n \"ol\",\n \"dl\",\n \"table\",\n]);\n\n/** All placeholder classes prepareForEditMode may add to an empty element. */\nexport const EMPTY_PLACEHOLDER_CLASSES = [\n \"empty-text-placeholder\",\n \"empty-container-placeholder\",\n] as const;\n\n/**\n * The empty-placeholder class prepareForEditMode would add for this node, or null. Used by the\n * canvas patcher to keep placeholder classes in sync when patching text without a full render.\n *\n * @param {JxMutableNode} node\n */\nexport function computeEmptyPlaceholderClass(node: JxMutableNode): string | null {\n if (!node.tagName || node.textContent || node.innerHTML) {\n return null;\n }\n // Layout-originated nodes ($__layout, set by markLayoutNodes) are read-only in page context;\n // Edit affordances like \"Click here to add text\" don't apply to them.\n if (node.$__layout) {\n return null;\n }\n if (Array.isArray(node.children) && node.children.length > 0) {\n return null;\n }\n if (textTags.has(displayTagName(node.tagName))) {\n return \"empty-text-placeholder\";\n }\n if (containerTags.has(displayTagName(node.tagName))) {\n return \"empty-container-placeholder\";\n }\n return null;\n}\n\n/**\n * Convert a template string to a displayable expression for edit mode. Replaces ${expr} with ❮ expr\n * ❯ so the runtime renders it as literal text.\n *\n * @param {string} str\n */\nexport function templateToEditDisplay(str: string) {\n return str.replaceAll(/\\$\\{([^}]+)\\}/g, \"\\u276A $1 \\u276B\");\n}\n\n/**\n * Reverse templateToEditDisplay: walk all text nodes in `el` and replace ❪ expr ❫ back to ${expr}\n * so the user edits raw template syntax.\n *\n * @param {HTMLElement} el\n */\nexport function restoreTemplateExpressions(el: HTMLElement) {\n const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);\n while (walker.nextNode()) {\n const node = walker.currentNode as Text;\n if (node.data.includes(\"\\u276A\")) {\n node.data = node.data.replaceAll(/\\u276A\\s*(.*?)\\s*\\u276B/g, \"${$1}\");\n }\n }\n}\n\n/**\n * Build the edit-mode visual for a mapped array: a `<div class=\"repeater-perimeter\">` wrapping a\n * single prepared instance of the map template. Always one element (an empty perimeter when the\n * template is missing) so the array keeps a 1:1 DOM node at its sibling index. The perimeter is an\n * edit-only device — it is never compiled or rendered in preview.\n *\n * @param {JxMutableNode} arrayObj\n * @returns {Record<string, unknown>}\n */\nfunction arrayToPerimeter(arrayObj: JxMutableNode): Record<string, unknown> {\n const template = arrayObj.map;\n return {\n children:\n template && typeof template === \"object\"\n ? [prepareForEditMode(template as JxMutableNode)]\n : [],\n className: \"repeater-perimeter\",\n tagName: \"div\",\n };\n}\n\n/**\n * Prepare a document for edit-mode rendering. Replaces template strings with readable literal text,\n * $prototype:Array with placeholders, and $ref bindings with display labels. Preserves state so the\n * runtime can still initialise scope.\n *\n * @param {JxMutableNode} node\n * @returns {JxMutableNode}\n */\nexport function prepareForEditMode(node: JxMutableNode): JxMutableNode {\n if (!node || typeof node !== \"object\") {\n return node;\n }\n if (Array.isArray(node)) {\n // Arrays of nodes round-trip element-wise; the array itself is not a node.\n return (node as JxMutableNode[]).map((n) => prepareForEditMode(n)) as unknown as JxMutableNode;\n }\n\n // A mapped-array node itself → its edit-mode perimeter (e.g. when the patcher re-renders an\n // Array node directly). Members inside a children array funnel here via the children branch.\n if ((node as Record<string, unknown>).$prototype === \"Array\") {\n return arrayToPerimeter(node) as unknown as JxMutableNode;\n }\n\n const /** @type {Record<string, unknown>} */ obj = node as Record<string, unknown>;\n\n const out: Record<string, unknown> = {};\n let needsMediaPlaceholder = false;\n const isMediaElement = mediaTags.has((obj.tagName as string) || \"\");\n\n // Check if this media element lacks a resolvable src (top-level or in attributes)\n if (isMediaElement) {\n const attrs = obj.attributes as Record<string, unknown> | undefined;\n const topSrc = obj.src;\n const attrSrc = attrs?.src;\n const topPoster = obj.poster;\n const attrPoster = attrs?.poster;\n const hasSrc = (topSrc && topSrc !== \"\") || (attrSrc && attrSrc !== \"\");\n const hasPoster = (topPoster && topPoster !== \"\") || (attrPoster && attrPoster !== \"\");\n if (!hasSrc && !hasPoster) {\n needsMediaPlaceholder = true;\n }\n }\n\n for (const [k, v] of Object.entries(obj)) {\n if (k === \"state\" || k === \"$media\" || k === \"$elements\") {\n out[k] = v; // Preserve as-is for runtime resolution\n } else if (k === \"$props\" && v && typeof v === \"object\") {\n // Process $props values: convert template strings to display format\n const propsOut: Record<string, unknown> = {};\n for (const [pk, pv] of Object.entries(v)) {\n if (typeof pv === \"string\" && pv.includes(\"${\")) {\n // Image-like prop → neutral placeholder (the component renders it as an <img src>); link\n // Targets → inert \"\"; everything else → the readable ❪ expr ❫ binding text.\n if (isImageUrlKey(pk)) {\n propsOut[pk] = PLACEHOLDER_IMG;\n } else if (pk === \"href\" || pk === \"action\") {\n propsOut[pk] = \"\";\n } else {\n propsOut[pk] = templateToEditDisplay(pv);\n }\n } else if (pv && typeof pv === \"object\" && (pv as Record<string, unknown>).$ref) {\n const ref = (pv as Record<string, unknown>).$ref as string;\n const label = ref.startsWith(\"#/state/\") ? ref.slice(8) : ref;\n propsOut[pk] = `{${label}}`;\n } else {\n propsOut[pk] = pv;\n }\n }\n out[k] = propsOut;\n } else if (k === \"children\") {\n if (Array.isArray(v)) {\n // Each member recurses; array pseudo-elements become a single repeater-perimeter element\n // (via the top-level array case) so they stay a 1:1 DOM node among their siblings.\n out.children = v.map((c) => prepareForEditMode(c as JxMutableNode));\n } else if (\n v &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).$prototype === \"Array\"\n ) {\n // Legacy whole-children repeater → a single perimeter as the sole child.\n out.children = [prepareForEditMode(v as JxMutableNode)];\n } else {\n out.children = prepareForEditMode(v as JxMutableNode);\n }\n } else if (k === \"cases\" && obj.$switch && v && typeof v === \"object\") {\n // Replace $switch cases with a placeholder showing the first case or a label\n const caseKeys = Object.keys(v);\n if (caseKeys.length > 0) {\n const firstCase = (v as Record<string, unknown>)[caseKeys[0]!];\n out.children =\n firstCase && typeof firstCase === \"object\" && !(firstCase as Record<string, unknown>).$ref\n ? [prepareForEditMode(firstCase as JxMutableNode)]\n : [\n {\n style: {\n background: \"color-mix(in srgb, var(--danger) 8%, transparent)\",\n border: \"1px dashed color-mix(in srgb, var(--danger) 40%, transparent)\",\n borderRadius: \"4px\",\n color: \"var(--danger)\",\n fontFamily: \"'JetBrains Mono', 'SF Mono', 'Fira Code', monospace\",\n fontSize: \"11px\",\n fontStyle: \"italic\",\n padding: \"6px 10px\",\n },\n tagName: \"div\",\n textContent: `[$switch: ${caseKeys.join(\" | \")}]`,\n },\n ];\n }\n } else if (k === \"attributes\" && isMediaElement && v && typeof v === \"object\") {\n // Process attributes for media elements: replace src/poster with transparent pixel\n const attrs = v as Record<string, unknown>;\n const processed: Record<string, unknown> = {};\n for (const [ak, av] of Object.entries(attrs)) {\n if (ak === \"src\" || ak === \"poster\") {\n if (typeof av === \"string\" && av !== \"\" && !av.includes(\"${\")) {\n processed[ak] = av;\n } else {\n needsMediaPlaceholder = true;\n processed[ak] = TRANSPARENT_PX;\n }\n } else if (typeof av === \"string\" && av.includes(\"${\")) {\n const isUrlAttr = ak === \"href\" || ak === \"action\";\n processed[ak] = isUrlAttr ? \"\" : templateToEditDisplay(av);\n } else if (av && typeof av === \"object\" && (av as Record<string, unknown>).$ref) {\n const ref = (av as Record<string, unknown>).$ref as string;\n const label = ref.startsWith(\"#/state/\") ? ref.slice(8) : ref;\n processed[ak] = `{${label}}`;\n } else {\n processed[ak] = av;\n }\n }\n out.attributes = processed;\n } else if (k === \"style\") {\n // Replace template strings in style values with empty strings\n if (v && typeof v === \"object\") {\n const s: Record<string, unknown> = {};\n for (const [sk, sv] of Object.entries(v)) {\n s[sk] = typeof sv === \"string\" && sv.includes(\"${\") ? \"\" : sv;\n }\n out.style = s;\n } else {\n out.style = v;\n }\n } else if (typeof v === \"string\" && v.includes(\"${\")) {\n // Template string in a display property → show raw expression\n const isMediaSrc =\n (k === \"src\" || k === \"poster\") && mediaTags.has((obj.tagName as string) || \"\");\n if (isMediaSrc) {\n needsMediaPlaceholder = true;\n out[k] = TRANSPARENT_PX;\n } else {\n const isUrlAttr = k === \"src\" || k === \"href\" || k === \"poster\" || k === \"action\";\n out[k] = isUrlAttr ? \"\" : templateToEditDisplay(v);\n }\n } else if (v && typeof v === \"object\" && (v as Record<string, unknown>).$ref) {\n // $ref binding → show ref path as literal text\n const ref = (v as Record<string, unknown>).$ref as string;\n const label = ref.startsWith(\"#/state/\") ? ref.slice(8) : ref;\n const isMediaSrc =\n (k === \"src\" || k === \"poster\") && mediaTags.has((obj.tagName as string) || \"\");\n if (isMediaSrc) {\n needsMediaPlaceholder = true;\n out[k] = TRANSPARENT_PX;\n } else {\n out[k] = `{${label}}`;\n }\n } else {\n // Empty src/poster on media elements → use transparent pixel placeholder\n if (\n (k === \"src\" || k === \"poster\") &&\n v === \"\" &&\n mediaTags.has((obj.tagName as string) || \"\")\n ) {\n needsMediaPlaceholder = true;\n out[k] = TRANSPARENT_PX;\n } else {\n out[k] = prepareForEditMode(v as JxMutableNode);\n }\n }\n }\n\n // Mark empty elements with placeholder classes for design-mode visibility\n const placeholderClass = computeEmptyPlaceholderClass(out as JxMutableNode);\n if (placeholderClass) {\n out.className = out.className ? `${out.className} ${placeholderClass}` : placeholderClass;\n }\n\n // Media elements with missing/dynamic src get a placeholder class\n if (needsMediaPlaceholder) {\n const cls = (out.className as string) || \"\";\n if (!cls.includes(\"empty-media-placeholder\")) {\n out.className = cls ? `${cls} empty-media-placeholder` : \"empty-media-placeholder\";\n }\n }\n\n return out;\n}\n",
35
+ "/**\n * Component test props (M6) — the previewParams mirror for component docs. A non-instantiated\n * component definition renders on the canvas with its state defaults; \"test values\" let the author\n * pick per-prop values that the canvas render seeds into the definition's state, so templates,\n * dataScope snapshots, and live/snapshot expression previews all see real data.\n *\n * Pure and DOM-free: {@link componentPropEntries} derives the editable prop rows from the doc's\n * state (the same plain-data entries the CEM export publishes as fields), and\n * {@link substitutePreviewProps} rebuilds a render doc with chosen values seeded — never mutating\n * the source document (the substitutePreviewParams contract).\n */\n\nimport type { JsonValue } from \"./types\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\nimport { isPrivateStateKey } from \"@jxsuite/schema/guards\";\n\n/** One editable prop row: the state key and its current default value (undefined = none). */\nexport interface ComponentPropEntry {\n name: string;\n value: JsonValue | undefined;\n}\n\n/** Whether the doc is a component definition (a custom-element root) rather than a page. */\nexport function isComponentDoc(doc: JxMutableNode | null | undefined): boolean {\n return typeof doc?.tagName === \"string\" && doc.tagName.includes(\"-\");\n}\n\n/**\n * Classify a state entry as a prop (plain data the CEM export publishes as a field): naked\n * literals/arrays/objects and expanded/typed signal defs — never expressions, computeds, functions,\n * templates, or $prototype data sources (overriding those would clobber behavior, the boundPropKey\n * rule).\n */\nfunction propShape(def: unknown): \"literal\" | \"signal\" | null {\n if (def === null || typeof def === \"number\" || typeof def === \"boolean\") {\n return \"literal\";\n }\n if (typeof def === \"string\") {\n return def.includes(\"${\") ? null : \"literal\"; // Template strings render computed values.\n }\n if (Array.isArray(def)) {\n return \"literal\";\n }\n if (typeof def === \"object\") {\n const d = def as Record<string, unknown>;\n if (d.$expression || d.$compute || d.$prototype || d.$handler) {\n return null;\n }\n // An expanded signal ({default}) or a typed prop def ({type}/schema keywords) seeds through\n // Its `default`; any other plain object is a Shape-1 naked value.\n return \"default\" in d || \"type\" in d ? \"signal\" : \"literal\";\n }\n return null;\n}\n\n/**\n * The component's editable prop entries, derived from the doc's state — non-private plain-data\n * entries with their current default values (the CEM-export \"field\" subset).\n */\nexport function componentPropEntries(doc: JxMutableNode | null | undefined): ComponentPropEntry[] {\n const state = (doc?.state ?? {}) as Record<string, unknown>;\n const out: ComponentPropEntry[] = [];\n for (const [name, def] of Object.entries(state)) {\n if (isPrivateStateKey(name)) {\n continue; // Private entries are not props (spec.md §5.6).\n }\n const shape = propShape(def);\n if (!shape) {\n continue;\n }\n const value =\n shape === \"signal\"\n ? ((def as { default?: JsonValue }).default as JsonValue | undefined)\n : (def as JsonValue);\n out.push({ name, value });\n }\n return out;\n}\n\n/**\n * Rebuild `renderDoc` with the chosen test-prop values seeded into its state: a literal entry is\n * replaced by the value; a signal/typed entry keeps its metadata and gets the value as `default`\n * (exactly what buildScope reads). Pure — returns a shallow rebuild; the render doc shares node\n * references with the tab's source document, so in-place mutation would corrupt the edited doc.\n */\nexport function substitutePreviewProps(\n renderDoc: JxMutableNode,\n props: Record<string, JsonValue>,\n): JxMutableNode {\n const state = { ...((renderDoc.state ?? {}) as Record<string, unknown>) };\n let seeded = false;\n for (const [name, value] of Object.entries(props)) {\n const shape = propShape(state[name]);\n if (!shape) {\n continue; // Unknown/behavioral entries are never overridden by a stale test value.\n }\n state[name] =\n shape === \"signal\" ? { ...(state[name] as Record<string, unknown>), default: value } : value;\n seeded = true;\n }\n if (!seeded) {\n return renderDoc;\n }\n return { ...renderDoc, state } as JxMutableNode;\n}\n",
36
+ "/**\n * Deterministic mapping from Function-def `$src` module specifiers to bundled asset URLs, plus the\n * asset-mount math that publishes files living outside the project root at a stable site URL.\n * Shared between the compiler's sidecar bundler (which writes the bundle) and extension `lower()`\n * implementations (which emit the URL into client code) so neither needs to depend on the other.\n *\n * The mapping is intentionally hash-free: the same specifier always yields the same URL, letting\n * lowered defs reference bundles the compiler produces later in the build. Distinct specifiers that\n * collide on a slug are rejected by the bundler at build time.\n *\n * Pure string math only — no node imports — so browser hosts can import this module.\n */\n\n/** Prefix for npm package specifiers in `$src` (spec §12): `npm:<pkg>[/subpath]`. */\nexport const NPM_SPECIFIER_PREFIX = \"npm:\";\n\n/** URL directory (under the site root) where bundled sidecars are written. */\nexport const SIDECAR_ASSET_DIR = \"/assets/\";\n\n/** True when a `$src` specifier names an npm package rather than a project file. */\nexport function isNpmSpecifier(specifier: string): boolean {\n return specifier.startsWith(NPM_SPECIFIER_PREFIX);\n}\n\n/**\n * Map a Function-def `$src` specifier to its bundled asset URL.\n *\n * `npm:@jxsuite/search/client` → `/assets/jxsuite-search-client.js` `./lib/search-helpers.ts` →\n * `/assets/lib-search-helpers.js`\n */\nexport function sidecarAssetPath(specifier: string): string {\n let base = specifier;\n if (isNpmSpecifier(base)) {\n base = base.slice(NPM_SPECIFIER_PREFIX.length);\n }\n base = base\n .replace(/^\\.\\//, \"\")\n .replace(/\\.(js|ts|mjs|mts)$/, \"\")\n .replaceAll(\"@\", \"\")\n .replaceAll(/[/\\\\]+/g, \"-\")\n .replaceAll(/[^\\w.-]/g, \"-\")\n .replaceAll(/-+/g, \"-\")\n .replaceAll(/^-|-$/g, \"\");\n return `${SIDECAR_ASSET_DIR}${base}.js`;\n}\n\n/**\n * Map a bare npm specifier naming a **file** — a stylesheet, a font, a prebuilt script — to the URL\n * the build copies it to.\n *\n * Unlike {@link sidecarAssetPath} this keeps the extension, because the file is copied rather than\n * bundled and both the browser and the host dispatch on it.\n *\n * @docs framework/site/seo\n */\nexport function npmAssetPath(specifier: string): string {\n const ext = /\\.(\\w+)$/.exec(specifier)?.[1] ?? \"\";\n const base = specifier\n .replace(/\\.\\w+$/, \"\")\n .replaceAll(\"@\", \"\")\n .replaceAll(/[/\\\\]+/g, \"-\")\n .replaceAll(/[^\\w.-]/g, \"-\")\n .replaceAll(/-+/g, \"-\")\n .replaceAll(/^-|-$/g, \"\");\n return ext === \"\" ? `${SIDECAR_ASSET_DIR}${base}` : `${SIDECAR_ASSET_DIR}${base}.${ext}`;\n}\n\n// ─── Asset mounts (specs/extensions.md §8.5) ─────────────────────────────────\n\n/**\n * A site URL prefix backed by a real directory. Extensions declaring the `assets` capability return\n * mounts so hosts can publish files that live outside the project root (an external content\n * source's co-located images) without knowing anything about the section that owns them.\n */\nexport interface AssetMount {\n /** Site-absolute URL prefix, e.g. `/content/docs` (no trailing slash). */\n urlPrefix: string;\n /** Absolute directory the prefix maps onto. */\n dir: string;\n}\n\n/** Normalize a path or prefix for comparison: forward slashes, no trailing slash. */\nfunction normalizeDir(value: string): string {\n const forward = value.replaceAll(\"\\\\\", \"/\");\n return forward.length > 1 && forward.endsWith(\"/\") ? forward.slice(0, -1) : forward;\n}\n\n/** Normalize a mount's URL prefix: leading slash, no trailing slash. */\nexport function normalizeAssetPrefix(prefix: string): string {\n const forward = normalizeDir(prefix);\n return forward.startsWith(\"/\") ? forward : `/${forward}`;\n}\n\n/** Mounts sorted so the most specific (longest) candidate matches first. */\nfunction bySpecificity(mounts: readonly AssetMount[], key: \"dir\" | \"urlPrefix\"): AssetMount[] {\n return [...mounts].toSorted((a, b) => b[key].length - a[key].length);\n}\n\n/** True when `path` is `dir` itself or sits underneath it (both already normalized). */\nfunction isUnder(path: string, dir: string): boolean {\n return path === dir || path.startsWith(`${dir}/`);\n}\n\n/**\n * Map an absolute file path to its mounted site URL, or null when no mount contains it. Path\n * segments are percent-encoded so the URL survives HTML attributes; `resolveAssetUrl` reverses it.\n *\n * @param {readonly AssetMount[]} mounts\n * @param {string} absolutePath - Absolute filesystem path\n * @returns {string | null}\n */\nexport function assetUrlFor(mounts: readonly AssetMount[], absolutePath: string): string | null {\n const path = normalizeDir(absolutePath);\n for (const mount of bySpecificity(mounts, \"dir\")) {\n const dir = normalizeDir(mount.dir);\n if (!isUnder(path, dir) || path === dir) {\n continue;\n }\n const rest = path.slice(dir.length + 1);\n const encoded = rest\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n return `${normalizeAssetPrefix(mount.urlPrefix)}/${encoded}`;\n }\n return null;\n}\n\n/**\n * Map a mounted site URL back to its absolute file path, or null when it matches no mount. Query\n * and hash are dropped, the path is decoded ONCE (a still-encoded dot or slash after that decode is\n * a bypass attempt and is rejected), and `.`/`..` segments are refused outright — so the result can\n * never escape the mount directory.\n *\n * @param {readonly AssetMount[]} mounts\n * @param {string} url - Site-absolute URL (e.g. `/content/docs/images/hero.png`)\n * @returns {string | null}\n */\nexport function resolveAssetUrl(mounts: readonly AssetMount[], url: string): string | null {\n const pathname = url.split(\"#\")[0]!.split(\"?\")[0]!;\n if (!pathname.startsWith(\"/\")) {\n return null;\n }\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return null;\n }\n if (/%2e|%2f/i.test(decoded)) {\n return null;\n }\n for (const mount of bySpecificity(mounts, \"urlPrefix\")) {\n const prefix = normalizeAssetPrefix(mount.urlPrefix);\n if (!decoded.startsWith(`${prefix}/`)) {\n continue;\n }\n const rest = decoded.slice(prefix.length + 1);\n const segments = rest.split(\"/\");\n if (segments.some((s) => s === \"\" || s === \".\" || s === \"..\")) {\n return null;\n }\n return `${normalizeDir(mount.dir)}/${segments.join(\"/\")}`;\n }\n return null;\n}\n\n/** Characters that terminate a URL inside markup: quotes, whitespace, CSS `url()` parens, `<>`. */\nconst URL_TERMINATOR = String.raw`\"'\\s<>()\\\\`;\n\n/**\n * Collect every mounted URL referenced by a compiled artifact (HTML, CSS, JSON-LD). Scanning output\n * text rather than the document tree catches references wherever they came from — markdown images,\n * hand-authored pages, `$head` metadata, `url()` in stylesheets — with no per-attribute knowledge.\n *\n * @param {string} text - Compiled HTML or CSS\n * @param {readonly AssetMount[]} mounts\n * @returns {string[]} Unique mounted URLs, in first-seen order\n */\nexport function collectAssetUrls(text: string, mounts: readonly AssetMount[]): string[] {\n const found = new Set<string>();\n for (const mount of mounts) {\n const prefix = normalizeAssetPrefix(mount.urlPrefix);\n const pattern = new RegExp(\n `${prefix.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, String.raw`\\$&`)}/[^${URL_TERMINATOR}]+`,\n \"g\",\n );\n for (const match of text.matchAll(pattern)) {\n const url = match[0].split(\"#\")[0]!.split(\"?\")[0]!;\n // A trailing slash names a directory, not a file — prose quoting the mount prefix\n // (\"published under /content/docs/images/\") is a mention, not a reference.\n if (!url.endsWith(\"/\")) {\n found.add(url);\n }\n }\n }\n return [...found].filter(Boolean);\n}\n",
37
+ "/**\n * Content-relative asset references, resolved for the canvas.\n *\n * A content entry references media relative to ITSELF — `![](./images/hero.png)` — so the file\n * reads correctly in a plain markdown editor and so collections sourced outside the project root\n * still reach their media (specs/site-architecture.md §9.3). On the built site the collection\n * loader rewrites those refs onto the content type's asset mount,\n * `/content/<type>/images/hero.png`.\n *\n * Studio opens an entry as a STANDALONE document, so that loader never runs and the canvas would\n * render the authored path verbatim — which the browser resolves against `canvas.html`, not the\n * entry. This module applies the same mount mapping to the render document so the canvas previews\n * the URL production actually serves.\n *\n * The URL math is `assetUrlFor` from `@jxsuite/schema/asset-paths` — the same function the loader\n * and the compiler use — so the three cannot drift. It is pure string containment, which works\n * unchanged on the project-relative paths Studio deals in.\n *\n * The SOURCE document is never touched: the authored relative ref is what gets serialized back to\n * disk, and the properties panel shows the author what they wrote.\n *\n * One deliberate divergence from the loader: it declines to rewrite a ref whose target does not\n * exist (`existsSync`), leaving an unresolvable path alone rather than changing its meaning. The\n * browser has no filesystem, so this rewrites optimistically. A missing file is broken either way;\n * pointing at the mount URL is the more informative failure, and it is the URL the built site would\n * have attempted.\n *\n * @docs studio/projects/media\n */\n\nimport { assetUrlFor } from \"@jxsuite/schema/asset-paths\";\nimport { projectState } from \"../store\";\nimport { activeTab } from \"../workspace/workspace\";\nimport type { AssetMount } from \"@jxsuite/schema/asset-paths\";\nimport type { ContentSectionEntry } from \"../types\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** Node keys whose value is a media reference. Mirrors `ASSET_KEYS` in the content loader. */\nconst ASSET_KEYS = [\"src\", \"poster\"] as const;\n\n/** Content type names safe in a URL path segment. Mirrors `SAFE_TYPE_NAME` in the content loader. */\nconst SAFE_TYPE_NAME = /^[\\w.~-]+$/;\n\n/** The project.json section key content types live under; also their URL namespace. */\nconst SECTION_KEY = \"content\";\n\n/**\n * A value that is already a URL, a template, or a fragment — never a content-relative file. Mirrors\n * `isNonRelativeRef` in the content loader.\n */\nfunction isNonRelativeRef(value: string): boolean {\n return (\n value === \"\" ||\n value.startsWith(\"/\") ||\n value.startsWith(\"#\") ||\n value.includes(\"${\") ||\n /^[a-z][\\w+.-]*:/i.test(value)\n );\n}\n\n/** Strip `./` and any trailing slash from a configured `source`, the way collectionDirs does. */\nfunction normalizeSource(source: string): string {\n return source.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n}\n\n/**\n * Resolve `ref` against `dir` in a pure, POSIX-ish way — no `node:path`, and no leading-slash\n * assumption, because Studio's paths are project-relative. Returns null when the result would climb\n * above the project root (`../` past the top), which can never name a mounted file.\n */\nexport function resolveRelativePath(dir: string, ref: string): string | null {\n const segments = dir === \"\" || dir === \".\" ? [] : dir.replaceAll(\"\\\\\", \"/\").split(\"/\");\n const out = segments.filter((s) => s !== \"\" && s !== \".\");\n for (const segment of ref.replaceAll(\"\\\\\", \"/\").split(\"/\")) {\n if (segment === \"\" || segment === \".\") {\n continue;\n }\n if (segment === \"..\") {\n if (out.length === 0) {\n return null; // Escapes the project root.\n }\n out.pop();\n continue;\n }\n out.push(segment);\n }\n return out.join(\"/\");\n}\n\n/** The directory portion of a project-relative file path (`\"\"` for a root-level file). */\nexport function dirOf(path: string): string {\n const normalized = path.replaceAll(\"\\\\\", \"/\");\n const slash = normalized.lastIndexOf(\"/\");\n return slash === -1 ? \"\" : normalized.slice(0, slash);\n}\n\n/**\n * The asset mount for the content type that owns `documentPath`, or null when the document is not a\n * directory-backed content entry.\n *\n * Only in-project sources can match: an entry Studio can address project-relatively is by\n * definition inside the project, and a source pointing elsewhere (`../../docs`) names files the\n * file tree cannot reach in the first place.\n */\nexport function contentMountFor(\n documentPath: string | null | undefined,\n content: Record<string, ContentSectionEntry> | null | undefined,\n): AssetMount | null {\n if (!documentPath || !content) {\n return null;\n }\n const path = documentPath.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\");\n let best: AssetMount | null = null;\n for (const [name, def] of Object.entries(content)) {\n if (!def?.source || !SAFE_TYPE_NAME.test(name)) {\n continue;\n }\n const dir = normalizeSource(def.source);\n // A single-file source is not a collection directory — its siblings are not its assets.\n if (dir === \"\" || dir.startsWith(\"..\") || /\\.[a-z0-9]+$/i.test(dir)) {\n continue;\n }\n if (path.startsWith(`${dir}/`) && (!best || dir.length > best.dir.length)) {\n best = { dir, urlPrefix: `/${SECTION_KEY}/${name}` };\n }\n }\n return best;\n}\n\n/**\n * The mounted URL for one authored reference, or null to leave it as written. A ref is rewritten\n * only when it is relative and lands inside the collection directory — anything else (an absolute\n * URL, a project-root path, a bound template, a `../` escape out of the collection) keeps the\n * meaning it already had.\n */\nexport function mountedRefFor(value: string, entryDir: string, mount: AssetMount): string | null {\n if (isNonRelativeRef(value)) {\n return null;\n }\n const bare = value.split(\"#\")[0]!.split(\"?\")[0]!;\n let decoded: string;\n try {\n decoded = decodeURIComponent(bare);\n } catch {\n return null;\n }\n const target = resolveRelativePath(entryDir, decoded);\n if (target === null) {\n return null;\n }\n const url = assetUrlFor([mount], target);\n if (!url) {\n return null; // Outside the collection — not the mount's to publish.\n }\n return `${url}${value.slice(bare.length)}`;\n}\n\n/**\n * Rewrite one node's media refs, returning the node unchanged when nothing applies.\n *\n * PURE REBUILD: a node with a rewritten ref is replaced by a shallow copy, and so is every ancestor\n * on the path to it. Untouched subtrees keep their original references, so the render doc still\n * shares the vast majority of its nodes with the source doc.\n */\nfunction rewriteNode(node: JxMutableNode, entryDir: string, mount: AssetMount): JxMutableNode {\n const record = node as unknown as Record<string, unknown>;\n /** Accumulated changed keys; stays null (and the node is returned as-is) when nothing applies. */\n let patch: Record<string, unknown> | null = null;\n\n for (const key of ASSET_KEYS) {\n const value = record[key];\n if (typeof value === \"string\") {\n const rewritten = mountedRefFor(value, entryDir, mount);\n if (rewritten) {\n patch ??= {};\n patch[key] = rewritten;\n }\n }\n }\n\n const attributes = record.attributes as Record<string, unknown> | undefined;\n if (attributes) {\n let nextAttrs: Record<string, unknown> | null = null;\n for (const key of ASSET_KEYS) {\n const value = attributes[key];\n if (typeof value === \"string\") {\n const rewritten = mountedRefFor(value, entryDir, mount);\n if (rewritten) {\n nextAttrs ??= { ...attributes };\n nextAttrs[key] = rewritten;\n }\n }\n }\n if (nextAttrs) {\n patch ??= {};\n patch.attributes = nextAttrs;\n }\n }\n\n const children = record.children as unknown[] | undefined;\n if (Array.isArray(children)) {\n let nextChildren: unknown[] | null = null;\n for (const [i, child] of children.entries()) {\n if (!child || typeof child !== \"object\") {\n continue;\n }\n const rewrittenChild = rewriteNode(child as JxMutableNode, entryDir, mount);\n if (rewrittenChild !== child) {\n nextChildren ??= [...children];\n nextChildren[i] = rewrittenChild;\n }\n }\n if (nextChildren) {\n patch ??= {};\n patch.children = nextChildren;\n }\n }\n\n return patch ? ({ ...node, ...patch } as JxMutableNode) : node;\n}\n\n/**\n * Map a content entry's relative media refs onto its content type's asset mount, for rendering.\n *\n * Returns `doc` itself when the document is not a content entry or carries no rewritable ref, so\n * the common case costs one walk and allocates nothing.\n */\nexport function rewriteContentAssets(\n doc: JxMutableNode,\n documentPath: string | null | undefined,\n content: Record<string, ContentSectionEntry> | null | undefined,\n): JxMutableNode {\n const mount = contentMountFor(documentPath, content);\n if (!mount) {\n return doc;\n }\n return rewriteNode(doc, dirOf(documentPath!.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\")), mount);\n}\n\n/**\n * The src a PARENT-REALM preview (a media-picker thumbnail) should load for an authored value.\n *\n * The canvas gets its mapping through {@link rewriteContentAssets} on the render doc, but panel\n * chrome renders in the parent document, where a content-relative value would resolve against\n * `index.html` and 404 exactly as it did in the canvas. Same mapping, same rule — resolved against\n * the ACTIVE tab, which is the entry whose field is being edited.\n *\n * Non-content documents and already-absolute values pass through untouched.\n */\nexport function previewAssetSrc(value: string): string {\n if (!value) {\n return value;\n }\n const documentPath = activeTab.value?.documentPath;\n const mount = contentMountFor(\n documentPath,\n projectState?.projectConfig?.content as Record<string, ContentSectionEntry> | undefined,\n );\n if (!mount) {\n return value;\n }\n return mountedRefFor(value, dirOf(documentPath!), mount) ?? value;\n}\n",
38
+ "/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Canvas live render — extracted from studio.js (Phase 4p). Async runtime rendering pipeline that\n * builds live canvas DOM using @jxsuite/runtime. Handles element registration, scope building, path\n * mapping ($map remapping), site-level style injection, and $head element injection.\n */\n\nimport { projectState, stripEventHandlers } from \"../store\";\nimport { displayTagName } from \"@jxsuite/schema/guards\";\nimport { canvasModeOfTab } from \"./canvas-surface\";\nimport { toRaw } from \"../reactivity\";\nimport {\n distributePageIntoLayout,\n getEffectiveElements,\n getEffectiveHead,\n getEffectiveImports,\n getEffectiveLayoutPath,\n getEffectiveMedia,\n resolveLayoutDoc,\n} from \"../site-context\";\nimport { canvasBaseOrigin } from \"./canvas-origin\";\nimport { componentRegistry, computeRelativePath } from \"../files/components\";\nimport { prepareForEditMode } from \"../utils/edit-display\";\nimport {\n paramBoundStateKeys,\n resolveParamBoundState,\n substitutePreviewParams,\n} from \"../page-params\";\nimport { isComponentDoc, substitutePreviewProps } from \"../component-props\";\nimport { rewriteContentAssets } from \"./content-assets\";\n\nimport type { JxElement, JxMutableNode, JxPath } from \"@jxsuite/schema/types\";\nimport type { ComponentEntry } from \"../files/components.js\";\nimport type { ContentSectionEntry } from \"../types\";\nimport type { LayoutMarker } from \"./path-mapping\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { WireMapperCtx } from \"./iframe-protocol\";\n\n/**\n * Walk the merged document tree to find where page children were distributed into the layout slot.\n * Returns the `prefix` path to the container whose children hold the page content (first container\n * with a non-$__layout child), plus the `offset` — the index of the first page-content child within\n * that container's children array. The offset is non-zero when the layout places sibling nodes\n * (e.g. a `<noscript>`) before the `<slot>`, which shifts every page child's render index relative\n * to its page-document index. The path mapper subtracts this offset so canvas paths line up with\n * the page document (and thus the layers panel).\n *\n * @param {JxMutableNode} node\n * @param {(string | number)[]} [path]\n * @returns {{ prefix: (string | number)[]; offset: number } | null}\n */\nfunction findPageContentPrefix(\n node: JxMutableNode,\n path: (string | number)[] = [],\n): { prefix: (string | number)[]; offset: number } | null {\n if (!node || typeof node !== \"object\") {\n return null;\n }\n if (Array.isArray(node.children)) {\n const firstPageIdx = node.children.findIndex(\n (child) => child && typeof child === \"object\" && !child.$__layout,\n );\n if (firstPageIdx !== -1) {\n return { offset: firstPageIdx, prefix: [...path, \"children\"] };\n }\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (child && typeof child === \"object\" && child.$__layout) {\n const found = findPageContentPrefix(child, [...path, \"children\", i]);\n if (found) {\n return found;\n }\n }\n }\n }\n return null;\n}\n\n/**\n * Recursively mark every node of a layout doc tree with its ORIGIN — `$__layout: { file, path }` —\n * so the renderer can both tell layout nodes apart from page content and say which node of which\n * file each one is. The marker used to be a bare `true`, which made a layout node identifiable but\n * unaddressable: the canvas could tell you had clicked something it could not edit, but not what\n * you had clicked or where to go to edit it. `path` is the node's own path inside `file`, so the\n * editor can open the layout with that node selected. See {@link LayoutMarker}.\n */\nexport function markLayoutNodes(node: JxMutableNode, file: string, path: JxPath = []) {\n if (!node || typeof node !== \"object\") {\n return;\n }\n node.$__layout = { file, path } satisfies LayoutMarker;\n if (Array.isArray(node.children)) {\n for (const [i, child] of node.children.entries()) {\n if (typeof child === \"string\") {\n continue;\n }\n markLayoutNodes(child, file, [...path, \"children\", i]);\n }\n }\n if (Array.isArray(node.$elements)) {\n for (const [i, el] of node.$elements.entries()) {\n if (typeof el !== \"string\") {\n markLayoutNodes(el as JxMutableNode, file, [...path, \"$elements\", i]);\n }\n }\n }\n}\n\n/**\n * Resolve a document into the form the iframe canvas renders: layout-distributed, edit-transformed,\n * with components/imports/$media/$head merged in, plus the path-mapper context and site style. This\n * is the \"parent resolves, iframe renders\" split — the realm-specific work (defineElement,\n * injecting $head/site-style into the DOM, buildScope/renderNode) happens inside the iframe from\n * this result.\n *\n * **`tab` is the tab the render is FOR, and it is a parameter because it is not \"the active tab\".**\n * This function opened with `const tab = activeTab.value` and took its mode from an injected\n * `getCanvasMode()` — the focused pane's, one layer down — which threw away everything the caller\n * had already resolved correctly: `canvas-render.ts` picks the document with\n * `tabOfPane(surface.paneId)` and threads that tab's id through `mountIframeCanvas` →\n * `preparePassRender`. Six values came from the wrong tab whenever the pane being drawn was not the\n * focused one: `documentPath` (hence `docBase` and the `isPage` test), `showLayout`,\n * `previewParams`, `previewProps`, and the composed `canvasMode`.\n *\n * The mode is the one with teeth. `mountIframeCanvas` ends with `setHostPreview(state, message.mode\n * === \"preview\")`, so a side pane in Edit whose neighbour was in Preview got a PREVIEW frame — no\n * overlay, no editing messages honoured — and a pane being previewed beside an editing one got an\n * editable frame for a document nobody was editing. `canvasModeOfTab(tab)` is the same composition\n * every other gate reads, applied to the tab that is actually being drawn.\n *\n * @param {JxMutableNode} doc\n * @param {Tab | null} tab — the tab whose document and view settings this render is of.\n */\nexport async function resolveCanvasDocument(\n doc: JxMutableNode,\n tab: Tab | null,\n): Promise<{\n renderDoc: JxMutableNode;\n docBase: string | undefined;\n mapperCtx: WireMapperCtx;\n siteStyle: Record<string, unknown> | null;\n}> {\n const S = { documentPath: tab?.documentPath, mode: tab?.doc.mode };\n const canvasMode = canvasModeOfTab(tab);\n\n let renderDoc =\n canvasMode === \"preview\"\n ? structuredClone(toRaw(doc))\n : prepareForEditMode(stripEventHandlers(doc));\n\n let layoutWrapped = false;\n const isPage =\n S.documentPath &&\n projectState?.isSiteProject &&\n (S.documentPath.startsWith(\"pages/\") || S.documentPath.startsWith(\"./pages/\"));\n let pageContentPrefix: (string | number)[] | null = null;\n let pageContentOffset = 0;\n\n // Layout wrapping obeys the tab-bar's \"show layout elements\" toggle (default on); with it off,\n // The page renders alone — the unwrapped path is identical to a non-layout page.\n if (isPage && tab?.session.ui.showLayout !== false) {\n const layoutPath = getEffectiveLayoutPath(doc.$layout);\n if (layoutPath) {\n const layoutDoc = (await resolveLayoutDoc(layoutPath)) as JxMutableNode | null;\n if (layoutDoc) {\n // The SAME normalization resolveLayoutDoc reads the file with, so the marker's `file` is a\n // Path the editor can hand straight to navigateToComponent when the author asks to open it.\n markLayoutNodes(layoutDoc, layoutPath.replace(/^\\.\\//, \"\"));\n const pageForSlots = canvasMode === \"preview\" ? structuredClone(toRaw(doc)) : renderDoc;\n const merged = distributePageIntoLayout(layoutDoc, pageForSlots);\n renderDoc =\n canvasMode === \"preview\" ? merged : prepareForEditMode(stripEventHandlers(merged));\n layoutWrapped = true;\n const pageContent = findPageContentPrefix(merged);\n pageContentPrefix = pageContent?.prefix ?? null;\n pageContentOffset = pageContent?.offset ?? 0;\n }\n }\n }\n\n const root = projectState?.projectRoot || \"\";\n const docPrefix = root ? `${root}/` : \"\";\n const docBase = S.documentPath\n ? `${canvasBaseOrigin()}/${docPrefix}${S.documentPath}`\n : undefined;\n\n // Substitute chosen dynamic route params ({$ref: \"#/$params/x\"} → literal), inject state.$page,\n // And bake the substituted class-prototype state entries via the backend resolver — in every\n // Mode, so ContentEntry state is real data for preview templates AND the design/edit data\n // Explorer. Pure rebuild: renderDoc shares node references with the tab's source document\n // (posted as shadowDoc), whose $refs must survive for editing/serialization.\n if (isPage && tab) {\n const { previewParams } = tab.session.ui;\n if (previewParams && Object.keys(previewParams).length > 0) {\n const boundKeys = paramBoundStateKeys(\n (doc as { state?: Record<string, unknown> }).state ?? null,\n );\n renderDoc = substitutePreviewParams(renderDoc, previewParams, S.documentPath);\n await resolveParamBoundState(renderDoc, boundKeys, docBase);\n }\n }\n\n // Component definition docs (non-page): seed chosen test-prop values into the render doc's state\n // So a non-instantiated component previews with real data — templates, dataScope snapshots, and\n // Live/snapshot expression previews all see the values (M6, the previewParams mirror). Pure\n // Rebuild for the same reason as substitutePreviewParams above.\n if (!isPage && tab && isComponentDoc(renderDoc)) {\n const { previewProps } = tab.session.ui;\n if (previewProps && Object.keys(previewProps).length > 0) {\n renderDoc = substitutePreviewProps(renderDoc, previewProps);\n }\n }\n\n // A content entry references its media relative to ITSELF; the built site serves those files from\n // The content type's asset mount. Studio opens the entry standalone, so the collection loader that\n // Normally performs that mapping never runs — do it here, on the RENDER doc only, so the canvas\n // Previews the URL production serves while the source doc keeps the authored relative ref.\n renderDoc = rewriteContentAssets(\n renderDoc,\n S.documentPath,\n projectState?.projectConfig?.content as Record<string, ContentSectionEntry> | undefined,\n );\n\n const arrayPaths = new Set<string>();\n if (canvasMode === \"design\" || canvasMode === \"edit\") {\n (function findArrayPaths(node: JxMutableNode, path: (string | number)[]) {\n if (!node || typeof node !== \"object\") {\n return;\n }\n if ((node as unknown as { $prototype?: string }).$prototype === \"Array\") {\n arrayPaths.add(path.join(\"/\"));\n const mapDef = (node as JxMutableNode).map;\n if (mapDef && typeof mapDef === \"object\") {\n findArrayPaths(mapDef, [...path, \"map\"]);\n }\n return;\n }\n if (Array.isArray(node.children)) {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (typeof child === \"string\") {\n continue;\n }\n findArrayPaths(child!, [...path, \"children\", i]);\n }\n } else if (\n node.children &&\n typeof node.children === \"object\" &&\n (node.children as unknown as { $prototype?: string }).$prototype === \"Array\"\n ) {\n findArrayPaths(node.children as JxMutableNode, [...path, \"children\"]);\n }\n if (node.$switch && node.cases) {\n for (const [k, v] of Object.entries(node.cases)) {\n findArrayPaths(v, [...path, \"cases\", k]);\n }\n }\n })(doc, []);\n }\n\n // Component auto-discovery (content mode, wrapped layout, or a layout opened on its own) —\n // Mirrors the legacy render path. A directly-opened layout is neither a page (so it never\n // Sets layoutWrapped) nor content mode (a plain .json file skips the mode-setting parse),\n // So it needs its own gate; scoping to layouts/ avoids the single-component-edit path, where\n // The doc's own root tag would otherwise inject a $ref to itself.\n const isLayoutDoc =\n S.documentPath != null &&\n (S.documentPath.startsWith(\"layouts/\") || S.documentPath.startsWith(\"./layouts/\"));\n const effectiveElements = getEffectiveElements(renderDoc.$elements as (JxElement | string)[]);\n if ((S.mode === \"content\" || layoutWrapped || isLayoutDoc) && componentRegistry.length > 0) {\n const existingRefs = new Set(\n effectiveElements.map((e: JxElement | string) => (typeof e === \"string\" ? e : e?.$ref)),\n );\n const collectTags = (node: JxMutableNode): Set<string> => {\n const tags = new Set<string>();\n if (!node || typeof node !== \"object\") {\n return tags;\n }\n if (node.tagName) {\n tags.add(displayTagName(node.tagName));\n }\n if (Array.isArray(node.children)) {\n for (const child of node.children) {\n if (typeof child !== \"string\") {\n for (const t of collectTags(child)) {\n tags.add(t);\n }\n }\n }\n }\n return tags;\n };\n for (const tag of collectTags(renderDoc)) {\n const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tag);\n if (comp && comp.source !== \"npm\" && comp.path) {\n const relPath = computeRelativePath(S.documentPath ?? null, comp.path);\n if (!existingRefs.has(relPath)) {\n effectiveElements.push({ $ref: relPath });\n existingRefs.add(relPath);\n }\n }\n }\n }\n if (effectiveElements.length > 0) {\n renderDoc.$elements = effectiveElements as (string | JxMutableNode | { $ref: string })[];\n }\n renderDoc.imports = getEffectiveImports(renderDoc.imports);\n // The effective-media/head getters return the merged value or undefined. Optional properties\n // Cannot be assigned undefined under exactOptionalPropertyTypes, so clear them by deleting the key\n // When the getter yields nothing.\n const media = getEffectiveMedia(renderDoc.$media);\n if (media === undefined) {\n delete renderDoc.$media;\n } else {\n renderDoc.$media = media as NonNullable<JxMutableNode[\"$media\"]>;\n }\n const head = getEffectiveHead(renderDoc.$head);\n if (head === undefined) {\n delete renderDoc.$head;\n } else {\n renderDoc.$head = head as NonNullable<JxMutableNode[\"$head\"]>;\n }\n\n return {\n docBase,\n mapperCtx: {\n arrayPaths: [...arrayPaths],\n canvasMode,\n layoutWrapped,\n pageContentOffset,\n pageContentPrefix,\n },\n renderDoc,\n siteStyle: (projectState?.projectConfig?.style as Record<string, unknown>) ?? null,\n };\n}\n",
39
+ "/**\n * Canvas render instrumentation. Counts full renders vs surgical patches, and times the render hot\n * path, so tests and profiling runs can verify that ordinary edits neither rebuild the canvas nor\n * blow a frame budget.\n *\n * Counters answer \"did this edit escalate?\"; timings answer \"what did it cost?\". Durations are\n * always recorded (a `performance.now()` pair is free at render frequency); `performance.mark` /\n * `performance.measure` entries — the ones that show up on a DevTools flame chart — are emitted\n * only when debug mode is on, so a normal session's timeline stays clean.\n *\n * Inspect in the browser via `globalThis.__jxCanvasPerf`; enable per-event logging and timeline\n * marks with `localStorage[\"jx-canvas-debug\"] = \"1\"`.\n */\n\n/** Rolling window per span. Bounded so a long session cannot grow the sample arrays. */\nconst SAMPLE_LIMIT = 128;\n\n/** Span names, so producers and the profiling gate agree on the keys. */\nexport const SPAN_FULL_RENDER = \"fullRender\";\nexport const SPAN_MOUNT_CANVAS = \"mountCanvas\";\nexport const SPAN_PATCH_BATCH = \"patchBatch\";\n/**\n * The parent-side render payload — resolve the document, then serialize it for the wire. Built ONCE\n * per render pass and shared by every host in it, so this span's `count` is passes, not panels.\n */\nexport const SPAN_PREPARE_RENDER = \"prepareRender\";\n\nexport interface SpanStats {\n /** Completed spans recorded under this name. */\n count: number;\n /** Duration of the most recent span, in ms. */\n lastMs: number;\n /** Longest span observed, in ms. */\n maxMs: number;\n /** 95th percentile over the retained window (up to {@link SAMPLE_LIMIT} samples), in ms. */\n p95Ms: number;\n /** Sum of every recorded duration, in ms — divide by `count` for the mean. */\n totalMs: number;\n}\n\nexport interface CanvasPerf {\n /** Full renderCanvas() invocations (whole-canvas orchestration). */\n fullRenders: number;\n /** Individual panel renders (one per breakpoint panel per full render). */\n panelRenders: number;\n /**\n * Parent-side render payloads built — one document resolution plus one wire serialization.\n *\n * This is the fan-out denominator. Divide {@link CanvasPerf.hostRenderPosts} by it: the quotient\n * is how many canvas iframes one render pass fed from a single resolution, and a quotient of 1\n * when more than one host is live means the fan-out is not happening.\n */\n renderPreparations: number;\n /** Render messages posted to canvas iframe hosts (the fan-out numerator). */\n hostRenderPosts: number;\n /** Doc-effect triggers skipped because the change was consumed by the patcher. */\n skippedFullRenders: number;\n /** Patch ops posted to the live canvas hosts instead of escalating to a render. */\n patchedOps: number;\n /** Patch batches that escalated to a full render. */\n escalations: number;\n /**\n * Times a FOLLOWING pane re-resolved to a different document (§18.4's companion presets).\n *\n * The tripwire for the one way the follow ships slow. The `component` follow observes the\n * selection, and the selection moves on every click — so it memoises on its ANSWER: twenty clicks\n * inside one `<my-card>` resolve to the same definition and must cost nothing. A number that\n * climbs with keystrokes or with clicks inside one component means the memo is being defeated,\n * usually by traversing the reactive document instead of `toRaw`'s.\n */\n derivedRetargets: number;\n /**\n * Times a following pane RE-RESOLVED — ran `derivedTarget` and reconciled, whether or not the\n * answer changed.\n *\n * The other half of the follow's cost, and the half {@link CanvasPerf.derivedRetargets} cannot\n * see: the memo makes a repeated answer free to ACT on, and says nothing about how often the\n * question is asked. It is asked once per effect run, and the effect's tracked inputs are meant\n * to be the source tab's identity and its selection — nothing else. A number that climbs with\n * keystrokes means the document was read through the reactive proxy instead of `toRaw`'s, which\n * makes every character typed in the source pane re-walk the tree.\n */\n derivedResolves: number;\n lastEscalationReason: string;\n /** Duration of the most recent full canvas render, in ms (0 before the first render). */\n lastFullRenderMs: number;\n /** 95th percentile full-render duration over the retained window, in ms. */\n p95FullRenderMs: number;\n /** Per-span timing stats, keyed by span name. */\n timings: Record<string, SpanStats>;\n}\n\nexport const canvasPerf: CanvasPerf = {\n derivedResolves: 0,\n derivedRetargets: 0,\n escalations: 0,\n fullRenders: 0,\n hostRenderPosts: 0,\n lastEscalationReason: \"\",\n lastFullRenderMs: 0,\n p95FullRenderMs: 0,\n panelRenders: 0,\n patchedOps: 0,\n renderPreparations: 0,\n skippedFullRenders: 0,\n timings: {},\n};\n\n(globalThis as Record<string, unknown>).__jxCanvasPerf = canvasPerf;\n\n/** Retained duration samples per span, parallel to `canvasPerf.timings`. */\nconst samples = new Map<string, number[]>();\n\nfunction debugEnabled() {\n try {\n return typeof localStorage !== \"undefined\" && Boolean(localStorage.getItem(\"jx-canvas-debug\"));\n } catch {\n return false;\n }\n}\n\n/** Monotonic clock, or 0 when the environment has no `performance` (durations then read as 0). */\nfunction now(): number {\n return typeof performance !== \"undefined\" && typeof performance.now === \"function\"\n ? performance.now()\n : 0;\n}\n\n/** Log a canvas perf event when debug mode is on. */\nexport function perfLog(event: string, detail?: unknown) {\n if (debugEnabled()) {\n console.debug(`[jx-canvas] ${event}`, detail ?? \"\");\n }\n}\n\n/** Record an escalation to full render with its reason. */\nexport function recordEscalation(reason: string) {\n canvasPerf.escalations += 1;\n canvasPerf.lastEscalationReason = reason;\n perfLog(\"escalation\", reason);\n}\n\n/** P95 by nearest rank, sorted into a new array so the retained sample order is preserved. */\nfunction percentile95(values: readonly number[]): number {\n if (values.length === 0) {\n return 0;\n }\n const sorted = values.toSorted((a, b) => a - b);\n // Nearest-rank: index of the smallest value at or above the 95th percentile.\n const index = Math.min(sorted.length - 1, Math.ceil(sorted.length * 0.95) - 1);\n return sorted[Math.max(0, index)] ?? 0;\n}\n\n/**\n * Record a completed span duration. Exported so a producer that already has a duration (or a test)\n * can feed the same aggregation the `time*` helpers use.\n */\nexport function recordSpan(name: string, ms: number) {\n const duration = Number.isFinite(ms) && ms > 0 ? ms : 0;\n let window = samples.get(name);\n if (!window) {\n window = [];\n samples.set(name, window);\n }\n window.push(duration);\n if (window.length > SAMPLE_LIMIT) {\n window.shift();\n }\n const previous = canvasPerf.timings[name];\n const stats: SpanStats = {\n count: (previous?.count ?? 0) + 1,\n lastMs: duration,\n maxMs: Math.max(previous?.maxMs ?? 0, duration),\n p95Ms: percentile95(window),\n totalMs: (previous?.totalMs ?? 0) + duration,\n };\n canvasPerf.timings[name] = stats;\n if (name === SPAN_FULL_RENDER) {\n canvasPerf.lastFullRenderMs = stats.lastMs;\n canvasPerf.p95FullRenderMs = stats.p95Ms;\n }\n perfLog(`span:${name}`, `${duration.toFixed(2)}ms`);\n}\n\n/**\n * Open a span. The returned function closes it, records the duration, and returns it — call it\n * exactly once, and prefer {@link timeSpan} / {@link timeSpanAsync} when the body is a single\n * expression so an early return cannot skip the close.\n */\nexport function beginSpan(name: string): () => number {\n const start = now();\n const debug = debugEnabled();\n const startMark = `jx-${name}-start`;\n if (debug) {\n try {\n performance.mark(startMark);\n } catch {\n // Marks are diagnostics; never let them break a render.\n }\n }\n let closed = false;\n return () => {\n if (closed) {\n return canvasPerf.timings[name]?.lastMs ?? 0;\n }\n closed = true;\n const duration = now() - start;\n if (debug) {\n try {\n performance.measure(`jx-${name}`, startMark);\n performance.clearMarks(startMark);\n } catch {\n // Ditto.\n }\n }\n recordSpan(name, duration);\n return duration;\n };\n}\n\n/** Time a synchronous body. The span closes even when the body throws. */\nexport function timeSpan<T>(name: string, body: () => T): T {\n const end = beginSpan(name);\n try {\n return body();\n } finally {\n end();\n }\n}\n\n/** Time an async body. The span closes when the promise settles, including on rejection. */\nexport async function timeSpanAsync<T>(name: string, body: () => Promise<T>): Promise<T> {\n const end = beginSpan(name);\n try {\n return await body();\n } finally {\n end();\n }\n}\n\n/** Reset all counters and timings (for tests). */\nexport function resetCanvasPerf() {\n canvasPerf.fullRenders = 0;\n canvasPerf.panelRenders = 0;\n canvasPerf.renderPreparations = 0;\n canvasPerf.hostRenderPosts = 0;\n canvasPerf.skippedFullRenders = 0;\n canvasPerf.patchedOps = 0;\n canvasPerf.escalations = 0;\n canvasPerf.derivedRetargets = 0;\n canvasPerf.derivedResolves = 0;\n canvasPerf.lastEscalationReason = \"\";\n canvasPerf.lastFullRenderMs = 0;\n canvasPerf.p95FullRenderMs = 0;\n canvasPerf.timings = {};\n samples.clear();\n}\n",
40
+ "/**\n * Slicing a block's content by CHARACTER OFFSET, preserving inline markup.\n *\n * A selection that spans blocks cuts through the middle of the first and last of them, so deleting\n * it means keeping `[0, from)` of one block and `[to, end)` of another — by rendered character\n * position, across whatever nesting of `<strong>`, `<em>`, `<code>` and links the author has built.\n * Cutting \"he**ll**o\" at offset 3 has to yield \"he\" + a bold \"l\", not a truncated string.\n *\n * The offsets here are the same ones {@link file://../canvas/iframe-position.ts} produces from the\n * DOM, so a caret position and a content slice always agree on what \"offset 3\" means.\n *\n * Pure: no DOM, no document, no reactivity — the whole thing is exercisable as data.\n *\n * @docs studio/editing/writing\n */\n\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** A block's content as a children array — the form both storage shapes normalize to. */\nexport type Content = (JxMutableNode | string)[];\n\n/**\n * The content of `node` as a children array, whichever way it is stored.\n *\n * A block holds its text either as `textContent` (all-plain) or as `children` (mixed inline\n * markup), and every operation that joins or cuts blocks has to handle both.\n */\nexport function contentOf(node: JxMutableNode | undefined | null): Content {\n if (!node) {\n return [];\n }\n if (Array.isArray(node.children)) {\n return node.children as Content;\n }\n return typeof node.textContent === \"string\" && node.textContent.length > 0\n ? [node.textContent]\n : [];\n}\n\n/** The rendered text length of a content array. */\nexport function contentLength(children: Content): number {\n let n = 0;\n for (const child of children) {\n n += typeof child === \"string\" ? child.length : contentLength(contentOf(child));\n }\n return n;\n}\n\n/**\n * The sub-content covering characters `[start, end)`, with inline elements preserved.\n *\n * An inline element that straddles a boundary is kept with its content clipped — so cutting a bold\n * run in half leaves a shorter bold run, not plain text. Elements that fall entirely outside the\n * range are dropped; empty results are omitted rather than left as empty tags.\n */\nexport function sliceContent(children: Content, start: number, end: number): Content {\n const out: Content = [];\n let pos = 0;\n for (const child of children) {\n if (pos >= end) {\n break;\n }\n if (typeof child === \"string\") {\n const childEnd = pos + child.length;\n if (childEnd > start) {\n const text = child.slice(\n Math.max(0, start - pos),\n Math.max(0, Math.min(end, childEnd) - pos),\n );\n if (text) {\n out.push(text);\n }\n }\n pos = childEnd;\n continue;\n }\n const inner = contentOf(child);\n const len = contentLength(inner);\n const childEnd = pos + len;\n if (len === 0) {\n // A void inline (a `<br>`, an `<img>`) contributes no characters, so it can never satisfy a\n // Length-based overlap test — it sits AT a position rather than spanning one. Keep it when\n // The range covers that position, or every slice would silently drop it.\n if (pos >= start && pos < end) {\n // Copied verbatim: giving a `<br>` an empty `textContent` would be noise in the source.\n out.push({ ...child });\n }\n } else if (childEnd > start) {\n const kept = sliceContent(inner, Math.max(0, start - pos), Math.min(end, childEnd) - pos);\n if (kept.length > 0) {\n out.push(withContent(child, kept));\n }\n }\n pos = childEnd;\n }\n return out;\n}\n\n/** A copy of `node` carrying `children`, folded back to `textContent` when it is all plain text. */\nfunction withContent(node: JxMutableNode, children: Content): JxMutableNode {\n const { children: _drop, textContent: _dropText, ...rest } = node;\n if (children.length === 0) {\n return { ...rest, textContent: \"\" };\n }\n if (children.length === 1 && typeof children[0] === \"string\") {\n return { ...rest, textContent: children[0] };\n }\n return { ...rest, children };\n}\n\n/**\n * Merge adjacent plain strings and drop empties, so a spliced result does not carry the seams of\n * how it was built. Mirrors the normalization a contenteditable commit performs.\n */\nexport function normalizeContent(children: Content): Content {\n const out: Content = [];\n for (const child of children) {\n if (typeof child === \"string\") {\n if (child.length === 0) {\n continue;\n }\n const prev = out.at(-1);\n if (typeof prev === \"string\") {\n out[out.length - 1] = prev + child;\n continue;\n }\n }\n out.push(child);\n }\n return out;\n}\n\n/**\n * The content a block should hold after `[from, to)` is replaced by `text`, where `head` is the\n * block the range starts in and `tail` the block it ends in.\n *\n * Collapsing a cross-block range is the same shape as a merge: keep the head's prefix, keep the\n * tail's suffix, and join them — with any typed replacement between.\n */\nexport function spliceAcross(\n head: Content,\n from: number,\n tail: Content,\n to: number,\n text = \"\",\n): Content {\n return normalizeContent([\n ...sliceContent(head, 0, from),\n ...(text ? [text] : []),\n ...sliceContent(tail, to, contentLength(tail)),\n ]);\n}\n\n/** `{ children }` when the content carries markup, else the folded `{ textContent }` form. */\nexport function toStored(children: Content): {\n children?: Content;\n textContent?: string;\n} {\n const normalized = normalizeContent(children);\n if (normalized.length === 0) {\n return { textContent: \"\" };\n }\n if (normalized.length === 1 && typeof normalized[0] === \"string\") {\n return { textContent: normalized[0] };\n }\n return { children: normalized };\n}\n",
41
+ "/// <reference lib=\"dom\" />\n/**\n * Inline-edit apply logic — turns the serializable result of a contenteditable session (committed\n * children/text, a split, or a slash-insert) into `transactDoc` mutations. The inline editing\n * session lives inside the canvas iframe, which posts these plain-JSON results across the bridge\n * for this apply. Every input here is plain JSON — no DOM, no Range — so it crosses the frame\n * boundary.\n */\n\nimport { childIndex, getNodeAtPath, parentElementPath } from \"../store\";\nimport { isAncestor } from \"../state\";\nimport { isTabActive } from \"../workspace/workspace\";\nimport {\n mutateInsertNode,\n mutateRemoveNode,\n mutateUpdateProp,\n mutateUpdateProperty,\n transactDoc,\n} from \"../tabs/transact\";\nimport { defaultDef } from \"../panels/shared\";\n\nimport { contentLength, contentOf, spliceAcross, toStored } from \"./content-slice\";\nimport type { JxContentResult, SlashCommand } from \"./inline-edit\";\nimport type { JxPath } from \"../state\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * Whether a committed inline-edit result is effectively empty (blank text / lone whitespace /\n * `<br>`).\n */\nexport function isEmptyContent(commitData?: JxContentResult): boolean {\n if (!commitData) {\n return true;\n }\n if (commitData.textContent != null && commitData.textContent.trim() === \"\") {\n return true;\n }\n const kids = commitData.children;\n if (!kids) {\n return false;\n }\n if (kids.length === 0) {\n return true;\n }\n if (kids.length === 1 && typeof kids[0] === \"string\" && kids[0].trim() === \"\") {\n return true;\n }\n return kids.length === 1 && typeof kids[0] === \"object\" && kids[0]?.tagName === \"br\";\n}\n\n/**\n * Commit edited content to the node at `path` of `tab`'s document (children when rich, else\n * textContent). No-op if unchanged or the originating tab is gone. `tab` is the tab the edit\n * session belonged to (resolved host-side from the posting iframe) — NEVER the active tab at\n * message time, which may have changed while the commit was in flight.\n */\nexport function applyInlineCommit(\n tab: Tab | null,\n path: JxPath,\n children: (JxMutableNode | string)[] | null,\n textContent: string | null,\n opts: { coalesceKey?: string | null } = {},\n): void {\n if (!tab) {\n return;\n }\n const node = getNodeAtPath(tab.doc.document, path);\n // Only clear the counterpart key when it actually exists: deleting an absent key is a semantic\n // No-op, but the recorded op isn't — a spurious `set-prop children` turns a cheap in-place text\n // Patch into a subtree re-render (and, pre-relaxation, forced a full render inside components).\n if (children) {\n if (node && JSON.stringify(node.children) === JSON.stringify(children)) {\n return;\n }\n transactDoc(\n tab,\n (t) => {\n if (node?.textContent != null) {\n mutateUpdateProperty(t, path, \"textContent\");\n }\n mutateUpdateProperty(t, path, \"children\", children);\n },\n { coalesceKey: opts.coalesceKey ?? null },\n );\n } else if (textContent != null) {\n if (node && node.textContent === textContent && !node.children) {\n return;\n }\n transactDoc(\n tab,\n (t) => {\n if (node?.children) {\n mutateUpdateProperty(t, path, \"children\");\n }\n mutateUpdateProperty(t, path, \"textContent\", textContent);\n },\n { coalesceKey: opts.coalesceKey ?? null },\n );\n }\n}\n\n/**\n * Commit a prop-bound inline edit: persist `value` into `$props[prop]` of the component instance at\n * `path`. The unchanged-value no-op is LOAD-BEARING, not cosmetic: Escape-cancel and\n * patch-disturbed sessions post unchanged values, and without the equality check a commit→patch→\n * disturb→re-commit cycle loops (and pollutes undo history). An empty value deletes the prop\n * (mutateUpdateProp), reverting the instance to the definition default — same as clearing the\n * sidebar field.\n */\nexport function applyInlinePropCommit(\n tab: Tab | null,\n path: JxPath,\n prop: string,\n value: string,\n): void {\n if (!tab) {\n return;\n }\n const node = getNodeAtPath(tab.doc.document, path);\n if (!node) {\n return;\n }\n const current = (node.$props as Record<string, unknown> | undefined)?.[prop];\n if (`${current ?? \"\"}` === value) {\n return;\n }\n transactDoc(tab, (t) => {\n mutateUpdateProp(t, path, prop, value);\n });\n}\n\n/**\n * Join the block at `fromPath` onto the end of the block at `intoPath`, removing the former.\n *\n * Backspace at a block's start and Delete at a block's end are the same operation approached from\n * either side, so both land here. Returns the caret's document position at the seam — the join\n * point, not the end — or null when the merge was refused.\n *\n * Refused when either block is missing, or when one contains the other: a `<li>` and the `<p>`\n * inside it are adjacent in document order but merging them would mean a node absorbing its own\n * parent.\n */\nexport function applyBlockMerge(\n tab: Tab | null,\n fromPath: JxPath,\n intoPath: JxPath,\n): { path: JxPath; offset: number } | null {\n if (!tab) {\n return null;\n }\n const from = getNodeAtPath(tab.doc.document, fromPath) as JxMutableNode | undefined;\n const into = getNodeAtPath(tab.doc.document, intoPath) as JxMutableNode | undefined;\n if (!from || !into) {\n return null;\n }\n if (isAncestor(fromPath, intoPath) || isAncestor(intoPath, fromPath)) {\n return null;\n }\n\n const head = contentOf(into);\n const tail = contentOf(from);\n const seam = contentLength(head);\n const merged = toStored([...head, ...tail]);\n\n transactDoc(tab, (t) => {\n // Write the joined content BEFORE removing the source: updating a node never shifts indices,\n // So `fromPath` is still valid when the removal runs.\n if (merged.children) {\n if (into.textContent != null) {\n mutateUpdateProperty(t, intoPath, \"textContent\");\n }\n mutateUpdateProperty(t, intoPath, \"children\", merged.children);\n } else {\n if (into.children) {\n mutateUpdateProperty(t, intoPath, \"children\");\n }\n mutateUpdateProperty(t, intoPath, \"textContent\", merged.textContent ?? \"\");\n }\n mutateRemoveNode(t, fromPath);\n // A container emptied by the removal (the `<ul>` behind a list's last item) would otherwise\n // Linger as invisible structure that still occupies layout and shows up in the layers panel.\n pruneEmptyAncestors(t, parentElementPath(fromPath) as JxPath);\n if (isTabActive(tab)) {\n t.session.selection = [intoPath];\n }\n });\n\n return { offset: seam, path: intoPath };\n}\n\n/**\n * Remove `path` and its now-childless ancestors, stopping at the document root or the first\n * ancestor that still has content.\n */\nfunction pruneEmptyAncestors(tab: Tab, path: JxPath): void {\n let cur = path;\n while (cur.length > 0) {\n const node = getNodeAtPath(tab.doc.document, cur) as JxMutableNode | undefined;\n const kids = node?.children;\n if (!node || !Array.isArray(kids) || kids.length > 0) {\n return;\n }\n const parent = parentElementPath(cur) as JxPath | null;\n mutateRemoveNode(tab, cur);\n if (!parent) {\n return;\n }\n cur = parent;\n }\n}\n\n/**\n * Apply a paragraph split to `tab`'s document: keep `before` in the node, insert a new `<p>` with\n * `after`. Returns its path (unchanged when `tab` is gone — the caller may still use it for\n * bookkeeping, but nothing is mutated).\n */\nexport function applyInlineSplit(\n tab: Tab | null,\n path: JxPath,\n before: JxContentResult,\n after: JxContentResult,\n): JxPath {\n const parentPath = parentElementPath(path) as JxPath;\n const idx = childIndex(path) as number;\n const newPath = [...parentPath, \"children\", idx + 1];\n if (!tab) {\n return newPath;\n }\n const newNode: JxMutableNode = { tagName: \"p\" };\n if (after.textContent != null) {\n newNode.textContent = after.textContent;\n } else if (after.children) {\n newNode.children = after.children;\n } else {\n newNode.textContent = \"\";\n }\n\n transactDoc(tab, (t) => {\n if (before.textContent != null) {\n mutateUpdateProperty(t, path, \"children\");\n mutateUpdateProperty(t, path, \"textContent\", before.textContent);\n } else if (before.children) {\n mutateUpdateProperty(t, path, \"textContent\");\n mutateUpdateProperty(t, path, \"children\", before.children);\n }\n mutateInsertNode(t, parentPath, idx + 1, newNode);\n // A background tab's selection stays exactly as the user left it — only the visible tab's\n // Selection follows the split.\n if (isTabActive(tab)) {\n t.session.selection = [newPath];\n }\n });\n return newPath;\n}\n\n/**\n * Apply a slash-insert at `path` of `tab`'s document: swap the (empty) node's tag in place, or\n * commit pending content and insert a new element after it. Returns the path to edit next (the\n * swapped node or the new one); nothing is mutated when `tab` is gone.\n */\nexport function applyInlineInsert(\n tab: Tab | null,\n path: JxPath,\n cmd: SlashCommand,\n commitData: JxContentResult | undefined,\n): JxPath {\n if (isEmptyContent(commitData)) {\n if (!tab) {\n return path;\n }\n transactDoc(tab, (t) => {\n mutateUpdateProperty(t, path, \"tagName\", cmd.tag);\n mutateUpdateProperty(t, path, \"children\");\n const def = defaultDef(cmd.tag);\n if (def.textContent && def.textContent !== \"Paragraph text\") {\n mutateUpdateProperty(t, path, \"textContent\", def.textContent);\n } else {\n mutateUpdateProperty(t, path, \"textContent\");\n }\n if (isTabActive(tab)) {\n t.session.selection = [path];\n }\n });\n return path;\n }\n\n const parentPath = parentElementPath(path) as JxPath;\n const idx = childIndex(path) as number;\n const newPath = [...parentPath, \"children\", idx + 1];\n if (!tab) {\n return newPath;\n }\n const elementDef = defaultDef(cmd.tag);\n\n transactDoc(tab, (t) => {\n if (commitData?.children) {\n mutateUpdateProperty(t, path, \"textContent\");\n mutateUpdateProperty(t, path, \"children\", commitData.children);\n } else if (commitData?.textContent != null) {\n mutateUpdateProperty(t, path, \"children\");\n mutateUpdateProperty(t, path, \"textContent\", commitData.textContent);\n }\n mutateInsertNode(t, parentPath, idx + 1, structuredClone(elementDef));\n if (isTabActive(tab)) {\n t.session.selection = [newPath];\n }\n });\n return newPath;\n}\n\n/**\n * Replace a selection that spans blocks with `text` (empty for a deletion).\n *\n * Collapsing a cross-block range is a merge with both ends clipped: the first block keeps what\n * precedes the selection, the last keeps what follows it, the two are joined, and every block\n * between them is removed. `between` is supplied by the iframe because document order lives in the\n * rendered DOM — the same reason a boundary merge names its neighbour there.\n *\n * Returns the caret's position after the collapse (the join point, plus any typed text), or null\n * when the range does not resolve.\n */\nexport function applyRangeReplace(\n tab: Tab | null,\n from: { path: JxPath; offset: number },\n to: { path: JxPath; offset: number },\n between: JxPath[],\n text: string,\n): { path: JxPath; offset: number } | null {\n if (!tab) {\n return null;\n }\n const head = getNodeAtPath(tab.doc.document, from.path) as JxMutableNode | undefined;\n const tail = getNodeAtPath(tab.doc.document, to.path) as JxMutableNode | undefined;\n if (!head || !tail) {\n return null;\n }\n if (isAncestor(from.path, to.path) || isAncestor(to.path, from.path)) {\n return null;\n }\n\n const joined = toStored(\n spliceAcross(contentOf(head), from.offset, contentOf(tail), to.offset, text),\n );\n // Remove the deepest/last paths first so an earlier removal cannot shift a later one's index.\n const removals = [...between, to.path].toSorted(comparePathsDescending);\n\n transactDoc(tab, (t) => {\n if (joined.children) {\n if (head.textContent != null) {\n mutateUpdateProperty(t, from.path, \"textContent\");\n }\n mutateUpdateProperty(t, from.path, \"children\", joined.children);\n } else {\n if (head.children) {\n mutateUpdateProperty(t, from.path, \"children\");\n }\n mutateUpdateProperty(t, from.path, \"textContent\", joined.textContent ?? \"\");\n }\n for (const path of removals) {\n if (getNodeAtPath(t.doc.document, path)) {\n mutateRemoveNode(t, path);\n pruneEmptyAncestors(t, parentElementPath(path) as JxPath);\n }\n }\n if (isTabActive(tab)) {\n t.session.selection = [from.path];\n }\n });\n\n return { offset: from.offset + text.length, path: from.path };\n}\n\n/**\n * Order two paths so the LATER one in the document sorts first — the order removals must run in,\n * since removing an earlier sibling renumbers every path after it.\n */\nfunction comparePathsDescending(a: JxPath, b: JxPath): number {\n const len = Math.min(a.length, b.length);\n for (let i = 0; i < len; i++) {\n const av = a[i];\n const bv = b[i];\n if (av === bv) {\n continue;\n }\n if (typeof av === \"number\" && typeof bv === \"number\") {\n return bv - av;\n }\n return String(bv).localeCompare(String(av));\n }\n return b.length - a.length;\n}\n",
42
+ "/// <reference lib=\"dom\" />\n/**\n * Parent-side canvas overlay layer for the iframe host. Because the cross-origin bridge forbids the\n * parent from reading the iframe's DOM, selection/hover boxes are drawn from rects the iframe posts\n * back (see {@link measureHits}/`hover`). This module owns the pure rect→overlay math ({@link\n * canvasRectToParent}) and a small DOM layer that floats above the iframe, reusing the same\n * `overlay-box`/`overlay-selection`/`overlay-hover` classes as the legacy canvas for visual\n * parity.\n */\n\nimport type { SerializableRect } from \"./iframe-protocol\";\n\n/** An overlay box position in the parent overlay layer's local coordinates. */\nexport interface OverlayPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n/**\n * Map a rect measured in the iframe's own viewport to the parent overlay layer's coordinates. The\n * overlay layer is positioned exactly over the iframe (same top-left), so the only transform is the\n * zoom `scale` (applied as a CSS `transform: scale()` on the iframe element, hence a plain multiply\n * here). Kept pure so the zoom math is unit-tested independently of the DOM.\n */\nexport function canvasRectToParent(rect: SerializableRect, scale = 1): OverlayPlacement {\n return {\n height: rect.height * scale,\n left: rect.x * scale,\n top: rect.y * scale,\n width: rect.width * scale,\n };\n}\n\n/**\n * Map a parent-viewport cursor (e.g. a pragmatic `location.current.input`, in true post-transform\n * parent px) into the iframe's own viewport coordinates. The iframe + overlay are descendants of\n * the scaled `panzoom-wrap`, so the cursor must be DIVIDED by the zoom `scale` (the inverse of the\n * CSS `transform: scale()` the browser already applied). `iframeRect` is `rectOf(iframe)` (its GBCR\n * bakes in pan + scale, so subtracting its `left`/`top` cancels the pan offset). Pure, so the\n * sign/order of the transform is unit-tested independently of the DOM. Empirical `scale` is derived\n * by the caller as `rectOf(iframe).width / iframe.clientWidth` (NOT `effectiveZoom()` — a separate\n * path that can desync).\n */\nexport function parentCursorToIframe(\n cursor: { x: number; y: number },\n iframeRect: { left: number; top: number },\n scale = 1,\n): { x: number; y: number } {\n return {\n x: (cursor.x - iframeRect.left) / scale,\n y: (cursor.y - iframeRect.top) / scale,\n };\n}\n\n/** The geometric side a drop indicator draws on (mirrors {@link DropPreview}'s `edge`). */\nexport type DropEdge = \"top\" | \"bottom\" | \"inside\";\n\n/** A floating overlay layer over the iframe that draws a selection box and a hover box. */\nexport interface OverlayLayer {\n /**\n * Position the selection box (or hide it when `placement` is null). `label` shows a small badge\n * on the box (stylebook draws the selected tag, e.g. \"<p>\", via the legacy `.overlay-label` CSS);\n * omitted/null hides it.\n */\n setSelection: (placement: OverlayPlacement | null, label?: string | null) => void;\n /**\n * Draw remote collaborators' selection boxes (colored outline + name tag). Replaces the whole set\n * each call; pass [] to clear. Placements are overlay-local coords like setSelection's.\n */\n setPresence: (items: { placement: OverlayPlacement; color: string; label: string }[]) => void;\n /**\n * Draw the NON-primary members of a multi-selection (§6.5). Replaces the whole set each call;\n * pass [] to clear, which is what a selection of one always does — one selected node draws the\n * selection box and nothing else, exactly as it did before the selection became a list.\n */\n setCoSelection: (placements: OverlayPlacement[]) => void;\n /** Position the hover box (or hide it when `placement` is null). */\n setHover: (placement: OverlayPlacement | null) => void;\n /**\n * Draw the drop indicator for a drag-over (Phase 4c). `placement` is the reference node's rect in\n * overlay-local coords (the caller maps the iframe-space `referenceRect` via\n * {@link canvasRectToParent} at scale=1 — the overlay is INSIDE the scaled panzoom-wrap, so the\n * browser already scales it; multiplying by zoom would double-scale, D-2). `edge` \"inside\" → a\n * dashed box over the reference; \"top\"/\"bottom\" → a thin line at the reference's top/bottom edge.\n * Pass null to hide.\n */\n setDropIndicator: (placement: OverlayPlacement | null, edge?: DropEdge) => void;\n /**\n * Position the clickable insertion \"+\" at `placement` (overlay-local coords, mapped via\n * {@link canvasRectToParent} at scale=1 like the drop indicator, D-2), centered on the anchor box\n * and tagged with `edge` (for the `[data-edge]` styling). Pass null to hide it. This is the ONE\n * element on the otherwise `pointer-events:none` overlay that captures pointer events, so the\n * author can actually click it; the caller wires its click/mouseenter/mouseleave via\n * {@link insertButton}.\n */\n setInsertZone: (placement: OverlayPlacement | null, edge?: InsertButtonEdge) => void;\n /**\n * Highlight the image an external file drop would REPLACE (flow 5). Distinct from\n * {@link setDropIndicator}, which shows where a new element would be inserted — the two answer\n * different questions (\"this picture is about to change\" vs. \"the element lands here\"), so a drop\n * shows exactly one of them. `placement` is overlay-local like the others; null hides it.\n */\n setReplaceTarget: (placement: OverlayPlacement | null) => void;\n /**\n * Hide (or restore) the whole layer. Preview renders get it suppressed: the editing affordances\n * are gated message-by-message in the host, and this is the single switch that guarantees none of\n * them can be PAINTED over a page that is supposed to look shipped — including any box a\n * still-in-flight reply from a pre-preview render would otherwise land.\n */\n setSuppressed: (suppressed: boolean) => void;\n /** The clickable \"+\" button, so the caller can attach click + hover (grace-timer) listeners. */\n readonly insertButton: HTMLButtonElement;\n /** The layer root element (caller appends it over the iframe). */\n readonly root: HTMLElement;\n /** Remove the layer from the DOM. */\n dispose: () => void;\n}\n\n/** The geometric side the insertion \"+\" anchors to (mirrors {@link InsertZone}'s `edge`). */\nexport type InsertButtonEdge = \"top\" | \"bottom\" | \"left\" | \"right\" | \"center\";\n\nfunction place(box: HTMLElement, placement: OverlayPlacement | null): void {\n if (!placement) {\n box.style.display = \"none\";\n return;\n }\n box.style.display = \"block\";\n box.style.left = `${placement.left}px`;\n box.style.top = `${placement.top}px`;\n box.style.width = `${placement.width}px`;\n box.style.height = `${placement.height}px`;\n}\n\n/** Build (but do not mount) an overlay layer with hidden selection + hover boxes. */\nexport function createOverlayLayer(doc: Document = document): OverlayLayer {\n const root = doc.createElement(\"div\");\n root.className = \"jx-canvas-iframe-overlay\";\n // Float over the iframe without intercepting pointer events (the iframe handles its own hit-test).\n root.style.cssText = \"position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:2\";\n\n const selectionBox = doc.createElement(\"div\");\n selectionBox.className = \"overlay-box overlay-selection\";\n selectionBox.style.display = \"none\";\n\n const selectionLabel = doc.createElement(\"div\");\n selectionLabel.className = \"overlay-label\";\n selectionLabel.style.display = \"none\";\n selectionBox.append(selectionLabel);\n\n const hoverBox = doc.createElement(\"div\");\n hoverBox.className = \"overlay-box overlay-hover\";\n hoverBox.style.display = \"none\";\n\n // Reuses the legacy `.canvas-drop-indicator` CSS (`.line` = thin bar, `.inside` = dashed box).\n const dropBox = doc.createElement(\"div\");\n dropBox.className = \"canvas-drop-indicator\";\n dropBox.style.display = \"none\";\n\n // The clickable insertion \"+\" — reuses the legacy `.insertion-helper` circle styling. It is the\n // ONE element on the `pointer-events:none` overlay that re-enables pointer events, so the author\n // Can click it (the legacy CSS-anchor positioning rules are inert here — no `position-anchor` is\n // Set — so it is positioned explicitly via left/top by placeInsertButton).\n const insertButton = doc.createElement(\"button\");\n insertButton.className = \"insertion-helper\";\n insertButton.textContent = \"+\";\n insertButton.style.pointerEvents = \"auto\";\n insertButton.style.display = \"none\";\n\n // The \"this picture will be replaced\" highlight for an external file drop.\n const replaceBox = doc.createElement(\"div\");\n replaceBox.className = \"canvas-replace-target\";\n replaceBox.style.display = \"none\";\n\n // Remote collaborators' selection boxes live in their own container, replaced wholesale.\n const presenceGroup = doc.createElement(\"div\");\n presenceGroup.className = \"overlay-presence-group\";\n\n // The other members of a multi-selection, same container discipline as presence.\n const coSelectionGroup = doc.createElement(\"div\");\n coSelectionGroup.className = \"overlay-coselection-group\";\n\n root.append(\n hoverBox,\n selectionBox,\n coSelectionGroup,\n dropBox,\n replaceBox,\n insertButton,\n presenceGroup,\n );\n\n return {\n dispose: () => root.remove(),\n insertButton,\n root,\n setDropIndicator: (placement, edge = \"inside\") => placeDropIndicator(dropBox, placement, edge),\n setHover: (placement) => place(hoverBox, placement),\n setInsertZone: (placement, edge = \"center\") => placeInsertButton(insertButton, placement, edge),\n setReplaceTarget: (placement) => place(replaceBox, placement),\n setSuppressed: (suppressed) => {\n root.style.display = suppressed ? \"none\" : \"\";\n },\n setCoSelection: (placements) => {\n coSelectionGroup.replaceChildren();\n for (const placement of placements) {\n const box = doc.createElement(\"div\");\n box.className = \"overlay-box overlay-selection overlay-coselection\";\n place(box, placement);\n coSelectionGroup.append(box);\n }\n },\n setPresence: (items) => {\n presenceGroup.replaceChildren();\n for (const item of items) {\n const box = doc.createElement(\"div\");\n box.className = \"overlay-box overlay-presence\";\n box.style.cssText =\n `position:absolute;display:block;pointer-events:none;` +\n `outline:1.5px solid ${item.color};outline-offset:1px;` +\n `left:${item.placement.left}px;top:${item.placement.top}px;` +\n `width:${item.placement.width}px;height:${item.placement.height}px`;\n const tag = doc.createElement(\"div\");\n tag.className = \"overlay-presence-tag\";\n tag.textContent = item.label;\n tag.style.cssText =\n `position:absolute;top:-18px;left:-2px;padding:1px 5px;border-radius:3px;` +\n `font:10px/1.4 sans-serif;color:#fff;white-space:nowrap;background:${item.color}`;\n box.append(tag);\n presenceGroup.append(box);\n }\n },\n setSelection: (placement, label = null) => {\n place(selectionBox, placement);\n if (placement && label) {\n selectionLabel.textContent = label;\n selectionLabel.style.display = \"block\";\n } else {\n selectionLabel.style.display = \"none\";\n }\n },\n };\n}\n\n/**\n * Position the insertion \"+\" centered on the anchor `placement` (a zero-thickness edge box from the\n * iframe), or hide it when null. Sets `data-edge` for the `[data-edge]` styling and toggles the\n * `visible` class the legacy CSS uses (display + opacity). Explicit left/top centering replaces the\n * legacy CSS-anchor positioning, which can't reach across the iframe boundary.\n */\nfunction placeInsertButton(\n btn: HTMLButtonElement,\n placement: OverlayPlacement | null,\n edge: InsertButtonEdge,\n): void {\n if (!placement) {\n btn.style.display = \"none\";\n btn.classList.remove(\"visible\");\n return;\n }\n btn.dataset.edge = edge;\n btn.classList.add(\"visible\");\n // Center the 20×20 circle on the anchor box's midpoint (the edge for a zero-thickness box).\n btn.style.display = \"grid\";\n btn.style.left = `${placement.left + placement.width / 2}px`;\n btn.style.top = `${placement.top + placement.height / 2}px`;\n btn.style.translate = \"-50% -50%\";\n}\n\n/**\n * Position the drop indicator box. `inside` → a dashed box over the reference rect; `top`/`bottom`\n * → a thin horizontal line at the reference's top/bottom (full reference width, zero-height bar).\n * The placement is already in overlay-local coords at scale=1 (D-2).\n */\nfunction placeDropIndicator(\n box: HTMLElement,\n placement: OverlayPlacement | null,\n edge: DropEdge,\n): void {\n if (!placement) {\n box.style.display = \"none\";\n return;\n }\n box.style.display = \"block\";\n box.style.left = `${placement.left}px`;\n box.style.width = `${placement.width}px`;\n if (edge === \"inside\") {\n box.className = \"canvas-drop-indicator inside\";\n box.style.top = `${placement.top}px`;\n box.style.height = `${placement.height}px`;\n return;\n }\n box.className = \"canvas-drop-indicator line\";\n box.style.height = \"\";\n box.style.top = `${edge === \"top\" ? placement.top : placement.top + placement.height}px`;\n}\n",
43
+ "/// <reference lib=\"dom\" />\n/**\n * Render-path mapping — pure logic shared by the legacy in-realm path mapper (which stores paths in\n * the `elToPath` WeakMap) and the iframe host (which stamps them as `data-jx-path` attributes).\n *\n * The runtime fires `onNodeCreated(el, renderPath, def, state)` for every node. The render path is\n * not always the document path: layout-wrapped pages shift page content under a layout prefix, and\n * `prepareForEditMode` renders mapped arrays (`$prototype: Array`) as a `repeater-perimeter` whose\n * single child hop must be collapsed back to a `map` segment. {@link classifyRenderNode} resolves a\n * render path to either a document path or a \"layout\" marker; {@link serializeJxPath} encodes the\n * result for the `data-jx-path` attribute.\n */\n\nimport type { JxPath } from \"../state\";\n\n/** Context the mapper needs, computed once per render by whoever prepared the document. */\nexport interface PathMapCtx {\n canvasMode: string;\n layoutWrapped: boolean;\n pageContentPrefix: JxPath | null;\n pageContentOffset: number | null;\n arrayPaths: Set<string>;\n}\n\n/**\n * The marker `markLayoutNodes` stamps on every node of a resolved layout document (see\n * {@link file://./canvas-live-render.ts}). It names the layout FILE and the node's own path inside\n * that file — enough for the editor to select the node, label it, and open the layout at it. It\n * used to be a bare `true`, which is why clicking layout chrome on a fresh project selected nothing\n * at all: the render had thrown away the only two facts needed to act on the click.\n */\nexport interface LayoutMarker {\n /** Project-relative path of the layout document, e.g. `layouts/base.json`. */\n file: string;\n /** The node's path WITHIN the layout document. */\n path: JxPath;\n}\n\n/**\n * A render node either belongs to the layout (carrying its origin in the layout file, since it has\n * no page-document path) or maps to a page-document path.\n *\n * `chrome` distinguishes the two very different kinds of layout node. Most are chrome — a header, a\n * footer, a `<noscript>` — regions the page cannot edit in place. But the nodes on the path down to\n * the `<slot>` (the layout root, the `<main>` around it) WRAP the page content, so they must stay\n * transparent: dimming or freezing them would dim and freeze the whole document. Only chrome is\n * dimmed, labelled, and made `contenteditable=\"false\"`.\n */\nexport type RenderNodeClass =\n | { kind: \"layout\"; layoutFile: string; layoutPath: JxPath; chrome: boolean }\n | { kind: \"path\"; path: JxPath };\n\n/**\n * Whether `path` is the page-content container or one of its ancestors — i.e. whether this node's\n * subtree contains the distributed page content. `prefix` is the render path of the container whose\n * children hold that content (`PathMapCtx.pageContentPrefix`).\n */\nexport function wrapsPageContent(path: JxPath, prefix: JxPath | null): boolean {\n if (!prefix) {\n return false;\n }\n return path.length <= prefix.length && path.every((seg, i) => prefix[i] === seg);\n}\n\n/**\n * Resolve a runtime render path to a document path (or flag it as layout-originated). Pure — the\n * caller decides whether to record the result in a WeakMap or `data-jx-*` attributes.\n */\nexport function classifyRenderNode(path: JxPath, def: unknown, ctx: PathMapCtx): RenderNodeClass {\n // Layout-originated nodes have no page-document path; the caller stamps their origin instead\n // (data-jx-layout-path / data-jx-layout-file).\n const marker =\n ctx.layoutWrapped && typeof def === \"object\"\n ? (def as { $__layout?: unknown } | null)?.$__layout\n : undefined;\n if (marker) {\n const origin = (typeof marker === \"object\" ? marker : {}) as Partial<LayoutMarker>;\n return {\n // The root is never chrome even when the layout distributed nothing: it IS the render, and a\n // Dimmed, frozen root would be a canvas nobody can touch.\n chrome: path.length > 0 && !wrapsPageContent(path, ctx.pageContentPrefix),\n kind: \"layout\",\n layoutFile: typeof origin.file === \"string\" ? origin.file : \"\",\n layoutPath: Array.isArray(origin.path) ? origin.path : [],\n };\n }\n\n let mappedPath = path;\n\n // Strip the layout prefix so paths are relative to the original page document.\n // Page children render at indices [offset, offset+1, …] when the layout places siblings before\n // The <slot>, so subtract the offset to recover the page's 0-based child indices.\n if (ctx.layoutWrapped && ctx.pageContentPrefix) {\n const pfx = ctx.pageContentPrefix;\n if (path.length >= pfx.length && pfx.every((seg, i) => path[i] === seg)) {\n const rest = path.slice(pfx.length);\n const [containerIdx] = rest;\n mappedPath =\n typeof containerIdx === \"number\"\n ? [\"children\", containerIdx - (ctx.pageContentOffset ?? 0), ...rest.slice(1)]\n : [\"children\", ...rest];\n }\n }\n\n // Collapse repeater-perimeter template hops: for an array document path P, a render path of\n // `[...P, \"children\", 0, ...rest]` maps to `[...P, \"map\", ...rest]`. Loop for nested repeaters.\n if ((ctx.canvasMode === \"design\" || ctx.canvasMode === \"edit\") && ctx.arrayPaths.size > 0) {\n let changed = true;\n while (changed) {\n changed = false;\n for (let i = 1; i < mappedPath.length - 1; i++) {\n if (\n mappedPath[i] === \"children\" &&\n mappedPath[i + 1] === 0 &&\n ctx.arrayPaths.has(mappedPath.slice(0, i).join(\"/\"))\n ) {\n mappedPath = [...mappedPath.slice(0, i), \"map\", ...mappedPath.slice(i + 2)];\n changed = true;\n break;\n }\n }\n }\n }\n\n return { kind: \"path\", path: mappedPath };\n}\n\n/** Encode a document path for the `data-jx-path` attribute (preserves string-vs-number segments). */\nexport function serializeJxPath(path: JxPath): string {\n return JSON.stringify(path);\n}\n\n/** Decode a `data-jx-path` attribute back into a document path. */\nexport function parseJxPath(serialized: string): JxPath {\n return JSON.parse(serialized) as JxPath;\n}\n",
44
+ "/// <reference lib=\"dom\" />\n/**\n * Cross-frame drag GHOST (Phase 4c, commit 5). A single parent-realm `position:fixed` layer that\n * follows the raw pointer 1:1 during a canvas drag. It lives OUTSIDE the scaled `panzoom-wrap`\n * (D-3) — a sibling of `#canvas-wrap` on `<body>` — so it tracks `clientX`/`clientY` directly and\n * is NEVER subject to the canvas zoom transform (drawing it in the scaled overlay would shrink/grow\n * it with zoom). pragmatic's native drag image is suppressed per source via\n * `disableNativeDragPreview`, so this is the only drag affordance the user sees.\n *\n * One ghost is reused across drags + panels: {@link setDragGhost} shows it with a label and moves\n * it to a cursor; {@link clearDragGhost} hides it. The element is created lazily on first show so\n * the module has no import-time DOM side effect (and stays inert in tests until used).\n */\n\nlet ghostEl: HTMLElement | null = null;\n\n/** Lazily create (once) the fixed ghost element appended to `<body>`. */\nfunction ensureGhost(doc: Document): HTMLElement {\n if (ghostEl?.isConnected) {\n return ghostEl;\n }\n const el = doc.createElement(\"div\");\n el.className = \"jx-drag-ghost\";\n // Fixed + non-interactive + above the canvas; offset slightly from the cursor so it doesn't sit\n // Under the pointer and block hit-testing visuals. Positioned via left/top on each move.\n el.style.cssText =\n \"position:fixed;left:0;top:0;z-index:9999;pointer-events:none;display:none;\" +\n \"padding:2px 8px;border-radius:4px;font-size:12px;line-height:1.4;white-space:nowrap;\" +\n \"background:var(--accent,#3b82f6);color:var(--accent-fg,#fff);box-shadow:0 2px 8px rgba(0,0,0,0.25);\" +\n \"transform:translate(8px,8px)\";\n doc.body.append(el);\n ghostEl = el;\n return el;\n}\n\n/**\n * Show the ghost with `label`, positioned at the raw pointer (`x`,`y` in parent-viewport px). Safe\n * to call every pointermove; reuses the one element.\n */\nexport function setDragGhost(label: string, x: number, y: number, doc: Document = document): void {\n const el = ensureGhost(doc);\n el.textContent = label;\n el.style.left = `${x}px`;\n el.style.top = `${y}px`;\n el.style.display = \"block\";\n}\n\n/** Move the ghost to a new pointer position without changing its label (no-op when hidden). */\nexport function moveDragGhost(x: number, y: number): void {\n if (!ghostEl || ghostEl.style.display === \"none\") {\n return;\n }\n ghostEl.style.left = `${x}px`;\n ghostEl.style.top = `${y}px`;\n}\n\n/** Hide the ghost (between drags). The element is retained for reuse. */\nexport function clearDragGhost(): void {\n if (ghostEl) {\n ghostEl.style.display = \"none\";\n }\n}\n",
45
+ "/**\n * Constraints — generic interpreter for a format class's `$studio.elements` metadata.\n *\n * Element allowlists and nesting rules are declared by the format (.class.json), not the studio;\n * this module turns that declaration into the validation helpers the editing surfaces use. Replaces\n * the hard-coded markdown allowlist.\n */\n\nimport type { StudioFormatHints } from \"./format-host\";\n\ntype ElementsHints = NonNullable<StudioFormatHints[\"elements\"]>;\n\nexport interface NestingValidator {\n blockTags: ReadonlySet<string>;\n inlineTags: ReadonlySet<string>;\n allTags: ReadonlySet<string>;\n isVoid: (tag: string) => boolean;\n isTextOnly: (tag: string) => boolean;\n /** Whether childTag may appear inside parentTag (\"_root\" for the document root). */\n isValidChild: (parentTag: string, childTag: string) => boolean;\n}\n\n/** Build a nesting validator from a format's `$studio.elements` declaration. */\nexport function createNestingValidator(elements?: ElementsHints): NestingValidator {\n const blockTags = new Set(elements?.block);\n const inlineTags = new Set(elements?.inline);\n const allTags = new Set([...blockTags, ...inlineTags]);\n const voidTags = new Set(elements?.void);\n const textOnly = new Set(elements?.textOnly);\n const nesting = elements?.nesting ?? {};\n\n return {\n allTags,\n blockTags,\n inlineTags,\n isTextOnly: (tag) => textOnly.has(tag),\n isValidChild(parentTag, childTag) {\n const rule = nesting[parentTag];\n if (!rule) {\n return true;\n } // Unknown parents (directive components) allow anything\n\n if (rule.only) {\n return rule.only.includes(childTag);\n }\n\n const isBlock = blockTags.has(childTag);\n const isInline = inlineTags.has(childTag);\n const isDirective = !allTags.has(childTag);\n\n if (isBlock && rule.block) {\n return true;\n }\n if (isInline && rule.inline) {\n return true;\n }\n if (isDirective && rule.directive) {\n return true;\n }\n\n return false;\n },\n isVoid: (tag) => voidTags.has(tag),\n };\n}\n\n/**\n * The format's verdict on which of ITS tags can hold a text caret, as a plain `tag → boolean` map.\n *\n * A caret belongs in a tag that accepts inline children. The format's `nesting` declaration already\n * says exactly that, so nothing needs re-deriving from tag names:\n *\n * - `nesting[tag].inline === true` — the tag holds text. Headings, paragraphs, list items, cells.\n * - `nesting[tag]` present without it — a container. Markdown's `blockquote` is `inline: false`\n * because it holds paragraphs, so the caret belongs in the `<p>` inside it, not the quote; `ul`,\n * `table` and `pre` use `only: [...]` and hold no text at all.\n * - The tag is in the format's `inline` list — it is markup WITHIN a block, not a block. Without\n * this, clicking a link would make the link itself the active block, and typing would commit to\n * the anchor's path rather than the paragraph's.\n *\n * Only tags the format actually mentions appear here. A tag it says nothing about — HTML that\n * reaches the canvas through a directive — is left to the studio's own element metadata, so this\n * map is a set of OVERRIDES rather than a complete answer.\n *\n * Returned as a plain object because it crosses to the canvas frame with the render message.\n */\nexport function formatEditableVerdicts(elements?: ElementsHints): Record<string, boolean> {\n const verdicts: Record<string, boolean> = {};\n for (const [tag, rule] of Object.entries(elements?.nesting ?? {})) {\n // \"_root\" is the document itself, not an element.\n if (tag !== \"_root\") {\n verdicts[tag] = rule?.inline === true;\n }\n }\n for (const tag of elements?.inline ?? []) {\n verdicts[tag] = false;\n }\n return verdicts;\n}\n",
46
+ "/// <reference lib=\"dom\" />\n/**\n * Parent-side iframe canvas host — manages the `<iframe>` that renders a panel's document. It keeps\n * one iframe per canvas element (reused across re-renders), resolves the document parent-side via\n * {@link resolveCanvasDocument}, and posts it over the authenticated channel once the iframe\n * signals `ready`. The parent never reads the iframe's DOM (cross-origin bridge model); it only\n * sends.\n */\n\nimport { postMessageChannel } from \"./iframe-channel\";\nimport { canvasBaseOrigin } from \"./canvas-origin\";\nimport { getPreviewNavigateHandler } from \"./preview-navigate\";\nimport { resolveCanvasDocument } from \"./canvas-live-render\";\nimport { canvasPerf, recordEscalation, SPAN_PREPARE_RENDER, timeSpanAsync } from \"./canvas-perf\";\nimport {\n applyBlockMerge,\n applyInlineCommit,\n applyRangeReplace,\n applyInlinePropCommit,\n applyInlineInsert,\n applyInlineSplit,\n} from \"../editor/inline-edit-apply\";\nimport { canvasRectToParent, createOverlayLayer } from \"./iframe-overlay\";\nimport { serializeJxPath } from \"./path-mapping\";\nimport { getActivePanel, panelMediaToActiveMedia } from \"./canvas-helpers\";\nimport { panToParentRect } from \"./canvas-utils\";\nimport { clearDragGhost, moveDragGhost } from \"../panels/drag-ghost\";\nimport { applyDropInstruction } from \"../panels/dnd\";\nimport { rectOf } from \"../utils/geometry\";\nimport { notify } from \"../services/notify\";\nimport { effect, effectScope } from \"../reactivity\";\nimport { pathsEqual, projectState, renderOnly } from \"../store\";\nimport { activeTab, focusPane, workspace } from \"../workspace/workspace\";\nimport {\n paneOfContainer,\n panelHostingCanvas,\n stageContaining,\n tabOfContainer,\n} from \"./canvas-surface\";\nimport { cloneSelection, primarySelection, toggleSelected } from \"../tabs/selection\";\nimport type { JxPath } from \"../state\";\nimport { setLayoutSelection, shell } from \"../shell\";\nimport { formatEditableVerdicts } from \"../format/constraints\";\nimport { formatByName } from \"../format/format-host\";\nimport { collabState } from \"../collab/collab-state\";\nimport { localeDirection } from \"@jxsuite/schema/locale\";\nimport { getPlatform, hasPlatform } from \"../platform\";\nimport type {\n ApplyFormatIntent,\n CanvasMode,\n DragSrcKind,\n DropPreview,\n EvalExprResult,\n FileDropHit,\n IframeToParent,\n InsertZone,\n NodeHit,\n ParentToIframe,\n SelectionSnapshot,\n SerializableRect,\n SerializedKey,\n SyncedChord,\n WireDocOp,\n} from \"./iframe-protocol\";\nimport type { IframeChannel } from \"./iframe-channel\";\nimport type { OverlayLayer, OverlayPlacement } from \"./iframe-overlay\";\nimport type { SlashCommand } from \"../editor/inline-edit\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxExpressionNode, JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** A rect in PARENT coordinates (overlay-local from {@link canvasRectToParent}, same field shape). */\ntype ParentRect = OverlayPlacement;\n\ninterface HostState {\n iframe: HTMLIFrameElement;\n /** The `.canvas-panel-canvas` element hosting the iframe + overlay (the WeakMap key). */\n canvasEl: HTMLElement;\n channel: IframeChannel<ParentToIframe, IframeToParent>;\n /**\n * The resolved canvasUrl this iframe was built with — so a host built early with the default URL\n * is rebuilt once the platform's loopback canvasUrl becomes available (electrobun resolves it\n * async).\n */\n canvasUrl: string;\n ready: boolean;\n pending: ParentToIframe | null;\n overlay: OverlayLayer;\n /** Primary selected path (mirrors `session.selection`'s last entry), for hover de-dupe. */\n selectionPath: (string | number)[] | null;\n /** The whole selection this host last measured, so a re-measure redraws every box. */\n selectionPaths: JxPath[];\n /** Id of the most recent selection `measure` request, so stale `geometry` replies are dropped. */\n selReqId: number;\n /**\n * The NON-primary selected paths the in-flight selection `measure` covers, serialized. The\n * geometry reply draws a co-selection box for every hit whose path is in this set — a set of one\n * selected node leaves it empty, so nothing but the selection box is ever drawn.\n */\n coSelectionKeys: Set<string>;\n /** Id of the most recent presence `measure` request (allocated from the selReqId counter). */\n presenceReqId: number;\n /** Serialized peer path → presence box meta for the in-flight presence measure. */\n presenceMeta: Map<string, { color: string; label: string }>;\n /**\n * Whether this host's iframe currently renders a PREVIEW. Preview is the fidelity view, so the\n * host refuses every editing message from it ({@link PREVIEW_BLOCKED}), suppresses the overlay\n * layer, and leaves the iframe at its CSS height so the frame scrolls its own document.\n *\n * Never assign this directly — go through {@link setHostPreview}, which applies the frame sizing\n * the flag implies in the SAME state transition. See {@link applyFrameSizing}.\n */\n preview: boolean;\n /**\n * The last content height this host's iframe measured and posted, or null before the first\n * measurement. Retained (rather than consumed and dropped) because frame sizing is a function of\n * `preview` too, and the iframe DEDUPES `contentHeight` on an unchanged measurement — so leaving\n * preview cannot rely on a fresh message arriving to restore the content-sized frame.\n */\n contentHeight: number | null;\n /** Whether the last measured content was a component-definition fragment (drops the 480px floor). */\n contentFragment: boolean;\n /** Whether an inline-edit session is live in this host's iframe (drives the format toolbar). */\n editing: boolean;\n /** The prop a live plain session edits (prop-bound text) — null for rich sessions/none. */\n editingProp: string | null;\n /** The latest selection snapshot from this host's iframe (active tags + caret rect + link). */\n snapshot: SelectionSnapshot | null;\n /** Highest snapshot `seq` seen, so stale (re-ordered) snapshots are dropped. */\n lastSnapshotSeq: number;\n /** The last non-null selection rect drawn (parent/overlay coords) — toolbar position fallback. */\n lastSelectionRect: ParentRect | null;\n /**\n * The gen of the render/patch this iframe's DOM currently reflects (set from `renderComplete`/\n * `patchComplete`). Cross-frame drag replies (`dragOver`/`dropResult`) are dropped unless their\n * `gen` matches, so a drop computed against a superseded render is never applied (Phase 4c).\n */\n lastRenderedGen: number;\n /**\n * The insertion \"+\" zone the overlay button currently anchors to (the iframe posts it on hover);\n * captured here so the button's click handler runs the slash-menu → mutateInsertNode flow against\n * the same parentPath/index. Null when no \"+\" is shown.\n */\n insertZone: InsertZone | null;\n /**\n * Grace timer (SALVAGED HIDE_DELAY) so a `null` zone post (cursor crossed mid-element on its way\n * to the button) doesn't yank the \"+\" before the author reaches it; cancelled on re-show / button\n * mouseenter. Null when not pending.\n */\n insertHideTimer: ReturnType<typeof setTimeout> | null;\n /**\n * Whether the cursor is currently ON the \"+\" (button mouseenter → true, mouseleave → false).\n *\n * The parent MUST hold this itself: the iframe cannot see the cursor once it lands on the button\n * (a parent-realm element overlaying the iframe), so it reports a full pointer-leave and posts\n * `insertZones: null` — which crosses the bridge ASYNCHRONOUSLY and therefore lands just AFTER\n * the button's own synchronous `mouseenter` cancelled the grace timer. Re-arming would then hide\n * the \"+\" ~300ms into the author's click, which is the whole flighty-affordance bug. The hide\n * checks this at FIRE time, so the ordering of the two signals no longer matters.\n */\n insertHover: boolean;\n /**\n * Id of the tab whose document this host's iframe DOM currently reflects. Adopted from\n * {@link HostState.pendingTabIds} ONLY when the render acks (`renderComplete`), so on the FIFO\n * channel any edit-session commit the iframe posts ahead of that ack still routes to the tab the\n * session belonged to. Doc-mutating bridge messages (editCommit/editSplit/editInsert/dropResult)\n * resolve their target tab from THIS — never from `activeTab` at message time, which may have\n * changed while the message was in flight (the cross-document bleed).\n */\n tabId: string | null;\n /** Tab id keyed by render gen for posted-but-unacked renders; adopted on `renderComplete`. */\n pendingTabIds: Map<number, string | null>;\n /**\n * Surgical patches posted to this iframe that have not acked (`patchComplete`/`patchError`).\n *\n * `pendingTabIds` covers full renders because it has to (identity adoption depends on it); a\n * patch carries no identity, so nothing counted it. Both are \"the DOM in that frame does not yet\n * reflect what this host has told it\", which is the question {@link canvasIdleBlockers} answers.\n */\n pendingPatches: number;\n /**\n * The frame's own last quiescence report (`{kind: \"idle\"}`), or null before the first one.\n *\n * Held PER HOST from the start. `shot.ts`'s \"Studio's only child frame\" is a coin flip the moment\n * P8 adds a second pane, and a global would have to be unpicked exactly then.\n */\n idle: Omit<Extract<IframeToParent, { kind: \"idle\" }>, \"kind\"> | null;\n /**\n * Resolvers for {@link measureCanvasPath} requests, keyed by the `measure` reqId.\n *\n * Allocated from the same `selReqId` counter as the selection and presence measures, so the three\n * can never collide and the `geometry` handler can dispatch on the id alone.\n */\n pendingMeasures: Map<number, (hits: NodeHit[]) => void>;\n /**\n * A split/insert re-entry deferred until this host's DOM contains the new element: a surgical\n * patch acks (`patchComplete`) at the SAME gen the host already reflects, an escalated full\n * render acks (`renderComplete`) at a bumped one — both satisfy `gen >= minGen`. An immediate\n * `enterEdit` would race the escalated ASYNC render and silently fail to find the element.\n */\n pendingEnterEdit: { path: (string | number)[]; minGen: number; offset?: number } | null;\n /**\n * Stylebook capability (set by {@link mountStylebookCanvas}, cleared by page mounts). The specimen\n * doc's paths decode to TAGS, not tab-document paths: hits route to the injected stylebook\n * handler instead of `session.selection`, the selection watcher measures the selected tag's card,\n * and the document-editing affordances (insert \"+\", context menu, grab-drags) are ignored for\n * this host.\n */\n stylebook: {\n pathToTag: ReadonlyMap<string, string>;\n tagToCardPath: ReadonlyMap<string, (string | number)[]>;\n } | null;\n /** Measure-request id of an in-flight pan-to-card (stylebook); -1 when none. */\n panReqId: number;\n}\n\n/**\n * Opaque drag-target host handle for the coordinator bridge. The bridge passes it back to the\n * session API ({@link beginDragSession}/{@link hostDragGeometry}/{@link postDragMessage}) without\n * reading its fields.\n */\nexport type DragHost = HostState;\n\nconst hosts = new WeakMap<HTMLElement, HostState>();\n\n/** Every live host, so the selection watcher can re-measure each one when selection changes. */\nconst liveHosts = new Set<HostState>();\n\n// ─── Cross-frame drag session (Phase 4c) ────────────────────────────────────────\n// The parent owns the drag session id and the source data (which never crosses the wire). The\n// Coordinator bridge drives the session through the exported API below; the host's dragOver/dropResult\n// Handlers stale-gate replies by `currentDragSeq` and the target host's `lastRenderedGen`.\n\n/** Monotonic session id, bumped on each {@link beginDragSession}. Stale replies carry an older seq. */\nlet currentDragSeq = 0;\n\n/** Parent-retained source data keyed by `dragSeq` (the block fragment never crosses the boundary). */\nconst retainedSrcData = new Map<number, Record<string, unknown>>();\n\n/**\n * The last session whose cursor-carrying `dragOver` arrived FROM an iframe, and when. While a\n * parent-originated drag is over the canvas, the native dragover/drop stream is delivered to the\n * IFRAME (not the parent), so the iframe drives the session's dragOvers and its native drop posts\n * the dropResult. The coordinator checks {@link sawIframeDragOver} in its `onDrop` to know the\n * parent's own drop location is frame-local garbage and the in-flight dropResult is authoritative.\n */\nlet lastIframeDragOverSeq = -1;\nlet lastIframeDragOverAt = 0;\n\n/**\n * How recently (ms) an iframe-driven dragOver still marks the iframe as owning the stream. Native\n * dragover re-fires ~350ms even with a stationary cursor, so an iframe the cursor is still over\n * stays fresh; once the cursor moves back to parent chrome (e.g. drops on the block-action-bar,\n * which overlays the iframe) the iframe stream stops and the parent's drop coords are trusted\n * again.\n */\nconst IFRAME_DRAGOVER_FRESH_MS = 600;\n\n/** Whether the iframe recently drove a `dragOver` for session `seq` (see above). */\nexport function sawIframeDragOver(seq: number): boolean {\n return (\n lastIframeDragOverSeq === seq && Date.now() - lastIframeDragOverAt <= IFRAME_DRAGOVER_FRESH_MS\n );\n}\n\n// ─── Live expression preview (M6) ───────────────────────────────────────────────\n// The parent asks a live iframe to evaluate expression nodes against its LIVE resolved scope and\n// Correlates the `evalResult` reply by reqId (the measure/geometry precedent), gen-gating it so a\n// Reply computed against a superseded render never paints badges.\n\n/** Monotonic eval request id (shared across hosts; stale replies carry an older/unknown id). */\nlet evalReqId = 0;\n\n/**\n * The panes whose NEXT page render may let automatic `$prototype: \"Request\"` entries fetch, even in\n * edit/design mode.\n *\n * Those fetches are suppressed outside preview because a full render re-resolves every state entry,\n * so an escalating authoring action would issue a request per render. But the Data activity's\n * Refresh exists to re-fire them on demand — its documented purpose — so it arms a pane and that\n * pane's next render consumes it. Deliberately one-shot: a subsequent escalation must not inherit\n * it.\n *\n * **A `boolean`, then a per-PASS boolean, now a set of panes** — the same fact narrowing each time\n * something else turned out to be able to claim it. Per-host was wrong because one Refresh mounts N\n * artboards and the first swallowed the arm. Per-pass was wrong for the same reason one pane\n * further out: two panes are two passes, both scheduled through rAF and both awaiting inside their\n * mount loop, so whichever reached `preparePassRender` first took an arm the OTHER pane's Refresh\n * had set — the button refreshed the pane nobody had pressed it in, and left its own pane\n * suppressed.\n */\nconst _autoRequestPanes = new Set<string>();\n\n/**\n * Open a preview link's target for real.\n *\n * Resolved against the CANVAS's origin, not the editor's: the canvas iframe is served from the\n * project's own origin so relative `src`/`href` resolve the way they will in production, and the\n * editor shell may sit on a different origin entirely (a deep `/edit/:owner/:repo` path in the\n * cloud). Resolving against `location` would send a root-relative `/about` to the wrong host.\n */\nfunction openPreviewHref(href: string, state: HostState): void {\n let resolved: URL;\n try {\n resolved = new URL(href, state.iframe.src || canvasBaseOrigin());\n } catch {\n return; // Unparseable even against a base — nothing sensible to open.\n }\n /*\n * Scheme allowlist. A page can carry any href, and handing `javascript:` or `data:` to\n * `window.open` would execute it — in the EDITOR's origin, since the shell is the opener. Web pages\n * and the contact affordances real sites use are all that Preview needs to follow.\n */\n if (![\"http:\", \"https:\", \"mailto:\", \"tel:\"].includes(resolved.protocol)) {\n return;\n }\n const url = resolved.href;\n const override = getPreviewNavigateHandler();\n if (override) {\n override(url);\n return;\n }\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n}\n\n/**\n * Arm one pane's next page render to allow automatic request fetches (Data activity Refresh).\n *\n * @param {string} paneId The pane the Refresh was pressed for — read ONCE by the caller, so the arm\n * and the `renderCanvas` that follows it cannot end up naming different panes.\n */\nexport function allowAutoRequestsOnNextRender(paneId: string): void {\n _autoRequestPanes.add(paneId);\n}\n\n/** Take `paneId`'s arm, if it has one. */\nfunction consumeAllowAutoRequests(paneId: string): boolean {\n return _autoRequestPanes.delete(paneId);\n}\n\n/** Pending eval resolvers keyed by reqId; a timeout or stale reply resolves null. */\nconst pendingEvals = new Map<number, (results: EvalExprResult[] | null) => void>();\n\n/**\n * Which host each in-flight request belongs to.\n *\n * `pendingEvals` and `pendingFlushes` are keyed by reqId alone, which was enough while nothing ever\n * released a host: an unanswered request simply timed out. A pane that goes away has to settle its\n * OWN requests and nobody else's, and the reqId does not say whose they are.\n */\nconst evalOwners = new Map<number, HostState>();\n\nconst flushOwners = new Map<number, HostState>();\n\n/** How long (ms) the parent waits for an `evalResult` before falling back to the snapshot. */\nexport const EVAL_TIMEOUT_MS = 300;\n\n/**\n * Post an `evalExpr` request to the live, ready iframe host rendering `tabId`'s document and\n * resolve with its results. Resolves `null` when no such host exists (caller falls back to the\n * snapshot evaluator immediately), when no reply lands within `timeoutMs`, or when the reply's gen\n * shows it was computed against a superseded render.\n */\nexport function requestCanvasEval(\n tabId: string | null,\n exprs: { id: string; node: unknown }[],\n contextPath: (string | number)[] | null,\n timeoutMs: number = EVAL_TIMEOUT_MS,\n): Promise<EvalExprResult[] | null> {\n let target: HostState | null = null;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n // Only a document host can answer (never a stylebook specimen catalog or a null-tab override\n // Doc like git-diff), and only the one whose iframe DOM reflects this tab's document.\n if (host.ready && !host.stylebook && tabId !== null && host.tabId === tabId) {\n target = host;\n break;\n }\n }\n if (!target) {\n return Promise.resolve(null);\n }\n evalReqId += 1;\n const reqId = evalReqId;\n // Expression nodes come off the reactive document — only plain values may cross postMessage.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const wireExprs = JSON.parse(JSON.stringify(exprs)) as { id: string; node: JxExpressionNode }[];\n target.channel.post({\n contextPath: contextPath ? [...contextPath] : null,\n exprs: wireExprs,\n gen: target.lastRenderedGen,\n kind: \"evalExpr\",\n reqId,\n });\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n pendingEvals.delete(reqId);\n evalOwners.delete(reqId);\n resolve(null);\n }, timeoutMs);\n evalOwners.set(reqId, target);\n pendingEvals.set(reqId, (results) => {\n clearTimeout(timer);\n evalOwners.delete(reqId);\n resolve(results);\n });\n });\n}\n\n// ─── Pending-edit flush ─────────────────────────────────────────────────────────\n// Text reaches the document on an idle tick, so anything that reads the document as authoritative\n// Must first ask every live frame to commit what the caret has typed since. Without this, saving\n// Mid-sentence writes the file WITHOUT the words still sitting in the caret's block.\n\n/** Monotonic flush request id. */\nlet flushReqId = 0;\n\n/** Pending flush resolvers keyed by reqId; a timeout resolves anyway rather than blocking a save. */\nconst pendingFlushes = new Map<number, () => void>();\n\n/** How long (ms) the parent waits for a frame to acknowledge a flush before saving regardless. */\nexport const FLUSH_TIMEOUT_MS = 250;\n\n/**\n * Ask every live frame rendering `tabId` to commit its pending text, and resolve once they have all\n * acknowledged (or the timeout elapses — a save must never hang on an unresponsive frame).\n */\nexport function flushCanvasEdits(\n tabId: string | null,\n timeoutMs: number = FLUSH_TIMEOUT_MS,\n): Promise<void> {\n const targets: HostState[] = [];\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && !host.stylebook && tabId !== null && host.tabId === tabId) {\n targets.push(host);\n }\n }\n if (targets.length === 0) {\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n let outstanding = targets.length;\n const timer = setTimeout(() => {\n for (const id of ids) {\n pendingFlushes.delete(id);\n flushOwners.delete(id);\n }\n resolve();\n }, timeoutMs);\n const settle = () => {\n outstanding -= 1;\n if (outstanding === 0) {\n clearTimeout(timer);\n resolve();\n }\n };\n const ids: number[] = [];\n for (const host of targets) {\n flushReqId += 1;\n const reqId = flushReqId;\n ids.push(reqId);\n pendingFlushes.set(reqId, settle);\n flushOwners.set(reqId, host);\n host.channel.post({ kind: \"flushEdits\", reqId });\n }\n });\n}\n\n/** The host backing a given canvas element (or null), for the coordinator's host resolution. */\nexport function hostForCanvas(canvasEl: HTMLElement): HostState | null {\n return hosts.get(canvasEl) ?? null;\n}\n\n/**\n * Resolve the live host whose iframe's parent-viewport rect ({@link rectOf}) contains `cursor`.\n * Used by the coordinator to pick the drop target by pointer position (NOT the active panel), so a\n * drag over any panel's canvas targets that panel. Returns null when the cursor is over no live\n * iframe.\n */\nexport function liveDragHostAt(cursor: { x: number; y: number }): HostState | null {\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n continue;\n }\n const r = rectOf(host.iframe);\n if (cursor.x >= r.left && cursor.x <= r.right && cursor.y >= r.top && cursor.y <= r.bottom) {\n return host;\n }\n }\n return null;\n}\n\n/**\n * Begin a drag session against `host`: bump the session id, retain `srcData` (keyed by the new\n * seq), and post `dragStart` with the source kind and the host's current rendered gen. Returns the\n * seq so the coordinator can tag subsequent move/drop posts.\n */\nexport function beginDragSession(\n host: HostState,\n src: DragSrcKind,\n srcData: Record<string, unknown>,\n): number {\n currentDragSeq += 1;\n retainedSrcData.set(currentDragSeq, srcData);\n // The src crosses postMessage: plain-copy the path so a reactive-proxy array (e.g. a live\n // Selection fed through a drag source) can't DataCloneError the structured clone. Test fake\n // Channels pass messages by reference and never exercise the clone, so guard at the boundary.\n const wireSrc: DragSrcKind =\n src.type === \"tree-node\" ? { path: [...src.path], type: \"tree-node\" } : { type: src.type };\n host.channel.post({\n dragSeq: currentDragSeq,\n gen: host.lastRenderedGen,\n kind: \"dragStart\",\n src: wireSrc,\n });\n return currentDragSeq;\n}\n\n/**\n * Adopt an IFRAME-DRIVEN (flow 3) drag session: the iframe already owns the pointer it started and\n * drives the whole gesture, so the parent does NOT post a `dragStart` — it only sets the\n * authoritative `currentDragSeq` to the iframe's seq and retains the (path-only) source data keyed\n * by it, so the iframe's `dragOver`/`dropResult` (which carry that same seq) pass the parent's seq\n * gate and the drop applies with the retained source. Returns the adopted seq.\n */\nexport function adoptDragSession(\n _host: HostState,\n _src: DragSrcKind,\n srcData: Record<string, unknown>,\n seq: number,\n): number {\n currentDragSeq = seq;\n retainedSrcData.set(seq, srcData);\n return seq;\n}\n\n/** The current drag session id, for the coordinator to tag its move/drop posts. */\nexport function currentDragSession(): number {\n return currentDragSeq;\n}\n\n/**\n * The EMPIRICAL zoom scale for `host`'s iframe — `rectOf(iframe).width / iframe.clientWidth` (D-2),\n * read FRESH so a pan/zoom mid-drag is reflected. NOT `effectiveZoom()` (a separate path that can\n * desync). The matching iframe parent-viewport rect is returned so the cursor map cancels the pan.\n */\nexport function hostDragGeometry(host: HostState): {\n scale: number;\n rect: { left: number; top: number };\n} {\n const rect = rectOf(host.iframe);\n const scale = host.iframe.clientWidth > 0 ? rect.width / host.iframe.clientWidth : 1;\n return { rect, scale };\n}\n\n// ─── Quiescence and point resolution ────────────────────────────────────────────\n// Two questions the parent realm could not previously answer about a cross-origin canvas: \"has it\n// Settled?\" and \"where on screen is this node?\". Both were answered by the CALLER instead — a sleep\n// And a `Math.abs(scale - 1) < 0.001` guess at whether a fit transform was in play. Both are the\n// Host's own arithmetic; it already does them for the selection overlay and the block action bar.\n\n/** A short, stable handle for a host inside a blocker string. */\nfunction hostLabel(host: HostState): string {\n if (host.stylebook) {\n return \"stylebook\";\n }\n return host.tabId ?? \"unbound\";\n}\n\n/**\n * Everything the canvas is still owed, one human-readable line per outstanding item, PER HOST.\n *\n * Empty means every live frame's DOM reflects what this host told it, its fonts have loaded, no\n * animation is running and no image retry is in flight. Naming the blockers is the whole point:\n * `probe.idle()` rejects with this list, so a slow subsystem identifies itself instead of being\n * answered with `+500 ms` and a wrong capture (plan §13.4).\n */\nexport function canvasIdleBlockers(): string[] {\n const blockers: string[] = [];\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n const at = `canvas[${hostLabel(host)}]`;\n if (!host.ready) {\n blockers.push(`${at}: frame has not handshaked`);\n continue;\n }\n const unacked = [...host.pendingTabIds.keys()];\n if (unacked.length > 0) {\n blockers.push(`${at}: gen ${unacked.join(\", \")} unacked`);\n }\n if (host.pendingPatches > 0) {\n blockers.push(`${at}: ${host.pendingPatches} unacked patch(es)`);\n }\n if (host.pendingMeasures.size > 0) {\n blockers.push(`${at}: ${host.pendingMeasures.size} measure(s) in flight`);\n }\n const { idle } = host;\n if (!idle) {\n blockers.push(`${at}: no quiescence report yet`);\n continue;\n }\n if (idle.gen !== host.lastRenderedGen) {\n blockers.push(`${at}: quiescence is for gen ${idle.gen}, DOM is gen ${host.lastRenderedGen}`);\n }\n if (!idle.fonts) {\n blockers.push(`${at}: fonts still loading`);\n }\n if (idle.animations > 0) {\n blockers.push(`${at}: ${idle.animations} running animation(s)`);\n }\n if (idle.images > 0) {\n blockers.push(`${at}: ${idle.images} pending image retry(ies)`);\n }\n }\n if (pendingEvals.size > 0) {\n blockers.push(`canvas: ${pendingEvals.size} expression eval(s) in flight`);\n }\n return blockers;\n}\n\n/**\n * A node's box in TOP-DOCUMENT coordinates, with `x`/`y` at its centre.\n *\n * The caller gets a point it can act on directly — click it, scroll to it, anchor a popover to it —\n * without knowing that a canvas iframe, a panzoom transform and an edit-zoom scale sit between the\n * document and the screen. P4.6's find-references jump, P8.4's jump bar and collab follow-peer all\n * want exactly this, and so does anything driving Studio from outside.\n */\nexport interface CanvasPoint {\n x: number;\n y: number;\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n/** How long a point request waits for its `geometry` reply before answering null. */\nexport const MEASURE_TIMEOUT_MS = 500;\n\n/** Frames of an unchanged iframe offset that end a reveal. */\nconst PAN_SETTLE_FRAMES = 2;\n\n/** Give up on a reveal that never settles rather than await it forever. */\nconst PAN_SETTLE_MAX_FRAMES = 40;\n\n/**\n * The live host a document path is addressed in: the one rendering the focused tab, else any ready\n * page host. A stylebook host is never it — its paths decode to TAGS, not document paths.\n */\nfunction hostForPath(): HostState | null {\n const tabId = activeTab.value?.id ?? null;\n let fallback: HostState | null = null;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (!host.ready || host.stylebook) {\n continue;\n }\n if (host.tabId === tabId) {\n return host;\n }\n fallback ??= host;\n }\n return fallback;\n}\n\n/**\n * Compose the host's own transforms onto an iframe-viewport rect.\n *\n * `scale` is the EMPIRICAL ratio {@link hostDragGeometry} reads fresh from the DOM, so it covers the\n * design-mode panzoom transform and edit-mode content zoom together — which is precisely the\n * distinction a caller cannot make from outside and used to guess at.\n */\nfunction pointForRect(host: HostState, rect: SerializableRect): CanvasPoint {\n const { rect: frame, scale } = hostDragGeometry(host);\n const left = frame.left + rect.x * scale;\n const top = frame.top + rect.y * scale;\n const width = rect.width * scale;\n const height = rect.height * scale;\n return { height, left, top, width, x: left + width / 2, y: top + height / 2 };\n}\n\n/** Ask one host to measure one path and resolve the reply as a top-document point. */\nfunction measureIn(\n host: HostState,\n path: readonly (string | number)[],\n): Promise<CanvasPoint | null> {\n return new Promise((resolve) => {\n host.selReqId += 1;\n const reqId = host.selReqId;\n const timer = setTimeout(() => {\n host.pendingMeasures.delete(reqId);\n resolve(null);\n }, MEASURE_TIMEOUT_MS);\n host.pendingMeasures.set(reqId, (hits) => {\n clearTimeout(timer);\n const [hit] = hits;\n resolve(hit ? pointForRect(host, hit.rect) : null);\n });\n // A plain copy: `session.selection` is a reactive proxy and only serializable values cross.\n host.channel.post({ kind: \"measure\", paths: [[...path]], reqId });\n });\n}\n\n/**\n * Where the node at `path` is on screen right now, or null when no canvas can answer.\n *\n * Read-only: it measures, it does not move anything. {@link revealCanvasPath} is the half that does.\n */\nexport function canvasPointAt(path: readonly (string | number)[]): Promise<CanvasPoint | null> {\n const host = hostForPath();\n return host ? measureIn(host, path) : Promise.resolve(null);\n}\n\n/**\n * Resolve once the iframe's offset has stopped moving.\n *\n * The iframe's own top is the right thing to watch precisely because it does not care HOW the pane\n * moved: a Design pan is a 250ms rAF tween of `view.panY`, an Edit reveal is one synchronous\n * `scrollTop` write, and both show up here as the frame's on-screen offset changing and then\n * holding still.\n */\nfunction panSettled(host: HostState): Promise<void> {\n return new Promise((resolve) => {\n let last = Number.NaN;\n let stable = 0;\n let frames = 0;\n const tick = () => {\n const { top } = rectOf(host.iframe);\n stable = top === last ? stable + 1 : 0;\n last = top;\n frames += 1;\n if (stable >= PAN_SETTLE_FRAMES || frames >= PAN_SETTLE_MAX_FRAMES) {\n resolve();\n return;\n }\n requestAnimationFrame(tick);\n };\n requestAnimationFrame(tick);\n });\n}\n\n/**\n * Bring the node at `path` into view and answer where it landed.\n *\n * The move is the same {@link panToParentRect} the stylebook's pan-to-card uses, and the second\n * measure is not belt-and-braces: the point BEFORE the move is not the point a caller can act on.\n *\n * `panToParentRect` is what makes this work on BOTH surfaces — it pans a panzoom stage and scrolls\n * a scrolling one. While it only panned, this function was a measured no-op in Edit mode: it\n * returned the node's original, off-screen point, and `runInput`'s caret step then clicked a point\n * outside the pane and selected nothing.\n */\nexport async function revealCanvasPath(\n path: readonly (string | number)[],\n): Promise<CanvasPoint | null> {\n const host = hostForPath();\n if (!host) {\n return null;\n }\n const before = await measureIn(host, path);\n if (!before) {\n return null;\n }\n /* Pan the stage the MEASUREMENT came from. `hostForPath` prefers the host rendering the focused\n tab but falls back to any ready page host, and the pan defaulted to `activeCanvasSurface()` —\n so on the fallback the reveal measured in one pane and scrolled the other, then re-measured a\n node that had not moved. `undefined` keeps the default for a host no pane claims (a detached\n artboard in a test). */\n const surface = panelHostingCanvas(host.canvasEl)?.surface;\n panToParentRect({ height: before.height, top: before.top }, surface);\n await panSettled(host);\n return measureIn(host, path);\n}\n\n/**\n * Pin the `.canvas-panel-viewport` (the white \"page\" surface, the canvas element's parent) to the\n * SCALED content height when edit-mode content zoom is active. A `transform: scale()` on the canvas\n * element rescales its painted box but never its ancestor's auto-height, so without this write the\n * viewport background would stay sized to the UN-zoomed iframe height. The scale is read from the\n * canvas element's own inline transform (written only by `applyEditZoom`) — NOT from\n * {@link hostDragGeometry}, whose empirical ratio also reflects design mode's panzoom-wrap\n * transform, where the viewport must keep its unscaled auto height.\n */\nfunction syncEditZoomViewportHeight(state: HostState): void {\n const viewport = state.canvasEl.parentElement;\n if (!viewport) {\n return;\n }\n const match = /scale\\(([\\d.]+)\\)/.exec(state.canvasEl.style.transform);\n const scale = match ? Number(match[1]!) : 1;\n viewport.style.height = scale === 1 ? \"\" : `${state.iframe.offsetHeight * scale}px`;\n}\n\n/**\n * Write the iframe's box from the host's CURRENT state — the render mode and the last content\n * measurement — and nothing else. Frame sizing is derived, never incremental, because the two\n * inputs arrive on different clocks: `preview` flips synchronously inside a mount, the measurement\n * arrives asynchronously over the channel, and the iframe DEDUPES a repeated measurement (so \"the\n * next `contentHeight` will fix it\" is false). Deriving both branches from one function called at\n * every transition of either input is what makes the two impossible to disagree.\n *\n * Preview keeps the iframe a REAL VIEWPORT: it stays at the CSS height the preview stage gives it\n * and scrolls its own document, so `position:sticky`, scroll-driven animation and\n * IntersectionObserver reveals fire exactly as they will in production. Growing the frame to its\n * content height — what every editing mode needs, so the parent overlay can reach every node — is\n * what stopped all three from ever firing in the one view whose job is fidelity.\n *\n * The cssText's 480px `min-height` is a pre-measurement floor so an empty/short PAGE stays a usable\n * canvas; a component DEFINITION (fragment) instead hugs its content, so drop the floor for it once\n * measured (else a short component leaves dead space below — pages keep the floor and stay tall via\n * `#jx-canvas-root`).\n */\nfunction applyFrameSizing(state: HostState): void {\n if (state.preview) {\n state.iframe.style.height = \"100%\";\n state.iframe.style.minHeight = \"0px\";\n return;\n }\n if (state.contentHeight === null) {\n // Nothing measured yet — the cssText defaults (height:100%; min-height:480px) stand.\n return;\n }\n state.iframe.style.height = `${state.contentHeight}px`;\n state.iframe.style.minHeight = state.contentFragment ? \"0px\" : \"480px\";\n syncEditZoomViewportHeight(state);\n}\n\n/**\n * Adopt a render mode's preview-ness as ONE state transition: the flag, the overlay suppression,\n * the dropped pending edit and the frame box all move together. Mounts must call this rather than\n * assigning `state.preview` — a mount resolves its document asynchronously, so between the mode\n * changing and the flag landing the host would otherwise answer a `contentHeight` with the previous\n * mode's sizing rule and never get a second chance to correct it.\n */\nfunction setHostPreview(state: HostState, preview: boolean): void {\n state.preview = preview;\n state.overlay.setSuppressed(preview);\n if (preview) {\n state.pendingEnterEdit = null;\n }\n applyFrameSizing(state);\n}\n\n/**\n * Declare, SYNCHRONOUSLY, which kind of render `canvasEl`'s host is about to receive.\n *\n * {@link mountIframeCanvas} resolves its document asynchronously, so the mode it will post is not\n * known to the host until an await has passed. The renderer knows it before the await — it is the\n * mode it just built the surface for — so it says so here, and the host's frame box moves with the\n * flag rather than trailing it. Without this the `contentHeight` the iframe posts during the\n * resolve is answered under the OUTGOING mode's sizing rule.\n */\nexport function adoptCanvasPreviewMode(canvasEl: HTMLElement, preview: boolean): void {\n setHostPreview(ensureHost(canvasEl), preview);\n}\n\n/** Post a parent→iframe drag message to `host`'s channel (the coordinator builds it purely). */\nexport function postDragMessage(host: HostState, msg: ParentToIframe): void {\n if (!host.iframe.isConnected) {\n return;\n }\n host.channel.post(msg);\n}\n\n/** Abandon the current session's retained source data (e.g. a drop landed off-canvas). */\nexport function endDragSession(dragSeq: number): void {\n retainedSrcData.delete(dragSeq);\n}\n\n/** Hide `host`'s drop indicator (the coordinator's timeout fallback when no dropResult arrives). */\nexport function clearDropIndicator(host: HostState): void {\n host.overlay.setDropIndicator(null);\n}\n\n/**\n * The coordinator's handler for a NATIVE drag stream entering an iframe with no session bound there\n * (the `nativeDragEnter` message) — the bridge binds/migrates its live pragmatic session to that\n * host. Installed by the bridge to avoid a host→bridge import cycle.\n */\nlet nativeDragEnterHandler: ((host: HostState) => void) | null = null;\n\n/** Register the coordinator's native-drag-enter handler (see {@link nativeDragEnterHandler}). */\nexport function setNativeDragEnterHandler(fn: (host: HostState) => void): void {\n nativeDragEnterHandler = fn;\n}\n\n/** Delay (ms) before hiding the insertion \"+\" so the cursor can reach it (SALVAGED HIDE_DELAY). */\nexport const INSERT_HIDE_DELAY = 300;\n\n/**\n * The parent-realm insertion handler: open the slash menu anchored at the \"+\" `btn` and, on select,\n * run `transactDoc → mutateInsertNode` for the captured `zone`. Injected from studio.ts (which owns\n * the slash-menu / transact / defaultDef wiring) so this host module — and its tests — stay free of\n * the lit/Spectrum slash-menu and the mutation pipeline, mirroring the native-drag handler.\n */\nlet insertZoneClickHandler: ((btn: HTMLElement, zone: InsertZone) => void) | null = null;\n\n/** Register the slash-menu → mutateInsertNode handler the insertion \"+\" runs on click. */\nexport function setInsertZoneClickHandler(fn: (btn: HTMLElement, zone: InsertZone) => void): void {\n insertZoneClickHandler = fn;\n}\n\n/**\n * The parent-realm handler for an external file drop on a canvas (flow 5): upload the files and\n * either replace an existing image's source or insert new elements. Injected from studio.ts for the\n * same reason as {@link insertZoneClickHandler} — it reaches the platform and the mutation pipeline,\n * which this module and its tests stay free of.\n */\nlet fileDropHandler:\n | ((\n tab: Tab | null,\n files: File[],\n hit: FileDropHit | null,\n preview: DropPreview | null,\n ) => void | Promise<void>)\n | null = null;\n\n/** Register the upload → replace-or-insert handler for external file drops (see flow 5). */\nexport function setFileDropHandler(\n fn: (\n tab: Tab | null,\n files: File[],\n hit: FileDropHit | null,\n preview: DropPreview | null,\n ) => void | Promise<void>,\n): void {\n fileDropHandler = fn;\n}\n\n/**\n * Draw the affordance for a file drag hovering `state`'s canvas: a solid highlight over the image\n * the drop would REPLACE, or the usual insert indicator. Exactly one shows at a time — they answer\n * different questions, and both at once would be ambiguous.\n */\nfunction showFileDropAffordance(\n state: HostState,\n hit: FileDropHit | null,\n preview: DropPreview | null,\n): void {\n const replacing = hit ? isReplaceableTag(hit.tagName) : false;\n if (replacing && hit) {\n state.overlay.setDropIndicator(null);\n state.overlay.setReplaceTarget(canvasRectToParent(hit.rect));\n return;\n }\n state.overlay.setReplaceTarget(null);\n state.overlay.setDropIndicator(\n preview ? canvasRectToParent(preview.referenceRect) : null,\n preview?.edge,\n );\n}\n\n/** Hide both file-drop affordances on `state`. */\nfunction clearFileDropAffordance(state: HostState): void {\n state.overlay.setReplaceTarget(null);\n state.overlay.setDropIndicator(null);\n}\n\n/**\n * Whether a drop on this tag would replace a picture rather than insert beside it. Kept in sync\n * with `REPLACE_ATTRS` in editor/file-drop-action.ts, which owns the authoritative decision — this\n * is the display-only preview, so a custom element (whose verdict needs the component registry) is\n * shown as an insert and may still resolve to a replace on drop.\n */\nfunction isReplaceableTag(tagName: string): boolean {\n return tagName === \"img\" || tagName === \"video\" || tagName === \"source\";\n}\n\n/**\n * Accept file drops on the canvas element itself — the margin around the iframe box. The iframe\n * swallows everything over the rendered page (Chromium routes native drags to the frame under the\n * cursor), so this only ever sees a drop on the surrounding gutter, which appends to the document\n * root. Attached once per canvas element; the guard makes a re-mount idempotent.\n */\nfunction registerCanvasGutterDrop(canvasEl: HTMLElement, host: () => HostState | null): void {\n if (canvasEl.dataset.jxGutterDrop === \"1\") {\n return;\n }\n canvasEl.dataset.jxGutterDrop = \"1\";\n canvasEl.addEventListener(\"dragover\", (e: DragEvent) => {\n if (![...(e.dataTransfer?.types ?? [])].includes(\"Files\")) {\n return;\n }\n e.preventDefault();\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"copy\";\n }\n });\n canvasEl.addEventListener(\"drop\", (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n const state = host();\n if (!files?.length || !state || state.stylebook) {\n return;\n }\n e.preventDefault();\n void fileDropHandler?.(hostTab(state), [...files], null, null);\n });\n}\n\n/** A canvas-originated slash-menu request, converted to PARENT-VIEWPORT coords by the host. */\nexport interface CanvasSlashRequest {\n rect: { left: number; top: number; bottom: number; width: number; height: number };\n filter: string;\n /** Whether the menu draws its own filter field — see the `slashShow` message for why. */\n showFilter?: boolean;\n onSelect: (cmd: SlashCommand) => void;\n onDismiss: () => void;\n}\n\n/**\n * The parent-realm slash-menu surface the canvas iframe drives (show at a rect, navigate by key,\n * dismiss). Injected from studio.ts (which owns the lit/Spectrum menu) so this host module — and\n * its tests — stay free of it, mirroring {@link insertZoneClickHandler}.\n */\nexport interface CanvasSlashHandler {\n show: (req: CanvasSlashRequest) => void;\n nav: (key: string) => void;\n dismiss: () => void;\n}\n\nlet canvasSlashHandler: CanvasSlashHandler | null = null;\n\n/** Register the parent-realm slash-menu surface the canvas iframe drives. */\nexport function setCanvasSlashHandler(handler: CanvasSlashHandler): void {\n canvasSlashHandler = handler;\n}\n\n/**\n * The parent-realm context-menu surface for canvas right-clicks (show at parent-viewport coords,\n * dismiss on a canvas left-click). Injected from studio.ts, same DI pattern as the slash handler.\n */\nexport interface CanvasContextMenuHandler {\n show: (args: { path: (string | number)[] | null; clientX: number; clientY: number }) => void;\n dismiss: () => void;\n}\n\nlet canvasContextMenuHandler: CanvasContextMenuHandler | null = null;\n\n/** Register the parent-realm context-menu surface the canvas iframe drives. */\nexport function setCanvasContextMenuHandler(handler: CanvasContextMenuHandler): void {\n canvasContextMenuHandler = handler;\n}\n\n/**\n * The parent-realm stylebook selection handler: a hit in a stylebook host decodes to a TAG (or null\n * for chrome/empty space) plus the clicked panel's media, and routes here — never to\n * `session.selection`. Injected from studio.ts (which owns selectStylebookTag), same DI pattern as\n * the slash/context handlers.\n */\nlet stylebookHitHandler: ((tag: string | null, media: string | null) => void) | null = null;\n\n/** Register the stylebook tag-selection handler stylebook hosts route hits to. */\nexport function setStylebookHitHandler(\n fn: (tag: string | null, media: string | null) => void,\n): void {\n stylebookHitHandler = fn;\n}\n\n/**\n * Decode a stylebook hit path to its tag/compound: exact `pathToTag` lookup, then trim trailing\n * path segments pairwise (\"children\", i) so a hit on an unmapped descendant resolves to its nearest\n * mapped ancestor. Null = chrome/empty space (deselect).\n */\nfunction resolveStylebookTag(\n pathToTag: ReadonlyMap<string, string>,\n path: (string | number)[],\n): string | null {\n let p = [...path];\n for (;;) {\n const tag = pathToTag.get(serializeJxPath(p));\n if (tag) {\n return tag;\n }\n if (p.length < 2) {\n return null;\n }\n p = p.slice(0, -2);\n }\n}\n\n/**\n * The single host whose iframe currently owns the inline-edit session. Only one editable can be\n * active across all panels, so the parent format toolbar reads/writes through this (fixes the\n * multi-panel bug where two hosts' editing state could fight).\n */\nlet activeEditHost: HostState | null = null;\n\n/**\n * Whether a text caret is live in a canvas iframe — the parent realm's only honest answer to \"is\n * the author typing right now\".\n *\n * The editing session runs INSIDE the cross-origin canvas frame, so `editor/inline-edit.ts`'s\n * `isEditing()` — a module-local `activeEl` in the PARENT bundle — is permanently false here. The\n * bridge already carries the truth: `editStart` opens a session, `selectionChanged` proves the\n * caret is still live in it, `editEnd` closes it. Derived rather than stored per host, so a frame\n * torn down mid-session (a mode switch, a closed tab) can never latch the flag on and go on\n * stealing ⌘C from a caret that no longer exists.\n */\nexport function isCaretActive(): boolean {\n const host = activeEditHost;\n return Boolean(host?.editing && host.iframe.isConnected);\n}\n\n/** Injected toolbar re-render (set by studio.ts → renderBlockActionBar); avoids a panel→host cycle. */\nlet toolbarRefresh: (() => void) | null = null;\n\n/** Register the parent toolbar's refresh fn (mirrors {@link setIframePatchEscalation}). */\nexport function setToolbarRefresh(fn: () => void): void {\n toolbarRefresh = fn;\n}\n\n/** Injected \"a pointer went down in a canvas\" signal (studio.ts → releaseBlockActionBar). */\nlet canvasPointerDownHandler: (() => void) | null = null;\n\n/**\n * Register what runs when a canvas frame reports a pointerdown. Pass `null` to unregister.\n *\n * Injected rather than imported for the reason {@link setToolbarRefresh} gives — this module\n * deliberately knows nothing about panels — and it exists as its own seam because\n * {@link focusHostPane} cannot serve as one: `focusPane` returns early when the pane already has\n * focus, which is the ordinary case (clicking around inside the pane you are already in) and\n * precisely the case the one subscriber, the block action bar's suppression release, is for.\n */\nexport function setCanvasPointerDownHandler(fn: (() => void) | null): void {\n canvasPointerDownHandler = fn;\n}\n\nlet selectionWatch: { stop: () => void } | null = null;\n\n/** Full-render escalation, injected by studio init (a patchError can't apply surgically). */\nlet patchEscalation: ((paneId: string) => void) | null = null;\n\n/**\n * Register the full-render fallback the host invokes when the iframe reports a `patchError`.\n *\n * Takes the PANE whose frame reported it: only that stage's DOM has fallen behind its document, and\n * re-rendering the other pane would reload iframes that applied their patch perfectly well.\n */\nexport function setIframePatchEscalation(fn: (paneId: string) => void): void {\n patchEscalation = fn;\n}\n\n/**\n * Post a surgical patch (value-carrying forward ops) to every ready live iframe host rendering\n * `tabId`'s document — a still-connected host showing another tab's doc must never fold a foreign\n * edit into its shadow doc. Returns how many hosts received it; the caller escalates to a full\n * render when that's zero (no host could apply the edit in place, so the suppressed full render\n * must run after all).\n *\n * **There is no `gen` parameter, and there cannot be one.** The generation a frame checks a patch\n * against belongs to the STAGE that frame is mounted on, and this loop deliberately spans stages:\n * one document displayed in two panes is two hosts with two independent `renderGeneration`s. A\n * single number for a multi-pane fan-out is not a parameter needing a better value — it is the bug.\n * Whichever pane had rendered more recently held the higher `renderedGen`, and `iframe-entry.ts`\n * dropped the patch there in silence, leaving a wrong picture on screen with `__jxCanvasPerf`\n * reporting a clean surgical apply. Each host's own generation is resolved inside the loop\n * instead.\n *\n * `host` is deliberately not a pane-scoped parameter name (see `PANE_PARAM_NAMES`), and the body\n * reads no focus: `panelHostingCanvas` resolves the stage from the host's own element.\n */\nexport function postPatchToHosts(forwardOps: WireDocOp[], tabId: string | null): number {\n let posted = 0;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && host.tabId === tabId) {\n /* NO FALLBACK GENERATION, and `?? 0` was the one bug this whole function exists to end.\n A host whose stage cannot be resolved — still `ready` and connected while its surface's\n panel list is between mutations across one of `renderCanvasImpl`'s awaits — was posted\n gen `0`. `0 < renderedGen` is the frame's `patch-behind-render` branch, whose `patchError`\n is handled by resolving the surface with THIS SAME failing lookup: `patchEscalation` was\n never called. Meanwhile `posted` had been incremented, so the caller did not throw, and\n `markConsumed` had already suppressed the full render. An edit disappeared with no counter\n moving. A stage we cannot name is a stage we cannot patch: skip it, let `posted` fall, and\n let the caller's `no-ready-iframe-host` escalate the whole batch. The escalation counter\n moves HERE too, because \"nothing was posted and nothing was wrong\" and \"nothing was posted\n because we could not name the stage\" are the two answers this must never confuse. */\n const stage = panelHostingCanvas(host.canvasEl)?.surface;\n if (!stage) {\n recordEscalation(\"host-stage-unresolved\");\n continue;\n }\n const gen = stage.renderGeneration;\n // Only the host that originated this edit already has the DOM the patch describes. A\n // Split-view panel on the same document did NOT type it and must render normally.\n const echoPaths = echoOrigin?.host === host ? echoOrigin.paths : undefined;\n host.channel.post(\n echoPaths\n ? { echoPaths, forwardOps, gen, kind: \"patch\" }\n : { forwardOps, gen, kind: \"patch\" },\n );\n host.pendingPatches += 1;\n posted += 1;\n }\n }\n return posted;\n}\n\n/**\n * The host whose own in-place commit is currently being applied, and the paths whose DOM it already\n * has right.\n *\n * Set for the duration of the `transactDoc` call inside the `editCommit` case and read by\n * {@link postPatchToHosts}, which runs synchronously inside it — the same begin/end shape\n * `transact.ts` uses for op recording. Never spans an await, so it cannot leak across messages.\n */\nlet echoOrigin: { host: HostState; paths: (string | number)[][] } | null = null;\n\n/**\n * Identifies the current visit to a block. Text commits sharing a run fold into ONE history entry —\n * typing commits on every pause, and without this a minute of writing would evict every structural\n * edit from the 100-entry ring and make ⌘Z walk back through the prose one pause at a time.\n */\nlet editRunSeq = 0;\n\n/**\n * Apply `fn` with `host`'s echo suppression armed for `paths`.\n *\n * This is what lets the caret survive its own edits: committing a block re-enters the patcher,\n * which would otherwise re-render the very subtree the user is typing in.\n */\nfunction withEchoSuppressed(host: HostState, paths: (string | number)[][], fn: () => void): void {\n echoOrigin = { host, paths };\n try {\n fn();\n } finally {\n echoOrigin = null;\n }\n}\n\n/** The tab whose document `state`'s iframe currently renders (null when unknown or closed). */\nfunction hostTab(state: HostState): Tab | null {\n return state.tabId ? (workspace.tabs.get(state.tabId) ?? null) : null;\n}\n\n/**\n * The tab a drag TARGET is showing — the one public reader on the opaque {@link DragHost} handle.\n *\n * `panels/canvas-dnd-bridge.ts` binds a session to the host under the cursor and then had nothing\n * to ask it, so the one fact it needed about the drag — what the dragged node is CALLED — came from\n * `activeTab`. The bridge is not supposed to read the handle's fields (that is what \"opaque\"\n * means), so the answer is a function rather than a widened type.\n */\nexport function dragHostTab(host: DragHost): Tab | null {\n return hostTab(host);\n}\n\n/**\n * Put the keyboard in the pane whose artboard was just clicked.\n *\n * `panels/pane-grid.ts` moves the pane focus on a `pointerdown` anywhere in a cell, and that\n * listener cannot see this click: the canvas is a cross-origin `<iframe>`, so a pointer event\n * inside it is delivered in the frame's own realm and never surfaces in the parent's. The `hit` and\n * `layoutHit` messages ARE that pointerdown, re-posted across the channel, so this is the seam.\n *\n * The pane comes from the artboard the message arrived through — `panelHostingCanvas` is the same\n * route the breakpoint and the escalation already take — never from the focus, which is the thing\n * being corrected. `focusPane` is a no-op when the pane already has focus, so the common case\n * (clicking around in the pane you are already in) costs one map lookup.\n */\nfunction focusHostPane(state: HostState): void {\n const paneId = panelHostingCanvas(state.canvasEl)?.surface.paneId;\n if (paneId) {\n focusPane(paneId);\n }\n}\n\n/** No selection. A shared frozen empty, so the \"this host shows nothing\" path allocates nothing. */\nconst NO_SELECTION: readonly JxPath[] = Object.freeze([]);\n\n/** The tab each pane is showing, by tab id. Reading it inside an effect tracks every pane. */\nfunction shownSelections(): Map<string, readonly JxPath[]> {\n const byTab = new Map<string, readonly JxPath[]>();\n for (const pane of workspace.panes) {\n const tab = pane.activeTabId ? workspace.tabs.get(pane.activeTabId) : null;\n if (!tab) {\n continue;\n }\n const sel = (tab.session.selection ?? []) as readonly JxPath[];\n // Track the selection deeply enough that a change WITHIN the set re-measures: the effect\n // Reads every path, not just the array reference.\n void sel.map((path) => path.join(\"/\")).join(\"|\");\n byTab.set(tab.id, sel);\n }\n return byTab;\n}\n\n/**\n * Lazily start one reactive watcher that re-measures each host's OWN document's selection.\n *\n * **Every other fan-out in this module filters by `host.tabId`** — `postPatchToHosts`,\n * `requestCanvasEval`, `flushCanvasEdits` — and this one did not. It read `activeTab` and posted\n * the result to every entry in `liveHosts`, so with two panes open the focused pane's selection\n * paths were measured inside the OTHER pane's frame, against a document that does not contain them,\n * and written over that host's own `selectionPath`/`selectionPaths`. The reverse cost more:\n * `requestSelection`'s `if (!primary)` branch clears the overlay, so the focused pane merely having\n * nothing selected erased the side pane's box — the unfocused pane could never show a selection at\n * all.\n */\nfunction ensureSelectionWatch(): void {\n if (selectionWatch) {\n return;\n }\n const scope = effectScope(true);\n scope.run(() => {\n effect(() => {\n const byTab = shownSelections();\n // Track the stylebook selection too: stylebook hosts measure the selected TAG's card\n // (session.selection is deliberately [] in stylebook mode).\n void shell.stylebook.selection;\n for (const host of liveHosts) {\n requestSelection(host, (host.tabId ? byTab.get(host.tabId) : null) ?? NO_SELECTION);\n }\n });\n });\n selectionWatch = { stop: () => scope.stop() };\n}\n\n/** Lazily start one reactive watcher that re-measures remote peers' selections in every host. */\nlet presenceWatchStarted = false;\nlet presenceTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction ensurePresenceWatch(): void {\n if (presenceWatchStarted) {\n return;\n }\n presenceWatchStarted = true;\n const scope = effectScope(true);\n scope.run(() => {\n effect(() => {\n // EVERY shown tab's roster, for the reason {@link ensureSelectionWatch} gives: a peer moving\n // Their cursor in the side pane's document is a repaint the side pane owes, and tracking only\n // The focused tab left the other pane's presence boxes frozen at whatever it last drew.\n for (const pane of workspace.panes) {\n const tab = pane.activeTabId ? workspace.tabs.get(pane.activeTabId) : null;\n if (!tab) {\n continue;\n }\n // Track the roster deeply enough that selection moves re-trigger.\n const { peers } = collabState(tab);\n void peers.map((peer) => JSON.stringify(peer.state.structuralSelection ?? null)).join(\"|\");\n }\n if (presenceTimer) {\n clearTimeout(presenceTimer);\n }\n // Debounced: awareness updates arrive per cursor move.\n presenceTimer = setTimeout(() => {\n presenceTimer = null;\n for (const host of liveHosts) {\n requestPresence(host);\n }\n }, 100);\n });\n });\n}\n\n/** Measure remote peers' selections in this host's iframe and draw colored boxes from the reply. */\nfunction requestPresence(host: HostState): void {\n if (host.stylebook || !host.ready || !host.iframe.isConnected) {\n return;\n }\n // THIS host's document, not the focused pane's — the peer boxes drawn in a frame have to be the\n // Peers looking at what that frame is showing, and `peer.state.focusedPath` is compared against\n // It below.\n const tab = hostTab(host);\n const peers = tab ? collabState(tab).peers : [];\n host.presenceMeta.clear();\n const paths: (string | number)[][] = [];\n for (const peer of peers) {\n const { structuralSelection } = peer.state;\n if (!structuralSelection || peer.state.focusedPath !== tab?.documentPath) {\n continue;\n }\n // A peer publishes their whole selection SET (§6.5). Every path gets its own box under the\n // Same name and colour — the meta map is keyed by path, so a peer selecting six nodes draws\n // Six boxes and a peer selecting one draws exactly the one box it always did.\n for (const path of structuralSelection) {\n const copy = [...path];\n paths.push(copy);\n host.presenceMeta.set(JSON.stringify(copy), {\n color: peer.state.user.color,\n label: peer.state.user.name ?? peer.state.user.login,\n });\n }\n }\n if (paths.length === 0) {\n host.presenceReqId = -1;\n host.overlay.setPresence([]);\n return;\n }\n host.selReqId += 1;\n host.presenceReqId = host.selReqId;\n host.channel.post({ kind: \"measure\", paths, reqId: host.presenceReqId });\n}\n\n/**\n * Track the selection on a host and ask its iframe to measure it (or clear the boxes when empty).\n *\n * The PRIMARY path is posted first and drawn as the selection box; the rest are drawn as\n * co-selection boxes from the same reply, so one round trip covers the whole set. With one path\n * selected the request is byte-identical to what it always was — one path in, one box out.\n */\nfunction requestSelection(host: HostState, sel: readonly JxPath[]): void {\n if (host.stylebook) {\n requestStylebookSelection(host);\n return;\n }\n const primary = primarySelection(sel);\n host.selectionPath = primary;\n host.selectionPaths = sel as JxPath[];\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n return;\n }\n if (!primary) {\n host.coSelectionKeys.clear();\n host.overlay.setSelection(null);\n host.overlay.setCoSelection([]);\n return;\n }\n if (!host.ready) {\n return;\n }\n // Post a plain copy: `session.selection` is a reactive proxy, and only serializable values may\n // Cross the postMessage boundary.\n const others = cloneSelection(sel.slice(0, -1));\n host.coSelectionKeys = new Set(others.map((path) => JSON.stringify(path)));\n host.selReqId += 1;\n host.channel.post({\n kind: \"measure\",\n paths: [[...primary], ...others],\n reqId: host.selReqId,\n });\n}\n\n/**\n * Stylebook variant of {@link requestSelection}: measure the SELECTED TAG's card (the specimen doc\n * addresses selection by tag, not by tab-document path). Cleared when no tag is selected or the tag\n * has no card in this host's generated doc.\n */\nfunction requestStylebookSelection(host: HostState): void {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n return;\n }\n const tag = shell.stylebook.selection;\n const cardPath = tag ? host.stylebook?.tagToCardPath.get(tag) : undefined;\n if (!tag || !cardPath) {\n host.overlay.setSelection(null);\n return;\n }\n if (!host.ready) {\n return;\n }\n host.selReqId += 1;\n host.channel.post({ kind: \"measure\", paths: [[...cardPath]], reqId: host.selReqId });\n}\n\n/**\n * The default iframe document URL (a static shell that boots the slim canvas bundle). Used when the\n * platform does not provide its own canvasUrl — i.e. the dev server and electrobun keep this path.\n */\nconst DEFAULT_CANVAS_URL = \"/packages/studio/canvas.html\";\n\n/**\n * Release one host: its channel, its overlay, its frame, and everything awaiting a reply from it.\n *\n * A settled-with-nothing reply rather than a dropped promise, because every caller of\n * `requestCanvasEval` / `flushCanvasEdits` / a measure is awaiting one: dropping the entry would\n * hang a save on a frame that no longer exists, and `canvasIdleBlockers()` would go on naming it.\n */\nfunction releaseHost(host: HostState): void {\n host.channel.dispose();\n for (const [reqId, resolve] of pendingEvals) {\n if (evalOwners.get(reqId) === host) {\n pendingEvals.delete(reqId);\n evalOwners.delete(reqId);\n resolve(null);\n }\n }\n for (const [reqId, settle] of pendingFlushes) {\n if (flushOwners.get(reqId) === host) {\n pendingFlushes.delete(reqId);\n flushOwners.delete(reqId);\n settle();\n }\n }\n for (const [, resolve] of host.pendingMeasures) {\n resolve([]);\n }\n host.pendingMeasures.clear();\n host.pendingTabIds.clear();\n cancelInsertHide(host);\n /* The module-level pointer at THIS host goes with it. Everything else here was already released\n and `activeEditHost` was not, so unsplitting a pane with a live inline-edit caret left the\n parent realm believing it was still editing: the format toolbar stayed up anchored to a\n detached frame, and `commitActiveEditSession()` posted `endEdit` through\n `iframe.contentWindow?.postMessage` on a removed frame — an optional-chained silent no-op, so\n the edit was lost without a word. Cleared here rather than guarded at each reader, because\n \"the host that owns the edit session\" cannot be a host that no longer exists. */\n if (activeEditHost === host) {\n activeEditHost = null;\n }\n host.overlay.root.remove();\n host.iframe.remove();\n hosts.delete(host.canvasEl);\n liveHosts.delete(host);\n}\n\n/**\n * Release every canvas host mounted under `root`, and say how many there were.\n *\n * The one NON-lazy path out of {@link liveHosts}. Eleven sites prune a disconnected host when they\n * happen to walk the set, which is enough to stop a dead frame being posted to and is not enough to\n * release it: `iframe-channel.ts` adds a `window` \"message\" listener that only `dispose()` removes,\n * and the sole parent-side `dispose()` was the URL-change rebuild in {@link ensureHost}. So a closed\n * pane — or any mode transition, which detaches every artboard — left one live listener and one\n * overlay subtree per frame, for the life of the window.\n *\n * @param {HTMLElement} root\n * @returns {number} How many hosts were released.\n */\nexport function releaseCanvasHosts(root: HTMLElement): number {\n let released = 0;\n for (const host of new Set(liveHosts)) {\n if (root.contains(host.canvasEl)) {\n releaseHost(host);\n released += 1;\n }\n }\n return released;\n}\n\n/* There is no `liveCanvasHostCount()`. A count the app never reads is a function reachable from\n nothing, which `tests/reachability.test.ts` refuses on principle — and the honest measure was\n already there: {@link releaseCanvasHosts} RETURNS how many it released. */\n\nfunction ensureHost(canvasEl: HTMLElement): HostState {\n // Read the platform's canvasUrl when one is registered; otherwise fall back to the default. The\n // Dev server leaves it unset, and some tests mount without a platform registered.\n const canvasUrl = (hasPlatform() ? getPlatform().canvasUrl : undefined) ?? DEFAULT_CANVAS_URL;\n const existing = hosts.get(canvasEl);\n if (existing) {\n if (existing.canvasUrl === canvasUrl) {\n return existing;\n }\n // The platform's loopback canvasUrl arrived after this host was built with the default URL\n // (electrobun resolves it async over RPC) — tear the early iframe down and rebuild against the\n // Right cross-origin origin.\n releaseHost(existing);\n }\n // ParentOrigin is the parent's real origin, passed into the iframe URL so the cross-origin iframe\n // Can target a postMessage back at it.\n const parentOrigin = location.origin;\n const token = crypto.randomUUID();\n // IframeOrigin is the iframe's own origin. For a RELATIVE canvasUrl (dev / chromium) it resolves to\n // The parent's location.origin (same-origin). For an absolute loopback canvasUrl (electrobun) it is\n // The loopback origin, so the channel accepts/targets the right cross-origin peer.\n const iframeOrigin = new URL(canvasUrl, location.href).origin;\n const iframe = document.createElement(\"iframe\");\n iframe.className = \"jx-canvas-iframe\";\n // Without a title the whole canvas is an unlabelled frame to assistive tech — and the canvas is\n // The artefact, not chrome.\n iframe.title = \"Canvas — live page render\";\n iframe.style.cssText =\n \"width:100%;min-height:480px;height:100%;border:0;display:block;background:#fff\";\n // Preserve any query already on canvasUrl (e.g. electrobun's ?win=7) and append the token (always)\n // Plus parentOrigin (conditionally — see below).\n const srcUrl = new URL(canvasUrl, location.href);\n srcUrl.searchParams.set(\"token\", token);\n // Pass parentOrigin into the iframe src ONLY when the PARENT is served over http(s) (dev / chromium\n // — same-origin, so the origin round-trips and the iframe can keep its acceptOrigin STRICT). For a\n // Non-http(s) parent (electrobun views://) OMIT it: a custom scheme may not surface as a postMessage\n // Origin (event.origin), so the iframe falls back to acceptOrigin '*' + the shared token (it logs\n // The warn) rather than silently stalling. The PARENT side here stays STRICT — acceptOrigin /\n // TargetOrigin are the real (loopback) iframeOrigin below, a gateable origin.\n if (location.protocol === \"http:\" || location.protocol === \"https:\") {\n srcUrl.searchParams.set(\"parentOrigin\", parentOrigin);\n }\n // Keep a relative canvasUrl relative in the src attribute (emit only path+query, not the resolved\n // Absolute URL) so the same-origin path stays byte-identical.\n iframe.src = iframeOrigin === parentOrigin ? `${srcUrl.pathname}${srcUrl.search}` : srcUrl.href;\n // Overlay boxes are positioned within the canvas element, so it must be a positioned ancestor.\n if (!canvasEl.style.position) {\n canvasEl.style.position = \"relative\";\n }\n const overlay = createOverlayLayer(document);\n canvasEl.replaceChildren(iframe, overlay.root);\n registerCanvasGutterDrop(canvasEl, () => hostForCanvas(canvasEl));\n const channel = postMessageChannel<ParentToIframe, IframeToParent>({\n acceptOrigin: iframeOrigin,\n source: window,\n // Read contentWindow lazily: a freshly-navigated iframe swaps its window, so never capture it.\n target: {\n postMessage: (message, targetOrigin) =>\n iframe.contentWindow?.postMessage(message, targetOrigin),\n },\n targetOrigin: iframeOrigin,\n token,\n });\n\n const state: HostState = {\n canvasEl,\n canvasUrl,\n channel,\n contentFragment: false,\n contentHeight: null,\n editing: false,\n editingProp: null,\n iframe,\n insertHideTimer: null,\n insertHover: false,\n coSelectionKeys: new Set<string>(),\n insertZone: null,\n lastRenderedGen: -1,\n lastSelectionRect: null,\n lastSnapshotSeq: 0,\n overlay,\n panReqId: -1,\n pending: null,\n idle: null,\n pendingEnterEdit: null,\n pendingMeasures: new Map(),\n pendingPatches: 0,\n pendingTabIds: new Map(),\n presenceMeta: new Map(),\n presenceReqId: -1,\n preview: false,\n ready: false,\n selectionPath: null,\n selectionPaths: [],\n selReqId: 0,\n snapshot: null,\n stylebook: null,\n tabId: null,\n };\n // The insertion \"+\" lives on the overlay (the one pointer-events:auto element there). Clicking it\n // Opens the slash menu → mutateInsertNode for the captured zone; mouseenter/leave record whether\n // The cursor is ON it, which both drives the grace timer and VETOES a hide the iframe's (async,\n // Later-arriving) leave post armed underneath the author — see {@link HostState.insertHover}.\n overlay.insertButton.addEventListener(\"click\", (e) => onInsertButtonClick(state, e));\n overlay.insertButton.addEventListener(\"mouseenter\", () => {\n state.insertHover = true;\n cancelInsertHide(state);\n });\n overlay.insertButton.addEventListener(\"mouseleave\", () => {\n state.insertHover = false;\n scheduleInsertHide(state);\n });\n channel.onMessage((msg) => handleMessage(state, msg));\n hosts.set(canvasEl, state);\n liveHosts.add(state);\n ensureSelectionWatch();\n ensurePresenceWatch();\n return state;\n}\n\n// ─── Insertion \"+\" affordance (cross-origin) ────────────────────────────────────\n\n/** Show the \"+\" for `zone`, capturing it on the host for the click handler; cancels any hide. */\nfunction showInsertZone(state: HostState, zone: InsertZone): void {\n cancelInsertHide(state);\n state.insertZone = zone;\n state.overlay.setInsertZone(canvasRectToParent(zone.rect), zone.edge);\n}\n\n/** Hide the \"+\" immediately and forget the captured zone. */\nfunction hideInsertZoneNow(state: HostState): void {\n cancelInsertHide(state);\n state.insertZone = null;\n state.insertHover = false;\n state.overlay.setInsertZone(null);\n}\n\n/**\n * Whether the cursor is on the \"+\" right now. {@link HostState.insertHover} is the primary signal;\n * the live `:hover` match is a belt-and-braces second one for a button that materialised UNDER an\n * already-stationary cursor (the browser updates `:hover` on that layout change, but a `mouseenter`\n * is not guaranteed).\n */\nfunction insertButtonHovered(state: HostState): boolean {\n const btn = state.overlay.insertButton;\n return state.insertHover || (typeof btn.matches === \"function\" && btn.matches(\":hover\"));\n}\n\n/**\n * Arm the grace timer to hide the \"+\" (SALVAGED HIDE_DELAY), replacing any pending one. The hide is\n * SKIPPED when the cursor turns out to be on the button by the time it fires — see\n * {@link HostState.insertHover} for why a cancel-on-mouseenter alone loses that race.\n */\nfunction scheduleInsertHide(state: HostState): void {\n cancelInsertHide(state);\n state.insertHideTimer = setTimeout(() => {\n state.insertHideTimer = null;\n if (insertButtonHovered(state)) {\n return;\n }\n hideInsertZoneNow(state);\n }, INSERT_HIDE_DELAY);\n}\n\n/** Cancel a pending grace-timer hide of the \"+\". */\nfunction cancelInsertHide(state: HostState): void {\n if (state.insertHideTimer !== null) {\n clearTimeout(state.insertHideTimer);\n state.insertHideTimer = null;\n }\n}\n\n/**\n * Click the \"+\": defer to the injected slash-menu → mutateInsertNode handler with the captured\n * zone.\n */\nfunction onInsertButtonClick(state: HostState, e: MouseEvent): void {\n e.stopPropagation();\n e.preventDefault();\n const zone = state.insertZone;\n if (!zone) {\n return;\n }\n insertZoneClickHandler?.(state.overlay.insertButton, zone);\n}\n\n/**\n * Messages a PREVIEW render is not allowed to act on. Preview must behave like the shipped page:\n * clicking selects nothing, nothing is outlined, there is no insertion \"+\", the browser's own\n * context menu stands, nothing can be dropped into it, and no text can be typed into it.\n *\n * The frame withholds most of these itself ({@link file://./iframe-interaction.ts}'s mode gate),\n * but the canvas bundle ships prebuilt in `dist/`, so the host refuses them independently rather\n * than trusting the frame's build to be current. Cleanup messages (`dragEnd`, `fileDragLeave`) are\n * deliberately NOT blocked — they only tear affordances down.\n */\nconst PREVIEW_BLOCKED: ReadonlySet<IframeToParent[\"kind\"]> = new Set([\n \"contextMenu\",\n \"dragOver\",\n \"dropResult\",\n \"editCommit\",\n \"editCommitProp\",\n \"editInsert\",\n \"editMerge\",\n \"editRangeReplace\",\n \"editSplit\",\n \"editStart\",\n \"fileDragOver\",\n \"fileDrop\",\n \"hit\",\n \"hover\",\n \"insertZones\",\n \"layoutHit\",\n \"nativeDragEnter\",\n]);\n\n/** Handle a message the iframe posted back: ready handshake, pointer hit/hover, measured geometry. */\nfunction handleMessage(state: HostState, msg: IframeToParent): void {\n if (state.preview && PREVIEW_BLOCKED.has(msg.kind)) {\n return;\n }\n switch (msg.kind) {\n case \"ready\": {\n state.ready = true;\n /* The chord table first, before the pending render: a frame that has painted a page the\n author can click into must already know which keystrokes to hand back. */\n const table = keymapSource?.();\n if (table) {\n state.channel.post({ chords: table.chords, kind: \"keymap\", mac: table.mac });\n }\n if (state.pending) {\n state.channel.post(state.pending);\n state.pending = null;\n }\n // Re-measure the current selection now that the iframe can answer.\n requestSelection(state, state.selectionPaths);\n return;\n }\n case \"paneFocus\": {\n /* The frame says only that a pointer went down in it. Every mode posts this, including\n preview — see the message's own docstring for the two holes in `hit` that it closes. */\n focusHostPane(state);\n // …and \"a pointer went down in a canvas\" is exactly what un-hides the block action bar: the\n // Author is back on the surface it belongs to. Harmless in preview, where the bar draws\n // Nothing anyway.\n canvasPointerDownHandler?.();\n return;\n }\n case \"hit\": {\n /* A click in a canvas is a click in a PANE, and the parent realm never saw it. See\n `focusHostPane`; it goes first so everything below writes into the pane the person is now\n in rather than starting a selection the Inspector will not show. `paneFocus` has usually\n beaten it here, and both stay: the canvas bundle ships prebuilt, so a frame whose build\n predates `paneFocus` must still focus its pane on a click that lands on a node. */\n focusHostPane(state);\n // Both, for the same reason and the same cost: the release is a no-op unless the bar is\n // Actually suppressed, so the pair of calls a modern frame makes is one null check.\n canvasPointerDownHandler?.();\n // Selecting a real document node retires any layout selection — the two are alternatives, and\n // A stale layout panel next to a fresh element selection would name the wrong thing.\n setLayoutSelection(null);\n // The clicked panel becomes the ACTIVE panel (same as clicking its header): getActivePanel(),\n // Header highlighting, and the style panel's breakpoint context all follow the click — and the\n // Block action bar anchors to the panel the selection was actually made in, not panel 0.\n let panelMedia: string | null = null;\n const clicked = panelHostingCanvas(state.canvasEl)?.panel;\n if (clicked && !clicked.mediaName?.startsWith(\"git-diff\")) {\n panelMedia = panelMediaToActiveMedia(clicked.mediaName);\n // The breakpoint belongs to the tab THIS host renders, resolved the same way every other\n // Doc-touching message in this switch resolves it. `updateUi` writes to `activeTab`, which\n // Is the focused pane's tab — so a click in an unfocused pane set the wrong document's\n // Breakpoint, and the Style panel then edited a compound block the person never opened.\n const hitTab = hostTab(state);\n if (hitTab) {\n hitTab.session.ui.activeMedia = panelMedia;\n }\n }\n // A canvas left-click closes an open context menu — its parent-realm outside-click listener\n // Can't see clicks inside the cross-origin iframe.\n canvasContextMenuHandler?.dismiss();\n // Stylebook host: the path decodes to a TAG (or null = deselect) and routes to the injected\n // Handler — specimen paths are NOT tab-document paths, so session.selection stays untouched.\n if (state.stylebook) {\n const tag = resolveStylebookTag(state.stylebook.pathToTag, msg.hit.path);\n stylebookHitHandler?.(tag, panelMedia);\n if (tag) {\n // Draw immediately from the posted rect; the selection watcher re-measures the CARD.\n const rect = canvasRectToParent(msg.hit.rect);\n state.overlay.setSelection(rect, `<${tag}>`);\n state.lastSelectionRect = rect;\n } else {\n state.overlay.setSelection(null);\n }\n return;\n }\n // A click in the canvas selects the node; the selection watcher redraws the box via `measure`.\n // Ctrl/Cmd-click ACCUMULATES instead — the same modifier the Outline uses, so the two\n // Surfaces answer the same gesture. Without the modifier this is a plain replace, which is\n // What every canvas click has always been.\n state.selectionPath = msg.hit.path;\n state.selectionPaths = [msg.hit.path];\n const tab = hostTab(state);\n if (tab) {\n tab.session.selection = msg.additive\n ? toggleSelected(tab.session.selection, msg.hit.path)\n : [msg.hit.path];\n }\n // Draw immediately from the posted rect for snappiness (the measure round-trip confirms it).\n {\n const rect = canvasRectToParent(msg.hit.rect);\n state.overlay.setSelection(rect);\n state.lastSelectionRect = rect;\n }\n return;\n }\n case \"layoutHit\": {\n // A click on layout chrome — a node with no page-document path, so it can never become a\n // `session.selection`. Before this it selected nothing and posted nothing, which is what made\n // The first click a new user makes (the site name in the header) appear to do nothing at all.\n // Specimen catalogs have no layout, so the stylebook host ignores it.\n if (state.stylebook) {\n return;\n }\n // Layout chrome is still canvas, and clicking it is still a click in a pane.\n focusHostPane(state);\n canvasContextMenuHandler?.dismiss();\n setLayoutSelection(msg.hit);\n // Mutually exclusive with a document selection: the inspector renders one panel or the other.\n state.selectionPath = null;\n state.selectionPaths = [];\n const tab = hostTab(state);\n if (tab) {\n tab.session.selection = [];\n }\n const rect = canvasRectToParent(msg.hit.rect);\n state.overlay.setSelection(rect, `LAYOUT · ${msg.hit.layoutFile}`);\n state.lastSelectionRect = rect;\n renderOnly(\"rightPanel\");\n return;\n }\n case \"hover\": {\n if (state.stylebook) {\n // Decode to a tag; suppress the box when hovering the selected tag (legacy parity).\n const tag = msg.hit ? resolveStylebookTag(state.stylebook.pathToTag, msg.hit.path) : null;\n const selected = shell.stylebook.selection;\n if (msg.hit && tag && tag !== selected) {\n state.overlay.setHover(canvasRectToParent(msg.hit.rect));\n } else {\n state.overlay.setHover(null);\n }\n return;\n }\n drawHover(state, msg.hit);\n return;\n }\n case \"insertZones\": {\n // Document-editing affordance — never for specimen catalogs (belt-and-braces with the\n // Iframe-side mode gate).\n if (state.stylebook) {\n return;\n }\n // The iframe recomputed the insertion \"+\" zones for the hovered node. Draw the \"+\" from the\n // First zone's rect (scale=1, D-2 — the overlay is inside the scaled panzoom-wrap); a null/empty\n // Set arms the grace timer rather than hiding immediately, so the cursor can reach the button.\n const zone = msg.zones?.[0] ?? null;\n if (zone) {\n showInsertZone(state, zone);\n } else {\n scheduleInsertHide(state);\n }\n return;\n }\n case \"geometry\": {\n // A `measureCanvasPath` caller is waiting on this exact id — answer it and stop. Checked\n // FIRST because these ids come from the same counter as the two overlay measures below, so\n // Falling through would let a point request repaint the selection box.\n const awaiting = state.pendingMeasures.get(msg.reqId);\n if (awaiting) {\n state.pendingMeasures.delete(msg.reqId);\n awaiting(msg.hits);\n return;\n }\n // Remote-presence reply: draw one colored box per measured peer selection.\n if (msg.reqId === state.presenceReqId) {\n state.presenceReqId = -1;\n const items: { placement: OverlayPlacement; color: string; label: string }[] = [];\n for (const hit of msg.hits) {\n const meta = state.presenceMeta.get(JSON.stringify(hit.path));\n if (meta) {\n items.push({ ...meta, placement: canvasRectToParent(hit.rect) });\n }\n }\n state.overlay.setPresence(items);\n return;\n }\n // Pan-to-card reply (stylebook): convert the card's iframe rect to parent-viewport space by\n // The empirical zoom + iframe offset and center it.\n if (msg.reqId === state.panReqId) {\n state.panReqId = -1;\n const [hit] = msg.hits;\n if (hit) {\n const { rect: ifr, scale } = hostDragGeometry(state);\n panToParentRect({ height: hit.rect.height * scale, top: hit.rect.y * scale + ifr.top });\n }\n return;\n }\n if (msg.reqId === state.selReqId) {\n // A stylebook host measures a SPECIMEN path — a card in a generated catalogue, which is\n // Not a `session.selection` path at all — so its one hit is its one box, as it always was.\n // Everywhere else the primary is chosen by PATH rather than by position, because a path\n // The iframe could not resolve is simply absent from `hits`.\n const primaryKey = JSON.stringify(state.selectionPath);\n const co: OverlayPlacement[] = [];\n let rect: ParentRect | null = null;\n if (state.stylebook) {\n const [hit] = msg.hits;\n rect = hit ? canvasRectToParent(hit.rect) : null;\n } else {\n for (const hit of msg.hits) {\n const key = JSON.stringify(hit.path);\n if (key === primaryKey) {\n rect = canvasRectToParent(hit.rect);\n } else if (state.coSelectionKeys.has(key)) {\n co.push(canvasRectToParent(hit.rect));\n }\n }\n }\n const sbTag = state.stylebook ? shell.stylebook.selection : null;\n state.overlay.setSelection(rect, sbTag ? `<${sbTag}>` : null);\n state.overlay.setCoSelection(co);\n if (rect) {\n state.lastSelectionRect = rect;\n }\n }\n return;\n }\n case \"evalResult\": {\n // A live expression-preview reply (M6). Resolve the pending request by reqId (unknown ids —\n // Already timed out or from a torn-down request — are dropped), gen-gating it so values\n // Computed against a superseded render resolve null (the caller keeps the snapshot preview).\n const resolve = pendingEvals.get(msg.reqId);\n if (!resolve) {\n return;\n }\n pendingEvals.delete(msg.reqId);\n evalOwners.delete(msg.reqId);\n resolve(msg.gen === state.lastRenderedGen ? msg.results : null);\n return;\n }\n case \"renderComplete\": {\n // Adopt the tab identity this render was mounted with. host.tabId flips ONLY here — after any\n // Edit-session commit the iframe posted ahead of this ack on the FIFO channel — so a commit\n // Racing a tab switch still routes to the tab its session belonged to.\n if (state.pendingTabIds.has(msg.gen)) {\n state.tabId = state.pendingTabIds.get(msg.gen) ?? null;\n }\n for (const gen of state.pendingTabIds.keys()) {\n if (gen <= msg.gen) {\n state.pendingTabIds.delete(gen);\n }\n }\n onDomUpdated(state, msg.gen);\n return;\n }\n case \"patchComplete\": {\n // A patch never re-targets the host (tabId untouched) — only the DOM/geometry changed.\n state.pendingPatches = Math.max(0, state.pendingPatches - 1);\n onDomUpdated(state, msg.gen);\n return;\n }\n case \"idle\": {\n // The frame's own quiescence report. Held, not acted on: it is read by\n // {@link canvasIdleBlockers} when something asks whether Studio has settled.\n state.idle = {\n animations: msg.animations,\n fonts: msg.fonts,\n gen: msg.gen,\n images: msg.images,\n };\n return;\n }\n case \"renderError\": {\n // The render never landed — its pending identity must not be adopted by a later ack.\n state.pendingTabIds.delete(msg.gen);\n // …and no `dataScope` will follow it, so a Refresh waiting on one must stop waiting. Without\n // This the button spins forever on the one failure it most needs to report.\n const failed = hostTab(state);\n if (failed) {\n failed.session.canvas.refreshing = false;\n renderOnly(\"leftPanel\");\n }\n // …and the author is told. `msg.message` was read NOWHERE: the canvas would go blank or stale\n // And the one string that said why was deleted with the pending id. Keyed on the host, so a\n // Render loop that fails every generation is one problem rather than sixty.\n notify.error(\"The page could not be rendered.\", {\n detail: msg.message,\n key: `canvas.render:${hostLabel(state)}`,\n source: \"Canvas\",\n });\n return;\n }\n case \"dataScope\": {\n // The iframe posted its resolved $defs snapshot right after renderComplete. Adopt it into the\n // Parent's canvas state so the data-explorer panel shows live data (buildScope moved into the\n // Iframe realm; the parent hard-codes scope:null at ready). Gate on the last-rendered gen so a\n // Snapshot from a superseded render can't clobber the current one, then re-render the left\n // Panel (which hosts the data-explorer) to reflect the new scope.\n if (msg.gen !== state.lastRenderedGen) {\n return;\n }\n // Onto the tab this host rendered, not the focused one: the snapshot describes THAT\n // Document's `$defs`, and `updateCanvas` would have filed a background pane's data under the\n // Foreground pane's tab — the Data panel then explains a document that is not on screen.\n const scoped = hostTab(state);\n if (scoped) {\n scoped.session.canvas.scope = msg.scope;\n // The answer a pending Refresh was waiting for. Clearing it HERE rather than on a timer is\n // The whole point: a fetch that takes two seconds keeps saying so for two seconds.\n scoped.session.canvas.refreshing = false;\n }\n renderOnly(\"leftPanel\");\n return;\n }\n case \"contentHeight\": {\n // The measurement is STATE, not an instruction: record it, then re-derive the frame box from\n // (preview flag, last measurement) so the two can never disagree. See applyFrameSizing.\n state.contentHeight = msg.height;\n state.contentFragment = msg.fragment;\n applyFrameSizing(state);\n return;\n }\n case \"dragOver\": {\n // Display-only drop indicator (Phase 4c). Drop stale replies: a different drag session\n // (dragSeq) or a superseded render (gen). The indicator draw side uses scale=1 (D-2) — the\n // Overlay is inside the scaled panzoom-wrap, so the browser already applies the zoom.\n if (msg.dragSeq !== currentDragSeq) {\n return;\n }\n // A cursor-carrying dragOver means the IFRAME is driving the over-stream from its own events\n // (native routing or flow 3) — not merely replying to a parent-forwarded dragMove. Record it\n // BEFORE the gen gate: it's a fact about event routing, not render freshness.\n if (msg.cursor) {\n lastIframeDragOverSeq = msg.dragSeq;\n lastIframeDragOverAt = Date.now();\n }\n if (msg.gen !== state.lastRenderedGen) {\n return;\n }\n if (msg.preview) {\n state.overlay.setDropIndicator(\n canvasRectToParent(msg.preview.referenceRect),\n msg.preview.edge,\n );\n } else {\n state.overlay.setDropIndicator(null);\n }\n // Flow 3 (iframe-driven) posts a `cursor` in iframe-viewport coords: the parent has no pointer\n // Of its own during an iframe-originated drag, so position the ghost by FORWARD-converting the\n // Cursor to parent-viewport space (the inverse of parentCursorToIframe). Parent-driven flows\n // (1/2/4) omit `cursor` — the bridge moves their ghost from the raw parent pointer.\n if (msg.cursor) {\n const g = hostDragGeometry(state);\n moveDragGhost(msg.cursor.x * g.scale + g.rect.left, msg.cursor.y * g.scale + g.rect.top);\n }\n return;\n }\n case \"nativeDragEnter\": {\n if (state.stylebook) {\n return; // A specimen catalog is never a drop target.\n }\n // A parent-originated NATIVE drag crossed onto this iframe before any session bound it (the\n // Parent never sees a cursor inside the iframe rect) — let the bridge bind/migrate here.\n nativeDragEnterHandler?.(state);\n return;\n }\n case \"dragEnd\": {\n // The iframe cancelled a flow-3 drag locally (Escape). Tear down the indicator/ghost and\n // Release the retained source data so no drop is applied.\n state.overlay.setDropIndicator(null);\n clearDragGhost();\n retainedSrcData.delete(msg.dragSeq);\n return;\n }\n case \"dropResult\": {\n // The authoritative, freshly-computed drop (Phase 4c). Apply through the realm-agnostic\n // Mutation helper with the PARENT-retained source data, unless stale or empty.\n if (msg.dragSeq !== currentDragSeq || msg.gen !== state.lastRenderedGen) {\n return;\n }\n if (msg.instruction && msg.targetPath) {\n const srcData = retainedSrcData.get(msg.dragSeq);\n if (srcData) {\n applyDropInstruction(hostTab(state), { type: msg.instruction }, srcData, msg.targetPath);\n }\n }\n retainedSrcData.delete(msg.dragSeq);\n // The drop resolved (or was empty) — tear down the display affordances on this host.\n state.overlay.setDropIndicator(null);\n clearDragGhost();\n return;\n }\n case \"fileDragOver\": {\n if (state.stylebook) {\n return; // A specimen catalog is never a drop target.\n }\n showFileDropAffordance(state, msg.hit, msg.preview);\n return;\n }\n case \"fileDragLeave\": {\n clearFileDropAffordance(state);\n return;\n }\n case \"fileDrop\": {\n clearFileDropAffordance(state);\n if (state.stylebook) {\n return;\n }\n void fileDropHandler?.(hostTab(state), msg.files, msg.hit, msg.preview);\n return;\n }\n case \"patchError\": {\n // The iframe couldn't apply the edit surgically — fall back to a full render of the live doc.\n // The patch is no longer outstanding either way; a counter that only went up would wedge\n // Every later idle() behind a message the host already handled.\n state.pendingPatches = Math.max(0, state.pendingPatches - 1);\n /* An UNRESOLVABLE stage escalates nothing, and that is now a complete answer rather than a\n hole. It used to be half of finding 9: `postPatchToHosts` posted a fabricated gen `0` to a\n host whose stage it could not name, the frame answered `patch-behind-render`, and this\n same failing lookup swallowed the escalation while `markConsumed` had already suppressed\n the pane's full render. The post side refuses to post at all now, so reaching here means\n the panel list was replaced BETWEEN the post and the ack — and that replacement is itself\n a newer full render of this stage, which is why scheduling one would rebuild a stage that\n is not stale. See the two tests either side of this in `iframe-host.test.ts`. */\n const failed = panelHostingCanvas(state.canvasEl)?.surface;\n if (failed) {\n patchEscalation?.(failed.paneId);\n }\n return;\n }\n case \"forwardKey\": {\n // A global shortcut pressed while the iframe had focus — replay it for the editor's handler.\n redispatchKey(msg.event);\n return;\n }\n case \"forwardWheel\": {\n // A wheel over the iframe — replay it on canvasWrap so the editor's zoom/pan handler fires (the\n // Cursor is mapped from iframe-viewport coords to parent-viewport via this host's scale + offset).\n redispatchWheel(state, msg);\n return;\n }\n case \"editStart\": {\n // Inline editing began in this host's iframe. Only one editable is active across all panels —\n // Tear down any other host's editing state and make this the single active edit host.\n if (activeEditHost && activeEditHost !== state) {\n activeEditHost.editing = false;\n activeEditHost.editingProp = null;\n activeEditHost.snapshot = null;\n }\n activeEditHost = state;\n // Each visit to a block is one undoable edit. Bumping the run id here breaks the history\n // Coalescing run, so returning to the same paragraph later is a separate ⌘Z step.\n editRunSeq += 1;\n state.editing = true;\n state.editingProp = msg.prop ?? null;\n state.snapshot = null;\n state.lastSnapshotSeq = 0;\n toolbarRefresh?.();\n return;\n }\n case \"selectionChanged\": {\n // Drop stale (re-ordered) snapshots; otherwise store the latest and refresh the toolbar.\n if (msg.seq <= state.lastSnapshotSeq) {\n return;\n }\n state.lastSnapshotSeq = msg.seq;\n state.snapshot = msg;\n /* A snapshot posts ONLY from a live session (the frame's `onSelectionChange` returns early\n when nothing is being edited), so it is independent proof that a caret is alive in this\n host — the third of the three messages {@link isCaretActive} is derived from. Adopting the\n host here recovers the flag if the `editStart` that opened the session never landed, and it\n cannot resurrect a finished one: the frame stops posting snapshots before it posts\n `editEnd`, and the channel is FIFO. */\n if (!state.editing) {\n state.editing = true;\n activeEditHost = state;\n }\n toolbarRefresh?.();\n return;\n }\n case \"flushComplete\": {\n const done = pendingFlushes.get(msg.reqId);\n if (done) {\n pendingFlushes.delete(msg.reqId);\n flushOwners.delete(msg.reqId);\n done();\n }\n return;\n }\n case \"editCommit\": {\n // Route to the tab this host's iframe renders — NOT activeTab, which may have changed while\n // The message was in flight (the cross-document bleed).\n const apply = () =>\n applyInlineCommit(hostTab(state), msg.path, msg.children, msg.textContent);\n // An in-place commit (the idle tick) leaves the caret in the block, so the echoed patch must\n // Not re-render it. A commit on release renders normally — the caret has already left.\n if (msg.inPlace) {\n withEchoSuppressed(state, [msg.path], apply);\n } else {\n apply();\n }\n return;\n }\n case \"editCommitProp\": {\n // A prop-bound plain session committed: persist into the instance's $props (same host-tab\n // Routing as editCommit; the unchanged-value no-op lives in the apply).\n //\n // A $props change re-renders the WHOLE component instance, which would tear out the nested\n // Editing host the caret is typing in — so an in-place commit is echo-suppressed exactly as a\n // Page block's is. The instance re-renders for real on release.\n const applyProp = () => applyInlinePropCommit(hostTab(state), msg.path, msg.prop, msg.value);\n if (msg.inPlace) {\n withEchoSuppressed(state, [msg.path], applyProp);\n } else {\n applyProp();\n }\n return;\n }\n case \"editMerge\": {\n // Joining two blocks removes one of them, so the caret has to be re-placed — at the SEAM,\n // Where the two blocks met, which is where the author's cursor visually was.\n const seam = applyBlockMerge(hostTab(state), msg.fromPath, msg.intoPath);\n if (seam) {\n deferEnterEdit(state, seam.path, seam.offset);\n }\n return;\n }\n case \"editRangeReplace\": {\n const caret = applyRangeReplace(hostTab(state), msg.from, msg.to, msg.between, msg.text);\n if (caret) {\n deferEnterEdit(state, caret.path, caret.offset);\n }\n return;\n }\n case \"editSplit\": {\n // The mutation lands now (surgical patch or escalated render); re-entry on the new paragraph\n // Is deferred until this host acks the DOM that contains it (see deferEnterEdit).\n deferEnterEdit(state, applyInlineSplit(hostTab(state), msg.path, msg.before, msg.after));\n return;\n }\n case \"editInsert\": {\n deferEnterEdit(state, applyInlineInsert(hostTab(state), msg.path, msg.cmd, msg.commitData));\n return;\n }\n case \"slashShow\": {\n // The iframe engine wants the slash menu at its edited element's rect (iframe-viewport) —\n // Convert to parent-viewport by the empirical zoom + iframe offset and show the real menu.\n // The select/dismiss callbacks post back over THIS host's channel, closing the loop.\n const { rect: ifr, scale } = hostDragGeometry(state);\n const left = msg.rect.x * scale + ifr.left;\n const top = msg.rect.y * scale + ifr.top;\n canvasSlashHandler?.show({\n filter: msg.filter,\n ...(msg.showFilter === true ? { showFilter: true } : {}),\n onDismiss: () => state.channel.post({ kind: \"slashDismissed\" }),\n onSelect: (cmd) => state.channel.post({ cmd: { ...cmd }, kind: \"slashSelect\" }),\n rect: {\n bottom: top + msg.rect.height * scale,\n height: msg.rect.height * scale,\n left,\n top,\n width: msg.rect.width * scale,\n },\n });\n return;\n }\n case \"slashNav\": {\n canvasSlashHandler?.nav(msg.key);\n return;\n }\n case \"slashDismiss\": {\n canvasSlashHandler?.dismiss();\n return;\n }\n case \"previewNavigate\": {\n openPreviewHref(msg.href, state);\n return;\n }\n case \"contextMenu\": {\n if (state.stylebook) {\n return; // The doc context menu's actions are meaningless for specimen paths.\n }\n /* A right-click is a click, and it is the ONLY message it delivers: `contextmenu` does not\n fire `click`, so `hit` — where the other half of this seam focuses the pane — never\n arrives. Without this line the menu was built against the FOCUSED document while pointing\n at a node in this one: `editor/context-menu.ts` writes `tab.session.selection = [path]`\n before it decides which rows to show, so right-clicking the side pane moved the PRIMARY\n pane's selection to a path from a different document, and Duplicate/Delete/Wrap then\n operated there. When the focused document had no such path the menu returned early and the\n right-click did nothing at all, silently. */\n focusHostPane(state);\n // A canvas right-click — convert to parent-viewport coords and show the Jx element menu.\n const { rect: ifr, scale } = hostDragGeometry(state);\n canvasContextMenuHandler?.show({\n clientX: msg.x * scale + ifr.left,\n clientY: msg.y * scale + ifr.top,\n path: msg.path ? [...msg.path] : null,\n });\n return;\n }\n case \"editEnd\": {\n // Ignore a superseded late editEnd (a re-enter's stop→start can deliver a stale one): only act\n // When this host is still the one editing.\n if (!state.editing) {\n return;\n }\n state.editing = false;\n state.editingProp = null;\n state.snapshot = null;\n if (activeEditHost === state) {\n activeEditHost = null;\n }\n toolbarRefresh?.();\n break;\n }\n default: {\n break;\n }\n }\n}\n\n/**\n * Shared renderComplete/patchComplete bookkeeping: the DOM (and so all geometry) just changed —\n * re-measure the selection box, record the gen the DOM now reflects (cross-frame drag replies are\n * stale-gated against it, Phase 4c), drop the \"+\" (anchored to a now-stale rect), and flush a\n * deferred split/insert re-entry once the DOM containing the new element is live.\n */\nfunction onDomUpdated(state: HostState, gen: number): void {\n state.lastRenderedGen = gen;\n requestSelection(state, state.selectionPaths);\n requestPresence(state);\n hideInsertZoneNow(state);\n if (state.pendingEnterEdit && gen >= state.pendingEnterEdit.minGen) {\n const { offset, path } = state.pendingEnterEdit;\n state.pendingEnterEdit = null;\n /* Re-enter only when this host STILL SHOWS THE TAB IT OWES THE CARET TO — which is a question\n about this host's pane, not about the focus. A background tab's iframe renders a different\n document, so re-entering there would grab the wrong element; the commit itself already landed\n in the right tab via `hostTab` routing.\n This asked `workspace.activeTabId` for two phases, which is the same question only while\n there is one stage. With two, the side pane could be displaying its tab, holding a caret it\n owed, and drop it because the PRIMARY had focus. */\n if (state.tabId !== null && state.tabId === tabOfContainer(state.canvasEl)?.id) {\n reenterEdit(state, path, offset);\n }\n }\n}\n\n/**\n * Defer re-entering inline editing on `path` until this host's DOM reflects the split/insert (see\n * {@link onDomUpdated}). `minGen` is the gen the host currently reflects: the surgical patch acks at\n * that same gen; an escalated full render acks at a bumped one — both satisfy `gen >= minGen`,\n * while a stale ack cannot. Latest-wins on overwrite.\n */\nfunction deferEnterEdit(state: HostState, path: (string | number)[], offset?: number): void {\n state.pendingEnterEdit = {\n minGen: state.lastRenderedGen,\n path: [...path],\n ...(offset === undefined ? {} : { offset }),\n };\n}\n\n/** Ask the host's iframe to (re-)enter inline editing on `path` (a plain copy crosses the bridge). */\nfunction reenterEdit(state: HostState, path: (string | number)[], offset?: number): void {\n state.channel.post({\n kind: \"enterEdit\",\n path: [...path],\n ...(offset === undefined ? {} : { offset }),\n });\n}\n\n/**\n * Replay a forwarded wheel on `canvasWrap` so the editor's zoom/pan handler fires. The forwarded\n * cursor is in iframe-viewport CSS px; map it to parent-viewport space by the host's empirical zoom\n * scale ({@link hostDragGeometry}) plus the iframe's on-screen offset, so ctrl+wheel zooms toward\n * the real cursor. A synthetic event triggers no native scroll, which is fine — the handler does\n * the work.\n */\nfunction redispatchWheel(\n state: HostState,\n msg: Extract<IframeToParent, { kind: \"forwardWheel\" }>,\n): void {\n const { rect, scale } = hostDragGeometry(state);\n /* The wheel goes back to the stage this FRAME is mounted on, not to \"the canvas\".\n `canvasWrap` was the focused pane's stage, so a wheel forwarded out of an unfocused pane's\n iframe panned the other pane. Resolved from the DOM rather than from the panel bookkeeping,\n because the frame is physically inside exactly one stage whether or not a pass has recorded an\n artboard for it yet. */\n const stage = stageContaining(state.canvasEl)?.wrap;\n if (!stage) {\n return;\n }\n stage.dispatchEvent(\n new WheelEvent(\"wheel\", {\n bubbles: true,\n cancelable: true,\n clientX: rect.left + msg.x * scale,\n clientY: rect.top + msg.y * scale,\n ctrlKey: msg.ctrlKey,\n deltaX: msg.deltaX,\n deltaY: msg.deltaY,\n metaKey: msg.metaKey,\n shiftKey: msg.shiftKey,\n }),\n );\n}\n\n/** Rebuild and dispatch a synthetic `keydown` on the editor document from a forwarded keystroke. */\nfunction redispatchKey(event: SerializedKey): void {\n document.dispatchEvent(\n new KeyboardEvent(\"keydown\", {\n altKey: event.altKey,\n bubbles: true,\n cancelable: true,\n code: event.code,\n ctrlKey: event.ctrlKey,\n key: event.key,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n }),\n );\n}\n\n/** Draw the hover box, hidden when there's no hover or it coincides with the current selection. */\nfunction drawHover(state: HostState, hit: NodeHit | null): void {\n if (!hit || pathsEqual(hit.path, state.selectionPath)) {\n state.overlay.setHover(null);\n return;\n }\n state.overlay.setHover(canvasRectToParent(hit.rect));\n}\n\n/**\n * The part of a `render` message that is a fact about the DOCUMENT rather than about a host: the\n * resolved and wire-serialized document, its base, the path-mapper context, the mode and the site\n * style. Everything a host contributes — its width, its preview flag, its tab-id bookkeeping —\n * stays outside.\n */\ntype PreparedRender = Omit<\n Extract<ParentToIframe, { kind: \"render\" }>,\n \"colorScheme\" | \"gen\" | \"kind\"\n>;\n\n/** One render pass's prepared payloads, by document IDENTITY. */\ntype PreparedDocs = Map<\n JxMutableNode,\n { tabId: string | null; viewTabId: string | null; payload: Promise<PreparedRender> }\n>;\n\n/**\n * How many render passes may be prepared at once. Two panes, each mid-pass, plus slack.\n *\n * A ceiling rather than \"however many are in flight\", because nothing tells this module when a pass\n * ENDS: the last artboard of a pass is indistinguishable from the first artboard of the next one. A\n * small LRU is the honest bound — a pass whose artboards are still arriving is always among the\n * most recently touched, and anything older cannot be reused by anyone.\n */\nconst PREPARED_PASS_LIMIT = 4;\n\n/**\n * The prepared payload for every render pass in flight, keyed by generation.\n *\n * A design-mode canvas draws one artboard per breakpoint, and every one of them renders the SAME\n * document at a different viewport width. Resolving it per artboard meant N layout merges, N\n * edit-mode transforms, 2N whole-document JSON round trips — and, on a dynamic-route page, N\n * backend round trips, because `resolveParamBoundState` POSTs each param-bound state entry to\n * `/__jx_resolve__` and that ran once per host. The pass resolves once and every host is fed from\n * the result.\n *\n * **It was ONE pass, and a second stage is what made that wrong.** The slot was replaced whenever\n * `gen` differed, on the reasoning that \"a render pass is exactly one generation, so the map is\n * dropped whole when the next pass starts\". That holds while a pass is the only thing running. Both\n * stages schedule through rAF and `mountIframeCanvas` awaits inside the loop, so two passes\n * INTERLEAVE at every await: pane A's second artboard came back to a slot pane B had just claimed,\n * re-resolved and re-serialized a document that had been prepared moments earlier, and evicted pane\n * B's in turn. Three preparations for three artboards — the fan-out this cache exists to remove,\n * restored exactly by the second pane.\n *\n * Within a generation the key is document IDENTITY, because git-diff mounts two different documents\n * under one generation and each gets its own entry. `tabId` rides along because `editableTags` is\n * derived from it, and the VIEW tab's id beside it because the whole resolution is derived from\n * THAT — the document path, the layout toggle, the preview params and the mode. A mismatch in\n * either re-prepares rather than reusing. `tabId` alone would not do: an override render nulls it,\n * so two git-diff documents would agree on `null` while being views of different tabs.\n */\nconst preparedPasses = new Map<number, PreparedDocs>();\n\n/**\n * This generation's prepared documents, created on first mention and touched to the front.\n *\n * Insertion order is the LRU order: re-inserting on every access is what keeps two interleaved\n * passes both live no matter how long they alternate, while a pass nobody has touched for four\n * generations falls off the end.\n */\nfunction preparedDocsFor(gen: number): PreparedDocs {\n const existing = preparedPasses.get(gen);\n if (existing) {\n preparedPasses.delete(gen);\n preparedPasses.set(gen, existing);\n return existing;\n }\n const fresh: PreparedDocs = new Map();\n preparedPasses.set(gen, fresh);\n for (const stale of preparedPasses.keys()) {\n if (preparedPasses.size <= PREPARED_PASS_LIMIT) {\n break;\n }\n preparedPasses.delete(stale);\n }\n return fresh;\n}\n\n/**\n * Resolve + serialize `doc` for the wire, once per render pass.\n *\n * Returns the SAME promise to every host in the pass, so the second artboard awaits the first one's\n * work instead of repeating it. The payload objects it yields are shared by reference across the\n * messages posted to each host: `postMessage` structured-clones on the way into each frame, so\n * every iframe still folds patches into a shadow doc that is its own. Nothing may mutate a\n * `PreparedRender` after it is built.\n */\nfunction preparePassRender(\n gen: number,\n doc: JxMutableNode,\n tabId: string | null,\n viewTab: Tab | null,\n paneId: string,\n): Promise<PreparedRender> {\n const byDoc = preparedDocsFor(gen);\n const viewTabId = viewTab?.id ?? null;\n const cached = byDoc.get(doc);\n if (cached && cached.tabId === tabId && cached.viewTabId === viewTabId) {\n return cached.payload;\n }\n // One-shot per PANE's pass, not per host and not globally. `allowAutoRequestsOnNextRender` arms\n // \"the next render of pane X\": consuming it inside the per-host mount meant whichever artboard\n // Mounted first swallowed it and the rest re-rendered with automatic `Request` entries still\n // Suppressed, and consuming a GLOBAL here meant whichever PANE's pass got here first did the\n // Same to the other one. `gen` comes from one monotonic counter shared by every surface, so a\n // Pass belongs to exactly one pane and this consume is that pane's.\n const allowAutoRequests = consumeAllowAutoRequests(paneId);\n const payload = timeSpanAsync(SPAN_PREPARE_RENDER, async (): Promise<PreparedRender> => {\n canvasPerf.renderPreparations += 1;\n const resolved = await resolveCanvasDocument(doc, viewTab);\n // The doc must be structured-cloneable to cross postMessage. A Jx document is JSON by contract,\n // So a JSON round-trip (NOT structuredClone, which would throw) drops residual functions /\n // Reactive proxy artifacts that would otherwise raise DataCloneError and silently drop the\n // Entire message.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableDoc = JSON.parse(JSON.stringify(resolved.renderDoc)) as unknown;\n // The RAW page doc (forward-op + data-jx-path coordinate space) crosses as the shadow doc.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableShadow = JSON.parse(JSON.stringify(doc)) as unknown;\n // Which tags can hold a caret depends on the document's vocabulary, so the format's verdicts\n // Ride with the render rather than being baked into the frame. Absent for a native document,\n // Where the studio's own element metadata answers on its own.\n // Resolve from THIS render's tab, not any host's `tabId` — that is only adopted when a render is\n // Acknowledged, so at post time it still names the previous render's document (null on first\n // Mount, which is exactly the render that matters).\n const renderTab = tabId ? (workspace.tabs.get(tabId) ?? null) : null;\n const formatElements = formatByName(renderTab?.doc.sourceFormat)?.studio?.elements;\n const editableTags = formatElements ? formatEditableVerdicts(formatElements) : undefined;\n return {\n doc: cloneableDoc,\n docBase: resolved.docBase ?? `${canvasBaseOrigin()}/`,\n mapperCtx: resolved.mapperCtx,\n mode: resolved.mapperCtx.canvasMode as CanvasMode,\n shadowDoc: cloneableShadow,\n siteStyle: resolved.siteStyle,\n ...(editableTags ? { editableTags } : {}),\n ...(allowAutoRequests ? { allowAutoRequests: true } : {}),\n };\n });\n byDoc.set(doc, { payload, tabId, viewTabId });\n return payload;\n}\n\n/**\n * Render `doc` into the iframe canvas mounted in `canvasEl`: resolve the document once for the\n * whole render pass ({@link preparePassRender}) and post it to this host (queued until the iframe\n * is `ready`).\n *\n * `widthPx` makes the panel's breakpoint width an EXPLICIT lever on the iframe element itself (only\n * `style.width` is touched — the rest of cssText, incl. `min-height:480px; height:100%`, is kept).\n * The iframe is a real viewport, so its CSS width is the layout viewport `@media` evaluates\n * against; setting it here survives iframe reuse and any future container-styling change. Null\n * (edit-mode / git-diff / full-width panels) falls back to `100%`. The iframe stays FIXED-HEIGHT —\n * content scrolls inside it like a real device viewport; narrowing the width does not auto-grow\n * it.\n *\n * `tabId` is the identity of the tab whose document this render shows (null for override docs like\n * git-diff, whose iframes must never route doc mutations anywhere). It is recorded against `gen`\n * and adopted into `host.tabId` only when the iframe acks the render — see\n * {@link HostState.tabId}.\n *\n * `viewTab` is a DIFFERENT question and that is why it is a second parameter: `tabId` asks \"where\n * do this frame's mutations go\", `viewTab` asks \"whose document path, layout toggle, preview params\n * and canvas mode resolve it\". They diverge for exactly the override case — a git-diff render has\n * no mutation target but is still a view OF the tab whose diff it is, and its `docBase` and edit\n * transform must come from that tab. The default derives it from the element, the way\n * `paneOfContainer` does everywhere else stage content is handed a host and nothing else; the one\n * production caller (`canvas-render.ts`) passes `tabOfPane(surface.paneId)` explicitly, because it\n * has already resolved it to pick the document.\n */\nexport async function mountIframeCanvas(\n gen: number,\n doc: JxMutableNode,\n canvasEl: HTMLElement,\n widthPx?: number | null,\n tabId: string | null = null,\n viewTab: Tab | null = tabOfContainer(canvasEl),\n): Promise<void> {\n const state = ensureHost(canvasEl);\n state.pendingTabIds.set(gen, tabId);\n // A page mount clears any stylebook capability from a previous mode's reuse of this host.\n state.stylebook = null;\n state.iframe.style.width = widthPx ? `${widthPx}px` : \"100%\";\n // Always resolve and post the latest render. The iframe drops stale generations itself (via its\n // Own `latestGen`), so the parent must NOT gate on `view.renderGeneration`: during boot many\n // Renders fire and the generation is usually stale by the time resolution finishes, which would\n // Otherwise drop every post.\n const prepared = await preparePassRender(gen, doc, tabId, viewTab, paneOfContainer(canvasEl));\n const message: ParentToIframe = {\n ...prepared,\n // Per-TAB, and read at POST time so a scheme flip that raced the shared resolution is not\n // Baked into the payload every host shares. `viewTab` is this artboard's tab — defaulted from\n // `tabOfContainer(canvasEl)`, the same route the rest of this mount takes.\n colorScheme: schemeWireFor(viewTab),\n gen,\n kind: \"render\",\n };\n // Preview is the fidelity view: no editing messages are honoured from it, no overlay is painted\n // Over it, and the frame stays viewport-sized so it scrolls for real. A mode switch to preview\n // Mid-split must likewise not start an edit session in the preview render. The flag and the frame\n // Box move together (setHostPreview) — this assignment sits AFTER an await, so any contentHeight\n // That landed while the document resolved was answered under the previous mode's rule.\n setHostPreview(state, message.mode === \"preview\");\n deliverRender(state, message);\n}\n\n/**\n * Hand a host its render — straight down the channel when the iframe is up, queued as `pending`\n * until it says `ready`. Counted either way: the message is this pass's work for this host whether\n * or not the frame has finished loading.\n */\nfunction deliverRender(state: HostState, message: ParentToIframe): void {\n canvasPerf.hostRenderPosts += 1;\n if (state.ready) {\n state.channel.post(message);\n } else {\n state.pending = message;\n }\n}\n\n/**\n * Mount a STYLEBOOK canvas: post the pre-generated specimen document (no `resolveCanvasDocument` —\n * the generator already merged the effective style/media and there is no layout/page mapping) and\n * arm the host's stylebook capability (tag-addressed hits/selection). Mounted with a NULL tab\n * identity: specimen paths are not tab-document paths, so any doc-mutating bridge message from this\n * host must drop — the existing null-tabId routing does exactly that.\n */\nexport function mountStylebookCanvas(\n gen: number,\n generated: {\n doc: JxMutableNode;\n pathToTag: ReadonlyMap<string, string>;\n tagToCardPath: ReadonlyMap<string, (string | number)[]>;\n },\n canvasEl: HTMLElement,\n widthPx: number | null,\n): void {\n const state = ensureHost(canvasEl);\n state.pendingTabIds.set(gen, null);\n state.stylebook = { pathToTag: generated.pathToTag, tagToCardPath: generated.tagToCardPath };\n setHostPreview(state, false);\n state.pendingEnterEdit = null;\n state.iframe.style.width = widthPx ? `${widthPx}px` : \"100%\";\n // Two independent plain clones: the iframe renders `doc` and folds styleUpdates into `shadowDoc`\n // (and fake test channels pass messages by reference, so sharing one object would alias them).\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableDoc = JSON.parse(JSON.stringify(generated.doc)) as unknown;\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableShadow = JSON.parse(JSON.stringify(generated.doc)) as unknown;\n const message: ParentToIframe = {\n // The specimen carries no tab identity, but the STAGE it is mounted into does: a stylebook is\n // Opened as a tab like anything else, and its `previewColorScheme` is that tab's.\n colorScheme: schemeWireFor(tabOfContainer(canvasEl)),\n doc: cloneableDoc,\n docBase: `${canvasBaseOrigin()}/`,\n gen,\n kind: \"render\",\n mapperCtx: {\n arrayPaths: [],\n canvasMode: \"stylebook\",\n layoutWrapped: false,\n pageContentOffset: null,\n pageContentPrefix: null,\n },\n mode: \"stylebook\",\n shadowDoc: cloneableShadow,\n // The generator already merged projectConfig.style into the doc's own style block — passing\n // SiteStyle too would double-apply it.\n siteStyle: null,\n };\n deliverRender(state, message);\n}\n\n/**\n * A TAB's forced preview scheme as wire data (auto → null).\n *\n * Takes its tab, and that is the whole fix. It was `activeSchemeWire()` — zero-argument, reading\n * `activeTab` — and both mounts call it while holding the artboard they are rendering INTO, so\n * every render of the side pane posted the FOCUSED tab's scheme over its own: a side tab set to\n * Dark rendered light whenever an Auto tab had the keyboard, and a side tab set to Auto rendered\n * dark whenever a Dark one did. Its own control went on saying what it had been set to, because the\n * record it reads is the one nobody wrote.\n *\n * This is verbatim the defect {@link postColorSchemeToLiveHosts} was given a `root` for. The PUSH\n * path was scoped and the RENDER path was not, and the per-pane effect in `studio.ts` only re-runs\n * when the scheme CHANGES — so nothing repaired the pane afterwards, and any later re-render (a\n * document edit, a breakpoint change, a mode switch) silently reverted it again.\n */\nfunction schemeWireFor(tab: Tab | null): \"light\" | \"dark\" | null {\n const s = tab?.session.ui.previewColorScheme;\n return s === \"light\" || s === \"dark\" ? s : null;\n}\n\n/**\n * Flip the color-scheme preview on every ready host (page and stylebook alike — both render\n * scheme-aware CSS). A pure attribute write iframe-side: no render, no patch, no gen.\n */\nexport function postColorSchemeToLiveHosts(\n scheme: \"light\" | \"dark\" | null,\n root?: HTMLElement | null,\n): void {\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n /* Scoped to one stage when the caller names one. The preview scheme is a per-TAB choice\n (`session.ui.previewColorScheme`), so with two live hosts an unscoped post flipped the other\n pane's document to a scheme nobody had asked it for — and left its own control still saying\n \"Auto\", because the record it reads belongs to the tab that was never changed. */\n if (root && !root.contains(host.iframe)) {\n continue;\n }\n if (host.ready) {\n host.channel.post({ kind: \"setColorScheme\", scheme });\n }\n }\n}\n\n/**\n * Flip the artboard's language on every ready host — `lang` and `dir`, and nothing else.\n *\n * This is what makes `i18n.switchLocale` a rendering context rather than a chip. Jx has no message\n * catalogue, so the text does not change; the direction does, and a layout that only mirrors in\n * production is a layout an author cannot check before shipping it.\n *\n * SCOPED to one stage when the caller names one, for the reason {@link postColorSchemeToLiveHosts}\n * carries the same parameter: the preview locale is a per-TAB choice, so with two live hosts an\n * unscoped post redraws the other pane's document in a language nobody asked it for — and leaves\n * its own control still naming the language it was never moved off.\n *\n * `dir` is computed here and sent with the tag: `localeDirection` is CLDR's answer through\n * `Intl.Locale`, and a frame deriving it again is a second copy of the RTL script list to keep.\n */\nexport function postLocaleToLiveHosts(locale: string | null, root?: HTMLElement | null): void {\n const dir = localeDirection(locale);\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (root && !root.contains(host.iframe)) {\n continue;\n }\n if (host.ready) {\n host.channel.post({ dir, kind: \"setLocale\", locale });\n }\n }\n}\n\n/**\n * Push the project's current site style to every ready PAGE host as an in-place sheet replace (live\n * design-token editing — stylebook hosts pre-merge site style into the specimen doc and are\n * skipped). Render-free; the next full render carries the same style via its own siteStyle.\n */\nexport function postSiteStyleToLiveHosts(): void {\n const config = projectState?.projectConfig;\n if (!config) {\n return;\n }\n // Site config comes off a reactive store — only plain values may cross postMessage.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const siteStyle = JSON.parse(JSON.stringify(config.style ?? null)) as Record<\n string,\n unknown\n > | null;\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const media = JSON.parse(JSON.stringify(config.$media ?? {})) as Record<string, string>;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && !host.stylebook) {\n host.channel.post({ kind: \"siteStyleUpdate\", media, siteStyle });\n }\n }\n}\n\n/**\n * Post a live style update to every ready stylebook host (gen-tagged per host so a stale update is\n * dropped iframe-side; the superseding render carries the same style). Returns how many hosts\n * received it — zero means no stylebook iframe is live yet and the caller should fall through to a\n * full render. Each post is followed by a selection re-measure so the box tracks the reflow.\n */\nexport function postStyleUpdateToStylebookHosts(style: Record<string, unknown>): number {\n let posted = 0;\n // Style objects come off the reactive doc — only plain values may cross postMessage.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneable = JSON.parse(JSON.stringify(style)) as Record<string, unknown>;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && host.stylebook) {\n host.channel.post({ gen: host.lastRenderedGen, kind: \"styleUpdate\", style: cloneable });\n posted += 1;\n requestSelection(host, host.selectionPaths);\n }\n }\n return posted;\n}\n\n/**\n * Pan the canvas so the selected tag's card is centered (layers-panel \"locate\" affordance). The\n * card lives inside the iframe, so it is measured over the bridge and the reply pans by the\n * converted parent-viewport rect (see the `geometry` handler's panReqId branch).\n */\nexport function panToStylebookTag(tag: string): void {\n const host = hostForActivePanel();\n if (!host?.stylebook || !host.ready) {\n return;\n }\n const cardPath = host.stylebook.tagToCardPath.get(tag);\n if (!cardPath) {\n return;\n }\n host.selReqId += 1;\n host.panReqId = host.selReqId;\n host.channel.post({ kind: \"measure\", paths: [[...cardPath]], reqId: host.selReqId });\n}\n\n// ─── Format-toolbar bridge (Phase 4b-2) ─────────────────────────────────────────\n\n/** The current edit session's editing flag + latest selection snapshot, for the parent toolbar. */\nexport function getEditSnapshot(): {\n editing: boolean;\n editingProp: string | null;\n snapshot: SelectionSnapshot | null;\n} {\n /* The same connectivity guard {@link isCaretActive} has, and for the same reason: a session\n belongs to a frame, and a frame that has left the document has no caret in it. `releaseHost`\n clears `activeEditHost`, so this is the second line rather than the first — it covers the frame\n detached by something that never routed through a release (a `hardClearCanvasWrap`, a mode\n transition mid-session), where an unguarded `editing: true` keeps the format toolbar on screen\n anchored to nothing. */\n const host = activeEditHost;\n if (!host || !host.iframe.isConnected) {\n return { editing: false, editingProp: null, snapshot: null };\n }\n return {\n editing: host.editing,\n editingProp: host.editingProp,\n snapshot: host.snapshot,\n };\n}\n\n/**\n * The chord table every live canvas frame forwards against, and the source it is computed from.\n *\n * `setKeymapSource` is called once at bootstrap with the app's registry, and again by nothing:\n * {@link publishKeymap} re-reads it, so a rebinding in Preferences reaches the canvas by the host\n * calling `publishKeymap()` rather than by anyone holding a stale copy.\n */\nlet keymapSource: (() => { mac: boolean; chords: readonly SyncedChord[] }) | null = null;\n\n/**\n * Tell the host how to read the live chord table.\n *\n * Injected rather than imported so this module keeps its one direction of dependency: the canvas\n * host knows nothing about the command registry, and the bootstrap that owns both wires them.\n */\nexport function setKeymapSource(\n source: () => { mac: boolean; chords: readonly SyncedChord[] },\n onChange?: (listener: () => void) => () => void,\n): void {\n keymapSource = source;\n // A copy with no invalidation is a second authority that drifts. `onChange` fires when the user\n // Rebinds a key, and reposting is what makes Preferences › Keyboard reach inside the canvas —\n // Which three hand-written lists in `iframe-keys.ts` could never do.\n onChange?.(() => publishKeymap());\n publishKeymap();\n}\n\n/**\n * Send the current chord table to every live frame.\n *\n * Called on a frame's `ready` (so a newly mounted canvas is never guessing) and whenever the keymap\n * changes (so rebinding ⌘B in Preferences rebinds it inside the page too — the thing three\n * hand-written lists in `iframe-keys.ts` could never do).\n */\nexport function publishKeymap(): void {\n const table = keymapSource?.();\n if (!table) {\n return;\n }\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready) {\n host.channel.post({ chords: table.chords, kind: \"keymap\", mac: table.mac });\n }\n }\n}\n\n/** Post an `applyFormat` intent to the active edit host's iframe (no-op when none/not ready). */\nexport function postApplyFormat(intent: ApplyFormatIntent): void {\n const host = activeEditHost;\n if (!host || !host.ready) {\n return;\n }\n host.channel.post({ intent, kind: \"applyFormat\" });\n}\n\n/**\n * Ask the active edit host's iframe to open the slash menu at its caret.\n *\n * The same shape and the same guard as {@link postApplyFormat}: the caret lives in the other realm,\n * so a command in this one can only ask. `activeEditHost` is null when no session is live, which is\n * exactly when `insert.openSlashMenu` refuses.\n */\nexport function postOpenSlash(): void {\n const host = activeEditHost;\n if (!host || !host.ready) {\n return;\n }\n host.channel.post({ kind: \"openSlash\" });\n}\n\n/**\n * Ask the active edit host's iframe to commit-and-end its inline-edit session (no-op when none).\n * The parent calls this when intent leaves the edit surface in the PARENT realm — a tab switch, a\n * chrome click outside the edit toolbars — which the iframe cannot observe itself. The resulting\n * `editCommit` routes by the host's tabId, so a commit racing a tab switch still lands in the\n * document its session belonged to.\n */\nexport function commitActiveEditSession(): void {\n const host = activeEditHost;\n // `isConnected` too: posting into a removed frame is an optional-chained no-op inside the\n // Channel, so the caller is told the commit was requested when nothing received it.\n if (host?.editing && host.ready && host.iframe.isConnected) {\n host.channel.post({ kind: \"endEdit\" });\n }\n}\n\n/** The live host backing the active panel's canvas (for non-edit selection-bar positioning). */\nfunction hostForActivePanel(): HostState | null {\n const panel = getActivePanel();\n return panel ? hostForCanvas(panel.canvas as HTMLElement) : null;\n}\n\n/**\n * The format toolbar's anchor rect, in PARENT-VIEWPORT space (the bar is `position:fixed`). Both\n * source rects — the edit session's caret snapshot and the `lastSelectionRect` fallback — are in\n * UNSCALED iframe-viewport px (D-2: the overlay draws them inside the scaled panzoom-wrap, so the\n * browser applies the zoom there); the fixed bar gets no such free ride, so scale by the live\n * empirical zoom ({@link hostDragGeometry}) and add the iframe's on-screen offset, whose GBCR\n * already bakes in pan + zoom + ancestor scroll. The empirical ratio covers BOTH scale sources:\n * design mode's panzoom-wrap transform and edit mode's content-zoom counter-scale (where it\n * evaluates to exactly `editZoom` — the iframe's layout width is `renderWidth / editZoom` while its\n * rendered width is `renderWidth`).\n */\nexport function getEditBarAnchorRect(): ParentRect | null {\n // The format toolbar follows the live caret/selection snapshot of the active edit session; the\n // Structural bar (tag badge / parent selector / move / convert / drag handle) must still position\n // On a plain selection with no inline-edit session, so fall back to the active panel's host and\n // Its last measured selection rect.\n const editHost = activeEditHost;\n const host = editHost ?? hostForActivePanel();\n if (!host) {\n return null;\n }\n const { rect: ifr, scale } = hostDragGeometry(host);\n const snapRect = host === editHost ? host.snapshot?.rect : null;\n if (snapRect) {\n return {\n height: snapRect.height * scale,\n left: snapRect.x * scale + ifr.left,\n top: snapRect.y * scale + ifr.top,\n width: snapRect.width * scale,\n };\n }\n if (host.lastSelectionRect) {\n // The fallback rect is overlay-local (same top-left + coordinate space as the iframe viewport).\n return {\n height: host.lastSelectionRect.height * scale,\n left: host.lastSelectionRect.left * scale + ifr.left,\n top: host.lastSelectionRect.top * scale + ifr.top,\n width: host.lastSelectionRect.width * scale,\n };\n }\n return null;\n}\n",
47
+ "/// <reference lib=\"dom\" />\n/**\n * The one empty-state pattern.\n *\n * Every region in the shell that can be empty renders through {@link renderEmptyState} instead of\n * hand-writing its own block, so the copy rules below are inherited rather than re-decided:\n *\n * 1. **One sentence saying what the region is _for_.** Not what is absent — \"No state defined\" is a\n * dead end, \"Data this page can read, compute or fetch lives here\" tells you what it is.\n * 2. **The action that fills it**, as a real button that does the thing. Compact states that sit\n * directly above their own add form are the one exception: the form _is_ the action.\n * 3. **One shared verb across equivalent surfaces.** Everything that wants a canvas selection says\n * {@link clickAnythingTo}; everything that wants an open document offers\n * {@link openPageAction}.\n *\n * A region with no object to show renders one of these in its own words — it never paints a bare\n * container.\n */\n\nimport { html, nothing } from \"lit-html\";\nimport { classMap } from \"lit-html/directives/class-map.js\";\nimport type { TemplateResult } from \"lit-html\";\n\n/** A button offered by an empty state. */\nexport interface EmptyStateAction {\n /** Imperative naming what happens — \"Add a value\", not \"Go to the Data panel\". */\n label: string;\n /** Optional Spectrum icon. Must carry `slot=\"icon\"`. */\n icon?: TemplateResult;\n run: () => void;\n disabled?: boolean;\n}\n\nexport interface EmptyStateSpec {\n /** One sentence: what this region is for. */\n message: string;\n /** Optional second sentence: where its content comes from. */\n detail?: string;\n /** The action(s) that fill the region. */\n actions?: EmptyStateAction[];\n /** An inline section inside an otherwise populated panel — tighter and left-aligned. */\n compact?: boolean;\n}\n\n/** The one verb every selection-driven surface shares. */\nexport const CANVAS_VERB = \"Click anything on the canvas\";\n\n/**\n * The shared selection prompt. `outcome` completes \"…to ⟨outcome⟩\": \"edit its content\", \"style it\",\n * \"wire it up\". Every inspector surface phrases its requirement this way so the rail does not read\n * as three different requirements.\n */\nexport function clickAnythingTo(outcome: string): string {\n return `${CANVAS_VERB} to ${outcome}.`;\n}\n\n/** Told the user something is gone: name it, then hand back the shared verb. */\nexport function staleSelectionMessage(): string {\n return `That element is no longer on the page. ${clickAnythingTo(\"pick another one\")}`;\n}\n\n/**\n * The one action every \"needs an open document\" empty state offers.\n *\n * Quick Access is reached through a lazy import on purpose: this module is imported by every panel\n * in the shell, and a static edge would drag the file browser, the format host and the recents\n * store into all of them. P2 replaces the closure with a command id.\n */\nexport function openPageAction(label = \"Open a page…\"): EmptyStateAction {\n return {\n label,\n run: () => {\n void import(\"./quick-search.js\").then((m) => {\n m.openQuickSearch();\n });\n },\n };\n}\n\n/** Render an empty state. */\nexport function renderEmptyState(spec: EmptyStateSpec): TemplateResult {\n const actions = spec.actions ?? [];\n return html`\n <div\n class=${classMap({\n \"empty-state\": true,\n \"empty-state--compact\": Boolean(spec.compact),\n \"empty-state--teach\": true,\n })}\n >\n <p class=\"empty-state-message\">${spec.message}</p>\n ${spec.detail ? html`<p class=\"empty-state-detail\">${spec.detail}</p>` : nothing}\n ${\n actions.length > 0\n ? html`<div class=\"empty-state-actions\">\n ${actions.map(\n (action) => html`\n <sp-action-button\n size=\"s\"\n class=\"empty-state-action\"\n ?disabled=${Boolean(action.disabled)}\n @click=${() => action.run()}\n >${action.icon ?? nothing}${action.label}</sp-action-button\n >\n `,\n )}\n </div>`\n : nothing\n }\n </div>\n `;\n}\n",
48
+ "/**\n * Levels.ts — the containment taxonomy and the level × placement matrix.\n *\n * Two vocabularies live here, and keeping them apart is the whole point (UX-REDESIGN-PLAN §5.1):\n *\n * - {@link Level} answers WHAT a record acts on. It governs placement and is CI-checked.\n * - {@link KeyScope} answers WHERE a chord is live. It governs keyboard dispatch only.\n *\n * Conflating them is how \"position encodes scope\" degrades into unenforced prose. The clearest case\n * is inline text formatting: Bold acts on a text range inside the selected node, so its `level` is\n * `selection`, while its `keyScope` is `caret` — which is what makes the chord live only when a\n * caret exists. There is deliberately no `range` level; a fifth level would demand a fifth region\n * and there is none.\n *\n * {@link PLACEMENT_MATRIX} is the normative table: each placement declares the set of levels it\n * admits. Mixed regions are mixed IN THE TABLE, never by prose exemption — the status bar is three\n * separate single-level placements, not one \"mixed\" one. `scripts/check-command-levels.ts`\n * validates every registered command's `menus` against this table, and `createCommandRegistry`\n * applies the same check at registration so a violation cannot reach a running app either.\n *\n * Panel placements (the two rail groups, the navigator dock body, the bottom dock, the inspector\n * dock) are part of the same matrix in `studio-ui-guidelines.md` §12 and live here too, in\n * {@link PANEL_PLACEMENT_MATRIX}: `registerPanel()` (`panels/panel-registry.ts`) now exists, so a\n * Panel record declares a `level` for the same reason a Command does and is checked the same way.\n * The two tables are separate because their placement VOCABULARIES are disjoint — a command is\n * never \"in the rail's upper group\", and a panel is never \"in the block action bar\".\n */\n\n/** Containment level — WHAT a record acts on. Governs placement. CI-checked. */\nexport const LEVELS = [\"application\", \"project\", \"document\", \"selection\"] as const;\n\nexport type Level = (typeof LEVELS)[number];\n\n/** Keyboard dispatch scope — WHERE a chord is live. Orthogonal to {@link Level}. */\nexport const KEY_SCOPES = [\"global\", \"canvas\", \"caret\", \"grid\", \"code\", \"dock\", \"palette\"] as const;\n\nexport type KeyScope = (typeof KEY_SCOPES)[number];\n\n/** Command categories. The palette renders rows as \"<Category>: <title>\". */\nexport const CATEGORIES = [\n \"File\",\n \"Edit\",\n \"Selection\",\n \"Insert\",\n \"View\",\n \"Document\",\n \"Project\",\n \"Source Control\",\n \"Publish\",\n \"Assistant\",\n \"Collaborate\",\n \"Help\",\n] as const;\n\nexport type Category = (typeof CATEGORIES)[number];\n\n/** Every surface a command may declare itself into. `\"never\"` means keyboard/API only. */\nexport const PLACEMENTS = [\n \"commandbar/primary\",\n \"commandbar/overflow\",\n \"statusbar/project\",\n \"statusbar/document\",\n \"statusbar/selection\",\n \"context/element\",\n \"context/file\",\n \"context/layer\",\n \"context/tab\",\n \"context/pane\",\n \"blockbar\",\n /**\n * The block action bar's SECOND cluster — inline formatting, shown while the caret is in text.\n *\n * A separate placement rather than a crowd inside `blockbar`, for the reason the status bar is\n * three placements and not one \"mixed\" region: the bar's verb cluster is capped at five, and\n * eight format verbs sharing that cap would push Bold into a `⋮` menu. Same level, same surface,\n * different budget — which is a row in the table, not an exemption in prose.\n */\n \"blockbar/format\",\n \"outline/row\",\n \"palette\",\n \"never\",\n] as const;\n\nexport type Placement = (typeof PLACEMENTS)[number];\n\n/** One row of the matrix: the levels a placement admits, plus why it is drawn that way. */\nexport interface PlacementRule {\n /** Levels this placement accepts. A command declaring any other level is a CI failure. */\n admits: readonly Level[];\n /** The reason, printed in the violation message so the fix is obvious from the failure. */\n note: string;\n}\n\n/**\n * The level × placement matrix — normative copy, mirrored into `studio-ui-guidelines.md` §12.\n *\n * Read a row as: \"this region renders records of these levels, and nothing else.\"\n */\nexport const PLACEMENT_MATRIX: Readonly<Record<Placement, PlacementRule>> = {\n \"commandbar/primary\": {\n admits: [\"application\", \"document\"],\n note: \"document only for Save / Undo / Redo / Open in Browser, by frequency; ≤5 total\",\n },\n \"commandbar/overflow\": {\n admits: [\"application\", \"project\", \"document\"],\n note: \"never selection — the Command Bar is not a selection surface\",\n },\n \"statusbar/project\": { admits: [\"project\"], note: \"the status bar's left field\" },\n \"statusbar/document\": { admits: [\"document\"], note: \"the status bar's centre field\" },\n \"statusbar/selection\": { admits: [\"selection\"], note: \"the status bar's right field\" },\n \"context/element\": { admits: [\"selection\"], note: \"the canvas element menu acts on a selection\" },\n \"context/file\": { admits: [\"project\"], note: \"a file row addresses the project's file set\" },\n \"context/layer\": { admits: [\"selection\"], note: \"an outline row IS a selection\" },\n \"context/tab\": { admits: [\"document\"], note: \"a tab addresses one document\" },\n \"context/pane\": { admits: [\"document\"], note: \"a pane hosts one document\" },\n blockbar: { admits: [\"selection\"], note: \"the floating bar owns selection-scoped verbs\" },\n \"blockbar/format\": {\n admits: [\"selection\"],\n note: \"the bar's inline-format cluster — a range inside the selection is still the selection\",\n },\n \"outline/row\": { admits: [\"selection\"], note: \"row actions act on the row's node\" },\n palette: {\n admits: [\"application\", \"project\", \"document\", \"selection\"],\n note: \"the level-agnostic surface; it groups rows by level\",\n },\n never: {\n admits: [\"application\", \"project\", \"document\", \"selection\"],\n note: \"keyboard- and API-only; no rendered surface to be misplaced in\",\n },\n};\n\n// ─── Panels ───────────────────────────────────────────────────────────────────\n\n/**\n * Every surface a Panel record may occupy.\n *\n * The rail's two level groups are SEPARATE placements, not one \"mixed\" region — principle 2's whole\n * point. `navigator` is the dock body below them, which hosts whichever panel the rail selected and\n * prints that panel's level in its header, so it is the one panel placement admitting two levels.\n */\nexport const PANEL_PLACEMENTS = [\n \"rail/project\",\n \"rail/document\",\n \"navigator\",\n \"inspector\",\n \"dock.bottom\",\n] as const;\n\nexport type PanelPlacement = (typeof PANEL_PLACEMENTS)[number];\n\n/**\n * The level × placement matrix for Panel records — normative copy, mirrored into\n * `studio-ui-guidelines.md` §12 beside {@link PLACEMENT_MATRIX}.\n *\n * The rail rows are what stop it re-accreting: a panel cannot be filed in the PROJECT group because\n * \"it feels project-ish\", only because the state it WRITES is the project's (principle 3).\n */\nexport const PANEL_PLACEMENT_MATRIX: Readonly<Record<PanelPlacement, PlacementRule>> = {\n \"rail/project\": {\n admits: [\"project\"],\n note: \"the rail's upper group — Files, Search, Source Control, Problems\",\n },\n \"rail/document\": {\n admits: [\"document\"],\n note: \"the rail's lower group — Outline, Page, Data, Packages\",\n },\n navigator: {\n admits: [\"project\", \"document\"],\n note: \"whichever level the hosted panel declares; the panel header prints it\",\n },\n inspector: { admits: [\"selection\"], note: \"the Inspector's tabs are selection surfaces\" },\n \"dock.bottom\": { admits: [\"project\", \"document\"], note: \"the panel header states which\" },\n};\n\n/** The subset of a Panel record this check reads. */\nexport interface PlaceablePanel {\n id: string;\n level: Level;\n /** The dock hosting the panel's body. */\n dock: \"navigator\" | \"inspector\" | \"bottom\";\n /** `false` for a panel with no rail button — it declares no rail-group placement. */\n rail?: boolean | undefined;\n}\n\n/** One rejected (panel, placement) pair. Shaped like {@link PlacementViolation}, keyed by panel. */\nexport interface PanelPlacementViolation {\n panelId: string;\n placement: string;\n level: string;\n message: string;\n}\n\n/** The dock body placement a panel's `dock` names. */\nfunction dockPlacement(dock: PlaceablePanel[\"dock\"]): PanelPlacement {\n return dock === \"bottom\" ? \"dock.bottom\" : dock;\n}\n\n/**\n * Every placement a Panel record occupies: its dock body, plus its rail group when it has a button.\n *\n * The rail group is DERIVED from the level rather than declared, which is what makes \"grouped by\n * level with a divider\" (§3.2 ②) a property of the data instead of an ordering convention in the\n * rail's template. A rail panel whose level has no group (`application`, `selection`) therefore\n * names a placement the matrix does not contain, and is rejected below.\n */\nexport function panelPlacements(panel: PlaceablePanel): string[] {\n const placements: string[] = [dockPlacement(panel.dock)];\n if (panel.rail !== false) {\n placements.push(`rail/${panel.level}`);\n }\n return placements;\n}\n\n/** Whether `value` is one of the {@link PANEL_PLACEMENTS}. */\nexport function isPanelPlacement(value: string): value is PanelPlacement {\n return (PANEL_PLACEMENTS as readonly string[]).includes(value);\n}\n\n/** Check one Panel record against {@link PANEL_PLACEMENT_MATRIX}. */\nexport function checkPanelPlacement(panel: PlaceablePanel): PanelPlacementViolation[] {\n const violations: PanelPlacementViolation[] = [];\n if (!isLevel(panel.level)) {\n violations.push({\n panelId: panel.id,\n placement: \"—\",\n level: String(panel.level),\n message:\n `declares unknown level \"${String(panel.level)}\" ` +\n `(expected one of: ${LEVELS.join(\", \")})`,\n });\n return violations;\n }\n for (const placement of panelPlacements(panel)) {\n if (!isPanelPlacement(placement)) {\n violations.push({\n panelId: panel.id,\n placement,\n level: panel.level,\n message:\n `is level \"${panel.level}\" and would render in \"${placement}\", which is not a panel ` +\n `placement — the rail has a group for project and one for document, and nothing else`,\n });\n continue;\n }\n const rule = PANEL_PLACEMENT_MATRIX[placement];\n if (!rule.admits.includes(panel.level)) {\n violations.push({\n panelId: panel.id,\n placement,\n level: panel.level,\n message:\n `is level \"${panel.level}\" but \"${placement}\" admits only ` +\n `${rule.admits.join(\", \")} — ${rule.note}`,\n });\n }\n }\n return violations;\n}\n\n/** Check a whole panel set. Empty result = the set satisfies the matrix. */\nexport function checkPanelPlacements(panels: readonly PlaceablePanel[]): PanelPlacementViolation[] {\n return panels.flatMap((panel) => checkPanelPlacement(panel));\n}\n\n// ─── Commands ─────────────────────────────────────────────────────────────────\n\n/** The subset of a command record the placement check needs. */\nexport interface PlaceableRecord {\n id: string;\n level: Level;\n menus?: readonly Placement[] | undefined;\n}\n\n/** One rejected (command, placement) pair. */\nexport interface PlacementViolation {\n commandId: string;\n placement: string;\n level: string;\n /** Ready-to-print explanation: what was declared, what the row admits, and why. */\n message: string;\n}\n\n/** Whether `placement` is one of the {@link PLACEMENTS}. */\nexport function isPlacement(value: string): value is Placement {\n return (PLACEMENTS as readonly string[]).includes(value);\n}\n\n/** Whether `level` is one of the {@link LEVELS}. */\nexport function isLevel(value: string): value is Level {\n return (LEVELS as readonly string[]).includes(value);\n}\n\n/** Whether the matrix lets a `level` record render in `placement`. */\nexport function placementAdmits(placement: Placement, level: Level): boolean {\n return PLACEMENT_MATRIX[placement].admits.includes(level);\n}\n\n/**\n * Check one record's declared placements against the matrix.\n *\n * A record with no `menus` defaults to `[\"palette\"]`, which admits every level, so the default is\n * always legal — a command has to opt IN to a region before it can be misplaced.\n */\nexport function checkRecordPlacements(record: PlaceableRecord): PlacementViolation[] {\n const violations: PlacementViolation[] = [];\n if (!isLevel(record.level)) {\n violations.push({\n commandId: record.id,\n placement: \"—\",\n level: String(record.level),\n message:\n `declares unknown level \"${String(record.level)}\" ` +\n `(expected one of: ${LEVELS.join(\", \")})`,\n });\n return violations;\n }\n for (const placement of record.menus ?? []) {\n if (!isPlacement(placement)) {\n violations.push({\n commandId: record.id,\n placement: String(placement),\n level: record.level,\n message: `declares unknown placement \"${String(placement)}\"`,\n });\n continue;\n }\n const rule = PLACEMENT_MATRIX[placement];\n if (!rule.admits.includes(record.level)) {\n violations.push({\n commandId: record.id,\n placement,\n level: record.level,\n message:\n `is level \"${record.level}\" but \"${placement}\" admits only ` +\n `${rule.admits.join(\", \")} — ${rule.note}`,\n });\n }\n }\n return violations;\n}\n\n/** Check a whole command set. Empty result = the set satisfies the matrix. */\nexport function checkPlacements(records: readonly PlaceableRecord[]): PlacementViolation[] {\n return records.flatMap((record) => checkRecordPlacements(record));\n}\n",
49
+ "/// <reference lib=\"dom\" />\n/**\n * Panel-registry.ts — one definition site per panel.\n *\n * A {@link PanelRecord} is to a surface what a `Command` is to an action: its name, the containment\n * level of the state it WRITES, the dock that hosts it, the predicate that decides whether it\n * exists at all, and the function that draws it. The rail, the panel header and the dock budget\n * become RENDERINGS of these records — plan §2 principle 1, applied to regions rather than verbs.\n *\n * It mirrors the shipped `settings/settings-modal.ts` contribution point\n * (`registerSettingsSection`) deliberately: a module-level `Map`, keyed by id, written by the\n * module that OWNS the surface. The one thing it adds is the field that makes the rail derivable —\n *\n * **`level` is required, and it is the level of the state the panel WRITES, not the state it\n * reads** (plan §2 principle 3). Insert reads the project's component registry and writes the\n * document tree, so it is `document`. Files reads documents and writes project files, so it is\n * `project`. That rule, and not intuition, is what settles every contested placement and what stops\n * the rail re-accreting: the two rail groups are two rows of\n * {@link\n * import(\"../commands/levels\").PANEL_PLACEMENT_MATRIX}, checked at registration exactly the\n * way a command's `menus` are.\n *\n * The predecessor was an eight-item array literal inside `panels/activity-bar.ts` — `{icon, label,\n * value}` — beside an eight-branch `if` chain in `panels/left-panel.ts` and a third list in\n * `shell.ts`. Three places to keep in step, none of which recorded what a panel was FOR.\n */\n\nimport { resolveI18n } from \"@jxsuite/schema/locale\";\nimport { checkPanelPlacement } from \"../commands/levels\";\nimport { emptyContext } from \"../commands/context\";\nimport { projectState } from \"../store\";\nimport { shell } from \"../shell\";\nimport { activeTab } from \"../workspace/workspace\";\nimport type { Level } from \"../commands/levels\";\nimport type { CommandContext } from \"../commands/context\";\nimport type { GitDiffState } from \"../types\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\nimport type { JxPath } from \"../state\";\nimport type { Tab, TabUi } from \"../tabs/tab\";\nimport type { nothing, TemplateResult } from \"lit-html\";\nimport type { renderGitPanel } from \"./git-panel\";\nimport type { renderHeadTemplate } from \"./head-panel\";\nimport type { renderImportsTemplate } from \"./imports-panel\";\nimport type { renderSignalsTemplate } from \"./signals-panel\";\n\n/**\n * The three docks that host panels.\n *\n * A panel's dock is where its BODY is drawn. Every rail button opens the NAVIGATOR, so a record\n * outside it is `rail: false` and is addressed by name instead — `view.setBottomTab` for the four\n * Bottom-dock tabs. The two were briefly independent, for Problems alone, and the cost was a\n * per-dock branch in three separate places plus a left-hand control that opened something along the\n * bottom. The Inspector has no records yet.\n */\nexport type PanelDock = \"navigator\" | \"inspector\" | \"bottom\";\n\n/**\n * What a Navigator panel is handed that its own module cannot import.\n *\n * This is `left-panel.ts`'s old `LeftPanelCtx`, moved to the registry because it is now the panel\n * CONTRACT rather than one orchestrator's private argument list. `studio.ts` still builds it: the\n * renderers it injects (the file tree, the head panel, the git panel) close over bootstrap state,\n * and injecting them is what keeps `panels/*` free of an import cycle back through `studio.ts`.\n */\nexport interface NavigatorPanelDeps {\n getCanvasMode: () => string;\n setCanvasMode: (tab: Tab | null, mode: string) => void;\n // Typed against their implementations so every call site stays checked. These are type-only\n // Imports, so they are erased — the modules themselves are never pulled in through this file.\n renderImportsTemplate: typeof renderImportsTemplate;\n renderFilesTemplate: () => TemplateResult;\n renderSignalsTemplate: typeof renderSignalsTemplate;\n renderHeadTemplate: typeof renderHeadTemplate;\n renderGitPanel: typeof renderGitPanel;\n renderCanvas: () => void;\n /** Canvas re-render that also lets automatic `Request` entries fetch (Data panel Refresh). */\n refreshData: () => void;\n defCategory: (def: unknown) => string;\n defBadgeLabel: (def: unknown) => string;\n navigateToComponent: (path: string) => void;\n webdata: Record<string, unknown>;\n defaultDef: (tag: string) => Record<string, unknown>;\n registerLayersDnD: () => void;\n registerElementsDnD: () => void;\n registerComponentsDnD: () => void;\n setupTreeKeyboard: (tree: HTMLElement) => void;\n registerFileTreeDnD: (ctx: { renderLeftPanel: () => void }) => void;\n setGitDiffState: (state: GitDiffState | null) => void;\n cloneRepository?: () => void;\n}\n\n/**\n * The focused document, as a document-level panel reads it. `null` when no tab is open.\n *\n * A `level: \"project\"` panel must not read this — that is principle 3's corollary, and the reason\n * the Source Control badge used to vanish when the last tab closed. {@link registerPanel} cannot\n * enforce it (a closure's imports are not inspectable), so the contract is stated here and asserted\n * by `tests/panel-registry.test.ts`, which renders every project-level panel with `doc: null`.\n */\nexport interface NavigatorDocument {\n document: JxMutableNode;\n mode: string;\n /** The whole selection SET the navigator/inspector panels render against (§6.5). */\n selection: JxPath[];\n canvas: Record<string, unknown> | null;\n content?: { frontmatter?: Record<string, unknown> } | undefined;\n documentPath?: string | null | undefined;\n ui: TabUi;\n}\n\n/** Everything a panel's `render` receives. One argument, so a record stays a one-liner. */\nexport interface NavigatorPanelContext {\n deps: NavigatorPanelDeps;\n /** The focused document, or `null`. Document-level panels render their empty state on `null`. */\n doc: NavigatorDocument | null;\n /** Repaint the Navigator — `left-panel.ts`'s scheduler, not a synchronous re-render. */\n rerender: () => void;\n}\n\n/** A panel's rendered body. `nothing` is legal — an empty panel is a state, not a bug. */\nexport type PanelBody = TemplateResult | typeof nothing;\n\n/** One panel, defined once. */\nexport interface PanelRecord {\n /** Lowercase, stable, and the value `view.setActivity` accepts — renaming one is a shot break. */\n id: string;\n /** The human name. The rail label AND the panel header, so there is one place it is spelled. */\n title: string;\n /** REQUIRED. The level of the state this panel WRITES. Checked against the panel matrix. */\n level: Level;\n dock: PanelDock;\n /** Icon key, resolved through `activity-bar.ts`'s `tabIcon()` map. */\n icon: string;\n /**\n * `false` for a panel with no rail button.\n *\n * Not a hiding mechanism — a rail-less panel is still reachable by `view.setActivity`, by the\n * palette and by another surface linking to it. It is how a record survives the interval between\n * losing its rail slot and gaining its real home (Insert becomes an overlay in P3.5; State folds\n * into Data). Declaring it `false` also removes the panel's `rail/<level>` placement, which is\n * what keeps the rail inside its four-per-group budget.\n */\n rail?: boolean;\n /**\n * The sentence a document-level panel shows instead of its body when no document is open.\n *\n * Said in the words of the thing the panel needs (\"Open a page to see the elements it is built\n * from.\"), so the ring collapses to a sentence rather than to an empty box. Absent means the\n * panel renders with `doc: null` — Insert does, because an element palette is meaningful before\n * you have chosen where to put anything.\n */\n requiresDocument?: string;\n /** Hide entirely — for a surface that does not exist yet. Default: always present. */\n when?: (ctx: CommandContext) => boolean;\n /** The rail badge, e.g. Source Control's changed-file count. `null`/`0` renders nothing. */\n badge?: (ctx: CommandContext) => number | string | null;\n render: (ctx: NavigatorPanelContext) => PanelBody;\n /**\n * Imperative work that needs the painted DOM — drag registrations, tree keyboard wiring.\n *\n * The eight `if (tab === …)` post-render branches `left-panel.ts` carried, moved onto the records\n * that caused them, so adding a panel cannot forget to drain the previous one's registrations.\n */\n afterRender?: (ctx: NavigatorPanelContext, host: HTMLElement) => void;\n}\n\n/**\n * The context a panel's `when` and `badge` are evaluated against.\n *\n * A SUBSET of the command context, built from the two records a panel predicate has ever needed:\n * the reactive `shell` (project-level source control, hoisted off `TabUi` for exactly this reason)\n * and `projectState`. Reading it inside a rendering effect is what makes the rail repaint when the\n * working tree changes, because both reads are tracked.\n *\n * **A key a panel gates on has to be here.** A subset is only safe while it covers every predicate\n * actually written: `isMultilingual` was declared, computed in `live-context.ts`, and left out of\n * this one — so the Languages panel's `when` read the `emptyContext()` default, and the Navigator\n * answered \"No Navigator panel is registered as i18n\" on a project that declares three languages.\n * Nothing failed; the panel was simply never visible.\n *\n * It is deliberately not `createLiveContext()`: that builder needs four facts only `studio.ts` can\n * inject (the canvas mode, the caret, the modal flag, the platform), and a rail that imported the\n * bootstrap to draw a badge would be the import cycle `live-context.ts` documents avoiding. When\n * the bootstrap wires panels the same way it wires commands, this function is what it replaces.\n */\nexport function panelContext(): CommandContext {\n const ctx = emptyContext();\n ctx.project.open = projectState !== null;\n ctx.project.isMultilingual =\n (resolveI18n(projectState?.projectConfig ?? {}).i18n?.locales.length ?? 0) > 1;\n ctx.git.dirtyCount = shell.git.status?.files?.length ?? 0;\n ctx.document.open = activeTab.value !== null;\n return ctx;\n}\n\n/** `[a-z]` then word characters — the same shape `navigator/panel:<id>` is matched by. */\nconst PANEL_ID_PATTERN = /^[a-z][\\w-]*$/;\n\nconst panelRegistry = new Map<string, PanelRecord>();\n\n/**\n * Define a panel. Throws on a duplicate id, a malformed id, or a matrix violation.\n *\n * Failing at registration is the same bet `createCommandRegistry.register` makes: a misplaced\n * surface is a design error, and a design error that only shows up as a wrong-looking rail is a\n * design error nobody fixes.\n *\n * @param {PanelRecord} panel\n */\nexport function registerPanel(panel: PanelRecord): void {\n if (!PANEL_ID_PATTERN.test(panel.id)) {\n throw new Error(\n `Panel id \"${panel.id}\" is malformed — expected /^[a-z][\\\\w-]*$/, because the id is also ` +\n `the region \"navigator/panel:${panel.id}\" and the value view.setActivity accepts.`,\n );\n }\n if (panelRegistry.has(panel.id)) {\n throw new Error(\n `Panel \"${panel.id}\" is already registered — a second definition site is the defect this ` +\n `registry exists to prevent.`,\n );\n }\n const violations = checkPanelPlacement({\n id: panel.id,\n level: panel.level,\n dock: panel.dock,\n rail: panel.rail,\n });\n if (violations.length > 0) {\n const detail = violations.map((violation) => ` ✗ ${panel.id} ${violation.message}`).join(\"\\n\");\n throw new Error(`Panel \"${panel.id}\" violates the level × placement matrix:\\n${detail}`);\n }\n panelRegistry.set(panel.id, panel);\n}\n\n/** Remove a panel — the contributed-extension path, and the reset every test needs. */\nexport function unregisterPanel(id: string): void {\n panelRegistry.delete(id);\n}\n\n/** Drop every registration. Tests only; the app registers once, at mount. */\nexport function resetPanels(): void {\n panelRegistry.clear();\n}\n\n/** One panel by id, or `undefined`. */\nexport function getPanel(id: string): PanelRecord | undefined {\n return panelRegistry.get(id);\n}\n\n/** Every registered panel, in registration order — which is rail order. */\nexport function listPanels(dock?: PanelDock): readonly PanelRecord[] {\n const all = [...panelRegistry.values()];\n return dock ? all.filter((panel) => panel.dock === dock) : all;\n}\n\n/** Whether a panel's `when` admits it in this context. A record with no `when` always does. */\nexport function isPanelVisible(panel: PanelRecord, ctx: CommandContext): boolean {\n return panel.when ? panel.when(ctx) : true;\n}\n\n/** One rail group: the level it hosts, its heading, and the panels in it. */\nexport interface RailGroup {\n level: Level;\n /** The group's accessible name — \"Project\" / \"Document\", the levels said out loud. */\n label: string;\n panels: readonly PanelRecord[];\n}\n\n/** The rail's two groups, in shell order. `application` and `selection` have no group. */\nconst RAIL_GROUP_LEVELS: readonly { level: Level; label: string }[] = [\n { level: \"project\", label: \"Project\" },\n { level: \"document\", label: \"Document\" },\n];\n\n/**\n * Every panel that has a rail button, whatever dock draws its body.\n *\n * The rail is NOT the Navigator's tab strip. `panelPlacements()` has always awarded `rail/<level>`\n * on `rail !== false` alone — the dock is a separate placement — and Problems is the panel that\n * proves it: its body is the Bottom dock's first tab (plan §7.2), and it still owns a rail slot and\n * a badge, because \"how many things need fixing\" is a question you ask without opening anything.\n * Filtering this by `dock === \"navigator\"` is what would put the same list in two hosts at once.\n */\nfunction railablePanels(): readonly PanelRecord[] {\n return listPanels().filter((panel) => panel.rail !== false);\n}\n\n/**\n * The rail, as data: every rail-able panel, grouped by level, `when`-filtered.\n *\n * Empty groups are dropped, so the divider between them is never drawn against nothing.\n *\n * @param {CommandContext} ctx\n */\nexport function railGroups(ctx: CommandContext): RailGroup[] {\n const railable = railablePanels();\n return RAIL_GROUP_LEVELS.map(({ level, label }) => ({\n level,\n label,\n panels: railable.filter((panel) => panel.level === level && isPanelVisible(panel, ctx)),\n })).filter((group) => group.panels.length > 0);\n}\n\n/**\n * The rail's panels flattened into rail order — PROJECT group, then DOCUMENT group.\n *\n * This is the order ⌘1–8 follow, and it is derived from the same two rows the rail draws rather\n * than from registration order, so a panel registered by its dock's module (Problems, from\n * `panels/bottom-dock.ts`) still lands in the slot its LEVEL gives it. `when` is not applied: a\n * chord roster that changed length with context would move every chord after the hidden panel.\n */\nexport function railPanelSet(): PanelRecord[] {\n const railable = railablePanels();\n return RAIL_GROUP_LEVELS.flatMap(({ level }) =>\n railable.filter((panel) => panel.level === level),\n );\n}\n\n/** One tabbed region and what it declares, in `commands/budget.ts`'s shape. */\nexport interface PanelDockDeclaration {\n dock: string;\n tabs: readonly string[];\n}\n\n/**\n * The rail's two groups as budget declarations — the `rail/*` rows `scripts/check-chrome-budget.ts`\n * counts, observed rather than written down. `commands/budget.ts` no longer carries a copy.\n *\n * `when` is deliberately NOT applied: the budget caps what the shell may GROW to, not what happens\n * to be visible in one context. Search is registered and hidden today, and it still spends its rail\n * slot — which is the point, because its arrival must not silently push the rail to five.\n */\nexport function railDeclarations(): PanelDockDeclaration[] {\n const railable = railablePanels();\n return RAIL_GROUP_LEVELS.map(({ level }) => ({\n dock: `rail/${level}`,\n tabs: railable.filter((panel) => panel.level === level).map((panel) => panel.title),\n })).filter((declaration) => declaration.tabs.length > 0);\n}\n"
50
+ ],
51
+ "mappings": "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",
52
+ "debugId": "E01F4562BAD57C3264756E2164756E21",
53
+ "names": []
54
+ }